Browse Source

Load management routes via plugin hook

Alec Nikolas Reiter 7 years ago
parent
commit
818bce1693
2 changed files with 357 additions and 247 deletions
  1. 1 4
      flaskbb/app.py
  2. 356 243
      flaskbb/management/views.py

+ 1 - 4
flaskbb/app.py

@@ -29,7 +29,7 @@ from flaskbb.extensions import (alembic, allows, babel, cache, celery, csrf,
                                 redis_store, themes, whooshee)
 from .auth import views as auth_views
 from .forum import views as forum_views
-from flaskbb.management.views import management
+from .management import views as management_views
 from flaskbb.message.views import message
 from flaskbb.plugins import spec
 from flaskbb.plugins.manager import FlaskBBPluginManager
@@ -158,9 +158,6 @@ def configure_celery_app(app, celery):
 def configure_blueprints(app):
     app.register_blueprint(user, url_prefix=app.config["USER_URL_PREFIX"])
     app.register_blueprint(
-        management, url_prefix=app.config["ADMIN_URL_PREFIX"]
-    )
-    app.register_blueprint(
         message, url_prefix=app.config["MESSAGE_URL_PREFIX"]
     )
 

+ 356 - 243
flaskbb/management/views.py

@@ -19,6 +19,8 @@ from flask.views import MethodView
 from flask_allows import Not, Permission
 from flask_babelplus import gettext as _
 from flask_login import current_user, login_fresh
+from pluggy import HookimplMarker
+
 from flaskbb import __version__ as flaskbb_version
 from flaskbb.extensions import allows, celery, db
 from flaskbb.forum.forms import UserSearchForm
@@ -28,28 +30,19 @@ from flaskbb.management.forms import (AddForumForm, AddGroupForm, AddUserForm,
                                       EditGroupForm, EditUserForm)
 from flaskbb.management.models import Setting, SettingsGroup
 from flaskbb.plugins.models import PluginRegistry, PluginStore
-from flaskbb.user.models import Group, Guest, User
 from flaskbb.plugins.utils import validate_plugin
+from flaskbb.user.models import Group, Guest, User
+from flaskbb.utils.forms import populate_settings_dict, populate_settings_form
 from flaskbb.utils.helpers import (get_online_users, register_view,
                                    render_template, time_diff, time_utcnow)
 from flaskbb.utils.requirements import (CanBanUser, CanEditUser, IsAdmin,
                                         IsAtleastModerator,
                                         IsAtleastSuperModerator)
 from flaskbb.utils.settings import flaskbb_config
-from flaskbb.utils.forms import populate_settings_dict, populate_settings_form
-
-logger = logging.getLogger(__name__)
-
 
-management = Blueprint("management", __name__)
+impl = HookimplMarker('flaskbb')
 
-
-@management.before_request
-def check_fresh_login():
-    """Checks if the login is fresh for the current user, otherwise the user
-    has to reauthenticate."""
-    if not login_fresh():
-        return current_app.login_manager.needs_refresh()
+logger = logging.getLogger(__name__)
 
 
 class ManagementSettings(MethodView):
@@ -65,9 +58,14 @@ class ManagementSettings(MethodView):
         active_nav = {}  # used to build the navigation
         plugin_obj = None
         if plugin is not None:
-            plugin_obj = PluginRegistry.query.filter_by(name=plugin).first_or_404()
-            active_nav.update({'key': plugin_obj.name,
-                               'title': plugin_obj.name.title()})
+            plugin_obj = PluginRegistry.query.filter_by(name=plugin
+                                                        ).first_or_404()
+            active_nav.update(
+                {
+                    'key': plugin_obj.name,
+                    'title': plugin_obj.name.title()
+                }
+            )
             form = plugin_obj.get_settings_form()
             old_settings = plugin_obj.settings
 
@@ -85,12 +83,18 @@ class ManagementSettings(MethodView):
 
         # get all groups and plugins - used to build the navigation
         all_groups = SettingsGroup.query.all()
