aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrubenwardy <rw@rubenwardy.com>2019-11-15 23:51:42 +0000
committerrubenwardy <rw@rubenwardy.com>2019-11-15 23:51:42 +0000
commit64f131ae27a7332245b5a4eb8e1e4879d7d99578 (patch)
treea0b4101ca9c2132a072f1586c0df693583c91cf7
parent015abe5a2507ad02273bc89953016c386aae4457 (diff)
downloadcheatdb-64f131ae27a7332245b5a4eb8e1e4879d7d99578.tar.xz
Refactor endpoints to use blueprints instead
-rw-r--r--.gitignore4
-rw-r--r--Dockerfile6
-rw-r--r--app/__init__.py35
-rw-r--r--app/blueprints/__init__.py10
-rw-r--r--app/blueprints/admin/__init__.py (renamed from app/views/users/__init__.py)6
-rw-r--r--app/blueprints/admin/admin.py (renamed from app/views/admin/admin.py)28
-rw-r--r--app/blueprints/admin/licenseseditor.py (renamed from app/views/admin/licenseseditor.py)14
-rw-r--r--app/blueprints/admin/tagseditor.py (renamed from app/views/admin/tagseditor.py)14
-rw-r--r--app/blueprints/admin/versioneditor.py (renamed from app/views/admin/versioneditor.py)14
-rw-r--r--app/blueprints/api/__init__.py (renamed from app/views/api.py)29
-rw-r--r--app/blueprints/homepage/__init__.py20
-rw-r--r--app/blueprints/metapackages/__init__.py (renamed from app/views/meta.py)12
-rw-r--r--app/blueprints/notifications/__init__.py (renamed from app/views/users/notifications.py)17
-rw-r--r--app/blueprints/packages/__init__.py (renamed from app/views/packages/__init__.py)3
-rw-r--r--app/blueprints/packages/editrequests.py (renamed from app/views/packages/editrequests.py)1
-rw-r--r--app/blueprints/packages/packages.py (renamed from app/views/packages/packages.py)55
-rw-r--r--app/blueprints/packages/releases.py (renamed from app/views/packages/releases.py)23
-rw-r--r--app/blueprints/packages/screenshots.py (renamed from app/views/packages/screenshots.py)13
-rw-r--r--app/blueprints/tasks/__init__.py (renamed from app/views/tasks.py)16
-rw-r--r--app/blueprints/threads/__init__.py (renamed from app/views/threads.py)42
-rw-r--r--app/blueprints/thumbnails/__init__.py (renamed from app/views/thumbnails.py)5
-rw-r--r--app/blueprints/todo/__init__.py (renamed from app/views/admin/todo.py)18
-rw-r--r--app/blueprints/users/__init__.py5
-rw-r--r--app/blueprints/users/githublogin.py (renamed from app/views/users/githublogin.py)13
-rw-r--r--app/blueprints/users/profile.py (renamed from app/views/users/users.py)69
-rw-r--r--app/models.py26
-rw-r--r--app/sass.py (renamed from app/views/sass.py)10
-rw-r--r--app/tasks/emails.py2
-rw-r--r--app/tasks/importtasks.py2
-rw-r--r--app/template_filters.py22
-rw-r--r--app/templates/admin/licenses/edit.html4
-rw-r--r--app/templates/admin/licenses/list.html4
-rw-r--r--app/templates/admin/list.html10
-rw-r--r--app/templates/admin/switch_user.html (renamed from app/templates/admin/switch_user_page.html)0
-rw-r--r--app/templates/admin/tags/edit.html4
-rw-r--r--app/templates/admin/tags/list.html4
-rw-r--r--app/templates/admin/versions/edit.html4
-rw-r--r--app/templates/admin/versions/list.html4
-rw-r--r--app/templates/base.html22
-rw-r--r--app/templates/emails/verify.html4
-rw-r--r--app/templates/flask_user/login.html4
-rw-r--r--app/templates/index.html8
-rw-r--r--app/templates/macros/threads.html12
-rw-r--r--app/templates/macros/topics.html8
-rw-r--r--app/templates/meta/list.html2
-rw-r--r--app/templates/notifications/list.html2
-rw-r--r--app/templates/packages/list.html2
-rw-r--r--app/templates/packages/release_edit.html2
-rw-r--r--app/templates/packages/view.html16
-rw-r--r--app/templates/tasks/view.html2
-rw-r--r--app/templates/todo/list.html4
-rw-r--r--app/templates/todo/topics.html16
-rw-r--r--app/templates/users/claim.html6
-rw-r--r--app/templates/users/list.html2
-rw-r--r--app/templates/users/user_profile_page.html10
-rw-r--r--app/views/__init__.py84
-rw-r--r--app/views/admin/__init__.py18
57 files changed, 396 insertions, 396 deletions
diff --git a/.gitignore b/.gitignore
index 7ab19d3..c8dd729 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,8 +6,8 @@ custom.css
tmp
log.txt
*.rdb
-uploads
-thumbnails
+app/public/uploads
+app/public/thumbnails
celerybeat-schedule
/data
diff --git a/Dockerfile b/Dockerfile
index 0bcaa9e..c88d0a3 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -10,10 +10,10 @@ RUN pip install -r ./requirements.txt
RUN pip install gunicorn
COPY utils utils
-COPY app app
-COPY migrations migrations
COPY config.cfg ./config.cfg
+COPY migrations migrations
+COPY app app
+RUN mkdir /home/cdb/app/public/uploads/
RUN chown cdb:cdb /home/cdb -R
-
USER cdb
diff --git a/app/__init__.py b/app/__init__.py
index c5d8000..a0b4ba5 100644
--- a/app/__init__.py
+++ b/app/__init__.py
@@ -48,6 +48,10 @@ gravatar = Gravatar(app,
use_ssl=True,
base_url=None)
+from .sass import sass
+sass(app)
+
+
if not app.debug and app.config["MAIL_UTILS_ERROR_SEND_TO"]:
from .maillogger import register_mail_error_handler
register_mail_error_handler(app, mail)
@@ -55,8 +59,33 @@ if not app.debug and app.config["MAIL_UTILS_ERROR_SEND_TO"]:
@babel.localeselector
def get_locale():
- return request.accept_languages.best_match(app.config['LANGUAGES'].keys())
+ return request.accept_languages.best_match(app.config['LANGUAGES'].keys())
+
+from . import models, tasks, template_filters
+
+from .blueprints import create_blueprints
+create_blueprints(app)
+
+from flask_login import logout_user
+
+@app.route("/uploads/<path:path>")
+def send_upload(path):
+ return send_from_directory("public/uploads", path)
+@menu.register_menu(app, ".help", "Help", order=19, endpoint_arguments_constructor=lambda: { 'path': 'help' })
+@app.route('/<path:path>/')
+def flatpage(path):
+ page = pages.get_or_404(path)
+ template = page.meta.get('template', 'flatpage.html')
+ return render_template(template, page=page)
-from . import models, tasks
-from .views import *
+@app.before_request
+def check_for_ban():
+ if current_user.is_authenticated:
+ if current_user.rank == models.UserRank.BANNED:
+ flash("You have been banned.", "error")
+ logout_user()
+ return redirect(url_for('user.login'))
+ elif current_user.rank == models.UserRank.NOT_JOINED:
+ current_user.rank = models.UserRank.MEMBER
+ models.db.session.commit()
diff --git a/app/blueprints/__init__.py b/app/blueprints/__init__.py
new file mode 100644
index 0000000..74aa9ae
--- /dev/null
+++ b/app/blueprints/__init__.py
@@ -0,0 +1,10 @@
+import os, importlib
+
+def create_blueprints(app):
+ dir = os.path.dirname(os.path.realpath(__file__))
+ modules = next(os.walk(dir))[1]
+
+ for modname in modules:
+ if all(c.islower() for c in modname):
+ module = importlib.import_module("." + modname, __name__)
+ app.register_blueprint(module.bp)
diff --git a/app/views/users/__init__.py b/app/blueprints/admin/__init__.py
index 45af431..66eb1ea 100644
--- a/app/views/users/__init__.py
+++ b/app/blueprints/admin/__init__.py
@@ -15,4 +15,8 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
-from . import users, githublogin, notifications
+from flask import Blueprint
+
+bp = Blueprint("admin", __name__)
+
+from . import admin, licenseseditor, tagseditor, versioneditor
diff --git a/app/views/admin/admin.py b/app/blueprints/admin/admin.py
index b359700..2a2bace 100644
--- a/app/views/admin/admin.py
+++ b/app/blueprints/admin/admin.py
@@ -18,7 +18,7 @@
from flask import *
from flask_user import *
import flask_menu as menu
-from app import app
+from . import bp
from app.models import *
from celery import uuid
from app.tasks.importtasks import importRepoScreenshot, importAllDependencies, makeVCSRelease
@@ -28,7 +28,7 @@ from wtforms import *
from app.utils import loginUser, rank_required, triggerNotif
import datetime
-@app.route("/admin/", methods=["GET", "POST"])
+@bp.route("/admin/", methods=["GET", "POST"])
@rank_required(UserRank.ADMIN)
def admin_page():
if request.method == "POST":
@@ -36,13 +36,13 @@ def admin_page():
if action == "delstuckreleases":
PackageRelease.query.filter(PackageRelease.task_id != None).delete()
db.session.commit()
- return redirect(url_for("admin_page"))
+ return redirect(url_for("admin.admin_page"))
elif action == "importmodlist":
task = importTopicList.delay()
- return redirect(url_for("check_task", id=task.id, r=url_for("todo_topics_page")))
+ return redirect(url_for("tasks.check", id=task.id, r=url_for("todo.topics")))
elif action == "checkusers":
task = checkAllForumAccounts.delay()
- return redirect(url_for("check_task", id=task.id, r=url_for("admin_page")))
+ return redirect(url_for("tasks.check", id=task.id, r=url_for("admin.admin_page")))
elif action == "importscreenshots":
packages = Package.query \
.filter_by(soft_deleted=False) \
@@ -52,7 +52,7 @@ def admin_page():
for package in packages:
importRepoScreenshot.delay(package.id)
- return redirect(url_for("admin_page"))
+ return redirect(url_for("admin.admin_page"))
elif action == "restore":
package = Package.query.get(request.form["package"])
if package is None:
@@ -60,10 +60,10 @@ def admin_page():
else:
package.soft_deleted = False
db.session.commit()
- return redirect(url_for("admin_page"))
+ return redirect(url_for("admin.admin_page"))
elif action == "importdepends":
task = importAllDependencies.delay()
- return redirect(url_for("check_task", id=task.id, r=url_for("admin_page")))
+ return redirect(url_for("tasks.check", id=task.id, r=url_for("admin.admin_page")))
elif action == "modprovides":
packages = Package.query.filter_by(type=PackageType.MOD).all()
mpackage_cache = {}
@@ -72,13 +72,13 @@ def admin_page():
p.provides.append(MetaPackage.GetOrCreate(p.name, mpackage_cache))
db.session.commit()
- return redirect(url_for("admin_page"))
+ return redirect(url_for("admin.admin_page"))
elif action == "recalcscores":
for p in Package.query.all():
p.recalcScore()
db.session.commit()
- return redirect(url_for("admin_page"))
+ return redirect(url_for("admin.admin_page"))
elif action == "vcsrelease":
for package in Package.query.filter(Package.repo.isnot(None)).all():
if package.releases.count() != 0:
@@ -110,19 +110,19 @@ class SwitchUserForm(FlaskForm):
submit = SubmitField("Switch")
-@app.route("/admin/switchuser/", methods=["GET", "POST"])
+@bp.route("/admin/switchuser/", methods=["GET", "POST"])
@rank_required(UserRank.ADMIN)
-def switch_user_page():
+def switch_user():
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))
+ return redirect(url_for("users.profile", 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)
+ return render_template("admin/switch_user.html", form=form)
diff --git a/app/views/admin/licenseseditor.py b/app/blueprints/admin/licenseseditor.py
index 343f4ee..c6fca02 100644
--- a/app/views/admin/licenseseditor.py
+++ b/app/blueprints/admin/licenseseditor.py
@@ -17,16 +17,16 @@
from flask import *
from flask_user import *
-from app import app
+from . import bp
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/")
+@bp.route("/licenses/")
@rank_required(UserRank.MODERATOR)
-def license_list_page():
+def license_list():
return render_template("admin/licenses/list.html", licenses=License.query.order_by(db.asc(License.name)).all())
class LicenseForm(FlaskForm):
@@ -34,10 +34,10 @@ class LicenseForm(FlaskForm):
is_foss = BooleanField("Is FOSS")
submit = SubmitField("Save")
-@app.route("/licenses/new/", methods=["GET", "POST"])
-@app.route("/licenses/<name>/edit/", methods=["GET", "POST"])
+@bp.route("/licenses/new/", methods=["GET", "POST"])
+@bp.route("/licenses/<name>/edit/", methods=["GET", "POST"])
@rank_required(UserRank.MODERATOR)
-def createedit_license_page(name=None):
+def create_edit_license(name=None):
license = None
if name is not None:
license = License.query.filter_by(name=name).first()
@@ -57,6 +57,6 @@ def createedit_license_page(name=None):
form.populate_obj(license)
db.session.commit()
- return redirect(url_for("license_list_page"))
+ return redirect(url_for("admin.license_list"))
return render_template("admin/licenses/edit.html", license=license, form=form)
diff --git a/app/views/admin/tagseditor.py b/app/blueprints/admin/tagseditor.py
index 7d88f28..8fb89f4 100644
--- a/app/views/admin/tagseditor.py
+++ b/app/blueprints/admin/tagseditor.py
@@ -17,16 +17,16 @@
from flask import *
from flask_user import *
-from app import app
+from . import bp
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/")
+@bp.route("/tags/")
@rank_required(UserRank.MODERATOR)
-def tag_list_page():
+def tag_list():
return render_template("admin/tags/list.html", tags=Tag.query.order_by(db.asc(Tag.title)).all())
class TagForm(FlaskForm):
@@ -34,10 +34,10 @@ class TagForm(FlaskForm):
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"])
+@bp.route("/tags/new/", methods=["GET", "POST"])
+@bp.route("/tags/<name>/edit/", methods=["GET", "POST"])
@rank_required(UserRank.MODERATOR)
-def createedit_tag_page(name=None):
+def create_edit_tag(name=None):
tag = None
if name is not None:
tag = Tag.query.filter_by(name=name).first()
@@ -52,6 +52,6 @@ def createedit_tag_page(name=None):
else:
form.populate_obj(tag)
db.session.commit()
- return redirect(url_for("createedit_tag_page", name=tag.name))
+ return redirect(url_for("admin.create_edit_tag", name=tag.name))
return render_template("admin/tags/edit.html", tag=tag, form=form)
diff --git a/app/views/admin/versioneditor.py b/app/blueprints/admin/versioneditor.py
index 6bcf93a..98a9a7c 100644
--- a/app/views/admin/versioneditor.py
+++ b/app/blueprints/admin/versioneditor.py
@@ -17,16 +17,16 @@
from flask import *
from flask_user import *
-from app import app
+from . import bp
from app.models import *
from flask_wtf import FlaskForm
from wtforms import *
from wtforms.validators import *
from app.utils import rank_required
-@app.route("/versions/")
+@bp.route("/versions/")
@rank_required(UserRank.MODERATOR)
-def version_list_page():
+def version_list():
return render_template("admin/versions/list.html", versions=MinetestRelease.query.order_by(db.asc(MinetestRelease.id)).all())
class VersionForm(FlaskForm):
@@ -34,10 +34,10 @@ class VersionForm(FlaskForm):
protocol = IntegerField("Protocol")
submit = SubmitField("Save")
-@app.route("/versions/new/", methods=["GET", "POST"])
-@app.route("/versions/<name>/edit/", methods=["GET", "POST"])
+@bp.route("/versions/new/", methods=["GET", "POST"])
+@bp.route("/versions/<name>/edit/", methods=["GET", "POST"])
@rank_required(UserRank.MODERATOR)
-def createedit_version_page(name=None):
+def create_edit_version(name=None):
version = None
if name is not None:
version = MinetestRelease.query.filter_by(name=name).first()
@@ -55,6 +55,6 @@ def createedit_version_page(name=None):
form.populate_obj(version)
db.session.commit()
- return redirect(url_for("version_list_page"))
+ return redirect(url_for("admin.version_list"))
return render_template("admin/versions/edit.html", version=version, form=form)
diff --git a/app/views/api.py b/app/blueprints/api/__init__.py
index ba42aca..5092f21 100644
--- a/app/views/api.py
+++ b/app/blueprints/api/__init__.py
@@ -17,31 +17,32 @@
from flask import *
from flask_user import *
-from app import app
from app.models import *
from app.utils import is_package_page
from app.querybuilder import QueryBuilder
-@app.route("/api/packages/")
-def api_packages_page():
+bp = Blueprint("api", __name__)
+
+@bp.route("/api/packages/")
+def packages():
qb = QueryBuilder(request.args)
query = qb.buildPackageQuery()
ver = qb.getMinetestVersion()
- pkgs = [package.getAsDictionaryShort(app.config["BASE_URL"], version=ver) \
+ pkgs = [package.getAsDictionaryShort(current_app.config["BASE_URL"], version=ver) \
for package in query.all()]
return jsonify(pkgs)
-@app.route("/api/packages/<author>/<name>/")
+@bp.route("/api/packages/<author>/<name>/")
@is_package_page
-def api_package_page(package):
- return jsonify(package.getAsDictionary(app.config["BASE_URL"]))
+def package(package):
+ return jsonify(package.getAsDictionary(current_app.config["BASE_URL"]))
-@app.route("/api/packages/<author>/<name>/dependencies/")
+@bp.route("/api/packages/<author>/<name>/dependencies/")
@is_package_page
-def api_package_deps_page(package):
+def package_dependencies(package):
ret = []
for dep in package.dependencies:
@@ -68,14 +69,14 @@ def api_package_deps_page(package):
return jsonify(ret)
-@app.route("/api/topics/")
-def api_topics_page():
+@bp.route("/api/topics/")
+def topics():
qb = QueryBuilder(request.args)
query = qb.buildTopicQuery(show_added=True)
return jsonify([t.getAsDictionary() for t in query.all()])
-@app.route("/api/topic_discard/", methods=["POST"])
+@bp.route("/api/topic_discard/", methods=["POST"])
@login_required
def topic_set_discard():
tid = request.args.get("tid")
@@ -93,7 +94,7 @@ def topic_set_discard():
return jsonify(topic.getAsDictionary())
-@app.route("/api/minetest_versions/")
-def api_minetest_versions_page():
+@bp.route("/api/minetest_versions/")
+def versions():
return jsonify([{ "name": rel.name, "protocol_version": rel.protocol }\
for rel in MinetestRelease.query.all() if rel.getActual() is not None])
diff --git a/app/blueprints/homepage/__init__.py b/app/blueprints/homepage/__init__.py
new file mode 100644
index 0000000..0d50bbd
--- /dev/null
+++ b/app/blueprints/homepage/__init__.py
@@ -0,0 +1,20 @@
+from flask import Blueprint, render_template
+
+bp = Blueprint("homepage", __name__)
+
+from app.models import *
+import flask_menu as menu
+from sqlalchemy.sql.expression import func
+
+@bp.route("/")
+@menu.register_menu(bp, ".", "Home")
+def home_page():
+ query = Package.query.filter_by(approved=True, soft_deleted=False)
+ count = query.count()
+ new = query.order_by(db.desc(Package.created_at)).limit(8).all()
+ pop_mod = query.filter_by(type=PackageType.MOD).order_by(db.desc(Package.score)).limit(8).all()
+ pop_gam = query.filter_by(type=PackageType.GAME).order_by(db.desc(Package.score)).limit(4).all()
+ pop_txp = query.filter_by(type=PackageType.TXP).order_by(db.desc(Package.score)).limit(4).all()
+ downloads = db.session.query(func.sum(PackageRelease.downloads)).first()[0]
+ return render_template("index.html", count=count, downloads=downloads, \
+ new=new, pop_mod=pop_mod, pop_txp=pop_txp, pop_gam=pop_gam)
diff --git a/app/views/meta.py b/app/blueprints/metapackages/__init__.py
index 9083289..ff54e6d 100644
--- a/app/views/meta.py
+++ b/app/blueprints/metapackages/__init__.py
@@ -16,17 +16,19 @@
from flask import *
+
+bp = Blueprint("metapackages", __name__)
+
from flask_user import *
-from app import app
from app.models import *
-@app.route("/metapackages/")
-def meta_package_list_page():
+@bp.route("/metapackages/")
+def list_all():
mpackages = MetaPackage.query.order_by(db.asc(MetaPackage.name)).all()
return render_template("meta/list.html", mpackages=mpackages)
-@app.route("/metapackages/<name>/")
-def meta_package_page(name):
+@bp.route("/metapackages/<name>/")
+def view(name):
mpackage = MetaPackage.query.filter_by(name=name).first()
if mpackage is None:
abort(404)
diff --git a/app/views/users/notifications.py b/app/blueprints/notifications/__init__.py
index 23dbb31..77263e5 100644
--- a/app/views/users/notifications.py
+++ b/app/blueprints/notifications/__init__.py
@@ -15,19 +15,20 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
-from flask import *
+from flask import Blueprint
from flask_user import current_user, login_required
-from app import app
-from app.models import *
+from app.models import db
-@app.route("/notifications/")
+bp = Blueprint("notifications", __name__)
+
+@bp.route("/notifications/")
@login_required
-def notifications_page():
+def list_all():
return render_template("notifications/list.html")
-@app.route("/notifications/clear/", methods=["POST"])
+@bp.route("/notifications/clear/", methods=["POST"])
@login_required
-def clear_notifications_page():
+def clear():
current_user.notifications.clear()
db.session.commit()
- return redirect(url_for("notifications_page"))
+ return redirect(url_for("notifications.list_all"))
diff --git a/app/views/packages/__init__.py b/app/blueprints/packages/__init__.py
index 5df5376..e4fc4f2 100644
--- a/app/views/packages/__init__.py
+++ b/app/blueprints/packages/__init__.py
@@ -14,5 +14,8 @@
# 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 Blueprint
+
+bp = Blueprint("packages", __name__)
from . import packages, screenshots, releases
diff --git a/app/views/packages/editrequests.py b/app/blueprints/packages/editrequests.py
index 7b52184..5ee9cd1 100644
--- a/app/views/packages/editrequests.py
+++ b/app/blueprints/packages/editrequests.py
@@ -14,7 +14,6 @@
# 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
diff --git a/app/views/packages/packages.py b/app/blueprints/packages/packages.py
index 38aacbe..1cc2f26 100644
--- a/app/views/packages/packages.py
+++ b/app/blueprints/packages/packages.py
@@ -18,11 +18,14 @@
from flask import render_template, abort, request, redirect, url_for, flash
from flask_user import current_user
import flask_menu as menu
-from app import app
+
+from . import bp
+
from app.models import *
from app.querybuilder import QueryBuilder
from app.tasks.importtasks import importRepoScreenshot
from app.utils import *
+
from flask_wtf import FlaskForm
from wtforms import *
from wtforms.validators import *
@@ -30,12 +33,12 @@ from wtforms.ext.sqlalchemy.fields import QuerySelectField, QuerySelectMultipleF
from sqlalchemy import or_
-@menu.register_menu(app, ".mods", "Mods", order=11, endpoint_arguments_constructor=lambda: { 'type': 'mod' })
-@menu.register_menu(app, ".games", "Games", order=12, endpoint_arguments_constructor=lambda: { 'type': 'game' })
-@menu.register_menu(app, ".txp", "Texture Packs", order=13, endpoint_arguments_constructor=lambda: { 'type': 'txp' })
-@menu.register_menu(app, ".random", "Random", order=14, endpoint_arguments_constructor=lambda: { 'random': '1' })
-@app.route("/packages/")
-def packages_page():
+@menu.register_menu(bp, ".mods", "Mods", order=11, endpoint_arguments_constructor=lambda: { 'type': 'mod' })
+@menu.register_menu(bp, ".games", "Games", order=12, endpoint_arguments_constructor=lambda: { 'type': 'game' })
+@menu.register_menu(bp, ".txp", "Texture Packs", order=13, endpoint_arguments_constructor=lambda: { 'type': 'txp' })
+@menu.register_menu(bp, ".random", "Random", order=14, endpoint_arguments_constructor=lambda: { 'random': '1' })
+@bp.route("/packages/")
+def list_all():
qb = QueryBuilder(request.args)
query = qb.buildPackageQuery()
title = qb.title
@@ -56,9 +59,9 @@ def packages_page():
search = request.args.get("q")
type_name = request.args.get("type")
- next_url = url_for("packages_page", type=type_name, q=search, page=query.next_num) \
+ next_url = url_for("packages.list_all", type=type_name, q=search, page=query.next_num) \
if query.has_next else None
- prev_url = url_for("packages_page", type=type_name, q=search, page=query.prev_num) \
+ prev_url = url_for("packages.list_all", type=type_name, q=search, page=query.prev_num) \
if query.has_prev else None
topics = None
@@ -79,9 +82,9 @@ def getReleases(package):
return package.releases.filter_by(approved=True).limit(5)
-@app.route("/packages/<author>/<name>/")
+@bp.route("/packages/<author>/<name>/")
@is_package_page
-def package_page(package):
+def view(package):
clearNotifications(package.getDetailsURL())
alternatives = None
@@ -147,9 +150,9 @@ def package_page(package):
threads=threads.all())
-@app.route("/packages/<author>/<name>/download/")
+@bp.route("/packages/<author>/<name>/download/")
@is_package_page
-def package_download_page(package):
+def download(package):
release = package.getDownloadRelease()
if release is None:
@@ -186,10 +189,10 @@ class PackageForm(FlaskForm):
forums = IntegerField("Forum Topic ID", [Optional(), NumberRange(0,999999)])
submit = SubmitField("Save")
-@app.route("/packages/new/", methods=["GET", "POST"])
-@app.route("/packages/<author>/<name>/edit/", methods=["GET", "POST"])
+@bp.route("/packages/new/", methods=["GET", "POST"])
+@bp.route("/packages/<author>/<name>/edit/", methods=["GET", "POST"])
@login_required
-def create_edit_package_page(author=None, name=None):
+def create_edit(author=None, name=None):
package = None
form = None
if author is None:
@@ -201,11 +204,11 @@ def create_edit_package_page(author=None, name=None):
author = User.query.filter_by(username=author).first()
if author is None:
flash("Unable to find that user", "error")
- return redirect(url_for("create_edit_package_page"))
+ return redirect(url_for("packages.create_edit"))
if not author.checkPerm(current_user, Permission.CHANGE_AUTHOR):
flash("Permission denied", "error")
- return redirect(url_for("create_edit_package_page"))
+ return redirect(url_for("packages.create_edit"))
else:
package = getPackageByInfo(author, name)
@@ -238,7 +241,7 @@ def create_edit_package_page(author=None, name=None):
Package.query.filter_by(name=form["name"].data, author_id=author.id).delete()
else:
flash("Package already exists!", "error")
- return redirect(url_for("create_edit_package_page"))
+ return redirect(url_for("packages.create_edit"))
package = Package()
package.author = author
@@ -247,7 +250,7 @@ def create_edit_package_page(author=None, name=None):
elif package.approved and package.name != form.name.data and \
not package.checkPerm(current_user, Permission.CHANGE_NAME):
flash("Unable to change package name", "danger")
- return redirect(url_for("create_edit_package_page", author=author, name=name))
+ return redirect(url_for("packages.create_edit", author=author, name=name))
else:
triggerNotif(package.author, current_user,
@@ -288,7 +291,7 @@ def create_edit_package_page(author=None, name=None):
next_url = package.getDetailsURL()
if wasNew and package.repo is not None:
task = importRepoScreenshot.delay(package.id)
- next_url = url_for("check_task", id=task.id, r=next_url)
+ next_url = url_for("tasks.check", id=task.id, r=next_url)
if wasNew and ("WTFPL" in package.license.name or "WTFPL" in package.media_license.name):
next_url = url_for("flatpage", path="help/wtfpl", r=next_url)
@@ -305,10 +308,10 @@ def create_edit_package_page(author=None, name=None):
packages=package_query.all(), \
mpackages=MetaPackage.query.order_by(db.asc(MetaPackage.name)).all())
-@app.route("/packages/<author>/<name>/approve/", methods=["POST"])
+@bp.route("/packages/<author>/<name>/approve/", methods=["POST"])
@login_required
@is_package_page
-def approve_package_page(package):
+def approve(package):
if not package.checkPerm(current_user, Permission.APPROVE_NEW):
flash("You don't have permission to do that.", "error")
@@ -329,10 +332,10 @@ def approve_package_page(package):
return redirect(package.getDetailsURL())
-@app.route("/packages/<author>/<name>/remove/", methods=["GET", "POST"])
+@bp.route("/packages/<author>/<name>/remove/", methods=["GET", "POST"])
@login_required
@is_package_page
-def remove_package_page(package):
+def remove(package):
if request.method == "GET":
return render_template("packages/remove.html", package=package)
@@ -343,7 +346,7 @@ def remove_package_page(package):
package.soft_deleted = True
- url = url_for("user_profile_page", username=package.author.username)
+ url = url_for("users.profile", username=package.author.username)
triggerNotif(package.author, current_user,
"{} deleted".format(package.title), url)
db.session.commit()
diff --git a/app/views/packages/releases.py b/app/blueprints/packages/releases.py
index 963f903..89a9a00 100644
--- a/app/views/packages/releases.py
+++ b/app/blueprints/packages/releases.py
@@ -17,10 +17,11 @@
from flask import *
from flask_user import *
-from app import app
+
+from . import bp
+
from app.models import *
from app.tasks.importtasks import makeVCSRelease
-
from app.utils import *
from celery import uuid
@@ -62,10 +63,10 @@ class EditPackageReleaseForm(FlaskForm):
query_factory=lambda: get_mt_releases(True), get_pk=lambda a: a.id, get_label=lambda a: a.name)
submit = SubmitField("Save")
-@app.route("/packages/<author>/<name>/releases/new/", methods=["GET", "POST"])
+@bp.route("/packages/<author>/<name>/releases/new/", methods=["GET", "POST"])
@login_required
@is_package_page
-def create_release_page(package):
+def create_release(package):
if not package.checkPerm(current_user, Permission.MAKE_RELEASE):
return redirect(package.getDetailsURL())
@@ -94,7 +95,7 @@ def create_release_page(package):
triggerNotif(package.author, current_user, msg, rel.getEditURL())
db.session.commit()
- return redirect(url_for("check_task", id=rel.task_id, r=rel.getEditURL()))
+ return redirect(url_for("tasks.check", id=rel.task_id, r=rel.getEditURL()))
else:
uploadedPath = doFileUpload(form.fileUpload.data, "zip", "a zip file")
if uploadedPath is not None:
@@ -115,9 +116,9 @@ def create_release_page(package):
return render_template("packages/release_new.html", package=package, form=form)
-@app.route("/packages/<author>/<name>/releases/<id>/download/")
+@bp.route("/packages/<author>/<name>/releases/<id>/download/")
@is_package_page
-def download_release_page(package, id):
+def download_release(package, id):
release = PackageRelease.query.get(id)
if release is None or release.package != package:
abort(404)
@@ -137,10 +138,10 @@ def download_release_page(package, id):
return redirect(release.url, code=300)
-@app.route("/packages/<author>/<name>/releases/<id>/", methods=["GET", "POST"])
+@bp.route("/packages/<author>/<name>/releases/<id>/", methods=["GET", "POST"])
@login_required
@is_package_page
-def edit_release_page(package, id):
+def edit_release(package, id):
release = PackageRelease.query.get(id)
if release is None or release.package != package:
abort(404)
@@ -190,10 +191,10 @@ class BulkReleaseForm(FlaskForm):
submit = SubmitField("Update")
-@app.route("/packages/<author>/<name>/releases/bulk_change/", methods=["GET", "POST"])
+@bp.route("/packages/<author>/<name>/releases/bulk_change/", methods=["GET", "POST"])
@login_required
@is_package_page
-def bulk_change_release_page(package):
+def bulk_change_release(package):
if not package.checkPerm(current_user, Permission.MAKE_RELEASE):
return redirect(package.getDetailsURL())
diff --git a/app/views/packages/screenshots.py b/app/blueprints/packages/screenshots.py
index dbb002b..c7fc7eb 100644
--- a/app/views/packages/screenshots.py
+++ b/app/blueprints/packages/screenshots.py
@@ -17,9 +17,10 @@
from flask import *
from flask_user import *
-from app import app
-from app.models import *
+from . import bp
+
+from app.models import *
from app.utils import *
from flask_wtf import FlaskForm
@@ -39,10 +40,10 @@ class EditScreenshotForm(FlaskForm):
delete = BooleanField("Delete")
submit = SubmitField("Save")
-@app.route("/packages/<author>/<name>/screenshots/new/", methods=["GET", "POST"])
+@bp.route("/packages/<author>/<name>/screenshots/new/", methods=["GET", "POST"])
@login_required
@is_package_page
-def create_screenshot_page(package, id=None):
+def create_screenshot(package, id=None):
if not package.checkPerm(current_user, Permission.ADD_SCREENSHOTS):
return redirect(package.getDetailsURL())
@@ -67,10 +68,10 @@ def create_screenshot_page(package, id=None):
return render_template("packages/screenshot_new.html", package=package, form=form)
-@app.route("/packages/<author>/<name>/screenshots/<id>/edit/", methods=["GET", "POST"])
+@bp.route("/packages/<author>/<name>/screenshots/<id>/edit/", methods=["GET", "POST"])
@login_required
@is_package_page
-def edit_screenshot_page(package, id):
+def edit_screenshot(package, id):
screenshot = PackageScreenshot.query.get(id)
if screenshot is None or screenshot.package != package:
abort(404)
diff --git a/app/views/tasks.py b/app/blueprints/tasks/__init__.py
index 20eaef5..8d002db 100644
--- a/app/views/tasks.py
+++ b/app/blueprints/tasks/__init__.py
@@ -18,28 +18,28 @@
from flask import *
from flask_user import *
import flask_menu as menu
-from app import app, csrf
+from app import csrf
from app.models import *
from app.tasks import celery, TaskError
from app.tasks.importtasks import getMeta
from app.utils import shouldReturnJson
-# from celery.result import AsyncResult
-
from app.utils import *
+bp = Blueprint("tasks", __name__)
+
@csrf.exempt
-@app.route("/tasks/getmeta/new/", methods=["POST"])
+@bp.route("/tasks/getmeta/new/", methods=["POST"])
@login_required
-def new_getmeta_page():
+def start_getmeta():
author = request.args.get("author")
author = current_user.forums_username if author is None else author
aresult = getMeta.delay(request.args.get("url"), author)
return jsonify({
- "poll_url": url_for("check_task", id=aresult.id),
+ "poll_url": url_for("tasks.check", id=aresult.id),
})
-@app.route("/tasks/<id>/")
-def check_task(id):
+@bp.route("/tasks/<id>/")
+def check(id):
result = celery.AsyncResult(id)
status = result.status
traceback = result.traceback
diff --git a/app/views/threads.py b/app/blueprints/threads/__init__.py
index e430577..0eee201 100644
--- a/app/views/threads.py
+++ b/app/blueprints/threads/__init__.py
@@ -16,8 +16,10 @@
from flask import *
+
+bp = Blueprint("threads", __name__)
+
from flask_user import *
-from app import app
from app.models import *
from app.utils import triggerNotif, clearNotifications
@@ -27,17 +29,17 @@ from flask_wtf import FlaskForm
from wtforms import *
from wtforms.validators import *
-@app.route("/threads/")
-def threads_page():
+@bp.route("/threads/")
+def list_all():
query = Thread.query
if not Permission.SEE_THREAD.check(current_user):
query = query.filter_by(private=False)
return render_template("threads/list.html", threads=query.all())
-@app.route("/threads/<int:id>/subscribe/", methods=["POST"])
+@bp.route("/threads/<int:id>/subscribe/", methods=["POST"])
@login_required
-def thread_subscribe_page(id):
+def subscribe(id):
thread = Thread.query.get(id)
if thread is None or not thread.checkPerm(current_user, Permission.SEE_THREAD):
abort(404)
@@ -49,12 +51,12 @@ def thread_subscribe_page(id):
thread.watchers.append(current_user)
db.session.commit()
- return redirect(url_for("thread_page", id=id))
+ return redirect(url_for("threads.view", id=id))
-@app.route("/threads/<int:id>/unsubscribe/", methods=["POST"])
+@bp.route("/threads/<int:id>/unsubscribe/", methods=["POST"])
@login_required
-def thread_unsubscribe_page(id):
+def unsubscribe(id):
thread = Thread.query.get(id)
if thread is None or not thread.checkPerm(current_user, Permission.SEE_THREAD):
abort(404)
@@ -66,12 +68,12 @@ def thread_unsubscribe_page(id):
else:
flash("Not subscribed to thread", "success")
- return redirect(url_for("thread_page", id=id))
+ return redirect(url_for("threads.view", id=id))
-@app.route("/threads/<int:id>/", methods=["GET", "POST"])
-def thread_page(id):
- clearNotifications(url_for("thread_page", id=id))
+@bp.route("/threads/<int:id>/", methods=["GET", "POST"])
+def view(id):
+ clearNotifications(url_for("threads.view", id=id))
thread = Thread.query.get(id)
if thread is None or not thread.checkPerm(current_user, Permission.SEE_THREAD):
@@ -106,11 +108,11 @@ def thread_page(id):
for user in thread.watchers:
if user != current_user:
- triggerNotif(user, current_user, msg, url_for("thread_page", id=thread.id))
+ triggerNotif(user, current_user, msg, url_for("threads.view", id=thread.id))
db.session.commit()
- return redirect(url_for("thread_page", id=id))
+ return redirect(url_for("threads.view", id=id))
else:
flash("Comment needs to be between 3 and 500 characters.")
@@ -124,9 +126,9 @@ class ThreadForm(FlaskForm):
private = BooleanField("Private")
submit = SubmitField("Open Thread")
-@app.route("/threads/new/", methods=["GET", "POST"])
+@bp.route("/threads/new/", methods=["GET", "POST"])
@login_required
-def new_thread_page():
+def new():
form = ThreadForm(formdata=request.form)
package = None
@@ -153,7 +155,7 @@ def new_thread_page():
# Only allow creating one thread when not approved
elif is_review_thread and package.review_thread is not None:
flash("A review thread already exists!", "error")
- return redirect(url_for("thread_page", id=package.review_thread.id))
+ return redirect(url_for("threads.view", id=package.review_thread.id))
elif not current_user.canOpenThreadRL():
flash("Please wait before opening another thread", "danger")
@@ -197,16 +199,16 @@ def new_thread_page():
notif_msg = None
if package is not None:
notif_msg = "New thread '{}' on package {}".format(thread.title, package.title)
- triggerNotif(package.author, current_user, notif_msg, url_for("thread_page", id=thread.id))
+ triggerNotif(package.author, current_user, notif_msg, url_for("threads.view", id=thread.id))
else:
notif_msg = "New thread '{}'".format(thread.title)
for user in User.query.filter(User.rank >= UserRank.EDITOR).all():
- triggerNotif(user, current_user, notif_msg, url_for("thread_page", id=thread.id))
+ triggerNotif(user, current_user, notif_msg, url_for("threads.view", id=thread.id))
db.session.commit()
- return redirect(url_for("thread_page", id=thread.id))
+ return redirect(url_for("threads.view", id=thread.id))
return render_template("threads/new.html", form=form, allow_private_change=allow_change, package=package)
diff --git a/app/views/thumbnails.py b/app/blueprints/thumbnails/__init__.py
index 8303067..1f46102 100644
--- a/app/views/thumbnails.py
+++ b/app/blueprints/thumbnails/__init__.py
@@ -16,7 +16,8 @@
from flask import *
-from app import app
+
+bp = Blueprint("thumbnails", __name__)
import os
from PIL import Image
@@ -57,7 +58,7 @@ def resize_and_crop(img_path, modified_path, size):
img.save(modified_path)
-@app.route("/thumbnails/<int:level>/<img>")
+@bp.route("/thumbnails/<int:level>/<img>")
def make_thumbnail(img, level):
if level > len(ALLOWED_RESOLUTIONS) or level <= 0:
abort(403)
diff --git a/app/views/admin/todo.py b/app/blueprints/todo/__init__.py
index 9909eff..f4f818a 100644
--- a/app/views/admin/todo.py
+++ b/app/blueprints/todo/__init__.py
@@ -14,17 +14,17 @@
# 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 app.querybuilder import QueryBuilder
-@app.route("/todo/", methods=["GET", "POST"])
+bp = Blueprint("todo", __name__)
+
+@bp.route("/todo/", methods=["GET", "POST"])
@login_required
-def todo_page():
+def view():
canApproveNew = Permission.APPROVE_NEW.check(current_user)
canApproveRel = Permission.APPROVE_RELEASE.check(current_user)
canApproveScn = Permission.APPROVE_SCREENSHOT.check(current_user)
@@ -51,7 +51,7 @@ def todo_page():
PackageScreenshot.query.update({ "approved": True })
db.session.commit()
- return redirect(url_for("todo_page"))
+ return redirect(url_for("todo.view"))
else:
abort(400)
@@ -69,9 +69,9 @@ def todo_page():
topics_to_add=topics_to_add, total_topics=total_topics)
-@app.route("/todo/topics/")
+@bp.route("/todo/topics/")
@login_required
-def todo_topics_page():
+def topics():
qb = QueryBuilder(request.args)
qb.setSortIfNone("date")
query = qb.buildTopicQuery()
@@ -88,10 +88,10 @@ def todo_topics_page():
num = 100
query = query.paginate(page, num, True)
- next_url = url_for("todo_topics_page", page=query.next_num, query=qb.search, \
+ next_url = url_for("todo.topics", page=query.next_num, query=qb.search, \
show_discarded=qb.show_discarded, n=num, sort=qb.order_by) \
if query.has_next else None
- prev_url = url_for("todo_topics_page", page=query.prev_num, query=qb.search, \
+ prev_url = url_for("todo.topics", page=query.prev_num, query=qb.search, \
show_discarded=qb.show_discarded, n=num, sort=qb.order_by) \
if query.has_prev else None
diff --git a/app/blueprints/users/__init__.py b/app/blueprints/users/__init__.py
new file mode 100644
index 0000000..98cf34a
--- /dev/null
+++ b/app/blueprints/users/__init__.py
@@ -0,0 +1,5 @@
+from flask import Blueprint
+
+bp = Blueprint("users", __name__)
+
+from . import githublogin, profile
diff --git a/app/views/users/githublogin.py b/app/blueprints/users/githublogin.py
index 9ea2584..458c637 100644
--- a/app/views/users/githublogin.py
+++ b/app/blueprints/users/githublogin.py
@@ -21,15 +21,16 @@ from flask_login import login_user, logout_user
from sqlalchemy import func
import flask_menu as menu
from flask_github import GitHub
-from app import app, github
+from . import bp
+from app import github
from app.models import *
from app.utils import loginUser
-@app.route("/user/github/start/")
-def github_signin_page():
+@bp.route("/user/github/start/")
+def github_signin():
return github.authorize("")
-@app.route("/user/github/callback/")
+@bp.route("/user/github/callback/")
@github.authorized_handler
def github_authorized(oauth_token):
next_url = request.args.get("next")
@@ -62,10 +63,10 @@ def github_authorized(oauth_token):
else:
if userByGithub is None:
flash("Unable to find an account for that Github user", "error")
- return redirect(url_for("user_claim_page"))
+ return redirect(url_for("users.claim"))
elif loginUser(userByGithub):
if current_user.password is None:
- return redirect(next_url or url_for("set_password_page", optional=True))
+ return redirect(next_url or url_for("users.set_password", optional=True))
else:
return redirect(next_url or url_for("home_page"))
else:
diff --git a/app/views/users/users.py b/app/blueprints/users/profile.py
index 1a81c7d..fd8d7d9 100644
--- a/app/views/users/users.py
+++ b/app/blueprints/users/profile.py
@@ -18,7 +18,8 @@
from flask import *
from flask_user import *
from flask_login import login_user, logout_user
-from app import app, markdown
+from app import markdown
+from . import bp
from app.models import *
from flask_wtf import FlaskForm
from wtforms import *
@@ -38,14 +39,14 @@ class UserProfileForm(FlaskForm):
submit = SubmitField("Save")
-@app.route("/users/", methods=["GET"])
-def user_list_page():
+@bp.route("/users/", methods=["GET"])
+def list_all():
users = User.query.order_by(db.desc(User.rank), db.asc(User.display_name)).all()
return render_template("users/list.html", users=users)
-@app.route("/users/<username>/", methods=["GET", "POST"])
-def user_profile_page(username):
+@bp.route("/users/<username>/", methods=["GET", "POST"])
+def profile(username):
user = User.query.filter_by(username=username).first()
if not user:
abort(404)
@@ -85,13 +86,13 @@ def user_profile_page(username):
db.session.commit()
task = sendVerifyEmail.delay(newEmail, token)
- return redirect(url_for("check_task", id=task.id, r=url_for("user_profile_page", username=username)))
+ return redirect(url_for("tasks.check", id=task.id, r=url_for("users.profile", username=username)))
# Save user_profile
db.session.commit()
# Redirect to home page
- return redirect(url_for("user_profile_page", username=username))
+ return redirect(url_for("users.profile", username=username))
packages = user.packages.filter_by(soft_deleted=False)
if not current_user.is_authenticated or (user != current_user and not current_user.canAccessTodoList()):
@@ -107,11 +108,11 @@ def user_profile_page(username):
.all()
# Process GET or invalid POST
- return render_template("users/user_profile_page.html",
+ return render_template("users/users.profile.html",
user=user, form=form, packages=packages, topics_to_add=topics_to_add)
-@app.route("/users/<username>/check/", methods=["POST"])
+@bp.route("/users/<username>/check/", methods=["POST"])
@login_required
def user_check(username):
user = User.query.filter_by(username=username).first()
@@ -125,9 +126,9 @@ def user_check(username):
abort(404)
task = checkForumAccount.delay(user.forums_username)
- next_url = url_for("user_profile_page", username=username)
+ next_url = url_for("users.profile", username=username)
- return redirect(url_for("check_task", id=task.id, r=next_url))
+ return redirect(url_for("tasks.check", id=task.id, r=next_url))
class SendEmailForm(FlaskForm):
@@ -136,14 +137,14 @@ class SendEmailForm(FlaskForm):
submit = SubmitField("Send")
-@app.route("/users/<username>/email/", methods=["GET", "POST"])
+@bp.route("/users/<username>/email/", methods=["GET", "POST"])
@rank_required(UserRank.MODERATOR)
-def send_email_page(username):
+def send_email(username):
user = User.query.filter_by(username=username).first()
if user is None:
abort(404)
- next_url = url_for("user_profile_page", username=user.username)
+ next_url = url_for("users.profile", username=user.username)
if user.email is None:
flash("User has no email address!", "error")
@@ -154,7 +155,7 @@ def send_email_page(username):
text = form.text.data
html = markdown(text)
task = sendEmailRaw.delay([user.email], form.subject.data, text, html)
- return redirect(url_for("check_task", id=task.id, r=next_url))
+ return redirect(url_for("tasks.check", id=task.id, r=next_url))
return render_template("users/send_email.html", form=form)
@@ -166,9 +167,9 @@ class SetPasswordForm(FlaskForm):
password2 = PasswordField("Verify password", [InputRequired(), Length(2, 100)])
submit = SubmitField("Save")
-@app.route("/user/set-password/", methods=["GET", "POST"])
+@bp.route("/user/set-password/", methods=["GET", "POST"])
@login_required
-def set_password_page():
+def set_password():
if current_user.password is not None:
return redirect(url_for("user.change_password"))
@@ -208,17 +209,17 @@ def set_password_page():
db.session.commit()
task = sendVerifyEmail.delay(newEmail, token)
- return redirect(url_for("check_task", id=task.id, r=url_for("user_profile_page", username=current_user.username)))
+ return redirect(url_for("tasks.check", id=task.id, r=url_for("users.profile", username=current_user.username)))
else:
- return redirect(url_for("user_profile_page", username=current_user.username))
+ return redirect(url_for("users.profile", username=current_user.username))
else:
flash("Passwords do not match", "error")
return render_template("users/set_password.html", form=form, optional=request.args.get("optional"))
-@app.route("/user/claim/", methods=["GET", "POST"])
-def user_claim_page():
+@bp.route("/user/claim/", methods=["GET", "POST"])
+def claim():
username = request.args.get("username")
if username is None:
username = ""
@@ -227,16 +228,16 @@ def user_claim_page():
user = User.query.filter_by(forums_username=username).first()
if user and user.rank.atLeast(UserRank.NEW_MEMBER):
flash("User has already been claimed", "error")
- return redirect(url_for("user_claim_page"))
+ return redirect(url_for("users.claim"))
elif user is None and method == "github":
flash("Unable to get Github username for user", "error")
- return redirect(url_for("user_claim_page"))
+ return redirect(url_for("users.claim"))
elif user is None:
flash("Unable to find that user", "error")
- return redirect(url_for("user_claim_page"))
+ return redirect(url_for("users.claim"))
if user is not None and method == "github":
- return redirect(url_for("github_signin_page"))
+ return redirect(url_for("users.github_signin"))
token = None
if "forum_token" in session:
@@ -253,12 +254,12 @@ def user_claim_page():
flash("Invalid username", "error")
elif ctype == "github":
task = checkForumAccount.delay(username)
- return redirect(url_for("check_task", id=task.id, r=url_for("user_claim_page", username=username, method="github")))
+ return redirect(url_for("tasks.check", id=task.id, r=url_for("users.claim", username=username, method="github")))
elif ctype == "forum":
user = User.query.filter_by(forums_username=username).first()
if user is not None and user.rank.atLeast(UserRank.NEW_MEMBER):
flash("That user has already been claimed!", "error")
- return redirect(url_for("user_claim_page"))
+ return redirect(url_for("users.claim"))
# Get signature
sig = None
@@ -267,7 +268,7 @@ def user_claim_page():
sig = profile.signature
except IOError:
flash("Unable to get forum signature - does the user exist?", "error")
- return redirect(url_for("user_claim_page", username=username))
+ return redirect(url_for("users.claim", username=username))
# Look for key
if token in sig:
@@ -278,21 +279,21 @@ def user_claim_page():
db.session.commit()
if loginUser(user):
- return redirect(url_for("set_password_page"))
+ return redirect(url_for("users.set_password"))
else:
flash("Unable to login as user", "error")
- return redirect(url_for("user_claim_page", username=username))
+ return redirect(url_for("users.claim", username=username))
else:
flash("Could not find the key in your signature!", "error")
- return redirect(url_for("user_claim_page", username=username))
+ return redirect(url_for("users.claim", username=username))
else:
flash("Unknown claim type", "error")
return render_template("users/claim.html", username=username, key=token)
-@app.route("/users/verify/")
-def verify_email_page():
+@bp.route("/users/verify/")
+def verify_email():
token = request.args.get("token")
ver = UserEmailVerification.query.filter_by(token=token).first()
if ver is None:
@@ -303,6 +304,6 @@ def verify_email_page():
db.session.commit()
if current_user.is_authenticated:
- return redirect(url_for("user_profile_page", username=current_user.username))
+ return redirect(url_for("users.profile", username=current_user.username))
else:
return redirect(url_for("home_page"))
diff --git a/app/models.py b/app/models.py
index 9148f05..3632ebc 100644
--- a/app/models.py
+++ b/app/models.py
@@ -501,27 +501,27 @@ class Package(db.Model):
return screenshot.url if screenshot is not None else None
def getDetailsURL(self):
- return url_for("package_page",
+ return url_for("packages.view",
author=self.author.username, name=self.name)
def getEditURL(self):
- return url_for("create_edit_package_page",
+ return url_for("packages.create_edit",
author=self.author.username, name=self.name)
def getApproveURL(self):
- return url_for("approve_package_page",
+ return url_for("packages.approve",
author=self.author.username, name=self.name)
def getRemoveURL(self):
- return url_for("remove_package_page",
+ return url_for("packages.remove",
author=self.author.username, name=self.name)
def getNewScreenshotURL(self):
- return url_for("create_screenshot_page",
+ return url_for("packages.create_screenshot",
author=self.author.username, name=self.name)
def getCreateReleaseURL(self):
- return url_for("create_release_page",
+ return url_for("packages.create_release",
author=self.author.username, name=self.name)
def getCreateEditRequestURL(self):
@@ -529,11 +529,11 @@ class Package(db.Model):
author=self.author.username, name=self.name)
def getBulkReleaseURL(self):
- return url_for("bulk_change_release_page",
+ return url_for("packages.bulk_change_release",
author=self.author.username, name=self.name)
def getDownloadURL(self):
- return url_for("package_download_page",
+ return url_for("packages.download",
author=self.author.username, name=self.name)
def getDownloadRelease(self, version=None, protonum=None):
@@ -716,13 +716,13 @@ class PackageRelease(db.Model):
def getEditURL(self):
- return url_for("edit_release_page",
+ return url_for("packages.edit_release",
author=self.package.author.username,
name=self.package.name,
id=self.id)
def getDownloadURL(self):
- return url_for("download_release_page",
+ return url_for("packages.download_release",
author=self.package.author.username,
name=self.package.name,
id=self.id)
@@ -758,7 +758,7 @@ class PackageScreenshot(db.Model):
def getEditURL(self):
- return url_for("edit_screenshot_page",
+ return url_for("packages.edit_screenshot",
author=self.package.author.username,
name=self.package.name,
id=self.id)
@@ -880,11 +880,11 @@ class Thread(db.Model):
def getSubscribeURL(self):
- return url_for("thread_subscribe_page",
+ return url_for("threads.subscribe",
id=self.id)
def getUnsubscribeURL(self):
- return url_for("thread_unsubscribe_page",
+ return url_for("threads.unsubscribe",
id=self.id)
def checkPerm(self, user, perm):
diff --git a/app/views/sass.py b/app/sass.py
index 825f494..f4a272f 100644
--- a/app/views/sass.py
+++ b/app/sass.py
@@ -15,8 +15,6 @@ import codecs
from flask import *
from scss import Scss
-from app import app
-
def _convert(dir, src, dst):
original_wd = os.getcwd()
os.chdir(dir)
@@ -31,7 +29,7 @@ def _convert(dir, src, dst):
outfile.write(output)
outfile.close()
-def _getDirPath(originalPath, create=False):
+def _getDirPath(app, originalPath, create=False):
path = originalPath
if not os.path.isdir(path):
@@ -47,8 +45,8 @@ def _getDirPath(originalPath, create=False):
def sass(app, inputDir='scss', outputPath='static', force=False, cacheDir="public/static"):
static_url_path = app.static_url_path
- inputDir = _getDirPath(inputDir)
- cacheDir = _getDirPath(cacheDir or outputPath, True)
+ inputDir = _getDirPath(app, inputDir)
+ cacheDir = _getDirPath(app, cacheDir or outputPath, True)
def _sass(filepath):
sassfile = "%s/%s.scss" % (inputDir, filepath)
@@ -63,5 +61,3 @@ def sass(app, inputDir='scss', outputPath='static', force=False, cacheDir="publi
return send_from_directory(cacheDir, filepath + ".css")
app.add_url_rule("/%s/<path:filepath>.css" % (outputPath), 'sass', _sass)
-
-sass(app)
diff --git a/app/tasks/emails.py b/app/tasks/emails.py
index 5eb915e..f81deaa 100644
--- a/app/tasks/emails.py
+++ b/app/tasks/emails.py
@@ -34,7 +34,7 @@ def sendVerifyEmail(newEmail, token):
If this was you, then please click this link to verify the address:
{}
- """.format(url_for('verify_email_page', token=token, _external=True))
+ """.format(url_for('users.verify_email', token=token, _external=True))
msg.html = render_template("emails/verify.html", token=token)
mail.send(msg)
diff --git a/app/tasks/importtasks.py b/app/tasks/importtasks.py
index e53dbfa..ed43584 100644
--- a/app/tasks/importtasks.py
+++ b/app/tasks/importtasks.py
@@ -15,7 +15,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
-import flask, json, os, git, tempfile, shutil
+import flask, json, os, git, tempfile, shutil, gitdb
from git import GitCommandError
from flask_sqlalchemy import SQLAlchemy
from urllib.error import HTTPError
diff --git a/app/template_filters.py b/app/template_filters.py
new file mode 100644
index 0000000..e535ce8
--- /dev/null
+++ b/app/template_filters.py
@@ -0,0 +1,22 @@
+from . import app
+from urllib.parse import urlparse
+
+@app.context_processor
+def inject_debug():
+ return dict(debug=app.debug)
+
+@app.template_filter()
+def throw(err):
+ raise Exception(err)
+
+@app.template_filter()
+def domain(url):
+ return urlparse(url).netloc
+
+@app.template_filter()
+def date(value):
+ return value.strftime("%Y-%m-%d")
+
+@app.template_filter()
+def datetime(value):
+ return value.strftime("%Y-%m-%d %H:%M") + " UTC"
diff --git a/app/templates/admin/licenses/edit.html b/app/templates/admin/licenses/edit.html
index c68b17f..eabe782 100644
--- a/app/templates/admin/licenses/edit.html
+++ b/app/templates/admin/licenses/edit.html
@@ -10,8 +10,8 @@
{% block content %}
<p>
- <a href="{{ url_for('license_list_page') }}">Back to list</a> |
- <a href="{{ url_for('createedit_license_page') }}">New License</a>
+ <a href="{{ url_for('admin.license_list') }}">Back to list</a> |
+ <a href="{{ url_for('admin.create_edit_license') }}">New License</a>
</p>
{% from "macros/forms.html" import render_field, render_submit_field %}
diff --git a/app/templates/admin/licenses/list.html b/app/templates/admin/licenses/list.html
index ff30805..869aac6 100644
--- a/app/templates/admin/licenses/list.html
+++ b/app/templates/admin/licenses/list.html
@@ -6,11 +6,11 @@ Licenses
{% block content %}
<p>
- <a href="{{ url_for('createedit_license_page') }}">New License</a>
+ <a href="{{ url_for('admin.create_edit_license') }}">New License</a>
</p>
<ul>
{% for l in licenses %}
- <li><a href="{{ url_for('createedit_license_page', name=l.name) }}">{{ l.name }}</a> [{{ l.is_foss and "Free" or "Non-free"}}]</li>
+ <li><a href="{{ url_for('admin.create_edit_license', name=l.name) }}">{{ l.name }}</a> [{{ l.is_foss and "Free" or "Non-free"}}]</li>
{% endfor %}
</ul>
{% endblock %}
diff --git a/app/templates/admin/list.html b/app/templates/admin/list.html
index ddfa30c..1048a88 100644
--- a/app/templates/admin/list.html
+++ b/app/templates/admin/list.html
@@ -6,11 +6,11 @@
{% block content %}
<ul>
- <li><a href="{{ url_for('user_list_page') }}">User list</a></li>
- <li><a href="{{ url_for('tag_list_page') }}">Tag Editor</a></li>
- <li><a href="{{ url_for('license_list_page') }}">License Editor</a></li>
- <li><a href="{{ url_for('version_list_page') }}">Version Editor</a></li>
- <li><a href="{{ url_for('switch_user_page') }}">Sign in as another user</a></li>
+ <li><a href="{{ url_for('users.list_all') }}">User list</a></li>
+ <li><a href="{{ url_for('admin.tag_list') }}">Tag Editor</a></li>
+ <li><a href="{{ url_for('admin.license_list') }}">License Editor</a></li>
+ <li><a href="{{ url_for('admin.version_list') }}">Version Editor</a></li>
+ <li><a href="{{ url_for('admin.switch_user') }}">Sign in as another user</a></li>
</ul>
<div class="card my-4">
diff --git a/app/templates/admin/switch_user_page.html b/app/templates/admin/switch_user.html
index 7d4a4a2..7d4a4a2 100644
--- a/app/templates/admin/switch_user_page.html
+++ b/app/templates/admin/switch_user.html
diff --git a/app/templates/admin/tags/edit.html b/app/templates/admin/tags/edit.html
index ccffa7f..5ffe2d0 100644
--- a/app/templates/admin/tags/edit.html
+++ b/app/templates/admin/tags/edit.html
@@ -10,8 +10,8 @@
{% block content %}
<p>
- <a href="{{ url_for('tag_list_page') }}">Back to list</a> |
- <a href="{{ url_for('createedit_tag_page') }}">New Tag</a>
+ <a href="{{ url_for('admin.tag_list') }}">Back to list</a> |
+ <a href="{{ url_for('admin.create_edit_tag') }}">New Tag</a>
</p>
{% from "macros/forms.html" import render_field, render_submit_field %}
diff --git a/app/templates/admin/tags/list.html b/app/templates/admin/tags/list.html
index 355f62d..daae8e7 100644
--- a/app/templates/admin/tags/list.html
+++ b/app/templates/admin/tags/list.html
@@ -6,11 +6,11 @@ Tags
{% block content %}
<p>
- <a href="{{ url_for('createedit_tag_page') }}">New Tag</a>
+ <a href="{{ url_for('admin.create_edit_tag') }}">New Tag</a>
</p>
<ul>
{% for t in tags %}
- <li><a href="{{ url_for('createedit_tag_page', name=t.name) }}">{{ t.title }}</a> [{{ t.packages | count }} packages]</li>
+ <li><a href="{{ url_for('admin.create_edit_tag', name=t.name) }}">{{ t.title }}</a> [{{ t.packages | count }} packages]</li>
{% endfor %}
</ul>
{% endblock %}
diff --git a/app/templates/admin/versions/edit.html b/app/templates/admin/versions/edit.html
index ea84c11..f1042fa 100644
--- a/app/templates/admin/versions/edit.html
+++ b/app/templates/admin/versions/edit.html
@@ -10,8 +10,8 @@
{% block content %}
<p>
- <a href="{{ url_for('version_list_page') }}">Back to list</a> |
- <a href="{{ url_for('createedit_version_page') }}">New Version</a>
+ <a href="{{ url_for('admin.version_list') }}">Back to list</a> |
+ <a href="{{ url_for('admin.create_edit_version') }}">New Version</a>
</p>
{% from "macros/forms.html" import render_field, render_submit_field %}
diff --git a/app/templates/admin/versions/list.html b/app/templates/admin/versions/list.html
index 5a95efd..f3dd236 100644
--- a/app/templates/admin/versions/list.html
+++ b/app/templates/admin/versions/list.html
@@ -6,11 +6,11 @@ Minetest Versions
{% block content %}
<p>
- <a href="{{ url_for('createedit_version_page') }}">New Version</a>
+ <a href="{{ url_for('admin.create_edit_version') }}">New Version</a>
</p>
<ul>
{% for v in versions %}
- <li><a href="{{ url_for('createedit_version_page', name=v.name) }}">{{ v.name }}</a></li>
+ <li><a href="{{ url_for('admin.create_edit_version', name=v.name) }}">{{ v.name }}</a></li>
{% endfor %}
</ul>
{% endblock %}
diff --git a/app/templates/base.html b/app/templates/base.html
index e39097c..faa867a 100644
--- a/app/templates/base.html
+++ b/app/templates/base.html
@@ -60,10 +60,10 @@
</form>
<ul class="navbar-nav ml-auto">
{% if current_user.is_authenticated %}
- <li class="nav-item"><a class="nav-link" href="{{ url_for('notifications_page') }}">
+ <li class="nav-item"><a class="nav-link" href="{{ url_for('notifications.list_all') }}">
<img src="/static/notification{% if current_user.notifications %}_alert{% endif %}.svg" />
</a></li>
- <li class="nav-item"><a class="nav-link" href="{{ url_for('create_edit_package_page') }}">+</a></li>
+ <li class="nav-item"><a class="nav-link" href="{{ url_for('packages.create_edit') }}">+</a></li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle"
data-toggle="dropdown"
@@ -73,24 +73,24 @@
<ul class="dropdown-menu" role="menu">
<li class="nav-item">
- <a class="nav-link" href="{{ url_for('user_profile_page', username=current_user.username) }}">Profile</a>
+ <a class="nav-link" href="{{ url_for('users.profile', username=current_user.username) }}">Profile</a>
</li>
<li class="nav-item">
- <a class="nav-link" href="{{ url_for('user_profile_page', username=current_user.username) }}#unadded-topics">Your unadded topics</a>
+ <a class="nav-link" href="{{ url_for('users.profile', username=current_user.username) }}#unadded-topics">Your unadded topics</a>
</li>
{% if current_user.canAccessTodoList() %}
- <li class="nav-item"><a class="nav-link" href="{{ url_for('todo_page') }}">{{ _("Work Queue") }}</a></li>
- <li class="nav-item"><a class="nav-link" href="{{ url_for('user_list_page') }}">{{ _("User list") }}</a></li>
+ <li class="nav-item"><a class="nav-link" href="{{ url_for('todo.view') }}">{{ _("Work Queue") }}</a></li>
+ <li class="nav-item"><a class="nav-link" href="{{ url_for('users.list_all') }}">{{ _("User list") }}</a></li>
{% endif %}
<li class="nav-item">
- <a class="nav-link" href="{{ url_for('todo_topics_page') }}">{{ _("All unadded topics") }}</a>
+ <a class="nav-link" href="{{ url_for('todo.topics') }}">{{ _("All unadded topics") }}</a>
</li>
{% if current_user.rank == current_user.rank.ADMIN %}
- <li class="nav-item"><a class="nav-link" href="{{ url_for('admin_page') }}">{{ _("Admin") }}</a></li>
+ <li class="nav-item"><a class="nav-link" href="{{ url_for('admin.admin_page') }}">{{ _("Admin") }}</a></li>
{% endif %}
{% if current_user.rank == current_user.rank.MODERATOR %}
- <li class="nav-item"><a class="nav-link" href="{{ url_for('tag_list_page') }}">{{ _("Tag Editor") }}</a></li>
- <li class="nav-item"><a class="nav-link" href="{{ url_for('license_list_page') }}">{{ _("License Editor") }}</a></li>
+ <li class="nav-item"><a class="nav-link" href="{{ url_for('admin.tag_list') }}">{{ _("Tag Editor") }}</a></li>
+ <li class="nav-item"><a class="nav-link" href="{{ url_for('admin.license_list') }}">{{ _("License Editor") }}</a></li>
{% endif %}
<li class="nav-item"><a class="nav-link" href="{{ url_for('user.logout') }}">{{ _("Sign out") }}</a></li>
</ul>
@@ -134,7 +134,7 @@
<a href="{{ url_for('flatpage', path='help') }}">{{ _("Help") }}</a> |
<a href="{{ url_for('flatpage', path='policy_and_guidance') }}">{{ _("Policy and Guidance") }}</a> |
<a href="{{ url_for('flatpage', path='help/reporting') }}">{{ _("Report / DMCA") }}</a> |
- <a href="{{ url_for('user_list_page') }}">{{ _("User List") }}</a>
+ <a href="{{ url_for('users.list_all') }}">{{ _("User List") }}</a>
{% if debug %}
<p style="color: red">
diff --git a/app/templates/emails/verify.html b/app/templates/emails/verify.html
index 38d488b..04a4bc5 100644
--- a/app/templates/emails/verify.html
+++ b/app/templates/emails/verify.html
@@ -16,12 +16,12 @@
If this was you, then please click this link to verify the address:
</p>
-<a class="btn" href="{{ url_for('verify_email_page', token=token, _external=True) }}">
+<a class="btn" href="{{ url_for('users.verify_email', token=token, _external=True) }}">
Confirm Email Address
</a>
<p style="font-size: 80%;">
- Or paste this into your browser: {{ url_for('verify_email_page', token=token, _external=True) }}
+ Or paste this into your browser: {{ url_for('users.verify_email', token=token, _external=True) }}
<p>
{% endblock %}
diff --git a/app/templates/flask_user/login.html b/app/templates/flask_user/login.html
index 642dc70..6214c8c 100644
--- a/app/templates/flask_user/login.html
+++ b/app/templates/flask_user/login.html
@@ -60,7 +60,7 @@ Sign in
{% from "flask_user/_macros.html" import render_field, render_checkbox_field, render_submit_field %}
<h2 class="card-header">{%trans%}Sign in with Github{%endtrans%}</h2>
<div class="card-body">
- <a class="btn btn-primary" href="{{ url_for('github_signin_page') }}">GitHub</a>
+ <a class="btn btn-primary" href="{{ url_for('users.github_signin') }}">GitHub</a>
</div>
</div>
</div>
@@ -72,7 +72,7 @@ Sign in
<div class="card-body">
<p>Create an account using your forum account or email.</p>
- <a href="{{ url_for('user_claim_page') }}" class="btn btn-primary">{%trans%}Claim your account{%endtrans%}</a>
+ <a href="{{ url_for('users.claim') }}" class="btn btn-primary">{%trans%}Claim your account{%endtrans%}</a>
</div>
</div>
</aside>
diff --git a/app/templates/index.html b/app/templates/index.html
index 0cb39dd..a7574d6 100644
--- a/app/templates/index.html
+++ b/app/templates/index.html
@@ -37,28 +37,28 @@
{% from "macros/packagegridtile.html" import render_pkggrid %}
- <a href="{{ url_for('packages_page', sort='created_at', order='desc') }}" class="btn btn-secondary float-right">
+ <a href="{{ url_for('packages.list_all', sort='created_at', order='desc') }}" class="btn btn-secondary float-right">
{{ _("See more") }}
</a>
<h2 class="my-3">{{ _("Recently Added") }}</h2>
{{ render_pkggrid(new) }}
- <a href="{{ url_for('packages_page', type='mod', sort='score', order='desc') }}" class="btn btn-secondary float-right">
+ <a href="{{ url_for('packages.list_all', type='mod', sort='score', order='desc') }}" class="btn btn-secondary float-right">
{{ _("See more") }}
</a>
<h2 class="my-3">{{ _("Top Mods") }}</h2>
{{ render_pkggrid(pop_mod) }}
- <a href="{{ url_for('packages_page', type='game', sort='score', order='desc') }}" class="btn btn-secondary float-right">
+ <a href="{{ url_for('packages.list_all', type='game', sort='score', order='desc') }}" class="btn btn-secondary float-right">
{{ _("See more") }}
</a>
<h2 class="my-3">{{ _("Top Games") }}</h2>
{{ render_pkggrid(pop_gam) }}
- <a href="{{ url_for('packages_page', type='txp', sort='score', order='desc') }}" class="btn btn-secondary float-right">
+ <a href="{{ url_for('packages.list_all', type='txp', sort='score', order='desc') }}" class="btn btn-secondary float-right">
{{ _("See more") }}
</a>
<h2 class="my-3">{{ _("Top Texture Packs") }}</h2>
diff --git a/app/templates/macros/threads.html b/app/templates/macros/threads.html
index fd7b648..16b67a0 100644
--- a/app/templates/macros/threads.html
+++ b/app/templates/macros/threads.html
@@ -4,7 +4,7 @@
{% for r in thread.replies %}
<li class="row my-2 mx-0">
<div class="col-md-1 p-1">
- <a href="{{ url_for('user_profile_page', username=r.author.username) }}">
+ <a href="{{ url_for('users.profile', username=r.author.username) }}">
<img class="img-responsive user-photo img-thumbnail img-thumbnail-1" src="{{ r.author.getProfilePicURL() }}">
</a>
</div>
@@ -12,11 +12,11 @@
<div class="card">
<div class="card-header">
<a class="author {{ r.author.rank.name }}"
- href="{{ url_for('user_profile_page', username=r.author.username) }}">
+ href="{{ url_for('users.profile', username=r.author.username) }}">
{{ r.author.display_name }}
</a>
<a name="reply-{{ r.id }}" class="text-muted float-right"
- href="{{ url_for('thread_page', id=thread.id) }}#reply-{{ r.id }}">
+ href="{{ url_for('threads.view', id=thread.id) }}#reply-{{ r.id }}">
{{ r.created_at | datetime }}
</a>
</div>
@@ -43,7 +43,7 @@
</div>
{% if current_user.canCommentRL() %}
- <form method="post" action="{{ url_for('thread_page', id=thread.id)}}" class="card-body">
+ <form method="post" action="{{ url_for('threads.view', id=thread.id)}}" class="card-body">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<textarea class="form-control markdown" required maxlength=500 name="comment"></textarea><br />
<input class="btn btn-primary" type="submit" value="Comment" />
@@ -65,14 +65,14 @@
{% for t in threads %}
<li {% if list_group %}class="list-group-item"{% endif %}>
{% if list_group %}
- <a href="{{ url_for('thread_page', id=t.id) }}">
+ <a href="{{ url_for('threads.view', id=t.id) }}">
{% if t.private %}&#x1f512; {% endif %}
{{ t.title }}
by {{ t.author.display_name }}
</a>
{% else %}
{% if t.private %}&#x1f512; {% endif %}
- <a href="{{ url_for('thread_page', id=t.id) }}">{{ t.title }}</a>
+ <a href="{{ url_for('threads.view', id=t.id) }}">{{ t.title }}</a>
by {{ t.author.display_name }}
{% endif %}
</li>
diff --git a/app/templates/macros/topics.html b/app/templates/macros/topics.html
index a6d0a42..987f810 100644
--- a/app/templates/macros/topics.html
+++ b/app/templates/macros/topics.html
@@ -18,14 +18,14 @@
{% if topic.wip %}[WIP]{% endif %}
</td>
{% if show_author %}
- <td><a href="{{ url_for('user_profile_page', username=topic.author.username) }}">{{ topic.author.display_name}}</a></td>
+ <td><a href="{{ url_for('users.profile', username=topic.author.username) }}">{{ topic.author.display_name}}</a></td>
{% endif %}
<td>{{ topic.name or ""}}</td>
<td>{{ topic.created_at | date }}</td>
<td class="btn-group">
{% if current_user == topic.author or topic.author.checkPerm(current_user, "CHANGE_AUTHOR") %}
<a class="btn btn-primary"
- href="{{ url_for('create_edit_package_page', author=topic.author.username, repo=topic.getRepoURL(), forums=topic.topic_id, title=topic.title, bname=topic.name) }}">
+ href="{{ url_for('packages.create_edit', author=topic.author.username, repo=topic.getRepoURL(), forums=topic.topic_id, title=topic.title, bname=topic.name) }}">
Create
</a>
{% endif %}
@@ -56,10 +56,10 @@
{% if topic.wip %}[WIP]{% endif %}
{% if topic.name %}[{{ topic.name }}]{% endif %}
{% if show_author %}
- by <a href="{{ url_for('user_profile_page', username=topic.author.username) }}">{{ topic.author.display_name }}</a>
+ by <a href="{{ url_for('users.profile', username=topic.author.username) }}">{{ topic.author.display_name }}</a>
{% endif %}
{% if topic.author == current_user or topic.author.checkPerm(current_user, "CHANGE_AUTHOR") %}
- | <a href="{{ url_for('create_edit_package_page', author=topic.author.username, repo=topic.getRepoURL(), forums=topic.topic_id, title=topic.title, bname=topic.name) }}">Create</a>
+ | <a href="{{ url_for('packages.create_edit', author=topic.author.username, repo=topic.getRepoURL(), forums=topic.topic_id, title=topic.title, bname=topic.name) }}">Create</a>
{% endif %}
</li>
{% endfor %}
diff --git a/app/templates/meta/list.html b/app/templates/meta/list.html
index e6daf99..525bafd 100644
--- a/app/templates/meta/list.html
+++ b/app/templates/meta/list.html
@@ -7,7 +7,7 @@ Meta Packages
{% block content %}
<ul>
{% for meta in mpackages %}
- <li><a href="{{ url_for('meta_package_page', name=meta.name) }}">{{ meta.name }}</a> ({{ meta.packages.filter_by(soft_deleted=False, approved=True).all() | count }} packages)</li>
+ <li><a href="{{ url_for('metapackages.view', name=meta.name) }}">{{ meta.name }}</a> ({{ meta.packages.filter_by(soft_deleted=False, approved=True).all() | count }} packages)</li>
{% else %}
<li><i>No meta packages found.</i></li>
{% endfor %}
diff --git a/app/templates/notifications/list.html b/app/templates/notifications/list.html
index d6de54e..7f09e5d 100644
--- a/app/templates/notifications/list.html
+++ b/app/templates/notifications/list.html
@@ -6,7 +6,7 @@ Notifications
{% block content %}
{% if current_user.notifications %}
- <form method="post" action="{{ url_for('clear_notifications_page') }}">
+ <form method="post" action="{{ url_for('notifications.clear') }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="submit" value="Clear All" />
</form>
diff --git a/app/templates/packages/list.html b/app/templates/packages/list.html
index cc0c6c9..4aea5a0 100644
--- a/app/templates/packages/list.html
+++ b/app/templates/packages/list.html
@@ -15,7 +15,7 @@
{% for n in range(1, page_max+1) %}
<li class="page-item {% if n == page %}active{% endif %}">
<a class="page-link"
- href="{{ url_for('packages_page', type=type, q=query, page=n) }}">
+ href="{{ url_for('packages.list_all', type=type, q=query, page=n) }}">
{{ n }}
</a>
</li>
diff --git a/app/templates/packages/release_edit.html b/app/templates/packages/release_edit.html
index 03f0d7a..37fc655 100644
--- a/app/templates/packages/release_edit.html
+++ b/app/templates/packages/release_edit.html
@@ -26,7 +26,7 @@
{% endif %}
{% if release.task_id %}
- Importing... <a href="{{ url_for('check_task', id=release.task_id, r=release.getEditURL()) }}">view task</a><br />
+ Importing... <a href="{{ url_for('tasks.check', id=release.task_id, r=release.getEditURL()) }}">view task</a><br />
{% if package.checkPerm(current_user, "CHANGE_RELEASE_URL") %}
{{ render_field(form.task_id) }}
{% endif %}
diff --git a/app/templates/packages/view.html b/app/templates/packages/view.html
index 8216c71..5da8797 100644
--- a/app/templates/packages/view.html
+++ b/app/templates/packages/view.html
@@ -103,7 +103,7 @@
{% if not review_thread and (package.author == current_user or package.checkPerm(current_user, "APPROVE_NEW")) %}
<div class="alert alert-info">
- <a class="float-right btn btn-sm btn-info" href="{{ url_for('new_thread_page', pid=package.id, title='Package approval comments') }}">Open Thread</a>
+ <a class="float-right btn btn-sm btn-info" href="{{ url_for('threads.new', pid=package.id, title='Package approval comments') }}">Open Thread</a>
Privately ask a question or give feedback
<div style="clear:both;"></div>
@@ -172,14 +172,14 @@
<td>Provides</td>
<td>{% for meta in package.provides %}
<a class="badge badge-primary"
- href="{{ url_for('meta_package_page', name=meta.name) }}">{{ meta.name }}</a>
+ href="{{ url_for('metapackages.view', name=meta.name) }}">{{ meta.name }}</a>
{% endfor %}</td>
</tr>
{% endif %}
<tr>
<td>Author</td>
<td class="{{ package.author.rank }}">
- <a href="{{ url_for('user_profile_page', username=package.author.username) }}">
+ <a href="{{ url_for('users.profile', username=package.author.username) }}">
{{ package.author.display_name }}
</a>
</td>
@@ -241,7 +241,7 @@
{{ dep.package.title }} by {{ dep.package.author.display_name }}
{% elif dep.meta_package %}
<a class="badge badge-{{ color }}"
- href="{{ url_for('meta_package_page', name=dep.meta_package.name) }}">
+ href="{{ url_for('metapackages.view', name=dep.meta_package.name) }}">
{{ dep.meta_package.name }}
{% else %}
{{ "Excepted package or meta_package in dep!" | throw }}
@@ -301,7 +301,7 @@
created {{ rel.releaseDate | date }}.
</small>
{% if (package.checkPerm(current_user, "MAKE_RELEASE") or package.checkPerm(current_user, "APPROVE_RELEASE")) and rel.task_id %}
- <a href="{{ url_for('check_task', id=rel.task_id, r=package.getDetailsURL()) }}">Importing...</a>
+ <a href="{{ url_for('tasks.check', id=rel.task_id, r=package.getDetailsURL()) }}">Importing...</a>
{% elif not rel.approved %}
Waiting for approval.
{% endif %}
@@ -320,7 +320,7 @@
<div class="card-header">
{% if package.approved and package.checkPerm(current_user, "CREATE_THREAD") %}
<a class="float-right"
- href="{{ url_for('new_thread_page', pid=package.id) }}">+</a>
+ href="{{ url_for('threads.new', pid=package.id) }}">+</a>
{% endif %}
Threads
</div>
@@ -332,7 +332,7 @@
{% if package.approved and package.checkPerm(current_user, "CREATE_THREAD") and current_user != package.author and not current_user.rank.atLeast(current_user.rank.EDITOR) %}
<a class="float-right"
- href="{{ url_for('new_thread_page', pid=package.id) }}">
+ href="{{ url_for('threads.new', pid=package.id) }}">
Report a problem with this listing
</a>
{% endif %}
@@ -381,7 +381,7 @@
<li>
<a href="{{ r.getURL() }}">{{ r.title }}</a>
by
- <a href="{{ url_for('user_profile_page', username=r.author.username) }}">{{ r.author.display_name }}</a>
+ <a href="{{ url_for('users.profile', username=r.author.username) }}">{{ r.author.display_name }}</a>
</li>
{% else %}
<li>No edit requests have been made.</li>
diff --git a/app/templates/tasks/view.html b/app/templates/tasks/view.html
index 97c3343..a348b1f 100644
--- a/app/templates/tasks/view.html
+++ b/app/templates/tasks/view.html
@@ -16,7 +16,7 @@ Working
<script>
// @author rubenwardy
// @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3-or-Later
- pollTask("{{ url_for('check_task', id=info.id) }}", true)
+ pollTask("{{ url_for('tasks.check', id=info.id) }}", true)
.then(function() { location.reload() })
.catch(function() { location.reload() })
</script>
diff --git a/app/templates/todo/list.html b/app/templates/todo/list.html
index 2e756af..2f09cb9 100644
--- a/app/templates/todo/list.html
+++ b/app/templates/todo/list.html
@@ -63,7 +63,7 @@
{% if canApproveScn and screenshots %}
<div class="card my-4">
<h3 class="card-header">Screenshots
- <form class="float-right" method="post" action="{{ url_for('todo_page') }}">
+ <form class="float-right" method="post" action="{{ url_for('todo.view') }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="hidden" name="action" value="screenshots_approve_all" />
<input class="btn btn-sm btn-primary" type="submit" value="Approve All" />
@@ -112,6 +112,6 @@
style="width: {{ perc }}%" aria-valuenow="{{ perc }}" aria-valuemin="0" aria-valuemax="100"></div>
</div>
- <a class="btn btn-primary" href="{{ url_for('todo_topics_page') }}">View Unadded Topic List</a>
+ <a class="btn btn-primary" href="{{ url_for('todo.topics') }}">View Unadded Topic List</a>
{% endblock %}
diff --git a/app/templates/todo/topics.html b/app/templates/todo/topics.html
index f9774d1..8afa3b0 100644
--- a/app/templates/todo/topics.html
+++ b/app/templates/todo/topics.html
@@ -8,15 +8,15 @@ Topics to be Added
<div class="float-right">
<div class="btn-group">
<a class="btn btn-primary {% if sort_by=='date' %}active{% endif %}"
- href="{{ url_for('todo_topics_page', q=query, show_discarded=show_discarded, n=n, sort='date') }}">
+ href="{{ url_for('todo.topics', q=query, show_discarded=show_discarded, n=n, sort='date') }}">
Sort by date
</a>
<a class="btn btn-primary {% if sort_by=='name' %}active{% endif %}"
- href="{{ url_for('todo_topics_page', q=query, show_discarded=show_discarded, n=n, sort='name') }}">
+ href="{{ url_for('todo.topics', q=query, show_discarded=show_discarded, n=n, sort='name') }}">
Sort by name
</a>
<a class="btn btn-primary {% if sort_by=='views' %}active{% endif %}"
- href="{{ url_for('todo_topics_page', q=query, show_discarded=show_discarded, n=n, sort='views') }}">
+ href="{{ url_for('todo.topics', q=query, show_discarded=show_discarded, n=n, sort='views') }}">
Sort by views
</a>
</div>
@@ -26,18 +26,18 @@ Topics to be Added
{% if current_user.rank.atLeast(current_user.rank.EDITOR) %}
{% if n >= 10000 %}
<a class="btn btn-primary"
- href="{{ url_for('todo_topics_page', q=query, show_discarded=show_discarded, n=100, sort=sort_by) }}">
+ href="{{ url_for('todo.topics', q=query, show_discarded=show_discarded, n=100, sort=sort_by) }}">
Paginated list
</a>
{% else %}
<a class="btn btn-primary"
- href="{{ url_for('todo_topics_page', q=query, show_discarded=show_discarded, n=10000, sort=sort_by) }}">
+ href="{{ url_for('todo.topics', q=query, show_discarded=show_discarded, n=10000, sort=sort_by) }}">
Unlimited list
</a>
{% endif %}
{% endif %}
- <a class="btn btn-primary" href="{{ url_for('todo_topics_page', q=query, show_discarded=not show_discarded, n=n, sort=sort_by) }}">
+ <a class="btn btn-primary" href="{{ url_for('todo.topics', q=query, show_discarded=not show_discarded, n=n, sort=sort_by) }}">
{% if not show_discarded %}
Show
{% else %}
@@ -61,7 +61,7 @@ Topics to be Added
style="width: {{ perc }}%" aria-valuenow="{{ perc }}" aria-valuemin="0" aria-valuemax="100"></div>
</div>
- <form method="GET" action="{{ url_for('todo_topics_page') }}" class="my-4">
+ <form method="GET" action="{{ url_for('todo.topics') }}" class="my-4">
<input type="hidden" name="show_discarded" value={{ show_discarded and "True" or "False" }} />
<input type="hidden" name="n" value={{ n }} />
<input type="hidden" name="sort" value={{ sort_by or "date" }} />
@@ -79,7 +79,7 @@ Topics to be Added
{% for i in range(1, page_max+1) %}
<li class="page-item {% if i == page %}active{% endif %}">
<a class="page-link"
- href="{{ url_for('todo_topics_page', page=i, query=query, show_discarded=show_discarded, n=n, sort=sort_by) }}">
+ href="{{ url_for('todo.topics', page=i, query=query, show_discarded=show_discarded, n=n, sort=sort_by) }}">
{{ i }}
</a>
</li>
diff --git a/app/templates/users/claim.html b/app/templates/users/claim.html
index db00d3f..ab66349 100644
--- a/app/templates/users/claim.html
+++ b/app/templates/users/claim.html
@@ -19,7 +19,7 @@ Creating an Account
Please log out to continue.
</p>
<p>
- <a href="{{ url_for('user.logout', next=url_for('user_claim_page')) }}" class="btn">Logout</a>
+ <a href="{{ url_for('user.logout', next=url_for('users.claim')) }}" class="btn">Logout</a>
</p>
{% else %}
<p>
@@ -44,7 +44,7 @@ Creating an Account
Use GitHub field in forum profile
</div>
- <form method="post" class="card-body" action="{{ url_for('user_claim_page') }}">
+ <form method="post" class="card-body" action="{{ url_for('users.claim') }}">
<input class="form-control" type="hidden" name="claim_type" value="github">
<input class="form-control" type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
@@ -73,7 +73,7 @@ Creating an Account
Verification token
</div>
- <form method="post" class="card-body" action="{{ url_for('user_claim_page') }}">
+ <form method="post" class="card-body" action="{{ url_for('users.claim') }}">
<input type="hidden" name="claim_type" value="forum">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
diff --git a/app/templates/users/list.html b/app/templates/users/list.html
index 5ec5662..345a039 100644
--- a/app/templates/users/list.html
+++ b/app/templates/users/list.html
@@ -8,7 +8,7 @@
<ul class="userlist">
{% for user in users %}
<li class="{{ user.rank }}">
- <a href="{{ url_for('user_profile_page', username=user.username) }}">
+ <a href="{{ url_for('users.profile', username=user.username) }}">
{{ user.display_name }}
</a> -
{{ user.rank.getTitle() }}
diff --git a/app/templates/users/user_profile_page.html b/app/templates/users/user_profile_page.html
index fc197e8..d1edf54 100644
--- a/app/templates/users/user_profile_page.html
+++ b/app/templates/users/user_profile_page.html
@@ -9,7 +9,7 @@
{% if not current_user.is_authenticated and user.rank == user.rank.NOT_JOINED and user.forums_username %}
<div class="alert alert-info">
<a class="float-right btn btn-default btn-sm"
- href="{{ url_for('user_claim_page', username=user.forums_username) }}">Claim</a>
+ href="{{ url_for('users.claim', username=user.forums_username) }}">Claim</a>
Is this you? Claim your account now!
</div>
@@ -57,7 +57,7 @@
{% if user.github_username %}
<a href="https://github.com/{{ user.github_username }}">GitHub</a>
{% elif user == current_user %}
- <a href="{{ url_for('github_signin_page') }}">Link Github</a>
+ <a href="{{ url_for('users.github_signin') }}">Link Github</a>
{% endif %}
{% if user.website_url %}
@@ -78,7 +78,7 @@
<td>Admin</td>
<td>
{% if user.email %}
- <a class="btn btn-primary" href="{{ url_for('send_email_page', username=user.username) }}">
+ <a class="btn btn-primary" href="{{ url_for('users.send_email', username=user.username) }}">
Email
</a>
{% else %}
@@ -97,7 +97,7 @@
<td>Profile Picture:</td>
<td>
{% if user.forums_username %}
- <form method="post" action="{{ url_for('user_check', username=user.username) }}" class="" style="display:inline-block;">
+ <form method="post" action="{{ url_for('users.user_check', username=user.username) }}" class="" style="display:inline-block;">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="submit" class="btn btn-primary" value="Sync with Forums" />
</form>
@@ -122,7 +122,7 @@
{% if user.password %}
Set | <a href="{{ url_for('user.change_password') }}">Change</a>
{% else %}
- Not set | <a href="{{ url_for('set_password_page') }}">Set</a>
+ Not set | <a href="{{ url_for('users.set_password') }}">Set</a>
{% endif %}
</td>
</tr>
diff --git a/app/views/__init__.py b/app/views/__init__.py
deleted file mode 100644
index 3abb7ee..0000000
--- a/app/views/__init__.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# 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 app import app, pages
-from flask import *
-from flask_user import *
-from app.models import *
-import flask_menu as menu
-from werkzeug.contrib.cache import SimpleCache
-from urllib.parse import urlparse
-from sqlalchemy.sql.expression import func
-cache = SimpleCache()
-
-@app.context_processor
-def inject_debug():
- return dict(debug=app.debug)
-
-@app.template_filter()
-def throw(err):
- raise Exception(err)
-
-@app.template_filter()
-def domain(url):
- return urlparse(url).netloc
-
-@app.template_filter()
-def date(value):
- return value.strftime("%Y-%m-%d")
-
-@app.template_filter()
-def datetime(value):
- return value.strftime("%Y-%m-%d %H:%M") + " UTC"
-
-@app.route("/uploads/<path:path>")
-def send_upload(path):
- return send_from_directory("public/uploads", path)
-
-@app.route("/")
-@menu.register_menu(app, ".", "Home")
-def home_page():
- query = Package.query.filter_by(approved=True, soft_deleted=False)
- count = query.count()
- new = query.order_by(db.desc(Package.created_at)).limit(8).all()
- pop_mod = query.filter_by(type=PackageType.MOD).order_by(db.desc(Package.score)).limit(8).all()
- pop_gam = query.filter_by(type=PackageType.GAME).order_by(db.desc(Package.score)).limit(4).all()
- pop_txp = query.filter_by(type=PackageType.TXP).order_by(db.desc(Package.score)).limit(4).all()
- downloads = db.session.query(func.sum(PackageRelease.downloads)).first()[0]
- return render_template("index.html", count=count, downloads=downloads, \
- new=new, pop_mod=pop_mod, pop_txp=pop_txp, pop_gam=pop_gam)
-
-from . import users, packages, meta, threads, api
-from . import sass, thumbnails, tasks, admin
-
-@menu.register_menu(app, ".help", "Help", order=19, endpoint_arguments_constructor=lambda: { 'path': 'help' })
-@app.route('/<path:path>/')
-def flatpage(path):
- page = pages.get_or_404(path)
- template = page.meta.get('template', 'flatpage.html')
- return render_template(template, page=page)
-
-@app.before_request
-def do_something_whenever_a_request_comes_in():
- if current_user.is_authenticated:
- if current_user.rank == UserRank.BANNED:
- flash("You have been banned.", "error")
- logout_user()
- return redirect(url_for('user.login'))
- elif current_user.rank == UserRank.NOT_JOINED:
- current_user.rank = UserRank.MEMBER
- db.session.commit()
diff --git a/app/views/admin/__init__.py b/app/views/admin/__init__.py
deleted file mode 100644
index 2e467da..0000000
--- a/app/views/admin/__init__.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# 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, versioneditor, todo