views.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. # -*- coding: utf-8 -*-
  2. """
  3. flaskbb.admin.views
  4. ~~~~~~~~~~~~~~~~~~~
  5. This module handles the admin views.
  6. :copyright: (c) 2014 by the FlaskBB Team.
  7. :license: BSD, see LICENSE for more details.
  8. """
  9. import sys
  10. import os
  11. from datetime import datetime
  12. from flask import (Blueprint, current_app, request, redirect, url_for, flash,
  13. __version__ as flask_version)
  14. from flask.ext.login import current_user
  15. from flask.ext.plugins import get_all_plugins, get_plugin, get_plugin_from_all
  16. from flaskbb import __version__ as flaskbb_version
  17. from flaskbb.forum.forms import UserSearchForm
  18. from flaskbb.utils.settings import flaskbb_config
  19. from flaskbb.utils.helpers import render_template
  20. from flaskbb.utils.decorators import admin_required
  21. from flaskbb.extensions import db
  22. from flaskbb.user.models import User, Group
  23. from flaskbb.forum.models import Post, Topic, Forum, Category, Report
  24. from flaskbb.admin.models import Setting, SettingsGroup
  25. from flaskbb.admin.forms import (AddUserForm, EditUserForm, AddGroupForm,
  26. EditGroupForm, EditForumForm, AddForumForm,
  27. CategoryForm)
  28. admin = Blueprint("admin", __name__)
  29. @admin.route("/")
  30. @admin_required
  31. def overview():
  32. python_version = "%s.%s" % (sys.version_info[0], sys.version_info[1])
  33. user_count = User.query.count()
  34. topic_count = Topic.query.count()
  35. post_count = Post.query.count()
  36. return render_template("admin/overview.html",
  37. python_version=python_version,
  38. flask_version=flask_version,
  39. flaskbb_version=flaskbb_version,
  40. user_count=user_count,
  41. topic_count=topic_count,
  42. post_count=post_count)
  43. @admin.route("/settings", methods=["GET", "POST"])
  44. @admin.route("/settings/<path:slug>", methods=["GET", "POST"])
  45. @admin_required
  46. def settings(slug=None):
  47. slug = slug if slug else "general"
  48. # get the currently active group
  49. active_group = SettingsGroup.query.filter_by(key=slug).first_or_404()
  50. # get all groups - used to build the navigation
  51. all_groups = SettingsGroup.query.all()
  52. SettingsForm = Setting.get_form(active_group)
  53. old_settings = Setting.get_settings(active_group)
  54. new_settings = {}
  55. form = SettingsForm()
  56. if form.validate_on_submit():
  57. for key, values in old_settings.iteritems():
  58. try:
  59. # check if the value has changed
  60. if values['value'] == form[key].data:
  61. continue
  62. else:
  63. new_settings[key] = form[key].data
  64. except KeyError:
  65. pass
  66. Setting.update(settings=new_settings, app=current_app)
  67. else:
  68. for key, values in old_settings.iteritems():
  69. try:
  70. form[key].data = values['value']
  71. except (KeyError, ValueError):
  72. pass
  73. return render_template("admin/settings.html", form=form,
  74. all_groups=all_groups, active_group=active_group)
  75. @admin.route("/users", methods=['GET', 'POST'])
  76. @admin_required
  77. def users():
  78. page = request.args.get("page", 1, type=int)
  79. search_form = UserSearchForm()
  80. if search_form.validate():
  81. users = search_form.get_results().\
  82. paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
  83. return render_template("admin/users.html", users=users,
  84. search_form=search_form)
  85. users = User.query. \
  86. paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
  87. return render_template("admin/users.html", users=users,
  88. search_form=search_form)
  89. @admin.route("/groups")
  90. @admin_required
  91. def groups():
  92. page = request.args.get("page", 1, type=int)
  93. groups = Group.query.\
  94. paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
  95. return render_template("admin/groups.html", groups=groups)
  96. @admin.route("/forums")
  97. @admin_required
  98. def forums():
  99. categories = Category.query.order_by(Category.position.asc()).all()
  100. return render_template("admin/forums.html", categories=categories)
  101. @admin.route("/reports")
  102. @admin_required
  103. def reports():
  104. page = request.args.get("page", 1, type=int)
  105. reports = Report.query.\
  106. order_by(Report.id.asc()).\
  107. paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
  108. return render_template("admin/reports.html", reports=reports)
  109. @admin.route("/plugins")
  110. @admin_required
  111. def plugins():
  112. plugins = get_all_plugins()
  113. return render_template("admin/plugins.html", plugins=plugins)
  114. @admin.route("/plugins/enable/<plugin>")
  115. def enable_plugin(plugin):
  116. plugin = get_plugin_from_all(plugin)
  117. if not plugin.enabled:
  118. plugin_dir = os.path.join(
  119. os.path.abspath(os.path.dirname(os.path.dirname(__file__))),
  120. "plugins", plugin.identifier
  121. )
  122. disabled_file = os.path.join(plugin_dir, "DISABLED")
  123. os.remove(disabled_file)
  124. flash("Plugin should be enabled. Please reload your app.", "success")
  125. flash("If you are using a host which doesn't support writting on the "
  126. "disk, this won't work - than you need to delete the "
  127. "'DISABLED' file by yourself.", "info")
  128. else:
  129. flash("Plugin is not enabled", "danger")
  130. return redirect(url_for("admin.plugins"))
  131. @admin.route("/plugins/disable/<plugin>")
  132. def disable_plugin(plugin):
  133. try:
  134. plugin = get_plugin(plugin)
  135. except KeyError:
  136. flash("Plugin {} not found".format(plugin), "danger")
  137. return redirect(url_for("admin.plugins"))
  138. plugin_dir = os.path.join(
  139. os.path.abspath(os.path.dirname(os.path.dirname(__file__))),
  140. "plugins", plugin.identifier
  141. )
  142. disabled_file = os.path.join(plugin_dir, "DISABLED")
  143. open(disabled_file, "a").close()
  144. flash("Plugin should be disabled. Please reload your app.", "success")
  145. flash("If you are using a host which doesn't "
  146. "support writting on the disk, this won't work - than you need to "
  147. "create a 'DISABLED' file by yourself.", "info")
  148. return redirect(url_for("admin.plugins"))
  149. @admin.route("/plugins/uninstall/<plugin>")
  150. def uninstall_plugin(plugin):
  151. plugin = get_plugin_from_all(plugin)
  152. if plugin.uninstallable:
  153. plugin.uninstall()
  154. Setting.invalidate_cache()
  155. flash("Plugin {} has been uninstalled.".format(plugin.name), "success")
  156. else:
  157. flash("Cannot uninstall Plugin {}".format(plugin.name), "danger")
  158. return redirect(url_for("admin.plugins"))
  159. @admin.route("/plugins/install/<plugin>")
  160. def install_plugin(plugin):
  161. plugin = get_plugin_from_all(plugin)
  162. if plugin.installable and not plugin.uninstallable:
  163. plugin.install()
  164. Setting.invalidate_cache()
  165. flash("Plugin {} has been installed.".format(plugin.name), "success")
  166. else:
  167. flash("Cannot install Plugin {}".format(plugin.name), "danger")
  168. return redirect(url_for("admin.plugins"))
  169. @admin.route("/reports/unread")
  170. @admin_required
  171. def unread_reports():
  172. page = request.args.get("page", 1, type=int)
  173. reports = Report.query.\
  174. filter(Report.zapped == None).\
  175. order_by(Report.id.desc()).\
  176. paginate(page, flaskbb_config['USERS_PER_PAGE'], False)
  177. return render_template("admin/unread_reports.html", reports=reports)
  178. @admin.route("/reports/<int:report_id>/markread")
  179. @admin.route("/reports/markread")
  180. @admin_required
  181. def report_markread(report_id=None):
  182. # mark single report as read
  183. if report_id:
  184. report = Report.query.filter_by(id=report_id).first_or_404()
  185. if report.zapped:
  186. flash("Report %s is already marked as read" % report.id, "success")
  187. return redirect(url_for("admin.reports"))
  188. report.zapped_by = current_user.id
  189. report.zapped = datetime.utcnow()
  190. report.save()
  191. flash("Report %s marked as read" % report.id, "success")
  192. return redirect(url_for("admin.reports"))
  193. # mark all as read
  194. reports = Report.query.filter(Report.zapped == None).all()
  195. report_list = []
  196. for report in reports:
  197. report.zapped_by = current_user.id
  198. report.zapped = datetime.utcnow()
  199. report_list.append(report)
  200. db.session.add_all(report_list)
  201. db.session.commit()
  202. flash("All reports were marked as read", "success")
  203. return redirect(url_for("admin.reports"))
  204. @admin.route("/users/<int:user_id>/edit", methods=["GET", "POST"])
  205. @admin_required
  206. def edit_user(user_id):
  207. user = User.query.filter_by(id=user_id).first_or_404()
  208. secondary_group_query = Group.query.filter(
  209. db.not_(Group.id == user.primary_group_id),
  210. db.not_(Group.banned == True),
  211. db.not_(Group.guest == True))
  212. form = EditUserForm(user)
  213. form.secondary_groups.query = secondary_group_query
  214. if form.validate_on_submit():
  215. form.populate_obj(user)
  216. user.primary_group_id = form.primary_group.data.id
  217. # Don't override the password
  218. if form.password.data:
  219. user.password = form.password.data
  220. user.save(groups=form.secondary_groups.data)
  221. flash("User successfully edited", "success")
  222. return redirect(url_for("admin.edit_user", user_id=user.id))
  223. else:
  224. form.username.data = user.username
  225. form.email.data = user.email
  226. form.birthday.data = user.birthday
  227. form.gender.data = user.gender
  228. form.website.data = user.website
  229. form.location.data = user.location
  230. form.signature.data = user.signature
  231. form.avatar.data = user.avatar
  232. form.notes.data = user.notes
  233. form.primary_group.data = user.primary_group
  234. form.secondary_groups.data = user.secondary_groups
  235. return render_template("admin/user_form.html", form=form,
  236. title="Edit User")
  237. @admin.route("/users/<int:user_id>/delete")
  238. @admin_required
  239. def delete_user(user_id):
  240. user = User.query.filter_by(id=user_id).first_or_404()
  241. user.delete()
  242. flash("User successfully deleted", "success")
  243. return redirect(url_for("admin.users"))
  244. @admin.route("/users/add", methods=["GET", "POST"])
  245. @admin_required
  246. def add_user():
  247. form = AddUserForm()
  248. if form.validate_on_submit():
  249. form.save()
  250. flash("User successfully added.", "success")
  251. return redirect(url_for("admin.users"))
  252. return render_template("admin/user_form.html", form=form,
  253. title="Add User")
  254. @admin.route("/groups/<int:group_id>/edit", methods=["GET", "POST"])
  255. @admin_required
  256. def edit_group(group_id):
  257. group = Group.query.filter_by(id=group_id).first_or_404()
  258. form = EditGroupForm(group)
  259. if form.validate_on_submit():
  260. form.populate_obj(group)
  261. group.save()
  262. flash("Group successfully edited.", "success")
  263. return redirect(url_for("admin.groups", group_id=group.id))
  264. else:
  265. form.name.data = group.name
  266. form.description.data = group.description
  267. form.admin.data = group.admin
  268. form.super_mod.data = group.super_mod
  269. form.mod.data = group.mod
  270. form.guest.data = group.guest
  271. form.banned.data = group.banned
  272. form.editpost.data = group.editpost
  273. form.deletepost.data = group.deletepost
  274. form.deletetopic.data = group.deletetopic
  275. form.posttopic.data = group.posttopic
  276. form.postreply.data = group.postreply
  277. return render_template("admin/group_form.html", form=form,
  278. title="Edit Group")
  279. @admin.route("/groups/<int:group_id>/delete")
  280. @admin_required
  281. def delete_group(group_id):
  282. group = Group.query.filter_by(id=group_id).first_or_404()
  283. group.delete()
  284. flash("Group successfully deleted.", "success")
  285. return redirect(url_for("admin.groups"))
  286. @admin.route("/groups/add", methods=["GET", "POST"])
  287. @admin_required
  288. def add_group():
  289. form = AddGroupForm()
  290. if form.validate_on_submit():
  291. form.save()
  292. flash("Group successfully added.", "success")
  293. return redirect(url_for("admin.groups"))
  294. return render_template("admin/group_form.html", form=form,
  295. title="Add Group")
  296. @admin.route("/forums/<int:forum_id>/edit", methods=["GET", "POST"])
  297. @admin_required
  298. def edit_forum(forum_id):
  299. forum = Forum.query.filter_by(id=forum_id).first_or_404()
  300. form = EditForumForm(forum)
  301. if form.validate_on_submit():
  302. form.populate_obj(forum)
  303. forum.save(moderators=form.moderators.data)
  304. flash("Forum successfully edited.", "success")
  305. return redirect(url_for("admin.edit_forum", forum_id=forum.id))
  306. else:
  307. form.title.data = forum.title
  308. form.description.data = forum.description
  309. form.position.data = forum.position
  310. form.category.data = forum.category
  311. form.external.data = forum.external
  312. form.locked.data = forum.locked
  313. form.show_moderators.data = forum.show_moderators
  314. if forum.moderators:
  315. form.moderators.data = ",".join([user.username
  316. for user in forum.moderators])
  317. else:
  318. form.moderators.data = None
  319. return render_template("admin/forum_form.html", form=form,
  320. title="Edit Forum")
  321. @admin.route("/forums/<int:forum_id>/delete")
  322. @admin_required
  323. def delete_forum(forum_id):
  324. forum = Forum.query.filter_by(id=forum_id).first_or_404()
  325. involved_users = User.query.filter(Topic.forum_id == forum.id,
  326. Post.user_id == User.id).all()
  327. forum.delete(involved_users)
  328. flash("Forum successfully deleted.", "success")
  329. return redirect(url_for("admin.forums"))
  330. @admin.route("/forums/add", methods=["GET", "POST"])
  331. @admin.route("/forums/<int:category_id>/add", methods=["GET", "POST"])
  332. @admin_required
  333. def add_forum(category_id=None):
  334. form = AddForumForm()
  335. if form.validate_on_submit():
  336. form.save()
  337. flash("Forum successfully added.", "success")
  338. return redirect(url_for("admin.forums"))
  339. else:
  340. if category_id:
  341. category = Category.query.filter_by(id=category_id).first()
  342. form.category.data = category
  343. return render_template("admin/forum_form.html", form=form,
  344. title="Add Forum")
  345. @admin.route("/category/add", methods=["GET", "POST"])
  346. @admin_required
  347. def add_category():
  348. form = CategoryForm()
  349. if form.validate_on_submit():
  350. form.save()
  351. flash("Category successfully created.", "success")
  352. return redirect(url_for("admin.forums"))
  353. return render_template("admin/category_form.html", form=form,
  354. title="Add Category")
  355. @admin.route("/category/<int:category_id>/edit", methods=["GET", "POST"])
  356. @admin_required
  357. def edit_category(category_id):
  358. category = Category.query.filter_by(id=category_id).first_or_404()
  359. form = CategoryForm()
  360. if form.validate_on_submit():
  361. form.populate_obj(category)
  362. category.save()
  363. else:
  364. form.title.data = category.title
  365. form.description.data = category.description
  366. form.position.data = category.position
  367. return render_template("admin/category_form.html", form=form,
  368. title="Edit Category")
  369. @admin.route("/category/<int:category_id>/delete", methods=["GET", "POST"])
  370. @admin_required
  371. def delete_category(category_id):
  372. category = Category.query.filter_by(id=category_id).first_or_404()
  373. involved_users = User.query.filter(Forum.category_id == category.id,
  374. Topic.forum_id == Forum.id,
  375. Post.user_id == User.id).all()
  376. category.delete(involved_users)
  377. flash("Category with all associated forums deleted.", "success")
  378. return redirect(url_for("admin.forums"))