-        all_plugins = PluginRegistry.query.filter(PluginRegistry.values != None).all()
+        all_plugins = PluginRegistry.query.filter(
+            PluginRegistry.values != None
+        ).all()
         form = populate_settings_form(form, old_settings)
 
-        return render_template("management/settings.html", form=form,
-                               all_groups=all_groups, all_plugins=all_plugins,
-                               active_nav=active_nav)
+        return render_template(
+            "management/settings.html",
+            form=form,
+            all_groups=all_groups,
+            all_plugins=all_plugins,
+            active_nav=active_nav
+        )
 
     def post(self, slug=None, plugin=None):
         form, old_settings, plugin_obj, active_nav = \
@@ -108,9 +112,13 @@ class ManagementSettings(MethodView):
 
             flash(_("Settings saved."), "success")
 
-        return render_template("management/settings.html", form=form,
-                               all_groups=all_groups, all_plugins=all_plugins,
-                               active_nav=active_nav)
+        return render_template(
+            "management/settings.html",
+            form=form,
+            all_groups=all_groups,
+            all_plugins=all_plugins,
+            active_nav=active_nav
+        )
 
 
 class ManageUsers(MethodView):
@@ -125,7 +133,9 @@ class ManageUsers(MethodView):
             page, flaskbb_config['USERS_PER_PAGE'], False
         )
 
-        return render_template('management/users.html', users=users, search_form=form)
+        return render_template(
+            'management/users.html', users=users, search_form=form
+        )
 
     def post(self):
         page = request.args.get('page', 1, type=int)
@@ -134,13 +144,17 @@ class ManageUsers(MethodView):
         if form.validate():
             users = form.get_results().\
                 paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
-            return render_template('management/users.html', users=users, search_form=form)
+            return render_template(
+                'management/users.html', users=users, search_form=form
+            )
 
         users = User.query.order_by(User.id.asc()).paginate(
             page, flaskbb_config['USERS_PER_PAGE'], False
         )
 
-        return render_template('management/users.html', users=users, search_form=form)
+        return render_template(
+            'management/users.html', users=users, search_form=form
+        )
 
 
 class EditUser(MethodView):
