|
@@ -21,7 +21,8 @@ from flaskbb import __version__ as flaskbb_version
|
|
|
from flaskbb.forum.forms import UserSearchForm
|
|
|
from flaskbb.utils.settings import flaskbb_config
|
|
|
from flaskbb.utils.helpers import render_template
|
|
|
-from flaskbb.utils.decorators import admin_required
|
|
|
+from flaskbb.utils.decorators import admin_required, moderator_required
|
|
|
+from flaskbb.utils.permissions import can_ban_user, can_edit_user, is_admin
|
|
|
from flaskbb.extensions import db
|
|
|
from flaskbb.user.models import User, Group
|
|
|
from flaskbb.forum.models import Post, Topic, Forum, Category, Report
|
|
@@ -35,7 +36,7 @@ management = Blueprint("management", __name__)
|
|
|
|
|
|
|
|
|
@management.route("/")
|
|
|
-@admin_required
|
|
|
+@moderator_required
|
|
|
def overview():
|
|
|
python_version = "%s.%s" % (sys.version_info[0], sys.version_info[1])
|
|
|
user_count = User.query.count()
|
|
@@ -91,8 +92,9 @@ def settings(slug=None):
|
|
|
all_groups=all_groups, active_group=active_group)
|
|
|
|
|
|
|
|
|
+# Users
|
|
|
@management.route("/users", methods=['GET', 'POST'])
|
|
|
-@admin_required
|
|
|
+@moderator_required
|
|
|
def users():
|
|
|
page = request.args.get("page", 1, type=int)
|
|
|
search_form = UserSearchForm()
|
|
@@ -110,122 +112,152 @@ def users():
|
|
|
search_form=search_form)
|
|
|
|
|
|
|
|
|
-@management.route("/groups")
|
|
|
-@admin_required
|
|
|
-def groups():
|
|
|
- page = request.args.get("page", 1, type=int)
|
|
|
+@management.route("/users/<int:user_id>/edit", methods=["GET", "POST"])
|
|
|
+@moderator_required
|
|
|
+def edit_user(user_id):
|
|
|
+ user = User.query.filter_by(id=user_id).first_or_404()
|
|
|
|
|
|
- groups = Group.query.\
|
|
|
- paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
|
|
|
+ if not can_edit_user(current_user) or is_admin(user):
|
|
|
+ flash("You are not allowed to edit this user.", "danger")
|
|
|
+ return redirect(url_for("management.users"))
|
|
|
|
|
|
- return render_template("management/groups.html", groups=groups)
|
|
|
+ secondary_group_query = Group.query.filter(
|
|
|
+ db.not_(Group.id == user.primary_group_id),
|
|
|
+ db.not_(Group.banned == True),
|
|
|
+ db.not_(Group.guest == True))
|
|
|
|
|
|
+ form = EditUserForm(user)
|
|
|
+ form.secondary_groups.query = secondary_group_query
|
|
|
+ if form.validate_on_submit():
|
|
|
+ form.populate_obj(user)
|
|
|
+ user.primary_group_id = form.primary_group.data.id
|
|
|
|
|
|
-@management.route("/forums")
|
|
|
-@admin_required
|
|
|
-def forums():
|
|
|
- categories = Category.query.order_by(Category.position.asc()).all()
|
|
|
- return render_template("management/forums.html", categories=categories)
|
|
|
+ # Don't override the password
|
|
|
+ if form.password.data:
|
|
|
+ user.password = form.password.data
|
|
|
|
|
|
+ user.save(groups=form.secondary_groups.data)
|
|
|
|
|
|
-@management.route("/reports")
|
|
|
-@admin_required
|
|
|
-def reports():
|
|
|
- page = request.args.get("page", 1, type=int)
|
|
|
- reports = Report.query.\
|
|
|
- order_by(Report.id.asc()).\
|
|
|
- paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
|
|
|
+ flash("User successfully edited", "success")
|
|
|
+ return redirect(url_for("management.edit_user", user_id=user.id))
|
|
|
+ else:
|
|
|
+ form.username.data = user.username
|
|
|
+ form.email.data = user.email
|
|
|
+ form.birthday.data = user.birthday
|
|
|
+ form.gender.data = user.gender
|
|
|
+ form.website.data = user.website
|
|
|
+ form.location.data = user.location
|
|
|
+ form.signature.data = user.signature
|
|
|
+ form.avatar.data = user.avatar
|
|
|
+ form.notes.data = user.notes
|
|
|
+ form.primary_group.data = user.primary_group
|
|
|
+ form.secondary_groups.data = user.secondary_groups
|
|
|
|
|
|
- return render_template("management/reports.html", reports=reports)
|
|
|
+ return render_template("management/user_form.html", form=form,
|
|
|
+ title="Edit User")
|
|
|
|
|
|
|
|
|
-@management.route("/plugins")
|
|
|
+@management.route("/users/<int:user_id>/delete")
|
|
|
@admin_required
|
|
|
-def plugins():
|
|
|
- plugins = get_all_plugins()
|
|
|
- return render_template("management/plugins.html", plugins=plugins)
|
|
|
-
|
|
|
-
|
|
|
-@management.route("/plugins/enable/<plugin>")
|
|
|
-def enable_plugin(plugin):
|
|
|
- plugin = get_plugin_from_all(plugin)
|
|
|
- if not plugin.enabled:
|
|
|
- plugin_dir = os.path.join(
|
|
|
- os.path.abspath(os.path.dirname(os.path.dirname(__file__))),
|
|
|
- "plugins", plugin.identifier
|
|
|
- )
|
|
|
+def delete_user(user_id):
|
|
|
+ user = User.query.filter_by(id=user_id).first_or_404()
|
|
|
+ user.delete()
|
|
|
+ flash("User successfully deleted", "success")
|
|
|
+ return redirect(url_for("management.users"))
|
|
|
|
|
|
- disabled_file = os.path.join(plugin_dir, "DISABLED")
|
|
|
|
|
|
- os.remove(disabled_file)
|
|
|
+@management.route("/users/add", methods=["GET", "POST"])
|
|
|
+@admin_required
|
|
|
+def add_user():
|
|
|
+ form = AddUserForm()
|
|
|
+ if form.validate_on_submit():
|
|
|
+ form.save()
|
|
|
+ flash("User successfully added.", "success")
|
|
|
+ return redirect(url_for("management.users"))
|
|
|
|
|
|
- flash("Plugin should be enabled. Please reload your app.", "success")
|
|
|
+ return render_template("management/user_form.html", form=form,
|
|
|
+ title="Add User")
|
|
|
|
|
|
- flash("If you are using a host which doesn't support writting on the "
|
|
|
- "disk, this won't work - than you need to delete the "
|
|
|
- "'DISABLED' file by yourself.", "info")
|
|
|
- else:
|
|
|
- flash("Plugin is not enabled", "danger")
|
|
|
|
|
|
- return redirect(url_for("management.plugins"))
|
|
|
+@management.route("/users/banned")
|
|
|
+@moderator_required
|
|
|
+def banned_users():
|
|
|
+ page = request.args.get("page", 1, type=int)
|
|
|
+ search_form = UserSearchForm()
|
|
|
|
|
|
+ users = User.query.filter(
|
|
|
+ Group.banned == True,
|
|
|
+ Group.id == User.primary_group_id
|
|
|
+ ).paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
|
|
|
|
|
|
-@management.route("/plugins/disable/<plugin>")
|
|
|
-def disable_plugin(plugin):
|
|
|
- try:
|
|
|
- plugin = get_plugin(plugin)
|
|
|
- except KeyError:
|
|
|
- flash("Plugin {} not found".format(plugin), "danger")
|
|
|
- return redirect(url_for("management.plugins"))
|
|
|
|
|
|
- plugin_dir = os.path.join(
|
|
|
- os.path.abspath(os.path.dirname(os.path.dirname(__file__))),
|
|
|
- "plugins", plugin.identifier
|
|
|
- )
|
|
|
+ if search_form.validate():
|
|
|
+ users = search_form.get_results().\
|
|
|
+ paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
|
|
|
|
|
|
- disabled_file = os.path.join(plugin_dir, "DISABLED")
|
|
|
+ return render_template("management/banned_users.html", users=users,
|
|
|
+ search_form=search_form)
|
|
|
|
|
|
- open(disabled_file, "a").close()
|
|
|
+ return render_template("management/banned_users.html", users=users,
|
|
|
+ search_form=search_form)
|
|
|
|
|
|
- flash("Plugin should be disabled. Please reload your app.", "success")
|
|
|
|
|
|
- flash("If you are using a host which doesn't "
|
|
|
- "support writting on the disk, this won't work - than you need to "
|
|
|
- "create a 'DISABLED' file by yourself.", "info")
|
|
|
+@management.route("/users/<int:user_id>/ban", methods=["GET", "POST"])
|
|
|
+@moderator_required
|
|
|
+def ban_user(user_id):
|
|
|
+ if not can_ban_user(current_user):
|
|
|
+ flash("You do not have the permissions to ban this user.")
|
|
|
+ return redirect(url_for("management.overview"))
|
|
|
|
|
|
- return redirect(url_for("management.plugins"))
|
|
|
+ user = User.query.filter_by(id=user_id).first_or_404()
|
|
|
|
|
|
+ # Do not allow moderators to ban admins
|
|
|
+ if user.get_permissions()['admin'] and \
|
|
|
+ (current_user.permissions['mod'] or
|
|
|
+ current_user.permissions['super_mod']):
|
|
|
|
|
|
-@management.route("/plugins/uninstall/<plugin>")
|
|
|
-def uninstall_plugin(plugin):
|
|
|
- plugin = get_plugin_from_all(plugin)
|
|
|
- if plugin.uninstallable:
|
|
|
- plugin.uninstall()
|
|
|
- Setting.invalidate_cache()
|
|
|
+ flash("A moderator cannot ban an admin user.", "danger")
|
|
|
+ return redirect(url_for("management.overview"))
|
|
|
|
|
|
- flash("Plugin {} has been uninstalled.".format(plugin.name), "success")
|
|
|
+ if user.ban():
|
|
|
+ flash("User was banned successfully.", "success")
|
|
|
else:
|
|
|
- flash("Cannot uninstall Plugin {}".format(plugin.name), "danger")
|
|
|
+ flash("Could not ban user.", "danger")
|
|
|
|
|
|
- return redirect(url_for("management.plugins"))
|
|
|
+ return redirect(url_for("management.banned_users"))
|
|
|
|
|
|
|
|
|
-@management.route("/plugins/install/<plugin>")
|
|
|
-def install_plugin(plugin):
|
|
|
- plugin = get_plugin_from_all(plugin)
|
|
|
- if plugin.installable and not plugin.uninstallable:
|
|
|
- plugin.install()
|
|
|
- Setting.invalidate_cache()
|
|
|
+@management.route("/users/<int:user_id>/unban", methods=["GET", "POST"])
|
|
|
+@moderator_required
|
|
|
+def unban_user(user_id):
|
|
|
+ if not can_ban_user(current_user):
|
|
|
+ flash("You do not have the permissions to unban this user.")
|
|
|
+ return redirect(url_for("management.overview"))
|
|
|
|
|
|
- flash("Plugin {} has been installed.".format(plugin.name), "success")
|
|
|
+ user = User.query.filter_by(id=user_id).first_or_404()
|
|
|
+
|
|
|
+ if user.unban():
|
|
|
+ flash("User is now unbanned.", "success")
|
|
|
else:
|
|
|
- flash("Cannot install Plugin {}".format(plugin.name), "danger")
|
|
|
+ flash("Could not unban user.", "danger")
|
|
|
|
|
|
- return redirect(url_for("management.plugins"))
|
|
|
+ return redirect(url_for("management.banned_users"))
|
|
|
+
|
|
|
+
|
|
|
+# Reports
|
|
|
+@management.route("/reports")
|
|
|
+@moderator_required
|
|
|
+def reports():
|
|
|
+ page = request.args.get("page", 1, type=int)
|
|
|
+ reports = Report.query.\
|
|
|
+ order_by(Report.id.asc()).\
|
|
|
+ paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
|
|
|
+
|
|
|
+ return render_template("management/reports.html", reports=reports)
|
|
|
|
|
|
|
|
|
@management.route("/reports/unread")
|
|
|
-@admin_required
|
|
|
+@moderator_required
|
|
|
def unread_reports():
|
|
|
page = request.args.get("page", 1, type=int)
|
|
|
reports = Report.query.\
|
|
@@ -238,7 +270,7 @@ def unread_reports():
|
|
|
|
|
|
@management.route("/reports/<int:report_id>/markread")
|
|
|
@management.route("/reports/markread")
|
|
|
-@admin_required
|
|
|
+@moderator_required
|
|
|
def report_markread(report_id=None):
|
|
|
# mark single report as read
|
|
|
if report_id:
|
|
@@ -269,67 +301,16 @@ def report_markread(report_id=None):
|
|
|
return redirect(url_for("management.reports"))
|
|
|
|
|
|
|
|
|
-@management.route("/users/<int:user_id>/edit", methods=["GET", "POST"])
|
|
|
-@admin_required
|
|
|
-def edit_user(user_id):
|
|
|
- user = User.query.filter_by(id=user_id).first_or_404()
|
|
|
-
|
|
|
- secondary_group_query = Group.query.filter(
|
|
|
- db.not_(Group.id == user.primary_group_id),
|
|
|
- db.not_(Group.banned == True),
|
|
|
- db.not_(Group.guest == True))
|
|
|
-
|
|
|
- form = EditUserForm(user)
|
|
|
- form.secondary_groups.query = secondary_group_query
|
|
|
- if form.validate_on_submit():
|
|
|
- form.populate_obj(user)
|
|
|
- user.primary_group_id = form.primary_group.data.id
|
|
|
-
|
|
|
- # Don't override the password
|
|
|
- if form.password.data:
|
|
|
- user.password = form.password.data
|
|
|
-
|
|
|
- user.save(groups=form.secondary_groups.data)
|
|
|
-
|
|
|
- flash("User successfully edited", "success")
|
|
|
- return redirect(url_for("management.edit_user", user_id=user.id))
|
|
|
- else:
|
|
|
- form.username.data = user.username
|
|
|
- form.email.data = user.email
|
|
|
- form.birthday.data = user.birthday
|
|
|
- form.gender.data = user.gender
|
|
|
- form.website.data = user.website
|
|
|
- form.location.data = user.location
|
|
|
- form.signature.data = user.signature
|
|
|
- form.avatar.data = user.avatar
|
|
|
- form.notes.data = user.notes
|
|
|
- form.primary_group.data = user.primary_group
|
|
|
- form.secondary_groups.data = user.secondary_groups
|
|
|
-
|
|
|
- return render_template("management/user_form.html", form=form,
|
|
|
- title="Edit User")
|
|
|
-
|
|
|
-
|
|
|
-@management.route("/users/<int:user_id>/delete")
|
|
|
+# Groups
|
|
|
+@management.route("/groups")
|
|
|
@admin_required
|
|
|
-def delete_user(user_id):
|
|
|
- user = User.query.filter_by(id=user_id).first_or_404()
|
|
|
- user.delete()
|
|
|
- flash("User successfully deleted", "success")
|
|
|
- return redirect(url_for("management.users"))
|
|
|
-
|
|
|
+def groups():
|
|
|
+ page = request.args.get("page", 1, type=int)
|
|
|
|
|
|
-@management.route("/users/add", methods=["GET", "POST"])
|
|
|
-@admin_required
|
|
|
-def add_user():
|
|
|
- form = AddUserForm()
|
|
|
- if form.validate_on_submit():
|
|
|
- form.save()
|
|
|
- flash("User successfully added.", "success")
|
|
|
- return redirect(url_for("management.users"))
|
|
|
+ groups = Group.query.\
|
|
|
+ paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
|
|
|
|
|
|
- return render_template("management/user_form.html", form=form,
|
|
|
- title="Add User")
|
|
|
+ return render_template("management/groups.html", groups=groups)
|
|
|
|
|
|
|
|
|
@management.route("/groups/<int:group_id>/edit", methods=["GET", "POST"])
|
|
@@ -357,6 +338,8 @@ def edit_group(group_id):
|
|
|
form.deletetopic.data = group.deletetopic
|
|
|
form.posttopic.data = group.posttopic
|
|
|
form.postreply.data = group.postreply
|
|
|
+ form.mod_edituser.data = group.mod_edituser
|
|
|
+ form.mod_banuser.data = group.mod_banuser
|
|
|
|
|
|
return render_template("management/group_form.html", form=form,
|
|
|
title="Edit Group")
|
|
@@ -384,6 +367,14 @@ def add_group():
|
|
|
title="Add Group")
|
|
|
|
|
|
|
|
|
+# Forums and Categories
|
|
|
+@management.route("/forums")
|
|
|
+@admin_required
|
|
|
+def forums():
|
|
|
+ categories = Category.query.order_by(Category.position.asc()).all()
|
|
|
+ return render_template("management/forums.html", categories=categories)
|
|
|
+
|
|
|
+
|
|
|
@management.route("/forums/<int:forum_id>/edit", methods=["GET", "POST"])
|
|
|
@admin_required
|
|
|
def edit_forum(forum_id):
|
|
@@ -493,3 +484,93 @@ def delete_category(category_id):
|
|
|
category.delete(involved_users)
|
|
|
flash("Category with all associated forums deleted.", "success")
|
|
|
return redirect(url_for("management.forums"))
|
|
|
+
|
|
|
+
|
|
|
+# Plugins
|
|
|
+@management.route("/plugins")
|
|
|
+@admin_required
|
|
|
+def plugins():
|
|
|
+ plugins = get_all_plugins()
|
|
|
+ return render_template("management/plugins.html", plugins=plugins)
|
|
|
+
|
|
|
+
|
|
|
+@management.route("/plugins/enable/<plugin>")
|
|
|
+@admin_required
|
|
|
+def enable_plugin(plugin):
|
|
|
+ plugin = get_plugin_from_all(plugin)
|
|
|
+ if not plugin.enabled:
|
|
|
+ plugin_dir = os.path.join(
|
|
|
+ os.path.abspath(os.path.dirname(os.path.dirname(__file__))),
|
|
|
+ "plugins", plugin.identifier
|
|
|
+ )
|
|
|
+
|
|
|
+ disabled_file = os.path.join(plugin_dir, "DISABLED")
|
|
|
+
|
|
|
+ os.remove(disabled_file)
|
|
|
+
|
|
|
+ flash("Plugin should be enabled. Please reload your app.", "success")
|
|
|
+
|
|
|
+ flash("If you are using a host which doesn't support writting on the "
|
|
|
+ "disk, this won't work - than you need to delete the "
|
|
|
+ "'DISABLED' file by yourself.", "info")
|
|
|
+ else:
|
|
|
+ flash("Plugin is not enabled", "danger")
|
|
|
+
|
|
|
+ return redirect(url_for("management.plugins"))
|
|
|
+
|
|
|
+
|
|
|
+@management.route("/plugins/disable/<plugin>")
|
|
|
+@admin_required
|
|
|
+def disable_plugin(plugin):
|
|
|
+ try:
|
|
|
+ plugin = get_plugin(plugin)
|
|
|
+ except KeyError:
|
|
|
+ flash("Plugin {} not found".format(plugin), "danger")
|
|
|
+ return redirect(url_for("management.plugins"))
|
|
|
+
|
|
|
+ plugin_dir = os.path.join(
|
|
|
+ os.path.abspath(os.path.dirname(os.path.dirname(__file__))),
|
|
|
+ "plugins", plugin.identifier
|
|
|
+ )
|
|
|
+
|
|
|
+ disabled_file = os.path.join(plugin_dir, "DISABLED")
|
|
|
+
|
|
|
+ open(disabled_file, "a").close()
|
|
|
+
|
|
|
+ flash("Plugin should be disabled. Please reload your app.", "success")
|
|
|
+
|
|
|
+ flash("If you are using a host which doesn't "
|
|
|
+ "support writting on the disk, this won't work - than you need to "
|
|
|
+ "create a 'DISABLED' file by yourself.", "info")
|
|
|
+
|
|
|
+ return redirect(url_for("management.plugins"))
|
|
|
+
|
|
|
+
|
|
|
+@management.route("/plugins/uninstall/<plugin>")
|
|
|
+@admin_required
|
|
|
+def uninstall_plugin(plugin):
|
|
|
+ plugin = get_plugin_from_all(plugin)
|
|
|
+ if plugin.uninstallable:
|
|
|
+ plugin.uninstall()
|
|
|
+ Setting.invalidate_cache()
|
|
|
+
|
|
|
+ flash("Plugin {} has been uninstalled.".format(plugin.name), "success")
|
|
|
+ else:
|
|
|
+ flash("Cannot uninstall Plugin {}".format(plugin.name), "danger")
|
|
|
+
|
|
|
+ return redirect(url_for("management.plugins"))
|
|
|
+
|
|
|
+
|
|
|
+@management.route("/plugins/install/<plugin>")
|
|
|
+@admin_required
|
|
|
+def install_plugin(plugin):
|
|
|
+ plugin = get_plugin_from_all(plugin)
|
|
|
+ if plugin.installable and not plugin.uninstallable:
|
|
|
+ plugin.install()
|
|
|
+ Setting.invalidate_cache()
|
|
|
+
|
|
|
+ flash("Plugin {} has been installed.".format(plugin.name), "success")
|
|
|
+ else:
|
|
|
+ flash("Cannot install Plugin {}".format(plugin.name), "danger")
|
|
|
+
|
|
|
+ return redirect(url_for("management.plugins"))
|