#! /usr/bin/python3 from app import app, db from app.models.users import Member, Group, GroupPrivilege from app.models.privs import SpecialPrivilege from app.models.trophies import Trophy, Title, TrophyMember from app.models.forum import Forum from app.utils import unicode_names import os import sys import yaml import readline import slugify from PIL import Image help_msg = """ This is the Planète Casio master shell. Type 'exit' or C-D to leave. Type a category name to see a list of elements. Available categories are: 'members' Registered community members 'groups' Privilege groups 'trophies' Trophies 'trophy-members' Trophies owned by members 'forums' Forum tree Type a category name followed by 'clear' to remove all entries in the category. Type 'create-groups-and-privs' to recreate all groups and privileges to the default. This function generates a minimal set of groups and members to prepare the database. 1. Deletes all groups 2. Creates groups 'Administrateur', 'Modérateur', 'Développeur', 'Rédacteur', 'Responsable Communauté', 'Partenaire', 'Compte communautaire', 'Robot', and 'Membre de CreativeCalc' 3. Grants privileges related to these groups 4. Recreates common accounts: 'Planète Casio' (community account) and 'GLaDOS' (robot) Type 'add-group #' to add a new member to a group. Type 'create-trophies' to reset trophies and titles and their icons. Type 'create-forums' to reset the forum tree. """ # # Category viewers # def members(*args): if args == ("clear",): for m in Member.query.all(): m.delete() db.session.commit() print("Removed all members.") return for m in Member.query.all(): print(m) def groups(*args): if args == ("clear",): for g in Group.query.all(): g.delete() db.session.commit() print("Removed all groups.") return for g in Group.query.all(): print(f"#{g.id} {g.name}") def trophies(*args): if args == ("clear",): for t in Trophy.query.all(): db.session.delete(t) db.session.commit() print("Removed all trophies.") return for t in Trophy.query.all(): print(t) def trophy_members(*args): for t in Trophy.query.all(): if t.owners == []: continue print(t) for m in t.owners: print(f" {m}") def forums(*args): if args == ("clear",): for f in Forum.query.all(): db.session.delete(f) db.session.commit() print("Removed all forums.") return for f in Forum.query.all(): parent = f"in {f.parent.url}" if f.parent is not None else "root" print(f"{f.url} ({parent}) [{f.prefix}]: {f.name}") print(f" {f.descr}") # # Creation and edition # def create_groups_and_privs(): # Clean up groups groups("clear") # Create base groups gr = [] with open(os.path.join(app.root_path, "data", "groups.yaml")) as fp: gr = yaml.safe_load(fp.read()) for g in gr: g["obj"] = Group(g["name"], g["css"], g["descr"]) db.session.add(g["obj"]) db.session.commit() for g in gr: for priv in g.get("privs", "").split(): db.session.add(GroupPrivilege(g["obj"], priv)) db.session.commit() print(f"Created {len(gr)} groups.") # Clean up test members for name in "PlanèteCasio GLaDOS".split(): m = Member.query.filter_by(name=name).first() if m is not None: m.delete() print("Removed test members.") # Create template members def addgroup(member, group): g = Group.query.filter_by(name=group).first() if g is not None: member.groups.append(g) m = Member("PlanèteCasio", "contact@planet-casio.com", "nologin") addgroup(m, "Compte communautaire") addgroup(m, "No login") db.session.add(m) m = Member("GLaDOS", "glados@aperture.science", "nologin") m.xp = 1338 addgroup(m, "Robot") addgroup(m, "No login") db.session.add(m) db.session.commit() db.session.add(SpecialPrivilege(m, "edit-posts")) db.session.add(SpecialPrivilege(m, "shoutbox-ban")) db.session.commit() print(f"Created 2 test members with some privileges.") def create_trophies(): # Clean up trophies trophies("clear") # Create base trophies tr = [] with open(os.path.join(app.root_path, "data", "trophies.yaml")) as fp: tr = yaml.safe_load(fp.read()) for t in tr: description = t.get("description", "") if t["is_title"]: trophy = Title(t["name"], description, t["hidden"], t.get("css", "")) else: trophy = Trophy(t["name"], description, t["hidden"]) db.session.add(trophy) db.session.commit() print(f"Created {len(tr)} trophies.") # Create their icons in /app/static/images/trophies names = [ slugify.slugify(t["name"]) for t in tr ] src = os.path.join(app.root_path, "data", "trophies.png") dst = os.path.join(app.root_path, "static", "images", "trophies") try: os.mkdir(dst) except FileExistsError: pass img = Image.open(src) def trophy_iterator(img): for y in range(img.height // 26): for x in range(img.width // 26): icon = img.crop((26*x+1, 26*y+1, 26*x+25, 26*y+25)) # Skip blank squares in the source image if len(icon.getcolors()) > 1: yield icon.resize((48,48)) for (name, icon) in zip(names, trophy_iterator(img)): icon.save(os.path.join(dst, f"{name}.png")) def create_forums(): # Clean up forums forums("clear") # Create the forum tree fr = [] success = 0 with open(os.path.join(app.root_path, "data", "forums.yaml")) as fp: fr = yaml.safe_load(fp.read()) for url, f in fr.items(): if url == "/": parent = None else: parent_url = url.rsplit('/', 1)[0] if parent_url == "": parent_url = "/" parent = Forum.query.filter_by(url=parent_url).first() if parent is None: print(f"error: no parent with url {parent_url} for {url}") continue f = Forum(url, f['name'], f['prefix'], f.get('descr', ''), parent) db.session.add(f) success += 1 db.session.commit() print(f"Created {success} forums.") def add_group(member, group): if group[0] != "#": print(f"error: group id {group} should start with '#'") return gid = int(group[1:]) norm = unicode_names.normalize(member) g = Group.query.filter_by(id=gid).first() m = Member.query.filter_by(norm=norm).first() if m is None: print(f"error: no member has a normalized name of '{norm}'") return m.groups.append(g) db.session.add(m) db.session.commit() # # Main program # print(help_msg) commands = { "exit": lambda: sys.exit(0), "members": members, "groups": groups, "trophies": trophies, "trophy-members": trophy_members, "forums": forums, "create-groups-and-privs": create_groups_and_privs, "create-trophies": create_trophies, "create-forums": create_forums, "add-group": add_group, } while True: try: print("@> ", end="") cmd = input().split() except EOFError: sys.exit(0) if not cmd: continue if cmd[0] not in commands: print(f"error: unknown command '{cmd[0]}'") else: commands[cmd[0]](*cmd[1:])