@@ -151,13 +165,15 @@ class EditUser(MethodView):
         user = User.query.filter_by(id=user_id).first_or_404()
         form = self.form(user)
         member_group = db.and_(
-            *[
+            * [
                 db.not_(getattr(Group, p))
                 for p in ['admin', 'mod', 'super_mod', 'banned', 'guest']
             ]
         )
 
-        filt = db.or_(Group.id.in_(g.id for g in current_user.groups), member_group)
+        filt = db.or_(
+            Group.id.in_(g.id for g in current_user.groups), member_group
+        )
 
         if Permission(IsAtleastSuperModerator, identity=current_user):
             filt = db.or_(filt, Group.mod)
@@ -173,19 +189,23 @@ class EditUser(MethodView):
         form.primary_group.query = group_query
         form.secondary_groups.query = group_query
 
-        return render_template('management/user_form.html', form=form, title=_('Edit User'))
+        return render_template(
+            'management/user_form.html', form=form, title=_('Edit User')
+        )
 
     def post(self, user_id):
         user = User.query.filter_by(id=user_id).first_or_404()
 
         member_group = db.and_(
-            *[
+            * [
                 db.not_(getattr(Group, p))
                 for p in ['admin', 'mod', 'super_mod', 'banned', 'guest']
             ]
         )
 
-        filt = db.or_(Group.id.in_(g.id for g in current_user.groups), member_group)
+        filt = db.or_(
+            Group.id.in_(g.id for g in current_user.groups), member_group
+        )
 
         if Permission(IsAtleastSuperModerator, identity=current_user):
             filt = db.or_(filt, Group.mod)
@@ -214,7 +234,9 @@ class EditUser(MethodView):
             flash(_('User updated.'), 'success')
             return redirect(url_for('management.edit_user', user_id=user.id))
 
-        return render_template('management/user_form.html', form=form, title=_('Edit User'))
+        return render_template(
+            'management/user_form.html', form=form, title=_('Edit User')
+        )
 
 
 class DeleteUser(MethodView):
@@ -264,7 +286,9 @@ class AddUser(MethodView):
     form = AddUserForm
 
     def get(self):
-        return render_template('management/user_form.html', form=self.form(), title=_('Add User'))
+        return render_template(
+            'management/user_form.html', form=self.form(), title=_('Add User')
+        )
 
     def post(self):
         form = self.form()
@@ -273,7 +297,9 @@ class AddUser(MethodView):
             flash(_('User added.'), 'success')
             return redirect(url_for('management.users'))
 
-        return render_template('management/user_form.html', form=form, title=_('Add User'))
+        return render_template(
+            'management/user_form.html', form=form, title=_('Add User')
+        )
 
 
 class BannedUsers(MethodView):
@@ -284,30 +310,38 @@ class BannedUsers(MethodView):
         page = request.args.get('page', 1, type=int)
         search_form = self.form()
 
-        users = User.query.filter(Group.banned == True, Group.id == User.primary_group_id
-                                  ).paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
+        users = User.query.filter(
+            Group.banned == True, Group.id == User.primary_group_id
+        ).paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
 
         return render_template(
-            'management/banned_users.html', users=users, search_form=search_form
+            'management/banned_users.html',
+            users=users,
+            search_form=search_form
         )
 
     def post(self):
         page = request.args.get('page', 1, type=int)
         search_form = self.form()
 
-        users = User.query.filter(Group.banned == True, Group.id == User.primary_group_id
-                                  ).paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
+        users = User.query.filter(
+            Group.banned == True, Group.id == User.primary_group_id
+        ).paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
 
         if search_form.validate():
             users = search_form.get_results().\
                 paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
 
             return render_template(
-                'management/banned_users.html', users=users, search_form=search_form
+                'management/banned_users.html',
+                users=users,
+                search_form=search_form
             )
 
         return render_template(
-            'management/banned_users.html', users=users, search_form=search_form
+            'management/banned_users.html',
+            users=users,
+            search_form=search_form
         )
 
 
@@ -316,7 +350,9 @@ class BanUser(MethodView):
 
     def post(self, user_id=None):
         if not Permission(CanBanUser, identity=current_user):
-            flash(_("You do not have the permissions to ban this user."), "danger")
+            flash(
+                _("You do not have the permissions to ban this user."), "danger"
+            )
             return redirect(url_for("management.overview"))
 
         # ajax request
@@ -328,18 +364,24 @@ class BanUser(MethodView):
             for user in users:
                 # don't let a user ban himself and do not allow a moderator to ban
                 # a admin user
-                if (current_user.id == user.id or Permission(IsAdmin, identity=user)
+                if (current_user.id == user.id
+                        or Permission(IsAdmin, identity=user)
                         and Permission(Not(IsAdmin), current_user)):
                     continue
 
                 elif user.ban():
                     data.append(
                         {
-                            "id": user.id,
-                            "type": "ban",
-                            "reverse": "unban",
-                            "reverse_name": _("Unban"),
-                            "reverse_url": url_for("management.unban_user", user_id=user.id)
+                            "id":
+                            user.id,
+                            "type":
+                            "ban",
+                            "reverse":
+                            "unban",
+                            "reverse_name":
+                            _("Unban"),
+                            "reverse_url":
+                            url_for("management.unban_user", user_id=user.id)
                         }
                     )
 
@@ -352,7 +394,8 @@ class BanUser(MethodView):
 
         user = User.query.filter_by(id=user_id).first_or_404()
         # Do not allow moderators to ban admins
-        if Permission(IsAdmin, identity=user) and Permission(Not(IsAdmin), identity=current_user):
+        if Permission(IsAdmin, identity=user) and Permission(
+                Not(IsAdmin), identity=current_user):
             flash(_("A moderator cannot ban an admin user."), "danger")
             return redirect(url_for("management.overview"))
 
@@ -369,7 +412,10 @@ class UnbanUser(MethodView):
     def post(self, user_id=None):
 
         if not Permission(CanBanUser, identity=current_user):
-            flash(_("You do not have the permissions to unban this user."), "danger")
+            flash(
+                _("You do not have the permissions to unban this user."),
+                "danger"
+            )
             return redirect(url_for("management.overview"))
 
         # ajax request
@@ -381,11 +427,16 @@ class UnbanUser(MethodView):
                 if user.unban():
                     data.append(
                         {
-                            "id": user.id,
-                            "type": "unban",
-                            "reverse": "ban",
-                            "reverse_name": _("Ban"),
-                            "reverse_url": url_for("management.ban_user", user_id=user.id)
+                            "id":
+                            user.id,
+                            "type":
+                            "unban",
+                            "reverse":
+                            "ban",
+                            "reverse_name":
+                            _("Ban"),
+                            "reverse_url":
+                            url_for("management.ban_user", user_id=user.id)
                         }
                     )
 
@@ -426,7 +477,9 @@ class AddGroup(MethodView):
 
     def get(self):
         return render_template(
-            'management/group_form.html', form=self.form(), title=_('Add Group')
+            'management/group_form.html',
+            form=self.form(),
+            title=_('Add Group')
         )
 
     def post(self):
@@ -436,7 +489,9 @@ class AddGroup(MethodView):
             flash(_('Group added.'), 'success')
             return redirect(url_for('management.groups'))
 
-        return render_template('management/group_form.html', form=form, title=_('Add Group'))
+        return render_template(
+            'management/group_form.html', form=form, title=_('Add Group')
+        )
 
 
 class EditGroup(MethodView):
@@ -446,7 +501,9 @@ class EditGroup(MethodView):
     def get(self, group_id):
         group = Group.query.filter_by(id=group_id).first_or_404()
         form = self.form(group)
-        return render_template('management/group_form.html', form=form, title=_('Edit Group'))
+        return render_template(
+            'management/group_form.html', form=form, title=_('Edit Group')
+        )
 
     def post(self, group_id):
         group = Group.query.filter_by(id=group_id).first_or_404()
@@ -462,7 +519,9 @@ class EditGroup(MethodView):
             flash(_('Group updated.'), 'success')
             return redirect(url_for('management.groups', group_id=group.id))
 
-        return render_template('management/group_form.html', form=form, title=_('Edit Group'))
+        return render_template(
+            'management/group_form.html', form=form, title=_('Edit Group')
+        )
 
 
 class DeleteGroup(MethodView):
@@ -535,11 +594,15 @@ class EditForum(MethodView):
         form = self.form(forum)
 
         if forum.moderators:
-            form.moderators.data = ','.join([user.username for user in forum.moderators])
+            form.moderators.data = ','.join(
+                [user.username for user in forum.moderators]
+            )
         else:
             form.moderators.data = None
 
-        return render_template('management/forum_form.html', form=form, title=_('Edit Forum'))
+        return render_template(
+            'management/forum_form.html', form=form, title=_('Edit Forum')
+        )
 
     def post(self, forum_id):
         forum = Forum.query.filter_by(id=forum_id).first_or_404()
@@ -551,11 +614,15 @@ class EditForum(MethodView):
             return redirect(url_for('management.edit_forum', forum_id=forum.id))
         else:
             if forum.moderators:
-                form.moderators.data = ','.join([user.username for user in forum.moderators])
+                form.moderators.data = ','.join(
+                    [user.username for user in forum.moderators]
+                )
             else:
                 form.moderators.data = None
 
-        return render_template('management/forum_form.html', form=form, title=_('Edit Forum'))
+        return render_template(
+            'management/forum_form.html', form=form, title=_('Edit Forum')
+        )
 
 
 class AddForum(MethodView):
@@ -571,7 +638,9 @@ class AddForum(MethodView):
             category = Category.query.filter_by(id=category_id).first()
             form.category.data = category
 
-        return render_template('management/forum_form.html', form=form, title=_('Add Forum'))
+        return render_template(
+            'management/forum_form.html', form=form, title=_('Add Forum')
+        )
 
     def post(self, category_id=None):
         form = self.form()
@@ -586,7 +655,9 @@ class AddForum(MethodView):
                 category = Category.query.filter_by(id=category_id).first()
                 form.category.data = category
 
-        return render_template('management/forum_form.html', form=form, title=_('Add Forum'))
+        return render_template(
+            'management/forum_form.html', form=form, title=_('Add Forum')
+        )
 
 
 class DeleteForum(MethodView):
@@ -595,8 +666,9 @@ class DeleteForum(MethodView):
     def post(self, forum_id):
         forum = Forum.query.filter_by(id=forum_id).first_or_404()
 
-        involved_users = User.query.filter(Topic.forum_id == forum.id,
-                                           Post.user_id == User.id).all()
+        involved_users = User.query.filter(
+            Topic.forum_id == forum.id, Post.user_id == User.id
+        ).all()
 
         forum.delete(involved_users)
 
@@ -610,7 +682,9 @@ class AddCategory(MethodView):
 
     def get(self):
         return render_template(
-            'management/category_form.html', form=self.form(), title=_('Add Category')
+            'management/category_form.html',
+            form=self.form(),
+            title=_('Add Category')
         )
 
     def post(self):
@@ -621,7 +695,9 @@ class AddCategory(MethodView):
             flash(_('Category added.'), 'success')
             return redirect(url_for('management.forums'))
 
-        return render_template('management/category_form.html', form=form, title=_('Add Category'))
+        return render_template(
+            'management/category_form.html', form=form, title=_('Add Category')
+        )
 
 
 class EditCategory(MethodView):
@@ -634,7 +710,9 @@ class EditCategory(MethodView):
         form = self.form(obj=category)
 
         return render_template(
-            'management/category_form.html', form=form, title=_('Edit Category')
+            'management/category_form.html',
+            form=form,
+            title=_('Edit Category')
         )
 
     def post(self, category_id):
@@ -648,7 +726,9 @@ class EditCategory(MethodView):
             category.save()
 
         return render_template(
-            'management/category_form.html', form=form, title=_('Edit Category')
+            'management/category_form.html',
+            form=form,
+            title=_('Edit Category')
         )
 
 
@@ -659,7 +739,8 @@ class DeleteCategory(MethodView):
         category = Category.query.filter_by(id=category_id).first_or_404()
 
         involved_users = User.query.filter(
-            Forum.category_id == category.id, Topic.forum_id == Forum.id, Post.user_id == User.id
+            Forum.category_id == category.id, Topic.forum_id == Forum.id,
+            Post.user_id == User.id
         ).all()
 
         category.delete(involved_users)
@@ -727,7 +808,10 @@ class MarkReportRead(MethodView):
         if report_id:
             report = Report.query.filter_by(id=report_id).first_or_404()
             if report.zapped:
-                flash(_("Report %(id)s is already marked as read.", id=report.id), "success")
+                flash(
+                    _("Report %(id)s is already marked as read.", id=report.id),
+                    "success"
+                )
                 return redirect(url_for("management.reports"))
 
             report.zapped_by = current_user.id
@@ -790,10 +874,12 @@ class ManagementOverview(MethodView):
 
     def get(self):
         # user and group stats
-        banned_users = User.query.filter(Group.banned == True,
-                                         Group.id == User.primary_group_id).count()
+        banned_users = User.query.filter(
+            Group.banned == True, Group.id == User.primary_group_id
+        ).count()
         if not current_app.config["REDIS_ENABLED"]:
-            online_users = User.query.filter(User.lastseen >= time_diff()).count()
+            online_users = User.query.filter(User.lastseen >= time_diff()
+                                             ).count()
         else:
             online_users = len(get_online_users())
 
@@ -855,14 +941,21 @@ class EnablePlugin(MethodView):
         plugin = PluginRegistry.query.filter_by(name=name).first_or_404()
 
         if plugin.enabled:
-            flash(_("Plugin %(plugin)s is already enabled.", plugin=plugin.name), "info")
+            flash(
+                _("Plugin %(plugin)s is already enabled.", plugin=plugin.name),
+                "info"
+            )
             return redirect(url_for("management.plugins"))
 
         plugin.enabled = True
         plugin.save()
 
-        flash(_("Plugin %(plugin)s enabled. Please restart FlaskBB now.",
-                plugin=plugin.name), "success")
+        flash(
+            _(
+                "Plugin %(plugin)s enabled. Please restart FlaskBB now.",
+                plugin=plugin.name
+            ), "success"
+        )
         return redirect(url_for("management.plugins"))
 
 
@@ -874,14 +967,20 @@ class DisablePlugin(MethodView):
         plugin = PluginRegistry.query.filter_by(name=name).first_or_404()
 
         if not plugin.enabled:
-            flash(_("Plugin %(plugin)s is already disabled.", plugin=plugin.name),
-                  "info")
+            flash(
+                _("Plugin %(plugin)s is already disabled.", plugin=plugin.name),
+                "info"
+            )
             return redirect(url_for("management.plugins"))
 
         plugin.enabled = False
         plugin.save()
-        flash(_("Plugin %(plugin)s disabled. Please restart FlaskBB now.",
-                plugin=plugin.name), "success")
+        flash(
+            _(
+                "Plugin %(plugin)s disabled. Please restart FlaskBB now.",
+                plugin=plugin.name
+            ), "success"
+        )
         return redirect(url_for("management.plugins"))
 
 
@@ -905,8 +1004,12 @@ class InstallPlugin(MethodView):
         plugin = PluginRegistry.query.filter_by(name=name).first_or_404()
 
         if not plugin.enabled:
-            flash(_("Can't install plugin. Enable '%(plugin)s' plugin first.",
-                    plugin=plugin.name), "danger")
+            flash(
+                _(
+                    "Can't install plugin. Enable '%(plugin)s' plugin first.",
+                    plugin=plugin.name
+                ), "danger"
+            )
             return redirect(url_for("management.plugins"))
 
         plugin.add_settings(plugin_module.SETTINGS)
@@ -914,161 +1017,171 @@ class InstallPlugin(MethodView):
         return redirect(url_for("management.plugins"))
 
 
-# Categories
-register_view(
-    management,
-    routes=['/category/add'],
-    view_func=AddCategory.as_view('add_category')
-)
-register_view(
-    management,
-    routes=["/category/<int:category_id>/delete"],
-    view_func=DeleteCategory.as_view('delete_category')
-)
-register_view(
-    management,
-    routes=['/category/<int:category_id>/edit'],
-    view_func=EditCategory.as_view('edit_category')
-)
-
-# Forums
-register_view(
-    management,
-    routes=['/forums/add', '/forums/<int:category_id>/add'],
-    view_func=AddForum.as_view('add_forum')
-)
-register_view(
-    management,
-    routes=['/forums/<int:forum_id>/delete'],
-    view_func=DeleteForum.as_view('delete_forum')
-)
-register_view(
-    management,
-    routes=['/forums/<int:forum_id>/edit'],
-    view_func=EditForum.as_view('edit_forum')
-)
-register_view(
-    management,
-    routes=['/forums'],
-    view_func=Forums.as_view('forums')
-)
-
-# Groups
-register_view(
-    management,
-    routes=['/groups/add'],
-    view_func=AddGroup.as_view('add_group')
-)
-register_view(
-    management,
-    routes=['/groups/<int:group_id>/delete', '/groups/delete'],
-    view_func=DeleteGroup.as_view('delete_group')
-)
-register_view(
-    management,
-    routes=['/groups/<int:group_id>/edit'],
-    view_func=EditGroup.as_view('edit_group')
-)
-register_view(
-    management,
-    routes=['/groups'],
-    view_func=Groups.as_view('groups')
-)
-
-# Plugins
-register_view(
-    management,
-    routes=['/plugins/<path:name>/disable'],
-    view_func=DisablePlugin.as_view('disable_plugin')
-)
-register_view(
-    management,
-    routes=['/plugins/<path:name>/enable'],
-    view_func=EnablePlugin.as_view('enable_plugin')
-)
-register_view(
-    management,
-    routes=['/plugins/<path:name>/install'],
-    view_func=InstallPlugin.as_view('install_plugin')
-)
-register_view(
-    management,
-    routes=['/plugins/<path:name>/uninstall'],
-    view_func=UninstallPlugin.as_view('uninstall_plugin')
-)
-register_view(
-    management,
-    routes=['/plugins'],
-    view_func=PluginsView.as_view('plugins')
-)
-
-# Reports
-register_view(
-    management,
-    routes=['/reports/<int:report_id>/delete', '/reports/delete'],
-    view_func=DeleteReport.as_view('delete_report')
-)
-register_view(
-    management,
-    routes=['/reports/<int:report_id>/markread', '/reports/markread'],
-    view_func=MarkReportRead.as_view('report_markread')
-)
-register_view(
-    management,
-    routes=['/reports/unread'],
-    view_func=UnreadReports.as_view('unread_reports')
-)
-register_view(
-    management,
-    routes=['/reports'],
-    view_func=Reports.as_view('reports')
-)
-
-# Settings
-register_view(
-    management,
-    routes=['/settings', '/settings/<path:slug>', '/settings/plugin/<path:plugin>'],
-    view_func=ManagementSettings.as_view('settings')
-)
-
-# Users
-register_view(
-    management,
-    routes=['/users/add'],
-    view_func=AddUser.as_view('add_user')
-)
-register_view(
-    management,
-    routes=['/users/banned'],
-    view_func=BannedUsers.as_view('banned_users')
-)
-register_view(
-    management,
-    routes=['/users/ban', '/users/<int:user_id>/ban'],
-    view_func=BanUser.as_view('ban_user')
-)
-register_view(
-    management,
-    routes=['/users/delete', '/users/<int:user_id>/delete'],
-    view_func=DeleteUser.as_view('delete_user')
-)
-register_view(
-    management,
-    routes=['/users/<int:user_id>/edit'],
-    view_func=EditUser.as_view('edit_user')
-)
-register_view(
-    management,
-    routes=['/users/unban', '/users/<int:user_id>/unban'],
-    view_func=UnbanUser.as_view('unban_user')
-)
-register_view(
-    management,
-    routes=['/users'],
-    view_func=ManageUsers.as_view('users')
-)
-register_view(
-    management,
-    routes=['/'],
-    view_func=ManagementOverview.as_view('overview')
-)
+@impl
+def flaskbb_load_blueprints(app):
+    management = Blueprint("management", __name__)
+
+    @management.before_request
+    def check_fresh_login():
+        """Checks if the login is fresh for the current user, otherwise the user
+        has to reauthenticate."""
+        if not login_fresh():
+            return current_app.login_manager.needs_refresh()
+
+    # Categories
+    register_view(
+        management,
+        routes=['/category/add'],
+        view_func=AddCategory.as_view('add_category')
+    )
+    register_view(
+        management,
+        routes=["/category/<int:category_id>/delete"],
+        view_func=DeleteCategory.as_view('delete_category')
+    )
+    register_view(
+        management,
+        routes=['/category/<int:category_id>/edit'],
+        view_func=EditCategory.as_view('edit_category')
+    )
+
+    # Forums
+    register_view(
+        management,
+        routes=['/forums/add', '/forums/<int:category_id>/add'],
+        view_func=AddForum.as_view('add_forum')
+    )
+    register_view(
+        management,
+        routes=['/forums/<int:forum_id>/delete'],
+        view_func=DeleteForum.as_view('delete_forum')
+    )
+    register_view(
+        management,
+        routes=['/forums/<int:forum_id>/edit'],
+        view_func=EditForum.as_view('edit_forum')
+    )
+    register_view(
+        management, routes=['/forums'], view_func=Forums.as_view('forums')
+    )
+
+    # Groups
+    register_view(
+        management,
+        routes=['/groups/add'],
+        view_func=AddGroup.as_view('add_group')
+    )
+    register_view(
+        management,
+        routes=['/groups/<int:group_id>/delete', '/groups/delete'],
+        view_func=DeleteGroup.as_view('delete_group')
+    )
+    register_view(
+        management,
+        routes=['/groups/<int:group_id>/edit'],
+        view_func=EditGroup.as_view('edit_group')
+    )
+    register_view(
+        management, routes=['/groups'], view_func=Groups.as_view('groups')
+    )
+
+    # Plugins
+    register_view(
+        management,
+        routes=['/plugins/<path:name>/disable'],
+        view_func=DisablePlugin.as_view('disable_plugin')
+    )
+    register_view(
+        management,
+        routes=['/plugins/<path:name>/enable'],
+        view_func=EnablePlugin.as_view('enable_plugin')
+    )
+    register_view(
+        management,
+        routes=['/plugins/<path:name>/install'],
+        view_func=InstallPlugin.as_view('install_plugin')
+    )
+    register_view(
+        management,
+        routes=['/plugins/<path:name>/uninstall'],
+        view_func=UninstallPlugin.as_view('uninstall_plugin')
+    )
+    register_view(
+        management,
+        routes=['/plugins'],
+        view_func=PluginsView.as_view('plugins')
+    )
+
+    # Reports
+    register_view(
+        management,
+        routes=['/reports/<int:report_id>/delete', '/reports/delete'],
+        view_func=DeleteReport.as_view('delete_report')
+    )
+    register_view(
+        management,
+        routes=['/reports/<int:report_id>/markread', '/reports/markread'],
+        view_func=MarkReportRead.as_view('report_markread')
+    )
+    register_view(
+        management,
+        routes=['/reports/unread'],
+        view_func=UnreadReports.as_view('unread_reports')
+    )
+    register_view(
+        management, routes=['/reports'], view_func=Reports.as_view('reports')
+    )
+
+    # Settings
+    register_view(
+        management,
+        routes=[
+            '/settings', '/settings/<path:slug>',
+            '/settings/plugin/<path:plugin>'
+        ],
+        view_func=ManagementSettings.as_view('settings')
+    )
+
+    # Users
+    register_view(
+        management,
+        routes=['/users/add'],
+        view_func=AddUser.as_view('add_user')
+    )
+    register_view(
+        management,
+        routes=['/users/banned'],
+        view_func=BannedUsers.as_view('banned_users')
+    )
+    register_view(
+        management,
+        routes=['/users/ban', '/users/<int:user_id>/ban'],
+        view_func=BanUser.as_view('ban_user')
+    )
+    register_view(
+        management,
+        routes=['/users/delete', '/users/<int:user_id>/delete'],
+        view_func=DeleteUser.as_view('delete_user')
+    )
+    register_view(
+        management,
+        routes=['/users/<int:user_id>/edit'],
+        view_func=EditUser.as_view('edit_user')
+    )
+    register_view(
+        management,
+        routes=['/users/unban', '/users/<int:user_id>/unban'],
+        view_func=UnbanUser.as_view('unban_user')
+    )
+    register_view(
+        management, routes=['/users'], view_func=ManageUsers.as_view('users')
+    )
+    register_view(
+        management,
+        routes=['/'],
+        view_func=ManagementOverview.as_view('overview')
+    )
+
+    app.register_blueprint(
+        management, url_prefix=app.config["ADMIN_URL_PREFIX"]
+    )