diff --git a/app/__init__.py b/app/__init__.py index c6ba42c..b53a7a4 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -29,6 +29,6 @@ from app.models.forum import Forum from app.models.notification import Notification from app.routes import index, search, users # To load routes at initialization from app.routes.account import login, account, notification -from app.routes.admin import index, groups, account, trophies +from app.routes.admin import index, groups, account, trophies, forums from app.utils import pluralize # To use pluralize into the templates from app.utils import is_title diff --git a/app/data/forums.yaml b/app/data/forums.yaml new file mode 100644 index 0000000..18d0a64 --- /dev/null +++ b/app/data/forums.yaml @@ -0,0 +1,93 @@ +# This file is a list of forums to create when setting up Planète Casio. +# +# * Keys are used as URLs paths and for unique identification. +# * Prefixes represent the privilege category for a forum. Owning privileges +# with this prefix allows the user to post in this forum and all its +# sub-forum regardless of their settings ("forum-root-*" are hyper powerful). +# * For open forums, use the prefix "open". + +/: + name: Forum de Planète Casio + prefix: root + +# News + +/news: + name: Actualités + prefix: news + +/news/projects: + name: Actualités des projets + prefix: projectnews + descr: Nouveautés des projets de la communauté. + +/news/calc: + name: Actualités des constructeurs de calculatrices + prefix: calcnews + descr: Nouveautés CASIO, nouveaux modèles de calculatrices, mises à jour du + système ou nouveautés d'autres constructeurs. + +/news/events: + name: Événements organisés par Planète Casio + prefix: eventnews + descr: Tous les événements organisés par Planète Casio ou la communauté. + +/news/other: + name: Autres nouveautés + prefix: othernews + descr: Actualités non catégorisées. + +# Help + +/help: + name: Aide et questions + prefix: help + +/help/transfers: + name: Questions sur les tranferts + prefix: transferhelp + descr: Questions sur le transfert de fichiers et l'installation de programmes + sur la calculatrice. + +/help/calc: + name: Question sur l'utilisation des calculatrices + prefix: calchelp + descr: Questions sur l'utilisation des applications de la calculatrice, + paramètres, formats de fichiers... + +/help/prog: + name: Questions de programmation + prefix: proghelp + descr: Questions sur le développement et le debuggage de programmes. + +/help/other: + name: Autres questions + prefix: otherhelp + descr: Questions non catégorisées. + +# Projects + +/projects: + name: Forum des projets + prefix: projects + +/projects/games: + name: Projets de jeux + prefix: gameprojects + +/projects/apps: + name: Projets d'applications, utilitaires, outils pour calculatrice + prefix: appprojects + +/projects/tools: + name: Projets pour d'autres plateformes + prefix: toolprojetcs + descr: Tous les projets tournant sur ordinateur, téléphone, ou toute autre + plateforme que la calculatrice. + +# Discussion + +/discussion: + name: Discussion + prefix: discussion + descr: Sujets hors-sujet et discussion libre. diff --git a/app/models/forum.py b/app/models/forum.py index 2d053fe..de586e6 100644 --- a/app/models/forum.py +++ b/app/models/forum.py @@ -5,22 +5,32 @@ class Forum(db.Model): __tablename__ = 'forum' id = db.Column(db.Integer, primary_key=True) - # Standalone properties + # Forum name, as displayed on the site (eg. "Problèmes de transfert") name = db.Column(db.Unicode(64)) - slug = db.Column(db.Unicode(64)) - description = db.Column(db.UnicodeText) + # Privilege prefix (sort of slug) for single-forum privileges (lowercase) + prefix = db.Column(db.Unicode(64)) + # Forum description, as displayed on the site + descr = db.Column(db.UnicodeText) + # Forum URL, for dynamic routes + url = db.Column(db.String(64)) # Relationships parent_id = db.Column(db.Integer, db.ForeignKey('forum.id'), nullable=True) parent = db.relationship('Forum', backref='sub_forums', remote_side=id, - lazy=True) + lazy=True, foreign_keys=parent_id) # Also [topics] which is provided by a backref from the Topic class - def __init__(self, name, description, priv_prefix): + def __init__(self, url, name, prefix, descr="", parent=None): + self.url = url self.name = name - self.description = description - self.priv_prefix = priv_prefix + self.descr = descr + self.prefix = prefix + + if isinstance(parent, str): + self.parent = Forum.query.filter_by(url=str).first() + else: + self.parent = parent def __repr__(self): return f'' diff --git a/app/routes/admin/forums.py b/app/routes/admin/forums.py new file mode 100644 index 0000000..000d872 --- /dev/null +++ b/app/routes/admin/forums.py @@ -0,0 +1,11 @@ +from app.utils.priv_required import priv_required +from app.utils.render import render +from app.models.forum import Forum +from app import app, db + +@app.route('/admin/forums', methods=['GET']) +@priv_required('access-admin-panel') +def adm_forums(): + main_forum = Forum.query.filter_by(parent=None).first() + + return render('admin/forums.html', main_forum=main_forum) diff --git a/app/templates/admin/forums.html b/app/templates/admin/forums.html new file mode 100644 index 0000000..ae19fa3 --- /dev/null +++ b/app/templates/admin/forums.html @@ -0,0 +1,32 @@ +{% extends "base/base.html" %} + +{# This macro will allow us to perform recursive HTML generation #} +{% macro forumtree(f) %} +
  • {{ f.name }} + +
  • +{% endmacro %} + +{% block title %} +Panneau d'administration »

    Forums

    +{% endblock %} + +{% block content %} +
    +

    Cette page permet de gérer l'arbre des forums.

    + +

    Arbre des forums

    + + {% if main_forum == None %} +

    Il n'y a aucun forum.

    + {% else %} + + {% endif %} +
    +{% endblock %} diff --git a/app/templates/admin/index.html b/app/templates/admin/index.html index 561f434..03f32f9 100644 --- a/app/templates/admin/index.html +++ b/app/templates/admin/index.html @@ -8,8 +8,9 @@

    Pages générales du panneau d'administration :

    {% endblock %} diff --git a/master.py b/master.py index 10aa9ce..98db175 100755 --- a/master.py +++ b/master.py @@ -4,6 +4,7 @@ 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 @@ -19,6 +20,7 @@ Type a category name to see a list of elements. Available categories are: '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. @@ -36,6 +38,8 @@ the database. Type 'add-group #' to add a new member to a group. Type 'create-trophies' to reset trophies and titles. + +Type 'create-forums' to reset the forum tree. """ # @@ -84,6 +88,19 @@ def trophy_members(*args): 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 # @@ -163,6 +180,36 @@ def create_trophies(): print(f"Created {len(tr)} trophies.") +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 '#'") @@ -194,8 +241,10 @@ commands = { "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, } diff --git a/migrations/versions/49427f8eb285_add_forum_urls.py b/migrations/versions/49427f8eb285_add_forum_urls.py new file mode 100644 index 0000000..c09291a --- /dev/null +++ b/migrations/versions/49427f8eb285_add_forum_urls.py @@ -0,0 +1,28 @@ +"""add forum urls + +Revision ID: 49427f8eb285 +Revises: a7aac1469393 +Create Date: 2019-09-02 21:16:06.971807 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '49427f8eb285' +down_revision = 'a7aac1469393' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('forum', sa.Column('url', sa.String(length=64), nullable=True)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('forum', 'url') + # ### end Alembic commands ### diff --git a/migrations/versions/a7aac1469393_forum_editions.py b/migrations/versions/a7aac1469393_forum_editions.py new file mode 100644 index 0000000..dde8573 --- /dev/null +++ b/migrations/versions/a7aac1469393_forum_editions.py @@ -0,0 +1,34 @@ +"""forum editions + +Revision ID: a7aac1469393 +Revises: e3b140752719 +Create Date: 2019-09-02 21:12:52.236043 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'a7aac1469393' +down_revision = 'e3b140752719' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('forum', sa.Column('descr', sa.UnicodeText(), nullable=True)) + op.add_column('forum', sa.Column('prefix', sa.Unicode(length=64), nullable=True)) + op.drop_column('forum', 'slug') + op.drop_column('forum', 'description') + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('forum', sa.Column('description', sa.TEXT(), autoincrement=False, nullable=True)) + op.add_column('forum', sa.Column('slug', sa.VARCHAR(length=64), autoincrement=False, nullable=True)) + op.drop_column('forum', 'prefix') + op.drop_column('forum', 'descr') + # ### end Alembic commands ###