From 75f3a90f20d6439c4d134c699674a9b331247345 Mon Sep 17 00:00:00 2001 From: Lephe Date: Sun, 1 Nov 2020 10:50:52 +0100 Subject: [PATCH] master.py: update forums with stateful logic The create-forums function has been replaced with an [update] subcommand of [forums]. This new function tries its best to keep existing forum objects, which is especially important once content has been created. Forums are identified by their URL. Changing the URL means the forum needs to be recreated. If the URL doesn't changed, metadata is updated without removing topics and subforums in that forum. * Improve the update model for forums in master.py * Fix a typo in the prefix for the tool projects subforum * Add the admin and assoc boards for permission testing --- app/data/forums.yaml | 17 +++++++++- master.py | 77 +++++++++++++++++++++++++++++++------------- 2 files changed, 71 insertions(+), 23 deletions(-) diff --git a/app/data/forums.yaml b/app/data/forums.yaml index 55e77c9..9f6c931 100644 --- a/app/data/forums.yaml +++ b/app/data/forums.yaml @@ -85,7 +85,7 @@ /projets/outils: name: Projets pour d'autres plateformes - prefix: toolprojetcs + prefix: toolprojects descr: Tous les projets tournant sur ordinateur, téléphone, ou toute autre plateforme que la calculatrice. @@ -103,3 +103,18 @@ name: Discussion prefix: discussion descr: Sujets hors-sujet et discussion libre. + +# Limited-access board +# Prefixes "admin" and "assoc" are reserved for this and require special +# privileges to list, read and edit topics and messages. + +/admin: + name: Administration + prefix: admin + descr: Discussions sur l'administration du site, accessible uniquement aux + membres de l'équipe. + +/creativecalc: + name: CreativeCalc + prefix: assoc + descr: Forum privé de l'association CreativeCalc, réservé aux membres. diff --git a/master.py b/master.py index 0261b04..768f050 100755 --- a/master.py +++ b/master.py @@ -24,7 +24,10 @@ Type a category name to see a list of elements. Available categories are: 'trophy-members' Trophies owned by members 'forums' Forum tree -Type a category name followed by 'clear' to remove all entries in the category. +For each category, an argument can be specified: +* 'clear' will remove all entries in the category (destroys a lot of data!) +* 'update' will update from the model in app/data/, when applicable + (currently available on: forums) 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 @@ -41,8 +44,6 @@ 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. - Type 'enable-user' to enable a email-disabled account. """ @@ -100,6 +101,10 @@ def forums(*args): print("Removed all forums.") return + if args == ("update",): + update_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}") @@ -218,17 +223,17 @@ def create_trophies_icons(): icon.save(os.path.join(dst, f"{name}.png")) -def create_forums(): - # Clean up forums - forums("clear") +def update_forums(): + # Get current forums + existing = Forum.query.all() - # Create the forum tree + # Get the list of forums we want to end up with 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(): + for url, info in fr.items(): if url == "/": parent = None else: @@ -241,12 +246,33 @@ def create_forums(): print(f"error: no parent with url {parent_url} for {url}") continue - f = Forum(url, f['name'], f['prefix'], f.get('descr', ''), parent) + descr = info.get("descr", "") + + # Either change an existing forum endpoint (same URL) or create one + f = Forum.query.filter_by(url=url).first() + if f is not None: + # No need to change the parent (same URL implies same parent) + changes = (f.name != info["name"]) or (f.prefix != info["prefix"])\ + or (f.descr != descr) + f.name = info["name"] + f.prefix = info["prefix"] + f.descr = descr + if changes: + print(f"[forum] Updated {url}") + else: + f = Forum(url, info["name"], info["prefix"], descr, parent) + print(f"[forum] Created {url}") + db.session.add(f) success += 1 + # Remove old forums + for f in existing: + if f.url not in fr: + f.delete() + print(f"[forum] Removed {f.url}") + db.session.commit() - print(f"Created {success} forums.") def add_group(member, group): if group[0] != "#": @@ -282,8 +308,6 @@ def enable_user(member): # Main program # -print(help_msg) - commands = { "exit": lambda: sys.exit(0), "members": members, @@ -294,21 +318,30 @@ commands = { "create-groups-and-privs": create_groups_and_privs, "create-trophies": create_trophies, "create-trophies-icons": create_trophies_icons, - "create-forums": create_forums, "add-group": add_group, "enable-user": enable_user, } -while True: - try: - print("@> ", end="") - cmd = input().split() - except EOFError: - sys.exit(0) - - if not cmd: - continue +def execute(cmd): if cmd[0] not in commands: print(f"error: unknown command '{cmd[0]}'") else: commands[cmd[0]](*cmd[1:]) + +# If a command is specified on the command-line, use it and do not prompt +if len(sys.argv) > 1: + execute(sys.argv[1:]) + sys.exit(0) +# Otherwise, prompt interactively +else: + print(help_msg) + + while True: + try: + print("@> ", end="") + cmd = input().split() + except EOFError: + sys.exit(0) + + if cmd: + execute(cmd)