aboutsummaryrefslogtreecommitdiff
path: root/app/views/admin
diff options
context:
space:
mode:
authorrubenwardy <rw@rubenwardy.com>2019-01-08 17:37:33 +0000
committerrubenwardy <rw@rubenwardy.com>2019-01-08 17:37:33 +0000
commit9639cf04f1b54865884850d608f08b5df4afe169 (patch)
tree871a03bc37826a760f44e60c50b68fac880c4eee /app/views/admin
parent9866e43b4b4c7ff5c2338e1ed681661496800db7 (diff)
downloadcheatdb-9639cf04f1b54865884850d608f08b5df4afe169.tar.xz
Improve views subfoldering
Diffstat (limited to 'app/views/admin')
-rw-r--r--app/views/admin/__init__.py18
-rw-r--r--app/views/admin/admin.py124
-rw-r--r--app/views/admin/licenseseditor.py62
-rw-r--r--app/views/admin/tagseditor.py57
-rw-r--r--app/views/admin/todo.py99
5 files changed, 360 insertions, 0 deletions
diff --git a/app/views/admin/__init__.py b/app/views/admin/__init__.py
new file mode 100644
index 0000000..b4b4f99
--- /dev/null
+++ b/app/views/admin/__init__.py
@@ -0,0 +1,18 @@
+# Content DB
+# Copyright (C) 2018 rubenwardy
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+from . import admin, licenseseditor, tagseditor, todo
diff --git a/app/views/admin/admin.py b/app/views/admin/admin.py
new file mode 100644
index 0000000..b2b615d
--- /dev/null
+++ b/app/views/admin/admin.py
@@ -0,0 +1,124 @@
+# Content DB
+# Copyright (C) 2018 rubenwardy
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+from flask import *
+from flask_user import *
+import flask_menu as menu
+from app import app
+from app.models import *
+from celery import uuid
+from app.tasks.importtasks import importRepoScreenshot, importAllDependencies, makeVCSRelease
+from app.tasks.forumtasks import importTopicList, checkAllForumAccounts
+from flask_wtf import FlaskForm
+from wtforms import *
+from app.utils import loginUser, rank_required, triggerNotif
+import datetime
+
+@app.route("/admin/", methods=["GET", "POST"])
+@rank_required(UserRank.ADMIN)
+def admin_page():
+ if request.method == "POST":
+ action = request.form["action"]
+ if action == "importmodlist":
+ task = importTopicList.delay()
+ return redirect(url_for("check_task", id=task.id, r=url_for("todo_topics_page")))
+ elif action == "checkusers":
+ task = checkAllForumAccounts.delay()
+ return redirect(url_for("check_task", id=task.id, r=url_for("admin_page")))
+ elif action == "importscreenshots":
+ packages = Package.query \
+ .filter_by(soft_deleted=False) \
+ .outerjoin(PackageScreenshot, Package.id==PackageScreenshot.package_id) \
+ .filter(PackageScreenshot.id==None) \
+ .all()
+ for package in packages:
+ importRepoScreenshot.delay(package.id)
+
+ return redirect(url_for("admin_page"))
+ elif action == "restore":
+ package = Package.query.get(request.form["package"])
+ if package is None:
+ flash("Unknown package", "error")
+ else:
+ package.soft_deleted = False
+ db.session.commit()
+ return redirect(url_for("admin_page"))
+ elif action == "importdepends":
+ task = importAllDependencies.delay()
+ return redirect(url_for("check_task", id=task.id, r=url_for("admin_page")))
+ elif action == "modprovides":
+ packages = Package.query.filter_by(type=PackageType.MOD).all()
+ mpackage_cache = {}
+ for p in packages:
+ if len(p.provides) == 0:
+ p.provides.append(MetaPackage.GetOrCreate(p.name, mpackage_cache))
+
+ db.session.commit()
+ return redirect(url_for("admin_page"))
+ elif action == "recalcscores":
+ for p in Package.query.all():
+ p.recalcScore()
+
+ db.session.commit()
+ return redirect(url_for("admin_page"))
+ elif action == "vcsrelease":
+ for package in Package.query.filter(Package.repo.isnot(None)).all():
+ if package.releases.count() != 0:
+ continue
+
+ rel = PackageRelease()
+ rel.package = package
+ rel.title = datetime.date.today().isoformat()
+ rel.url = ""
+ rel.task_id = uuid()
+ rel.approved = True
+ db.session.add(rel)
+ db.session.commit()
+
+ makeVCSRelease.apply_async((rel.id, "master"), task_id=rel.task_id)
+
+ msg = "{}: Release {} created".format(package.title, rel.title)
+ triggerNotif(package.author, current_user, msg, rel.getEditURL())
+ db.session.commit()
+
+ else:
+ flash("Unknown action: " + action, "error")
+
+ deleted_packages = Package.query.filter_by(soft_deleted=True).all()
+ return render_template("admin/list.html", deleted_packages=deleted_packages)
+
+class SwitchUserForm(FlaskForm):
+ username = StringField("Username")
+ submit = SubmitField("Switch")
+
+
+@app.route("/admin/switchuser/", methods=["GET", "POST"])
+@rank_required(UserRank.ADMIN)
+def switch_user_page():
+ form = SwitchUserForm(formdata=request.form)
+ if request.method == "POST" and form.validate():
+ user = User.query.filter_by(username=form["username"].data).first()
+ if user is None:
+ flash("Unable to find user", "error")
+ elif loginUser(user):
+ return redirect(url_for("user_profile_page", username=current_user.username))
+ else:
+ flash("Unable to login as user", "error")
+
+
+ # Process GET or invalid POST
+ return render_template("admin/switch_user_page.html", form=form)
diff --git a/app/views/admin/licenseseditor.py b/app/views/admin/licenseseditor.py
new file mode 100644
index 0000000..343f4ee
--- /dev/null
+++ b/app/views/admin/licenseseditor.py
@@ -0,0 +1,62 @@
+# Content DB
+# Copyright (C) 2018 rubenwardy
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+from flask import *
+from flask_user import *
+from app import app
+from app.models import *
+from flask_wtf import FlaskForm
+from wtforms import *
+from wtforms.validators import *
+from app.utils import rank_required
+
+@app.route("/licenses/")
+@rank_required(UserRank.MODERATOR)
+def license_list_page():
+ return render_template("admin/licenses/list.html", licenses=License.query.order_by(db.asc(License.name)).all())
+
+class LicenseForm(FlaskForm):
+ name = StringField("Name", [InputRequired(), Length(3,100)])
+ is_foss = BooleanField("Is FOSS")
+ submit = SubmitField("Save")
+
+@app.route("/licenses/new/", methods=["GET", "POST"])
+@app.route("/licenses/<name>/edit/", methods=["GET", "POST"])
+@rank_required(UserRank.MODERATOR)
+def createedit_license_page(name=None):
+ license = None
+ if name is not None:
+ license = License.query.filter_by(name=name).first()
+ if license is None:
+ abort(404)
+
+ form = LicenseForm(formdata=request.form, obj=license)
+ if request.method == "GET" and license is None:
+ form.is_foss.data = True
+ elif request.method == "POST" and form.validate():
+ if license is None:
+ license = License(form.name.data)
+ db.session.add(license)
+ flash("Created license " + form.name.data, "success")
+ else:
+ flash("Updated license " + form.name.data, "success")
+
+ form.populate_obj(license)
+ db.session.commit()
+ return redirect(url_for("license_list_page"))
+
+ return render_template("admin/licenses/edit.html", license=license, form=form)
diff --git a/app/views/admin/tagseditor.py b/app/views/admin/tagseditor.py
new file mode 100644
index 0000000..7d88f28
--- /dev/null
+++ b/app/views/admin/tagseditor.py
@@ -0,0 +1,57 @@
+# Content DB
+# Copyright (C) 2018 rubenwardy
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+from flask import *
+from flask_user import *
+from app import app
+from app.models import *
+from flask_wtf import FlaskForm
+from wtforms import *
+from wtforms.validators import *
+from app.utils import rank_required
+
+@app.route("/tags/")
+@rank_required(UserRank.MODERATOR)
+def tag_list_page():
+ return render_template("admin/tags/list.html", tags=Tag.query.order_by(db.asc(Tag.title)).all())
+
+class TagForm(FlaskForm):
+ title = StringField("Title", [InputRequired(), Length(3,100)])
+ name = StringField("Name", [Optional(), Length(1, 20), Regexp("^[a-z0-9_]", 0, "Lower case letters (a-z), digits (0-9), and underscores (_) only")])
+ submit = SubmitField("Save")
+
+@app.route("/tags/new/", methods=["GET", "POST"])
+@app.route("/tags/<name>/edit/", methods=["GET", "POST"])
+@rank_required(UserRank.MODERATOR)
+def createedit_tag_page(name=None):
+ tag = None
+ if name is not None:
+ tag = Tag.query.filter_by(name=name).first()
+ if tag is None:
+ abort(404)
+
+ form = TagForm(formdata=request.form, obj=tag)
+ if request.method == "POST" and form.validate():
+ if tag is None:
+ tag = Tag(form.title.data)
+ db.session.add(tag)
+ else:
+ form.populate_obj(tag)
+ db.session.commit()
+ return redirect(url_for("createedit_tag_page", name=tag.name))
+
+ return render_template("admin/tags/edit.html", tag=tag, form=form)
diff --git a/app/views/admin/todo.py b/app/views/admin/todo.py
new file mode 100644
index 0000000..47b8cb5
--- /dev/null
+++ b/app/views/admin/todo.py
@@ -0,0 +1,99 @@
+# Content DB
+# Copyright (C) 2018 rubenwardy
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+from flask import *
+from flask_user import *
+import flask_menu as menu
+from app import app
+from app.models import *
+
+@app.route("/todo/")
+@login_required
+def todo_page():
+ canApproveNew = Permission.APPROVE_NEW.check(current_user)
+ canApproveRel = Permission.APPROVE_RELEASE.check(current_user)
+ canApproveScn = Permission.APPROVE_SCREENSHOT.check(current_user)
+
+ packages = None
+ if canApproveNew:
+ packages = Package.query.filter_by(approved=False, soft_deleted=False).all()
+
+ releases = None
+ if canApproveRel:
+ releases = PackageRelease.query.filter_by(approved=False).all()
+
+ screenshots = None
+ if canApproveScn:
+ screenshots = PackageScreenshot.query.filter_by(approved=False).all()
+
+
+ topics_to_add = ForumTopic.query \
+ .filter(~ db.exists().where(Package.forums==ForumTopic.topic_id)) \
+ .filter_by(discarded=False) \
+ .count()
+
+ return render_template("todo/list.html", title="Reports and Work Queue",
+ packages=packages, releases=releases, screenshots=screenshots,
+ canApproveNew=canApproveNew, canApproveRel=canApproveRel, canApproveScn=canApproveScn,
+ topics_to_add=topics_to_add)
+
+
+@app.route("/todo/topics/")
+@login_required
+def todo_topics_page():
+ query = ForumTopic.query
+
+ show_discarded = request.args.get("show_discarded") == "True"
+ if not show_discarded:
+ query = query.filter_by(discarded=False)
+
+ total = query.count()
+
+ query = query.filter(~ db.exists().where(Package.forums==ForumTopic.topic_id)) \
+
+ sort_by = request.args.get("sort")
+ if sort_by == "name":
+ query = query.order_by(db.asc(ForumTopic.wip), db.asc(ForumTopic.name), db.asc(ForumTopic.title))
+ elif sort_by == "views":
+ query = query.order_by(db.desc(ForumTopic.views))
+ elif sort_by is None or sort_by == "date":
+ query = query.order_by(db.asc(ForumTopic.created_at))
+ sort_by = "date"
+
+ topic_count = query.count()
+
+ search = request.args.get("q")
+ if search is not None and search.strip() != "":
+ query = query.filter(ForumTopic.title.ilike('%' + search + '%'))
+
+ page = int(request.args.get("page") or 1)
+ num = int(request.args.get("n") or 100)
+ if num > 100 and not current_user.rank.atLeast(UserRank.EDITOR):
+ num = 100
+
+ query = query.paginate(page, num, True)
+ next_url = url_for("todo_topics_page", page=query.next_num, query=search, \
+ show_discarded=show_discarded, n=num, sort=sort_by) \
+ if query.has_next else None
+ prev_url = url_for("todo_topics_page", page=query.prev_num, query=search, \
+ show_discarded=show_discarded, n=num, sort=sort_by) \
+ if query.has_prev else None
+
+ return render_template("todo/topics.html", topics=query.items, total=total, \
+ topic_count=topic_count, query=search, show_discarded=show_discarded, \
+ next_url=next_url, prev_url=prev_url, page=page, page_max=query.pages, \
+ n=num, sort_by=sort_by)