views.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. # -*- coding: utf-8 -*-
  2. """
  3. flaskbb.management.views
  4. ~~~~~~~~~~~~~~~~~~~~~~~~
  5. This module handles the management views.
  6. :copyright: (c) 2014 by the FlaskBB Team.
  7. :license: BSD, see LICENSE for more details.
  8. """
  9. import sys
  10. from celery import __version__ as celery_version
  11. from flask import (Blueprint, current_app, request, redirect, url_for, flash,
  12. jsonify, __version__ as flask_version)
  13. from flask_login import current_user, login_fresh
  14. from flask_babelplus import gettext as _
  15. from flask_allows import Permission, Not
  16. from flaskbb import __version__ as flaskbb_version
  17. from flaskbb._compat import iteritems
  18. from flaskbb.forum.forms import UserSearchForm
  19. from flaskbb.utils.settings import flaskbb_config
  20. from flaskbb.utils.requirements import (IsAtleastModerator, IsAdmin,
  21. CanBanUser, CanEditUser,
  22. IsAtleastSuperModerator)
  23. from flaskbb.extensions import db, allows, celery
  24. from flaskbb.utils.helpers import (render_template, time_diff, time_utcnow,
  25. get_online_users, validate_plugin)
  26. from flaskbb.plugins.models import PluginRegistry, PluginStore
  27. from flaskbb.user.models import Guest, User, Group
  28. from flaskbb.forum.models import Post, Topic, Forum, Category, Report
  29. from flaskbb.management.models import Setting, SettingsGroup
  30. from flaskbb.management.forms import (AddUserForm, EditUserForm, AddGroupForm,
  31. EditGroupForm, EditForumForm,
  32. AddForumForm, CategoryForm)
  33. management = Blueprint("management", __name__)
  34. @management.before_request
  35. def check_fresh_login():
  36. """Checks if the login is fresh for the current user, otherwise the user
  37. has to reauthenticate."""
  38. if not login_fresh():
  39. return current_app.login_manager.needs_refresh()
  40. @management.route("/")
  41. @allows.requires(IsAtleastModerator)
  42. def overview():
  43. # user and group stats
  44. banned_users = User.query.filter(
  45. Group.banned == True,
  46. Group.id == User.primary_group_id
  47. ).count()
  48. if not current_app.config["REDIS_ENABLED"]:
  49. online_users = User.query.filter(User.lastseen >= time_diff()).count()
  50. else:
  51. online_users = len(get_online_users())
  52. unread_reports = Report.query.\
  53. filter(Report.zapped == None).\
  54. order_by(Report.id.desc()).\
  55. count()
  56. celery_inspect = celery.control.inspect()
  57. try:
  58. celery_running = True if celery_inspect.ping() else False
  59. except Exception:
  60. # catching Exception is bad, and just catching ConnectionError
  61. # from redis is also bad because you can run celery with other
  62. # brokers as well.
  63. celery_running = False
  64. python_version = "{}.{}.{}".format(
  65. sys.version_info[0], sys.version_info[1], sys.version_info[2]
  66. )
  67. stats = {
  68. "current_app": current_app,
  69. "unread_reports": unread_reports,
  70. # stats stats
  71. "all_users": User.query.count(),
  72. "banned_users": banned_users,
  73. "online_users": online_users,
  74. "all_groups": Group.query.count(),
  75. "report_count": Report.query.count(),
  76. "topic_count": Topic.query.count(),
  77. "post_count": Post.query.count(),
  78. # components
  79. "python_version": python_version,
  80. "celery_version": celery_version,
  81. "celery_running": celery_running,
  82. "flask_version": flask_version,
  83. "flaskbb_version": flaskbb_version,
  84. # plugins
  85. "plugins": []
  86. }
  87. return render_template("management/overview.html", **stats)
  88. @management.route("/settings", methods=["GET", "POST"])
  89. @management.route("/settings/<path:slug>", methods=["GET", "POST"])
  90. @management.route("/settings/plugin/<path:plugin>", methods=["GET", "POST"])
  91. @allows.requires(IsAdmin)
  92. def settings(slug=None, plugin=None):
  93. slug = slug if slug and not plugin else "general"
  94. active_settings = {}
  95. active_group, active_plugin = None, None
  96. if plugin is not None:
  97. active_plugin = PluginRegistry.query.filter_by(name=plugin).first_or_404()
  98. active_settings['key'] = active_plugin.name
  99. active_settings['title'] = active_plugin.name.title()
  100. form = active_plugin.get_settings_form()
  101. old_settings = active_plugin.settings
  102. elif slug is not None:
  103. active_group = SettingsGroup.query.filter_by(key=slug).first_or_404()
  104. active_settings['key'] = active_group.key
  105. active_settings['title'] = active_group.name
  106. form = Setting.get_form(active_group)()
  107. old_settings = Setting.get_settings(active_group)
  108. # get all groups and plugins - used to build the navigation
  109. all_groups = SettingsGroup.query.all()
  110. all_plugins = PluginRegistry.query.all()
  111. new_settings = {}
  112. if form.validate_on_submit():
  113. for key, value in iteritems(old_settings):
  114. try:
  115. # check if the value has changed
  116. if value == form[key].data:
  117. continue
  118. else:
  119. new_settings[key] = form[key].data
  120. except KeyError:
  121. pass
  122. if active_group is not None:
  123. Setting.update(settings=new_settings, app=current_app)
  124. else:
  125. active_plugin.settings.update(new_settings)
  126. active_plugin.save()
  127. flash(_("Settings saved."), "success")
  128. else:
  129. for key, value in iteritems(old_settings):
  130. try:
  131. form[key].data = value
  132. except (KeyError, ValueError):
  133. pass
  134. return render_template("management/settings.html", form=form,
  135. all_groups=all_groups, all_plugins=all_plugins,
  136. active_settings=active_settings,
  137. active_group=active_group)
  138. # Users
  139. @management.route("/users", methods=['GET', 'POST'])
  140. @allows.requires(IsAtleastModerator)
  141. def users():
  142. page = request.args.get("page", 1, type=int)
  143. search_form = UserSearchForm()
  144. if search_form.validate():
  145. users = search_form.get_results().\
  146. paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
  147. return render_template("management/users.html", users=users,
  148. search_form=search_form)
  149. users = User.query. \
  150. order_by(User.id.asc()).\
  151. paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
  152. return render_template("management/users.html", users=users,
  153. search_form=search_form)
  154. @management.route("/users/<int:user_id>/edit", methods=["GET", "POST"])
  155. @allows.requires(IsAtleastModerator)
  156. def edit_user(user_id):
  157. user = User.query.filter_by(id=user_id).first_or_404()
  158. if not Permission(CanEditUser, identity=current_user):
  159. flash(_("You are not allowed to edit this user."), "danger")
  160. return redirect(url_for("management.users"))
  161. member_group = db.and_(*[db.not_(getattr(Group, p)) for p in
  162. ['admin', 'mod', 'super_mod', 'banned', 'guest']])
  163. filt = db.or_(
  164. Group.id.in_(g.id for g in current_user.groups), member_group
  165. )
  166. if Permission(IsAtleastSuperModerator, identity=current_user):
  167. filt = db.or_(filt, Group.mod)
  168. if Permission(IsAdmin, identity=current_user):
  169. filt = db.or_(filt, Group.admin, Group.super_mod)
  170. if Permission(CanBanUser, identity=current_user):
  171. filt = db.or_(filt, Group.banned)
  172. group_query = Group.query.filter(filt)
  173. form = EditUserForm(user)
  174. form.primary_group.query = group_query
  175. form.secondary_groups.query = group_query
  176. if form.validate_on_submit():
  177. form.populate_obj(user)
  178. user.primary_group_id = form.primary_group.data.id
  179. # Don't override the password
  180. if form.password.data:
  181. user.password = form.password.data
  182. user.save(groups=form.secondary_groups.data)
  183. flash(_("User updated."), "success")
  184. return redirect(url_for("management.edit_user", user_id=user.id))
  185. return render_template("management/user_form.html", form=form,
  186. title=_("Edit User"))
  187. @management.route("/users/delete", methods=["POST"])
  188. @management.route("/users/<int:user_id>/delete", methods=["POST"])
  189. @allows.requires(IsAdmin)
  190. def delete_user(user_id=None):
  191. # ajax request
  192. if request.is_xhr:
  193. ids = request.get_json()["ids"]
  194. data = []
  195. for user in User.query.filter(User.id.in_(ids)).all():
  196. # do not delete current user
  197. if current_user.id == user.id:
  198. continue
  199. if user.delete():
  200. data.append({
  201. "id": user.id,
  202. "type": "delete",
  203. "reverse": False,
  204. "reverse_name": None,
  205. "reverse_url": None
  206. })
  207. return jsonify(
  208. message="{} users deleted.".format(len(data)),
  209. category="success",
  210. data=data,
  211. status=200
  212. )
  213. user = User.query.filter_by(id=user_id).first_or_404()
  214. if current_user.id == user.id:
  215. flash(_("You cannot delete yourself.", "danger"))
  216. return redirect(url_for("management.users"))
  217. user.delete()
  218. flash(_("User deleted."), "success")
  219. return redirect(url_for("management.users"))
  220. @management.route("/users/add", methods=["GET", "POST"])
  221. @allows.requires(IsAdmin)
  222. def add_user():
  223. form = AddUserForm()
  224. if form.validate_on_submit():
  225. form.save()
  226. flash(_("User added."), "success")
  227. return redirect(url_for("management.users"))
  228. return render_template("management/user_form.html", form=form,
  229. title=_("Add User"))
  230. @management.route("/users/banned", methods=["GET", "POST"])
  231. @allows.requires(IsAtleastModerator)
  232. def banned_users():
  233. page = request.args.get("page", 1, type=int)
  234. search_form = UserSearchForm()
  235. users = User.query.filter(
  236. Group.banned == True,
  237. Group.id == User.primary_group_id
  238. ).paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
  239. if search_form.validate():
  240. users = search_form.get_results().\
  241. paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
  242. return render_template("management/banned_users.html", users=users,
  243. search_form=search_form)
  244. return render_template("management/banned_users.html", users=users,
  245. search_form=search_form)
  246. @management.route("/users/ban", methods=["POST"])
  247. @management.route("/users/<int:user_id>/ban", methods=["POST"])
  248. @allows.requires(IsAtleastModerator)
  249. def ban_user(user_id=None):
  250. if not Permission(CanBanUser, identity=current_user):
  251. flash(_("You do not have the permissions to ban this user."), "danger")
  252. return redirect(url_for("management.overview"))
  253. # ajax request
  254. if request.is_xhr:
  255. ids = request.get_json()["ids"]
  256. data = []
  257. users = User.query.filter(User.id.in_(ids)).all()
  258. for user in users:
  259. # don't let a user ban himself and do not allow a moderator to ban
  260. # a admin user
  261. if (
  262. current_user.id == user.id or
  263. Permission(IsAdmin, identity=user) and
  264. Permission(Not(IsAdmin), current_user)
  265. ):
  266. continue
  267. elif user.ban():
  268. data.append({
  269. "id": user.id,
  270. "type": "ban",
  271. "reverse": "unban",
  272. "reverse_name": _("Unban"),
  273. "reverse_url": url_for("management.unban_user",
  274. user_id=user.id)
  275. })
  276. return jsonify(
  277. message="{} users banned.".format(len(data)),
  278. category="success",
  279. data=data,
  280. status=200
  281. )
  282. user = User.query.filter_by(id=user_id).first_or_404()
  283. # Do not allow moderators to ban admins
  284. if Permission(IsAdmin, identity=user) and \
  285. Permission(Not(IsAdmin), identity=current_user):
  286. flash(_("A moderator cannot ban an admin user."), "danger")
  287. return redirect(url_for("management.overview"))
  288. if not current_user.id == user.id and user.ban():
  289. flash(_("User is now banned."), "success")
  290. else:
  291. flash(_("Could not ban user."), "danger")
  292. return redirect(url_for("management.banned_users"))
  293. @management.route("/users/unban", methods=["POST"])
  294. @management.route("/users/<int:user_id>/unban", methods=["POST"])
  295. @allows.requires(IsAtleastModerator)
  296. def unban_user(user_id=None):
  297. if not Permission(CanBanUser, identity=current_user):
  298. flash(_("You do not have the permissions to unban this user."),
  299. "danger")
  300. return redirect(url_for("management.overview"))
  301. # ajax request
  302. if request.is_xhr:
  303. ids = request.get_json()["ids"]
  304. data = []
  305. for user in User.query.filter(User.id.in_(ids)).all():
  306. if user.unban():
  307. data.append({
  308. "id": user.id,
  309. "type": "unban",
  310. "reverse": "ban",
  311. "reverse_name": _("Ban"),
  312. "reverse_url": url_for("management.ban_user",
  313. user_id=user.id)
  314. })
  315. return jsonify(
  316. message="{} users unbanned.".format(len(data)),
  317. category="success",
  318. data=data,
  319. status=200
  320. )
  321. user = User.query.filter_by(id=user_id).first_or_404()
  322. if user.unban():
  323. flash(_("User is now unbanned."), "success")
  324. else:
  325. flash(_("Could not unban user."), "danger")
  326. return redirect(url_for("management.banned_users"))
  327. # Reports
  328. @management.route("/reports")
  329. @allows.requires(IsAtleastModerator)
  330. def reports():
  331. page = request.args.get("page", 1, type=int)
  332. reports = Report.query.\
  333. order_by(Report.id.asc()).\
  334. paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
  335. return render_template("management/reports.html", reports=reports)
  336. @management.route("/reports/unread")
  337. @allows.requires(IsAtleastModerator)
  338. def unread_reports():
  339. page = request.args.get("page", 1, type=int)
  340. reports = Report.query.\
  341. filter(Report.zapped == None).\
  342. order_by(Report.id.desc()).\
  343. paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
  344. return render_template("management/reports.html", reports=reports)
  345. @management.route("/reports/<int:report_id>/markread", methods=["POST"])
  346. @management.route("/reports/markread", methods=["POST"])
  347. @allows.requires(IsAtleastModerator)
  348. def report_markread(report_id=None):
  349. # AJAX request
  350. if request.is_xhr:
  351. ids = request.get_json()["ids"]
  352. data = []
  353. for report in Report.query.filter(Report.id.in_(ids)).all():
  354. report.zapped_by = current_user.id
  355. report.zapped = time_utcnow()
  356. report.save()
  357. data.append({
  358. "id": report.id,
  359. "type": "read",
  360. "reverse": False,
  361. "reverse_name": None,
  362. "reverse_url": None
  363. })
  364. return jsonify(
  365. message="{} reports marked as read.".format(len(data)),
  366. category="success",
  367. data=data,
  368. status=200
  369. )
  370. # mark single report as read
  371. if report_id:
  372. report = Report.query.filter_by(id=report_id).first_or_404()
  373. if report.zapped:
  374. flash(_("Report %(id)s is already marked as read.", id=report.id),
  375. "success")
  376. return redirect(url_for("management.reports"))
  377. report.zapped_by = current_user.id
  378. report.zapped = time_utcnow()
  379. report.save()
  380. flash(_("Report %(id)s marked as read.", id=report.id), "success")
  381. return redirect(url_for("management.reports"))
  382. # mark all as read
  383. reports = Report.query.filter(Report.zapped == None).all()
  384. report_list = []
  385. for report in reports:
  386. report.zapped_by = current_user.id
  387. report.zapped = time_utcnow()
  388. report_list.append(report)
  389. db.session.add_all(report_list)
  390. db.session.commit()
  391. flash(_("All reports were marked as read."), "success")
  392. return redirect(url_for("management.reports"))
  393. @management.route("/reports/<int:report_id>/delete", methods=["POST"])
  394. @management.route("/reports/delete", methods=["POST"])
  395. @allows.requires(IsAtleastModerator)
  396. def delete_report(report_id=None):
  397. if request.is_xhr:
  398. ids = request.get_json()["ids"]
  399. data = []
  400. for report in Report.query.filter(Report.id.in_(ids)).all():
  401. if report.delete():
  402. data.append({
  403. "id": report.id,
  404. "type": "delete",
  405. "reverse": False,
  406. "reverse_name": None,
  407. "reverse_url": None
  408. })
  409. return jsonify(
  410. message="{} reports deleted.".format(len(data)),
  411. category="success",
  412. data=data,
  413. status=200
  414. )
  415. report = Report.query.filter_by(id=report_id).first_or_404()
  416. report.delete()
  417. flash(_("Report deleted."), "success")
  418. return redirect(url_for("management.reports"))
  419. # Groups
  420. @management.route("/groups")
  421. @allows.requires(IsAdmin)
  422. def groups():
  423. page = request.args.get("page", 1, type=int)
  424. groups = Group.query.\
  425. order_by(Group.id.asc()).\
  426. paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
  427. return render_template("management/groups.html", groups=groups)
  428. @management.route("/groups/<int:group_id>/edit", methods=["GET", "POST"])
  429. @allows.requires(IsAdmin)
  430. def edit_group(group_id):
  431. group = Group.query.filter_by(id=group_id).first_or_404()
  432. form = EditGroupForm(group)
  433. if form.validate_on_submit():
  434. form.populate_obj(group)
  435. group.save()
  436. if group.guest:
  437. Guest.invalidate_cache()
  438. flash(_("Group updated."), "success")
  439. return redirect(url_for("management.groups", group_id=group.id))
  440. return render_template("management/group_form.html", form=form,
  441. title=_("Edit Group"))
  442. @management.route("/groups/<int:group_id>/delete", methods=["POST"])
  443. @management.route("/groups/delete", methods=["POST"])
  444. @allows.requires(IsAdmin)
  445. def delete_group(group_id=None):
  446. if request.is_xhr:
  447. ids = request.get_json()["ids"]
  448. if not (set(ids) & set(["1", "2", "3", "4", "5"])):
  449. data = []
  450. for group in Group.query.filter(Group.id.in_(ids)).all():
  451. group.delete()
  452. data.append({
  453. "id": group.id,
  454. "type": "delete",
  455. "reverse": False,
  456. "reverse_name": None,
  457. "reverse_url": None
  458. })
  459. return jsonify(
  460. message="{} groups deleted.".format(len(data)),
  461. category="success",
  462. data=data,
  463. status=200
  464. )
  465. return jsonify(
  466. message=_("You cannot delete one of the standard groups."),
  467. category="danger",
  468. data=None,
  469. status=404
  470. )
  471. if group_id is not None:
  472. if group_id <= 5: # there are 5 standard groups
  473. flash(_("You cannot delete the standard groups. "
  474. "Try renaming it instead.", "danger"))
  475. return redirect(url_for("management.groups"))
  476. group = Group.query.filter_by(id=group_id).first_or_404()
  477. group.delete()
  478. flash(_("Group deleted."), "success")
  479. return redirect(url_for("management.groups"))
  480. flash(_("No group chosen."), "danger")
  481. return redirect(url_for("management.groups"))
  482. @management.route("/groups/add", methods=["GET", "POST"])
  483. @allows.requires(IsAdmin)
  484. def add_group():
  485. form = AddGroupForm()
  486. if form.validate_on_submit():
  487. form.save()
  488. flash(_("Group added."), "success")
  489. return redirect(url_for("management.groups"))
  490. return render_template("management/group_form.html", form=form,
  491. title=_("Add Group"))
  492. # Forums and Categories
  493. @management.route("/forums")
  494. @allows.requires(IsAdmin)
  495. def forums():
  496. categories = Category.query.order_by(Category.position.asc()).all()
  497. return render_template("management/forums.html", categories=categories)
  498. @management.route("/forums/<int:forum_id>/edit", methods=["GET", "POST"])
  499. @allows.requires(IsAdmin)
  500. def edit_forum(forum_id):
  501. forum = Forum.query.filter_by(id=forum_id).first_or_404()
  502. form = EditForumForm(forum)
  503. if form.validate_on_submit():
  504. form.save()
  505. flash(_("Forum updated."), "success")
  506. return redirect(url_for("management.edit_forum", forum_id=forum.id))
  507. else:
  508. if forum.moderators:
  509. form.moderators.data = ",".join([
  510. user.username for user in forum.moderators
  511. ])
  512. else:
  513. form.moderators.data = None
  514. return render_template("management/forum_form.html", form=form,
  515. title=_("Edit Forum"))
  516. @management.route("/forums/<int:forum_id>/delete", methods=["POST"])
  517. @allows.requires(IsAdmin)
  518. def delete_forum(forum_id):
  519. forum = Forum.query.filter_by(id=forum_id).first_or_404()
  520. involved_users = User.query.filter(Topic.forum_id == forum.id,
  521. Post.user_id == User.id).all()
  522. forum.delete(involved_users)
  523. flash(_("Forum deleted."), "success")
  524. return redirect(url_for("management.forums"))
  525. @management.route("/forums/add", methods=["GET", "POST"])
  526. @management.route("/forums/<int:category_id>/add", methods=["GET", "POST"])
  527. @allows.requires(IsAdmin)
  528. def add_forum(category_id=None):
  529. form = AddForumForm()
  530. if form.validate_on_submit():
  531. form.save()
  532. flash(_("Forum added."), "success")
  533. return redirect(url_for("management.forums"))
  534. else:
  535. form.groups.data = Group.query.order_by(Group.id.asc()).all()
  536. if category_id:
  537. category = Category.query.filter_by(id=category_id).first()
  538. form.category.data = category
  539. return render_template("management/forum_form.html", form=form,
  540. title=_("Add Forum"))
  541. @management.route("/category/add", methods=["GET", "POST"])
  542. @allows.requires(IsAdmin)
  543. def add_category():
  544. form = CategoryForm()
  545. if form.validate_on_submit():
  546. form.save()
  547. flash(_("Category added."), "success")
  548. return redirect(url_for("management.forums"))
  549. return render_template("management/category_form.html", form=form,
  550. title=_("Add Category"))
  551. @management.route("/category/<int:category_id>/edit", methods=["GET", "POST"])
  552. @allows.requires(IsAdmin)
  553. def edit_category(category_id):
  554. category = Category.query.filter_by(id=category_id).first_or_404()
  555. form = CategoryForm(obj=category)
  556. if form.validate_on_submit():
  557. form.populate_obj(category)
  558. flash(_("Category updated."), "success")
  559. category.save()
  560. return render_template("management/category_form.html", form=form,
  561. title=_("Edit Category"))
  562. @management.route("/category/<int:category_id>/delete", methods=["POST"])
  563. @allows.requires(IsAdmin)
  564. def delete_category(category_id):
  565. category = Category.query.filter_by(id=category_id).first_or_404()
  566. involved_users = User.query.filter(Forum.category_id == category.id,
  567. Topic.forum_id == Forum.id,
  568. Post.user_id == User.id).all()
  569. category.delete(involved_users)
  570. flash(_("Category with all associated forums deleted."), "success")
  571. return redirect(url_for("management.forums"))
  572. # Plugins
  573. @management.route("/plugins")
  574. @allows.requires(IsAdmin)
  575. def plugins():
  576. plugins = current_app.pluggy.list_plugin_metadata()
  577. print(plugins)
  578. return render_template("management/plugins.html", plugins=plugins)
  579. @management.route("/plugins/<path:name>/enable", methods=["POST"])
  580. @allows.requires(IsAdmin)
  581. def enable_plugin(name):
  582. validate_plugin(name)
  583. plugin = PluginRegistry.query.filter_by(name=name).first_or_404()
  584. if plugin.enabled:
  585. flash(_("Plugin %(plugin)s is already enabled.", plugin=plugin.name),
  586. "info")
  587. return redirect(url_for("management.plugins"))
  588. plugin.enabled = True
  589. plugin.save()
  590. flash(_("Plugin %(plugin)s enabled. Please restart FlaskBB now.",
  591. plugin=plugin.name), "success")
  592. return redirect(url_for("management.plugins"))
  593. @management.route("/plugins/<path:name>/disable", methods=["POST"])
  594. @allows.requires(IsAdmin)
  595. def disable_plugin(name):
  596. validate_plugin(name)
  597. plugin = PluginRegistry.query.filter_by(name=name).first_or_404()
  598. if not plugin.enabled:
  599. flash(_("Plugin %(plugin)s is already disabled.", plugin=plugin.name),
  600. "info")
  601. return redirect(url_for("management.plugins"))
  602. plugin.enabled = False
  603. plugin.save()
  604. flash(_("Plugin %(plugin)s disabled. Please restart FlaskBB now.",
  605. plugin=plugin.name), "success")
  606. return redirect(url_for("management.plugins"))
  607. @management.route("/plugins/<path:name>/uninstall", methods=["POST"])
  608. @allows.requires(IsAdmin)
  609. def uninstall_plugin(name):
  610. validate_plugin(name)
  611. plugin = PluginRegistry.query.filter_by(name=name).first_or_404()
  612. plugin.delete()
  613. flash(_("Plugin has been uninstalled."), "success")
  614. return redirect(url_for("management.plugins"))
  615. @management.route("/plugins/<path:name>/install", methods=["POST"])
  616. @allows.requires(IsAdmin)
  617. def install_plugin(name):
  618. plugin_module = validate_plugin(name)
  619. plugin = PluginRegistry.query.filter_by(name=name).first_or_404()
  620. plugin.add_settings(plugin_module.SETTINGS)
  621. flash(_("Plugin has been installed."), "success")
  622. return redirect(url_for("management.plugins"))