Use snake_case for method names

This commit is contained in:
rubenwardy 2023-06-19 21:27:49 +01:00
parent 16f93b3e13
commit 45ed12ddf0
53 changed files with 390 additions and 387 deletions

@ -129,13 +129,13 @@ def check_for_ban():
models.db.session.commit()
from .utils import clearNotifications, is_safe_url, create_session
from .utils import clear_notifications, is_safe_url, create_session
@app.before_request
def check_for_notifications():
if current_user.is_authenticated:
clearNotifications(request.path)
clear_notifications(request.path)
@app.errorhandler(404)

@ -25,9 +25,9 @@ from sqlalchemy import or_, and_
from app.models import PackageRelease, db, Package, PackageState, PackageScreenshot, MetaPackage, User, \
NotificationType, PackageUpdateConfig, License, UserRank, PackageType
from app.tasks.emails import send_pending_digests
from app.tasks.forumtasks import importTopicList, checkAllForumAccounts
from app.tasks.importtasks import importRepoScreenshot, checkZipRelease, check_for_updates, updateAllGameSupport
from app.utils import addNotification, get_system_user
from app.tasks.forumtasks import import_topic_list, check_all_forum_accounts
from app.tasks.importtasks import import_repo_screenshot, check_zip_release, check_for_updates, update_all_game_support
from app.utils import add_notification, get_system_user
actions = {}
@ -54,13 +54,13 @@ def del_stuck_releases():
@action("Import forum topic list")
def import_topic_list():
task = importTopicList.delay()
task = import_topic_list.delay()
return redirect(url_for("tasks.check", id=task.id, r=url_for("todo.topics")))
@action("Check all forum accounts")
def check_all_forum_accounts():
task = checkAllForumAccounts.delay()
task = check_all_forum_accounts.delay()
return redirect(url_for("tasks.check", id=task.id, r=url_for("admin.admin_page")))
@ -142,9 +142,9 @@ def remind_wip():
packages_list = _package_list(packages)
havent = "haven't" if len(packages) > 1 else "hasn't"
addNotification(user, system_user, NotificationType.PACKAGE_APPROVAL,
add_notification(user, system_user, NotificationType.PACKAGE_APPROVAL,
f"Did you forget? {packages_list} {havent} been submitted for review yet",
url_for('todo.view_user', username=user.username))
url_for('todo.view_user', username=user.username))
db.session.commit()
@ -162,9 +162,9 @@ def remind_outdated():
packages = [pkg[0] for pkg in packages]
packages_list = _package_list(packages)
addNotification(user, system_user, NotificationType.PACKAGE_APPROVAL,
add_notification(user, system_user, NotificationType.PACKAGE_APPROVAL,
f"The following packages may be outdated: {packages_list}",
url_for('todo.view_user', username=user.username))
url_for('todo.view_user', username=user.username))
db.session.commit()
@ -241,9 +241,9 @@ def remind_video_url():
packages = [pkg[0] for pkg in packages]
packages_list = _package_list(packages)
addNotification(user, system_user, NotificationType.PACKAGE_APPROVAL,
add_notification(user, system_user, NotificationType.PACKAGE_APPROVAL,
f"You should add a video to {packages_list}",
url_for('users.profile', username=user.username))
url_for('users.profile', username=user.username))
db.session.commit()
@ -270,9 +270,9 @@ def remind_missing_game_support():
packages = [pkg[0] for pkg in packages]
packages_list = _package_list(packages)
addNotification(user, system_user, NotificationType.PACKAGE_APPROVAL,
add_notification(user, system_user, NotificationType.PACKAGE_APPROVAL,
f"You need to confirm whether the following packages support all games: {packages_list}",
url_for('todo.all_game_support', username=user.username))
url_for('todo.all_game_support', username=user.username))
db.session.commit()
@ -280,7 +280,7 @@ def remind_missing_game_support():
@action("Detect game support")
def detect_game_support():
task_id = uuid()
updateAllGameSupport.apply_async((), task_id=task_id)
update_all_game_support.apply_async((), task_id=task_id)
return redirect(url_for("tasks.check", id=task_id, r=url_for("admin.admin_page")))
@ -308,7 +308,7 @@ def check_releases():
tasks = []
for release in releases:
tasks.append(checkZipRelease.s(release.id, release.file_path))
tasks.append(check_zip_release.s(release.id, release.file_path))
result = group(tasks).apply_async()
@ -325,7 +325,7 @@ def reimport_packages():
for package in Package.query.filter(Package.state != PackageState.DELETED).all():
release = package.releases.first()
if release:
tasks.append(checkZipRelease.s(release.id, release.file_path))
tasks.append(check_zip_release.s(release.id, release.file_path))
result = group(tasks).apply_async()
@ -344,6 +344,6 @@ def import_screenshots():
.filter(PackageScreenshot.id == None) \
.all()
for package in packages:
importRepoScreenshot.delay(package.id)
import_repo_screenshot.delay(package.id)
return redirect(url_for("admin.admin_page"))

@ -19,7 +19,7 @@ from flask_login import current_user, login_user
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import InputRequired, Length
from app.utils import rank_required, addAuditLog, addNotification, get_system_user
from app.utils import rank_required, add_audit_log, add_notification, get_system_user
from . import bp
from .actions import actions
from app.models import UserRank, Package, db, PackageState, User, AuditSeverity, NotificationType
@ -75,11 +75,11 @@ class SendNotificationForm(FlaskForm):
def send_bulk_notification():
form = SendNotificationForm(request.form)
if form.validate_on_submit():
addAuditLog(AuditSeverity.MODERATION, current_user,
add_audit_log(AuditSeverity.MODERATION, current_user,
"Sent bulk notification", url_for("admin.admin_page"), None, form.title.data)
users = User.query.filter(User.rank >= UserRank.NEW_MEMBER).all()
addNotification(users, get_system_user(), NotificationType.OTHER, form.title.data, form.url.data, None)
add_notification(users, get_system_user(), NotificationType.OTHER, form.title.data, form.url.data, None)
db.session.commit()
return redirect(url_for("admin.admin_page"))
@ -105,8 +105,8 @@ def restore():
else:
package.state = target
addAuditLog(AuditSeverity.EDITOR, current_user, f"Restored package to state {target.value}",
package.get_url("packages.view"), package)
add_audit_log(AuditSeverity.EDITOR, current_user, f"Restored package to state {target.value}",
package.get_url("packages.view"), package)
db.session.commit()
return redirect(package.get_url("packages.view"))

@ -22,7 +22,7 @@ from wtforms.validators import InputRequired, Length
from app.markdown import render_markdown
from app.tasks.emails import send_user_email, send_bulk_email as task_send_bulk
from app.utils import rank_required, addAuditLog
from app.utils import rank_required, add_audit_log
from . import bp
from app.models import UserRank, User, AuditSeverity
@ -49,7 +49,7 @@ def send_single_email():
form = SendEmailForm(request.form)
if form.validate_on_submit():
addAuditLog(AuditSeverity.MODERATION, current_user,
add_audit_log(AuditSeverity.MODERATION, current_user,
"Sent email to {}".format(user.display_name), url_for("users.profile", username=username))
text = form.text.data
@ -65,7 +65,7 @@ def send_single_email():
def send_bulk_email():
form = SendEmailForm(request.form)
if form.validate_on_submit():
addAuditLog(AuditSeverity.MODERATION, current_user,
add_audit_log(AuditSeverity.MODERATION, current_user,
"Sent bulk email", url_for("admin.admin_page"), None, form.text.data)
text = form.text.data

@ -21,7 +21,7 @@ from flask_wtf import FlaskForm
from wtforms import StringField, BooleanField, SubmitField, URLField
from wtforms.validators import InputRequired, Length, Optional
from app.utils import rank_required, nonEmptyOrNone, addAuditLog
from app.utils import rank_required, nonempty_or_none, add_audit_log
from . import bp
from app.models import UserRank, License, db, AuditSeverity
@ -35,7 +35,7 @@ def license_list():
class LicenseForm(FlaskForm):
name = StringField("Name", [InputRequired(), Length(3, 100)])
is_foss = BooleanField("Is FOSS")
url = URLField("URL", [Optional()], filters=[nonEmptyOrNone])
url = URLField("URL", [Optional()], filters=[nonempty_or_none])
submit = SubmitField("Save")
@ -58,13 +58,13 @@ def create_edit_license(name=None):
db.session.add(license)
flash("Created license " + form.name.data, "success")
addAuditLog(AuditSeverity.MODERATION, current_user, f"Created license {license.name}",
url_for("admin.license_list"))
add_audit_log(AuditSeverity.MODERATION, current_user, f"Created license {license.name}",
url_for("admin.license_list"))
else:
flash("Updated license " + form.name.data, "success")
addAuditLog(AuditSeverity.MODERATION, current_user, f"Edited license {license.name}",
url_for("admin.license_list"))
add_audit_log(AuditSeverity.MODERATION, current_user, f"Edited license {license.name}",
url_for("admin.license_list"))
form.populate_obj(license)
db.session.commit()

@ -23,7 +23,7 @@ from wtforms.validators import InputRequired, Length, Optional, Regexp
from . import bp
from app.models import Permission, Tag, db, AuditSeverity
from app.utils import addAuditLog
from app.utils import add_audit_log
@bp.route("/tags/")
@ -72,13 +72,13 @@ def create_edit_tag(name=None):
tag.is_protected = form.is_protected.data
db.session.add(tag)
addAuditLog(AuditSeverity.EDITOR, current_user, f"Created tag {tag.name}",
url_for("admin.create_edit_tag", name=tag.name))
add_audit_log(AuditSeverity.EDITOR, current_user, f"Created tag {tag.name}",
url_for("admin.create_edit_tag", name=tag.name))
else:
form.populate_obj(tag)
addAuditLog(AuditSeverity.EDITOR, current_user, f"Edited tag {tag.name}",
url_for("admin.create_edit_tag", name=tag.name))
add_audit_log(AuditSeverity.EDITOR, current_user, f"Edited tag {tag.name}",
url_for("admin.create_edit_tag", name=tag.name))
db.session.commit()

@ -21,7 +21,7 @@ from flask_wtf import FlaskForm
from wtforms import StringField, IntegerField, SubmitField
from wtforms.validators import InputRequired, Length
from app.utils import rank_required, addAuditLog
from app.utils import rank_required, add_audit_log
from . import bp
from app.models import UserRank, MinetestRelease, db, AuditSeverity
@ -56,13 +56,13 @@ def create_edit_version(name=None):
db.session.add(version)
flash("Created version " + form.name.data, "success")
addAuditLog(AuditSeverity.MODERATION, current_user, f"Created version {version.name}",
url_for("admin.license_list"))
add_audit_log(AuditSeverity.MODERATION, current_user, f"Created version {version.name}",
url_for("admin.license_list"))
else:
flash("Updated version " + form.name.data, "success")
addAuditLog(AuditSeverity.MODERATION, current_user, f"Edited version {version.name}",
url_for("admin.version_list"))
add_audit_log(AuditSeverity.MODERATION, current_user, f"Edited version {version.name}",
url_for("admin.version_list"))
form.populate_obj(version)
db.session.commit()

@ -30,7 +30,7 @@ from app.markdown import render_markdown
from app.models import Tag, PackageState, PackageType, Package, db, PackageRelease, Permission, ForumTopic, \
MinetestRelease, APIToken, PackageScreenshot, License, ContentWarning, User, PackageReview, Thread
from app.querybuilder import QueryBuilder
from app.utils import is_package_page, get_int_or_abort, url_set_query, abs_url, isYes, get_request_date
from app.utils import is_package_page, get_int_or_abort, url_set_query, abs_url, is_yes, get_request_date
from . import bp
from .auth import is_api_authd
from .support import error, api_create_vcs_release, api_create_zip_release, api_create_screenshot, \
@ -66,19 +66,19 @@ def cached(max_age: int):
@cached(300)
def packages():
qb = QueryBuilder(request.args)
query = qb.buildPackageQuery()
query = qb.build_package_query()
if request.args.get("fmt") == "keys":
return jsonify([pkg.as_key_dict() for pkg in query.all()])
pkgs = qb.convertToDictionary(query.all())
pkgs = qb.convert_to_dictionary(query.all())
if "engine_version" in request.args or "protocol_version" in request.args:
pkgs = [pkg for pkg in pkgs if pkg.get("release")]
# Promote featured packages
if "sort" not in request.args and "order" not in request.args and "q" not in request.args:
featured_lut = set()
featured = qb.convertToDictionary(query.filter(Package.tags.any(name="featured")).all())
featured = qb.convert_to_dictionary(query.filter(Package.tags.any(name="featured")).all())
for pkg in featured:
featured_lut.add(f"{pkg['author']}/{pkg['name']}")
pkg["short_description"] = "Featured. " + pkg["short_description"]
@ -101,7 +101,7 @@ def package_view(package):
@cors_allowed
def package_hypertext(package):
formspec_version = request.args["formspec_version"]
include_images = isYes(request.args.get("include_images", "true"))
include_images = is_yes(request.args.get("include_images", "true"))
html = render_markdown(package.desc)
return jsonify(html_to_minetest(html, formspec_version, include_images))
@ -174,7 +174,7 @@ def package_dependencies(package):
@cors_allowed
def topics():
qb = QueryBuilder(request.args)
query = qb.buildTopicQuery(show_added=True)
query = qb.build_topic_query(show_added=True)
return jsonify([t.as_dict() for t in query.all()])
@ -346,7 +346,7 @@ def create_screenshot(token: APIToken, package: Package):
if file is None:
error(400, "Missing 'file' in multipart body")
return api_create_screenshot(token, package, data["title"], file, isYes(data.get("is_cover_image")))
return api_create_screenshot(token, package, data["title"], file, is_yes(data.get("is_cover_image")))
@bp.route("/api/packages/<author>/<name>/screenshots/<int:id>/")
@ -454,7 +454,7 @@ def list_all_reviews():
query = query.filter(PackageReview.author.has(User.username == request.args.get("author")))
if request.args.get("is_positive"):
if isYes(request.args.get("is_positive")):
if is_yes(request.args.get("is_positive")):
query = query.filter(PackageReview.rating > 3)
else:
query = query.filter(PackageReview.rating <= 3)
@ -499,7 +499,7 @@ def all_package_stats():
@cached(300)
def package_scores():
qb = QueryBuilder(request.args)
query = qb.buildPackageQuery()
query = qb.build_package_query()
pkgs = [package.as_score_dict() for package in query.all()]
return jsonify(pkgs)
@ -601,7 +601,7 @@ def versions():
@cors_allowed
def all_deps():
qb = QueryBuilder(request.args)
query = qb.buildPackageQuery()
query = qb.build_package_query()
def format_pkg(pkg: Package):
return {

@ -24,7 +24,7 @@ from wtforms.validators import InputRequired, Length
from wtforms_sqlalchemy.fields import QuerySelectField
from app.models import db, User, APIToken, Permission
from app.utils import randomString
from app.utils import random_string
from . import bp
from ..users.settings import get_setting_tabs
@ -87,7 +87,7 @@ def create_edit_token(username, id=None):
token = APIToken()
db.session.add(token)
token.owner = user
token.access_token = randomString(32)
token.access_token = random_string(32)
form.populate_obj(token)
db.session.commit()
@ -117,7 +117,7 @@ def reset_token(username, id):
elif token.owner != user:
abort(403)
token.access_token = randomString(32)
token.access_token = random_string(32)
db.session.commit() # save

@ -24,7 +24,7 @@ from flask_login import current_user
from sqlalchemy import func, or_, and_
from app import github, csrf
from app.models import db, User, APIToken, Package, Permission, AuditSeverity, PackageState
from app.utils import abs_url_for, addAuditLog, login_user_set_active
from app.utils import abs_url_for, add_audit_log, login_user_set_active
from app.blueprints.api.support import error, api_create_vcs_release
import hmac, requests
@ -76,8 +76,8 @@ def callback(oauth_token):
flash(gettext("Authorization failed [err=gh-login-failed]"), "danger")
return redirect(url_for("users.login"))
addAuditLog(AuditSeverity.USER, userByGithub, "Logged in using GitHub OAuth",
url_for("users.profile", username=userByGithub.username))
add_audit_log(AuditSeverity.USER, userByGithub, "Logged in using GitHub OAuth",
url_for("users.profile", username=userByGithub.username))
db.session.commit()
return ret

@ -34,7 +34,7 @@ from app.logic.LogicError import LogicError
from app.logic.packages import do_edit_package
from app.querybuilder import QueryBuilder
from app.rediscache import has_key, set_key
from app.tasks.importtasks import importRepoScreenshot, checkZipRelease
from app.tasks.importtasks import import_repo_screenshot, check_zip_release
from app.tasks.webhooktasks import post_discord_webhook
from app.logic.game_support import GameSupportResolver
@ -43,14 +43,14 @@ from app.models import Package, Tag, db, User, Tags, PackageState, Permission, P
Dependency, Thread, UserRank, PackageReview, PackageDevState, ContentWarning, License, AuditSeverity, \
PackageScreenshot, NotificationType, AuditLogEntry, PackageAlias, PackageProvides, PackageGameSupport, \
PackageDailyStats
from app.utils import is_user_bot, get_int_or_abort, is_package_page, abs_url_for, addAuditLog, getPackageByInfo, \
addNotification, get_system_user, rank_required, get_games_from_csv, get_daterange_options
from app.utils import is_user_bot, get_int_or_abort, is_package_page, abs_url_for, add_audit_log, get_package_by_info, \
add_notification, get_system_user, rank_required, get_games_from_csv, get_daterange_options
@bp.route("/packages/")
def list_all():
qb = QueryBuilder(request.args)
query = qb.buildPackageQuery()
query = qb.build_package_query()
title = qb.title
query = query.options(
@ -78,7 +78,7 @@ def list_all():
if package:
return redirect(package.get_url("packages.view"))
topic = qb.buildTopicQuery().first()
topic = qb.build_topic_query().first()
if qb.search and topic:
return redirect("https://forum.minetest.net/viewtopic.php?t=" + str(topic.topic_id))
@ -100,12 +100,12 @@ def list_all():
topics = None
if qb.search and not query.has_next:
qb.show_discarded = True
topics = qb.buildTopicQuery().all()
topics = qb.build_topic_query().all()
tags_query = db.session.query(func.count(Tags.c.tag_id), Tag) \
.select_from(Tag).join(Tags).join(Package).filter(Package.state==PackageState.APPROVED) \
.group_by(Tag.id).order_by(db.asc(Tag.title))
tags = qb.filterPackageQuery(tags_query).all()
tags = qb.filter_package_query(tags_query).all()
selected_tags = set(qb.tags)
@ -115,7 +115,7 @@ def list_all():
authors=authors, packages_count=query.total, topics=topics, noindex=qb.noindex)
def getReleases(package):
def get_releases(package):
if package.check_perm(current_user, Permission.MAKE_RELEASE):
return package.releases.limit(5)
else:
@ -158,7 +158,7 @@ def view(package):
Dependency.meta_package_id.in_([p.id for p in package.provides]))) \
.order_by(db.desc(Package.score)).limit(6).all()
releases = getReleases(package)
releases = get_releases(package)
review_thread = package.review_thread
if review_thread is not None and not review_thread.check_perm(current_user, Permission.SEE_THREAD):
@ -185,7 +185,7 @@ def view(package):
threads = Thread.query.filter_by(package_id=package.id, review_id=None)
if not current_user.is_authenticated:
threads = threads.filter_by(private=False)
elif not current_user.rank.atLeast(UserRank.APPROVER) and not current_user == package.author:
elif not current_user.rank.at_least(UserRank.APPROVER) and not current_user == package.author:
threads = threads.filter(or_(Thread.private == False, Thread.author == current_user))
has_review = current_user.is_authenticated and \
@ -310,10 +310,10 @@ def handle_create_edit(package: typing.Optional[Package], form: PackageForm, aut
if wasNew:
msg = f"Created package {author.username}/{form.name.data}"
addAuditLog(AuditSeverity.NORMAL, current_user, msg, package.get_url("packages.view"), package)
add_audit_log(AuditSeverity.NORMAL, current_user, msg, package.get_url("packages.view"), package)
if wasNew and package.repo is not None:
importRepoScreenshot.delay(package.id)
import_repo_screenshot.delay(package.id)
next_url = package.get_url("packages.view")
if wasNew and ("WTFPL" in package.license.name or "WTFPL" in package.media_license.name):
@ -347,7 +347,7 @@ def create_edit(author=None, name=None):
return redirect(url_for("packages.create_edit"))
else:
package = getPackageByInfo(author, name)
package = get_package_by_info(author, name)
if package is None:
abort(404)
if not package.check_perm(current_user, Permission.EDIT_PACKAGE):
@ -422,9 +422,9 @@ def move_to_state(package):
"Ready for Review: {}".format(package.get_url("packages.view", absolute=True)), True,
package.title, package.short_desc, package.get_thumb_url(2, True))
addNotification(package.maintainers, current_user, NotificationType.PACKAGE_APPROVAL, msg, package.get_url("packages.view"), package)
add_notification(package.maintainers, current_user, NotificationType.PACKAGE_APPROVAL, msg, package.get_url("packages.view"), package)
severity = AuditSeverity.NORMAL if current_user in package.maintainers else AuditSeverity.EDITOR
addAuditLog(severity, current_user, msg, package.get_url("packages.view"), package)
add_audit_log(severity, current_user, msg, package.get_url("packages.view"), package)
db.session.commit()
@ -457,8 +457,8 @@ def remove(package):
url = url_for("users.profile", username=package.author.username)
msg = "Deleted {}, reason={}".format(package.title, reason)
addNotification(package.maintainers, current_user, NotificationType.PACKAGE_EDIT, msg, url, package)
addAuditLog(AuditSeverity.EDITOR, current_user, msg, url, package)
add_notification(package.maintainers, current_user, NotificationType.PACKAGE_EDIT, msg, url, package)
add_audit_log(AuditSeverity.EDITOR, current_user, msg, url, package)
db.session.commit()
flash(gettext("Deleted package"), "success")
@ -472,8 +472,8 @@ def remove(package):
package.state = PackageState.WIP
msg = "Unapproved {}, reason={}".format(package.title, reason)
addNotification(package.maintainers, current_user, NotificationType.PACKAGE_APPROVAL, msg, package.get_url("packages.view"), package)
addAuditLog(AuditSeverity.EDITOR, current_user, msg, package.get_url("packages.view"), package)
add_notification(package.maintainers, current_user, NotificationType.PACKAGE_APPROVAL, msg, package.get_url("packages.view"), package)
add_audit_log(AuditSeverity.EDITOR, current_user, msg, package.get_url("packages.view"), package)
db.session.commit()
@ -512,12 +512,12 @@ def edit_maintainers(package):
if not user in package.maintainers:
if thread:
thread.watchers.append(user)
addNotification(user, current_user, NotificationType.MAINTAINER,
add_notification(user, current_user, NotificationType.MAINTAINER,
"Added you as a maintainer of {}".format(package.title), package.get_url("packages.view"), package)
for user in package.maintainers:
if user != package.author and not user in users:
addNotification(user, current_user, NotificationType.MAINTAINER,
add_notification(user, current_user, NotificationType.MAINTAINER,
"Removed you as a maintainer of {}".format(package.title), package.get_url("packages.view"), package)
package.maintainers.clear()
@ -526,9 +526,9 @@ def edit_maintainers(package):
package.maintainers.append(package.author)
msg = "Edited {} maintainers".format(package.title)
addNotification(package.author, current_user, NotificationType.MAINTAINER, msg, package.get_url("packages.view"), package)
add_notification(package.author, current_user, NotificationType.MAINTAINER, msg, package.get_url("packages.view"), package)
severity = AuditSeverity.NORMAL if current_user == package.author else AuditSeverity.MODERATION
addAuditLog(severity, current_user, msg, package.get_url("packages.view"), package)
add_audit_log(severity, current_user, msg, package.get_url("packages.view"), package)
db.session.commit()
@ -553,7 +553,7 @@ def remove_self_maintainers(package):
else:
package.maintainers.remove(current_user)
addNotification(package.author, current_user, NotificationType.MAINTAINER,
add_notification(package.author, current_user, NotificationType.MAINTAINER,
"Removed themself as a maintainer of {}".format(package.title), package.get_url("packages.view"), package)
db.session.commit()
@ -715,7 +715,7 @@ def game_support(package):
package.supports_all_games = form.supports_all_games.data
addAuditLog(AuditSeverity.NORMAL, current_user, "Edited game support", package.get_url("packages.game_support"), package)
add_audit_log(AuditSeverity.NORMAL, current_user, "Edited game support", package.get_url("packages.game_support"), package)
db.session.commit()
@ -723,7 +723,7 @@ def game_support(package):
release = package.releases.first()
if release:
task_id = uuid()
checkZipRelease.apply_async((release.id, release.file_path), task_id=task_id)
check_zip_release.apply_async((release.id, release.file_path), task_id=task_id)
next_url = url_for("tasks.check", id=task_id, r=next_url)
return redirect(next_url)

@ -27,7 +27,7 @@ from app.models import Package, db, User, PackageState, Permission, UserRank, Pa
PackageRelease, PackageUpdateTrigger, PackageUpdateConfig
from app.rediscache import has_key, set_key, make_download_key
from app.tasks.importtasks import check_update_config
from app.utils import is_user_bot, is_package_page, nonEmptyOrNone
from app.utils import is_user_bot, is_package_page, nonempty_or_none
from . import bp, get_package_tabs
@ -263,7 +263,7 @@ def set_update_config(package, form):
db.session.add(package.update_config)
form.populate_obj(package.update_config)
package.update_config.ref = nonEmptyOrNone(form.ref.data)
package.update_config.ref = nonempty_or_none(form.ref.data)
package.update_config.make_release = form.action.data == "make_release"
if package.update_config.trigger == PackageUpdateTrigger.COMMIT:
@ -349,7 +349,7 @@ def bulk_update_config(username=None):
if not user:
abort(404)
if current_user != user and not current_user.rank.atLeast(UserRank.EDITOR):
if current_user != user and not current_user.rank.at_least(UserRank.EDITOR):
abort(403)
form = PackageUpdateConfigFrom()

@ -26,8 +26,8 @@ from wtforms.validators import InputRequired, Length
from app.models import db, PackageReview, Thread, ThreadReply, NotificationType, PackageReviewVote, Package, UserRank, \
Permission, AuditSeverity, PackageState
from app.tasks.webhooktasks import post_discord_webhook
from app.utils import is_package_page, addNotification, get_int_or_abort, isYes, is_safe_url, rank_required, \
addAuditLog, has_blocked_domains
from app.utils import is_package_page, add_notification, get_int_or_abort, is_yes, is_safe_url, rank_required, \
add_audit_log, has_blocked_domains
from . import bp
@ -123,8 +123,8 @@ def review(package):
notif_msg = "Updated review '{}'".format(form.title.data)
type = NotificationType.OTHER
addNotification(package.maintainers, current_user, type, notif_msg,
url_for("threads.view", id=thread.id), package)
add_notification(package.maintainers, current_user, type, notif_msg,
url_for("threads.view", id=thread.id), package)
if was_new:
post_discord_webhook.delay(thread.author.username,
@ -163,11 +163,11 @@ def delete_review(package, reviewer):
thread.review = None
msg = "Converted review by {} to thread".format(review.author.display_name)
addAuditLog(AuditSeverity.MODERATION if current_user.username != reviewer else AuditSeverity.NORMAL,
current_user, msg, thread.get_view_url(), thread.package)
add_audit_log(AuditSeverity.MODERATION if current_user.username != reviewer else AuditSeverity.NORMAL,
current_user, msg, thread.get_view_url(), thread.package)
notif_msg = "Deleted review '{}', comments were kept as a thread".format(thread.title)
addNotification(package.maintainers, current_user, NotificationType.OTHER, notif_msg, url_for("threads.view", id=thread.id), package)
add_notification(package.maintainers, current_user, NotificationType.OTHER, notif_msg, url_for("threads.view", id=thread.id), package)
db.session.delete(review)
@ -191,7 +191,7 @@ def handle_review_vote(package: Package, review_id: int):
flash(gettext("You can't vote on your own reviews!"), "danger")
return
is_positive = isYes(request.form["is_positive"])
is_positive = is_yes(request.form["is_positive"])
vote = PackageReviewVote.query.filter_by(review=review, user=current_user).first()
if vote is None:

@ -25,7 +25,7 @@ from wtforms.validators import InputRequired, Length
from app.models import User, UserRank
from app.tasks.emails import send_user_email
from app.tasks.webhooktasks import post_discord_webhook
from app.utils import isNo, abs_url_samesite
from app.utils import is_no, abs_url_samesite
bp = Blueprint("report", __name__)
@ -37,7 +37,7 @@ class ReportForm(FlaskForm):
@bp.route("/report/", methods=["GET", "POST"])
def report():
is_anon = not current_user.is_authenticated or not isNo(request.args.get("anon"))
is_anon = not current_user.is_authenticated or not is_no(request.args.get("anon"))
url = request.args.get("url")
if url:

@ -20,8 +20,8 @@ from flask_login import login_required, current_user
from app import csrf
from app.models import UserRank
from app.tasks import celery
from app.tasks.importtasks import getMeta
from app.utils import shouldReturnJson
from app.tasks.importtasks import get_meta
from app.utils import should_return_json
bp = Blueprint("tasks", __name__)
@ -33,7 +33,7 @@ def start_getmeta():
from flask import request
author = request.args.get("author")
author = current_user.forums_username if author is None else author
aresult = getMeta.delay(request.args.get("url"), author)
aresult = get_meta.delay(request.args.get("url"), author)
return jsonify({
"poll_url": url_for("tasks.check", id=aresult.id),
})
@ -52,7 +52,7 @@ def check(id):
'status': status,
}
if current_user.is_authenticated and current_user.rank.atLeast(UserRank.ADMIN):
if current_user.is_authenticated and current_user.rank.at_least(UserRank.ADMIN):
info["error"] = str(traceback)
elif str(result)[1:12] == "TaskError: ":
info["error"] = str(result)[12:-1]
@ -65,7 +65,7 @@ def check(id):
'result': result,
}
if shouldReturnJson():
if should_return_json():
return jsonify(info)
else:
r = request.args.get("r")

@ -25,7 +25,7 @@ bp = Blueprint("threads", __name__)
from flask_login import current_user, login_required
from app.models import Package, db, User, Permission, Thread, UserRank, AuditSeverity, \
NotificationType, ThreadReply
from app.utils import addNotification, isYes, addAuditLog, get_system_user, rank_required, has_blocked_domains
from app.utils import add_notification, is_yes, add_audit_log, get_system_user, rank_required, has_blocked_domains
from flask_wtf import FlaskForm
from wtforms import StringField, TextAreaField, SubmitField, BooleanField
from wtforms.validators import InputRequired, Length
@ -99,7 +99,7 @@ def set_lock(id_):
if thread is None or not thread.check_perm(current_user, Permission.LOCK_THREAD):
abort(404)
thread.locked = isYes(request.args.get("lock"))
thread.locked = is_yes(request.args.get("lock"))
if thread.locked is None:
abort(400)
@ -110,8 +110,8 @@ def set_lock(id_):
msg = "Unlocked thread '{}'".format(thread.title)
flash(gettext("Unlocked thread"), "success")
addNotification(thread.watchers, current_user, NotificationType.OTHER, msg, thread.get_view_url(), thread.package)
addAuditLog(AuditSeverity.MODERATION, current_user, msg, thread.get_view_url(), thread.package)
add_notification(thread.watchers, current_user, NotificationType.OTHER, msg, thread.get_view_url(), thread.package)
add_audit_log(AuditSeverity.MODERATION, current_user, msg, thread.get_view_url(), thread.package)
db.session.commit()
@ -134,7 +134,7 @@ def delete_thread(id_):
db.session.delete(thread)
addAuditLog(AuditSeverity.MODERATION, current_user, msg, None, thread.package, summary)
add_audit_log(AuditSeverity.MODERATION, current_user, msg, None, thread.package, summary)
db.session.commit()
@ -167,7 +167,7 @@ def delete_reply(id_):
return render_template("threads/delete_reply.html", thread=thread, reply=reply)
msg = "Deleted reply by {}".format(reply.author.display_name)
addAuditLog(AuditSeverity.MODERATION, current_user, msg, thread.get_view_url(), thread.package, reply.comment)
add_audit_log(AuditSeverity.MODERATION, current_user, msg, thread.get_view_url(), thread.package, reply.comment)
db.session.delete(reply)
db.session.commit()
@ -206,8 +206,8 @@ def edit_reply(id_):
else:
msg = "Edited reply by {}".format(reply.author.display_name)
severity = AuditSeverity.NORMAL if current_user == reply.author else AuditSeverity.MODERATION
addNotification(reply.author, current_user, NotificationType.OTHER, msg, thread.get_view_url(), thread.package)
addAuditLog(severity, current_user, msg, thread.get_view_url(), thread.package, reply.comment)
add_notification(reply.author, current_user, NotificationType.OTHER, msg, thread.get_view_url(), thread.package)
add_audit_log(severity, current_user, msg, thread.get_view_url(), thread.package, reply.comment)
reply.comment = comment
@ -253,18 +253,18 @@ def view(id_):
continue
msg = "Mentioned by {} in '{}'".format(current_user.display_name, thread.title)
addNotification(mentioned, current_user, NotificationType.THREAD_REPLY,
msg, thread.get_view_url(), thread.package)
add_notification(mentioned, current_user, NotificationType.THREAD_REPLY,
msg, thread.get_view_url(), thread.package)
thread.watchers.append(mentioned)
msg = "New comment on '{}'".format(thread.title)
addNotification(thread.watchers, current_user, NotificationType.THREAD_REPLY, msg, thread.get_view_url(), thread.package)
add_notification(thread.watchers, current_user, NotificationType.THREAD_REPLY, msg, thread.get_view_url(), thread.package)
if thread.author == get_system_user():
approvers = User.query.filter(User.rank >= UserRank.APPROVER).all()
addNotification(approvers, current_user, NotificationType.EDITOR_MISC, msg,
thread.get_view_url(), thread.package)
add_notification(approvers, current_user, NotificationType.EDITOR_MISC, msg,
thread.get_view_url(), thread.package)
post_discord_webhook.delay(current_user.username,
"Replied to bot messages: {}".format(thread.get_view_url(absolute=True)), True)
@ -294,7 +294,7 @@ def new():
abort(404)
def_is_private = request.args.get("private") or False
if package is None and not current_user.rank.atLeast(UserRank.APPROVER):
if package is None and not current_user.rank.at_least(UserRank.APPROVER):
abort(404)
allow_private_change = not package or package.approved
@ -359,17 +359,17 @@ def new():
continue
msg = "Mentioned by {} in new thread '{}'".format(current_user.display_name, thread.title)
addNotification(mentioned, current_user, NotificationType.NEW_THREAD,
msg, thread.get_view_url(), thread.package)
add_notification(mentioned, current_user, NotificationType.NEW_THREAD,
msg, thread.get_view_url(), thread.package)
thread.watchers.append(mentioned)
notif_msg = "New thread '{}'".format(thread.title)
if package is not None:
addNotification(package.maintainers, current_user, NotificationType.NEW_THREAD, notif_msg, thread.get_view_url(), package)
add_notification(package.maintainers, current_user, NotificationType.NEW_THREAD, notif_msg, thread.get_view_url(), package)
approvers = User.query.filter(User.rank >= UserRank.APPROVER).all()
addNotification(approvers, current_user, NotificationType.EDITOR_MISC, notif_msg, thread.get_view_url(), package)
add_notification(approvers, current_user, NotificationType.EDITOR_MISC, notif_msg, thread.get_view_url(), package)
if is_review_thread:
post_discord_webhook.delay(current_user.username,

@ -22,7 +22,7 @@ from sqlalchemy import or_
from app.models import Package, PackageState, PackageScreenshot, PackageUpdateConfig, ForumTopic, db, \
PackageRelease, Permission, UserRank, License, MetaPackage, Dependency, AuditLogEntry, Tag, MinetestRelease
from app.querybuilder import QueryBuilder
from app.utils import get_int_or_abort, isYes
from app.utils import get_int_or_abort, is_yes
from . import bp
@ -85,7 +85,7 @@ def view_editor():
return render_template("todo/editor.html", current_tab="editor",
packages=packages, wip_packages=wip_packages, releases=releases, screenshots=screenshots,
canApproveNew=can_approve_new, canApproveRel=can_approve_rel, canApproveScn=can_approve_scn,
can_approve_new=can_approve_new, can_approve_rel=can_approve_rel, can_approve_scn=can_approve_scn,
license_needed=license_needed, total_packages=total_packages, total_to_tag=total_to_tag,
unfulfilled_meta_packages=unfulfilled_meta_packages, audit_log=audit_log)
@ -94,8 +94,8 @@ def view_editor():
@login_required
def topics():
qb = QueryBuilder(request.args)
qb.setSortIfNone("date")
query = qb.buildTopicQuery()
qb.set_sort_if_none("date")
query = qb.build_topic_query()
tmp_q = ForumTopic.query
if not qb.show_discarded:
@ -105,7 +105,7 @@ def topics():
page = get_int_or_abort(request.args.get("page"), 1)
num = get_int_or_abort(request.args.get("n"), 100)
if num > 100 and not current_user.rank.atLeast(UserRank.APPROVER):
if num > 100 and not current_user.rank.at_least(UserRank.APPROVER):
num = 100
query = query.paginate(page=page, per_page=num)
@ -126,10 +126,10 @@ def topics():
@login_required
def tags():
qb = QueryBuilder(request.args)
qb.setSortIfNone("score", "desc")
query = qb.buildPackageQuery()
qb.set_sort_if_none("score", "desc")
query = qb.build_package_query()
only_no_tags = isYes(request.args.get("no_tags"))
only_no_tags = is_yes(request.args.get("no_tags"))
if only_no_tags:
query = query.filter(Package.tags == None)
@ -153,7 +153,7 @@ def modnames():
@bp.route("/todo/outdated/")
@login_required
def outdated():
is_mtm_only = isYes(request.args.get("mtm"))
is_mtm_only = is_yes(request.args.get("mtm"))
query = db.session.query(Package).select_from(PackageUpdateConfig) \
.filter(PackageUpdateConfig.outdated_at.isnot(None)) \
@ -177,7 +177,7 @@ def outdated():
@bp.route("/todo/screenshots/")
@login_required
def screenshots():
is_mtm_only = isYes(request.args.get("mtm"))
is_mtm_only = is_yes(request.args.get("mtm"))
query = db.session.query(Package) \
.filter(~Package.screenshots.any()) \
@ -200,7 +200,7 @@ def screenshots():
@bp.route("/todo/mtver_support/")
@login_required
def mtver_support():
is_mtm_only = isYes(request.args.get("mtm"))
is_mtm_only = is_yes(request.args.get("mtm"))
current_stable = MinetestRelease.query.filter(~MinetestRelease.name.like("%-dev")).order_by(db.desc(MinetestRelease.id)).first()

@ -22,8 +22,8 @@ from sqlalchemy import or_, and_
from app.models import User, Package, PackageState, PackageScreenshot, PackageUpdateConfig, ForumTopic, db, \
PackageRelease, Permission, NotificationType, AuditSeverity, UserRank, PackageType
from app.tasks.importtasks import makeVCSRelease
from app.utils import addNotification, addAuditLog
from app.tasks.importtasks import make_vcs_release
from app.utils import add_notification, add_audit_log
from . import bp
@ -43,7 +43,7 @@ def view_user(username=None):
if not user:
abort(404)
if current_user != user and not current_user.rank.atLeast(UserRank.APPROVER):
if current_user != user and not current_user.rank.at_least(UserRank.APPROVER):
abort(403)
unapproved_packages = user.packages \
@ -97,7 +97,7 @@ def apply_all_updates(username):
if not user:
abort(404)
if current_user != user and not current_user.rank.atLeast(UserRank.EDITOR):
if current_user != user and not current_user.rank.at_least(UserRank.EDITOR):
abort(403)
outdated_packages = user.maintained_packages \
@ -124,13 +124,13 @@ def apply_all_updates(username):
db.session.add(rel)
db.session.commit()
makeVCSRelease.apply_async((rel.id, ref),
task_id=rel.task_id)
make_vcs_release.apply_async((rel.id, ref),
task_id=rel.task_id)
msg = "Created release {} (Applied all Git Update Detection)".format(rel.title)
addNotification(package.maintainers, current_user, NotificationType.PACKAGE_EDIT, msg,
rel.get_url("packages.create_edit"), package)
addAuditLog(AuditSeverity.NORMAL, current_user, msg, package.get_url("packages.view"), package)
add_notification(package.maintainers, current_user, NotificationType.PACKAGE_EDIT, msg,
rel.get_url("packages.create_edit"), package)
add_audit_log(AuditSeverity.NORMAL, current_user, msg, package.get_url("packages.view"), package)
db.session.commit()
return redirect(url_for("todo.view_user", username=username))
@ -144,7 +144,7 @@ def all_game_support(username=None):
return redirect(url_for("todo.all_game_support", username=current_user.username))
user: User = User.query.filter_by(username=username).one_or_404()
if current_user != user and not current_user.rank.atLeast(UserRank.EDITOR):
if current_user != user and not current_user.rank.at_least(UserRank.EDITOR):
abort(403)
packages = user.maintained_packages.filter(
@ -159,7 +159,7 @@ def all_game_support(username=None):
@login_required
def confirm_supports_all_games(username=None):
user: User = User.query.filter_by(username=username).one_or_404()
if current_user != user and not current_user.rank.atLeast(UserRank.EDITOR):
if current_user != user and not current_user.rank.at_least(UserRank.EDITOR):
abort(403)
packages = user.maintained_packages.filter(
@ -173,8 +173,8 @@ def confirm_supports_all_games(username=None):
package.supports_all_games = True
db.session.merge(package)
addAuditLog(AuditSeverity.NORMAL, current_user, "Enabled 'Supports all games' (bulk)",
package.get_url("packages.game_support"), package)
add_audit_log(AuditSeverity.NORMAL, current_user, "Enabled 'Supports all games' (bulk)",
package.get_url("packages.game_support"), package)
db.session.commit()

@ -25,8 +25,8 @@ from wtforms import StringField, SubmitField, BooleanField, PasswordField, valid
from wtforms.validators import InputRequired, Length, Regexp, DataRequired, Optional, Email, EqualTo
from app.tasks.emails import send_verify_email, send_anon_email, send_unsubscribe_verify, send_user_email
from app.utils import randomString, make_flask_login_password, is_safe_url, check_password_hash, addAuditLog, \
nonEmptyOrNone, post_login, is_username_valid
from app.utils import random_string, make_flask_login_password, is_safe_url, check_password_hash, add_audit_log, \
nonempty_or_none, post_login, is_username_valid
from . import bp
from app.models import User, AuditSeverity, db, UserRank, PackageAlias, EmailSubscription, UserNotificationPreferences, \
UserEmailVerification
@ -58,8 +58,8 @@ def handle_login(form):
flash(gettext("You need to confirm the registration email"), "danger")
return
addAuditLog(AuditSeverity.USER, user, "Logged in using password",
url_for("users.profile", username=user.username))
add_audit_log(AuditSeverity.USER, user, "Logged in using password",
url_for("users.profile", username=user.username))
db.session.commit()
if not login_user(user, remember=form.remember_me.data):
@ -97,7 +97,7 @@ def logout():
class RegisterForm(FlaskForm):
display_name = StringField(lazy_gettext("Display Name"), [Optional(), Length(1, 20)], filters=[nonEmptyOrNone])
display_name = StringField(lazy_gettext("Display Name"), [Optional(), Length(1, 20)], filters=[nonempty_or_none])
username = StringField(lazy_gettext("Username"), [InputRequired(),
Regexp("^[a-zA-Z0-9._-]+$", message=lazy_gettext(
"Only alphabetic letters (A-Za-z), numbers (0-9), underscores (_), minuses (-), and periods (.) allowed"))])
@ -154,10 +154,10 @@ def handle_register(form):
user.display_name = form.display_name.data
db.session.add(user)
addAuditLog(AuditSeverity.USER, user, "Registered with email, display name=" + user.display_name,
url_for("users.profile", username=user.username))
add_audit_log(AuditSeverity.USER, user, "Registered with email, display name=" + user.display_name,
url_for("users.profile", username=user.username))
token = randomString(32)
token = random_string(32)
ver = UserEmailVerification()
ver.user = user
@ -194,10 +194,10 @@ def forgot_password():
email = form.email.data
user = User.query.filter_by(email=email).first()
if user:
token = randomString(32)
token = random_string(32)
addAuditLog(AuditSeverity.USER, user, "(Anonymous) requested a password reset",
url_for("users.profile", username=user.username), None)
add_audit_log(AuditSeverity.USER, user, "(Anonymous) requested a password reset",
url_for("users.profile", username=user.username), None)
ver = UserEmailVerification()
ver.user = user
@ -241,12 +241,12 @@ def handle_set_password(form):
flash(gettext("Passwords do not match"), "danger")
return
addAuditLog(AuditSeverity.USER, current_user, "Changed their password", url_for("users.profile", username=current_user.username))
add_audit_log(AuditSeverity.USER, current_user, "Changed their password", url_for("users.profile", username=current_user.username))
current_user.password = make_flask_login_password(form.password.data)
if hasattr(form, "email"):
new_email = nonEmptyOrNone(form.email.data)
new_email = nonempty_or_none(form.email.data)
if new_email and new_email != current_user.email:
if EmailSubscription.query.filter_by(email=form.email.data, blacklisted=True).count() > 0:
flash(gettext(u"That email address has been unsubscribed/blacklisted, and cannot be used"), "danger")
@ -258,7 +258,7 @@ def handle_set_password(form):
gettext(u"We were unable to create the account as the email is already in use by %(display_name)s. Try a different email address.",
display_name=user_by_email.display_name))
else:
token = randomString(32)
token = random_string(32)
ver = UserEmailVerification()
ver.user = current_user
@ -329,8 +329,8 @@ def verify_email():
user = ver.user
addAuditLog(AuditSeverity.USER, user, "Confirmed their email",
url_for("users.profile", username=user.username))
add_audit_log(AuditSeverity.USER, user, "Confirmed their email",
url_for("users.profile", username=user.username))
was_activating = not user.is_active
@ -383,7 +383,7 @@ def unsubscribe_verify():
sub = EmailSubscription(email)
db.session.add(sub)
sub.token = randomString(32)
sub.token = random_string(32)
db.session.commit()
send_unsubscribe_verify.delay(form.email.data, get_locale().language)

@ -19,9 +19,9 @@ from flask_babel import gettext
from . import bp
from flask import redirect, render_template, session, request, flash, url_for
from app.models import db, User, UserRank
from app.utils import randomString, login_user_set_active, is_username_valid
from app.tasks.forumtasks import checkForumAccount
from app.utils.phpbbparser import getProfile
from app.utils import random_string, login_user_set_active, is_username_valid
from app.tasks.forumtasks import check_forum_account
from app.utils.phpbbparser import get_profile
@bp.route("/user/claim/", methods=["GET", "POST"])
@ -42,7 +42,7 @@ def claim_forums():
return redirect(url_for("users.claim_forums"))
user = User.query.filter_by(forums_username=username).first()
if user and user.rank.atLeast(UserRank.NEW_MEMBER):
if user and user.rank.at_least(UserRank.NEW_MEMBER):
flash(gettext("User has already been claimed"), "danger")
return redirect(url_for("users.claim_forums"))
elif method == "github":
@ -55,7 +55,7 @@ def claim_forums():
if "forum_token" in session:
token = session["forum_token"]
else:
token = randomString(12)
token = random_string(12)
session["forum_token"] = token
if request.method == "POST":
@ -65,17 +65,17 @@ def claim_forums():
if not is_username_valid(username):
flash(gettext("Invalid username, Only alphabetic letters (A-Za-z), numbers (0-9), underscores (_), minuses (-), and periods (.) allowed. Consider contacting an admin"), "danger")
elif ctype == "github":
task = checkForumAccount.delay(username)
task = check_forum_account.delay(username)
return redirect(url_for("tasks.check", id=task.id, r=url_for("users.claim_forums", 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):
if user is not None and user.rank.at_least(UserRank.NEW_MEMBER):
flash(gettext("That user has already been claimed!"), "danger")
return redirect(url_for("users.claim_forums"))
# Get signature
try:
profile = getProfile("https://forum.minetest.net", username)
profile = get_profile("https://forum.minetest.net", username)
sig = profile.signature if profile else None
except IOError as e:
if hasattr(e, 'message'):

@ -25,7 +25,7 @@ from wtforms.validators import Length, Optional, Email, URL
from app.models import User, AuditSeverity, db, UserRank, PackageAlias, EmailSubscription, UserNotificationPreferences, \
UserEmailVerification, Permission, NotificationType, UserBan
from app.tasks.emails import send_verify_email
from app.utils import nonEmptyOrNone, addAuditLog, randomString, rank_required, has_blocked_domains
from app.utils import nonempty_or_none, add_audit_log, random_string, rank_required, has_blocked_domains
from . import bp
@ -53,7 +53,7 @@ def get_setting_tabs(user):
},
]
if current_user.rank.atLeast(UserRank.MODERATOR):
if current_user.rank.at_least(UserRank.MODERATOR):
ret.append({
"id": "modtools",
"title": gettext("Moderator Tools"),
@ -64,7 +64,7 @@ def get_setting_tabs(user):
class UserProfileForm(FlaskForm):
display_name = StringField(lazy_gettext("Display Name"), [Optional(), Length(1, 20)], filters=[lambda x: nonEmptyOrNone(x.strip())])
display_name = StringField(lazy_gettext("Display Name"), [Optional(), Length(1, 20)], filters=[lambda x: nonempty_or_none(x.strip())])
website_url = StringField(lazy_gettext("Website URL"), [Optional(), URL()], filters = [lambda x: x or None])
donate_url = StringField(lazy_gettext("Donation URL"), [Optional(), URL()], filters = [lambda x: x or None])
submit = SubmitField(lazy_gettext("Save"))
@ -72,8 +72,8 @@ class UserProfileForm(FlaskForm):
def handle_profile_edit(form: UserProfileForm, user: User, username: str):
severity = AuditSeverity.NORMAL if current_user == user else AuditSeverity.MODERATION
addAuditLog(severity, current_user, "Edited {}'s profile".format(user.display_name),
url_for("users.profile", username=username))
add_audit_log(severity, current_user, "Edited {}'s profile".format(user.display_name),
url_for("users.profile", username=username))
display_name = form.display_name.data or user.username
if user.check_perm(current_user, Permission.CHANGE_DISPLAY_NAME) and \
@ -95,9 +95,9 @@ def handle_profile_edit(form: UserProfileForm, user: User, username: str):
user.display_name = display_name
severity = AuditSeverity.USER if current_user == user else AuditSeverity.MODERATION
addAuditLog(severity, current_user, "Changed display name of {} to {}"
.format(user.username, user.display_name),
url_for("users.profile", username=username))
add_audit_log(severity, current_user, "Changed display name of {} to {}"
.format(user.username, user.display_name),
url_for("users.profile", username=username))
if user.check_perm(current_user, Permission.CHANGE_PROFILE_URLS):
if has_blocked_domains(form.website_url.data, current_user.username, f"{user.username}'s website_url") or \
@ -167,12 +167,12 @@ def handle_email_notifications(user, prefs: UserNotificationPreferences, is_new,
flash(gettext("That email address has been unsubscribed/blacklisted, and cannot be used"), "danger")
return
token = randomString(32)
token = random_string(32)
severity = AuditSeverity.NORMAL if current_user == user else AuditSeverity.MODERATION
msg = "Changed email of {}".format(user.display_name)
addAuditLog(severity, current_user, msg, url_for("users.profile", username=user.username))
add_audit_log(severity, current_user, msg, url_for("users.profile", username=user.username))
ver = UserEmailVerification()
ver.user = user
@ -245,19 +245,19 @@ def delete(username):
if not user:
abort(404)
if user.rank.atLeast(UserRank.MODERATOR):
if user.rank.at_least(UserRank.MODERATOR):
flash(gettext("Users with moderator rank or above cannot be deleted"), "danger")
return redirect(url_for("users.account", username=username))
if request.method == "GET":
return render_template("users/delete.html", user=user, can_delete=user.can_delete())
if "delete" in request.form and (user.can_delete() or current_user.rank.atLeast(UserRank.ADMIN)):
if "delete" in request.form and (user.can_delete() or current_user.rank.at_least(UserRank.ADMIN)):
msg = "Deleted user {}".format(user.username)
flash(msg, "success")
addAuditLog(AuditSeverity.MODERATION, current_user, msg, None)
add_audit_log(AuditSeverity.MODERATION, current_user, msg, None)
if current_user.rank.atLeast(UserRank.ADMIN):
if current_user.rank.at_least(UserRank.ADMIN):
for pkg in user.packages.all():
pkg.review_thread = None
db.session.delete(pkg)
@ -273,7 +273,7 @@ def delete(username):
msg = "Deactivated user {}".format(user.username)
flash(msg, "success")
addAuditLog(AuditSeverity.MODERATION, current_user, msg, None)
add_audit_log(AuditSeverity.MODERATION, current_user, msg, None)
else:
assert False
@ -308,8 +308,8 @@ def modtools(username):
form = ModToolsForm(obj=user)
if form.validate_on_submit():
severity = AuditSeverity.NORMAL if current_user == user else AuditSeverity.MODERATION
addAuditLog(severity, current_user, "Edited {}'s account".format(user.display_name),
url_for("users.profile", username=username))
add_audit_log(severity, current_user, "Edited {}'s account".format(user.display_name),
url_for("users.profile", username=username))
# Copy form fields to user_profile fields
if user.check_perm(current_user, Permission.CHANGE_USERNAMES):
@ -322,17 +322,17 @@ def modtools(username):
user.username = form.username.data
user.display_name = form.display_name.data
user.forums_username = nonEmptyOrNone(form.forums_username.data)
user.github_username = nonEmptyOrNone(form.github_username.data)
user.forums_username = nonempty_or_none(form.forums_username.data)
user.github_username = nonempty_or_none(form.github_username.data)
if user.check_perm(current_user, Permission.CHANGE_RANK):
new_rank = form["rank"].data
if current_user.rank.atLeast(new_rank):
if current_user.rank.at_least(new_rank):
if new_rank != user.rank:
user.rank = form["rank"].data
msg = "Set rank of {} to {}".format(user.display_name, user.rank.get_title())
addAuditLog(AuditSeverity.MODERATION, current_user, msg,
url_for("users.profile", username=username))
add_audit_log(AuditSeverity.MODERATION, current_user, msg,
url_for("users.profile", username=username))
else:
flash(gettext("Can't promote a user to a rank higher than yourself!"), "danger")
@ -356,9 +356,9 @@ def modtools_set_email(username):
user.email = request.form["email"]
user.is_active = False
token = randomString(32)
addAuditLog(AuditSeverity.MODERATION, current_user, f"Set email and sent a password reset on {user.username}",
url_for("users.profile", username=user.username), None)
token = random_string(32)
add_audit_log(AuditSeverity.MODERATION, current_user, f"Set email and sent a password reset on {user.username}",
url_for("users.profile", username=user.username), None)
ver = UserEmailVerification()
ver.user = user
@ -396,8 +396,8 @@ def modtools_ban(username):
else:
user.rank = UserRank.BANNED
addAuditLog(AuditSeverity.MODERATION, current_user, f"Banned {user.username}, expires {user.ban.expires_at or '-'}, message: {message}",
url_for("users.profile", username=user.username), None)
add_audit_log(AuditSeverity.MODERATION, current_user, f"Banned {user.username}, expires {user.ban.expires_at or '-'}, message: {message}",
url_for("users.profile", username=user.username), None)
db.session.commit()
flash(f"Banned {user.username}", "success")
@ -420,8 +420,8 @@ def modtools_unban(username):
if user.rank == UserRank.BANNED:
user.rank = UserRank.MEMBER
addAuditLog(AuditSeverity.MODERATION, current_user, f"Unbanned {user.username}",
url_for("users.profile", username=user.username), None)
add_audit_log(AuditSeverity.MODERATION, current_user, f"Unbanned {user.username}",
url_for("users.profile", username=user.username), None)
db.session.commit()
flash(f"Unbanned {user.username}", "success")

@ -22,6 +22,7 @@ from sqlalchemy import and_, or_
from app.models import Package, PackageType, PackageState, PackageRelease
ValidationError = namedtuple("ValidationError", "status message")

@ -24,7 +24,7 @@ from flask_babel import lazy_gettext, LazyString
from app.logic.LogicError import LogicError
from app.models import User, Package, PackageType, MetaPackage, Tag, ContentWarning, db, Permission, AuditSeverity, \
License, UserRank, PackageDevState
from app.utils import addAuditLog, has_blocked_domains, diff_dictionaries, describe_difference
from app.utils import add_audit_log, has_blocked_domains, diff_dictionaries, describe_difference
from app.utils.url import clean_youtube_url
@ -173,7 +173,7 @@ def do_edit_package(user: User, package: Package, was_new: bool, was_web: bool,
if not was_web and tag.is_protected:
continue
if tag.is_protected and tag not in old_tags and not user.rank.atLeast(UserRank.EDITOR):
if tag.is_protected and tag not in old_tags and not user.rank.at_least(UserRank.EDITOR):
raise LogicError(400, lazy_gettext("Unable to add protected tag %(title)s to package", title=tag.title))
package.tags.append(tag)
@ -208,7 +208,7 @@ def do_edit_package(user: User, package: Package, was_new: bool, was_web: bool,
msg += " [" + diff_desc + "]"
severity = AuditSeverity.NORMAL if user in package.maintainers else AuditSeverity.EDITOR
addAuditLog(severity, user, msg, package.get_url("packages.view"), package, json.dumps(diff, indent=4))
add_audit_log(severity, user, msg, package.get_url("packages.view"), package, json.dumps(diff, indent=4))
db.session.commit()

@ -23,8 +23,8 @@ from flask_babel import lazy_gettext
from app.logic.LogicError import LogicError
from app.logic.uploads import upload_file
from app.models import PackageRelease, db, Permission, User, Package, MinetestRelease
from app.tasks.importtasks import makeVCSRelease, checkZipRelease
from app.utils import AuditSeverity, addAuditLog, nonEmptyOrNone
from app.tasks.importtasks import make_vcs_release, check_zip_release
from app.utils import AuditSeverity, add_audit_log, nonempty_or_none
def check_can_create_release(user: User, package: Package):
@ -54,11 +54,11 @@ def do_create_vcs_release(user: User, package: Package, title: str, ref: str,
msg = "Created release {}".format(rel.title)
else:
msg = "Created release {} ({})".format(rel.title, reason)
addAuditLog(AuditSeverity.NORMAL, user, msg, package.get_url("packages.view"), package)
add_audit_log(AuditSeverity.NORMAL, user, msg, package.get_url("packages.view"), package)
db.session.commit()
makeVCSRelease.apply_async((rel.id, nonEmptyOrNone(ref)), task_id=rel.task_id)
make_vcs_release.apply_async((rel.id, nonempty_or_none(ref)), task_id=rel.task_id)
return rel
@ -89,10 +89,10 @@ def do_create_zip_release(user: User, package: Package, title: str, file,
msg = "Created release {}".format(rel.title)
else:
msg = "Created release {} ({})".format(rel.title, reason)
addAuditLog(AuditSeverity.NORMAL, user, msg, package.get_url("packages.view"), package)
add_audit_log(AuditSeverity.NORMAL, user, msg, package.get_url("packages.view"), package)
db.session.commit()
checkZipRelease.apply_async((rel.id, uploaded_path), task_id=rel.task_id)
check_zip_release.apply_async((rel.id, uploaded_path), task_id=rel.task_id)
return rel

@ -21,7 +21,7 @@ from flask_babel import lazy_gettext
from app.logic.LogicError import LogicError
from app.logic.uploads import upload_file
from app.models import User, Package, PackageScreenshot, Permission, NotificationType, db, AuditSeverity
from app.utils import addNotification, addAuditLog
from app.utils import add_notification, add_audit_log
from app.utils.image import get_image_size
@ -58,8 +58,8 @@ def do_create_screenshot(user: User, package: Package, title: str, file, is_cove
else:
msg = "Created screenshot {} ({})".format(ss.title, reason)
addNotification(package.maintainers, user, NotificationType.PACKAGE_EDIT, msg, package.get_url("packages.view"), package)
addAuditLog(AuditSeverity.NORMAL, user, msg, package.get_url("packages.view"), package)
add_notification(package.maintainers, user, NotificationType.PACKAGE_EDIT, msg, package.get_url("packages.view"), package)
add_audit_log(AuditSeverity.NORMAL, user, msg, package.get_url("packages.view"), package)
db.session.commit()

@ -21,7 +21,7 @@ from flask_babel import lazy_gettext
from app import app
from app.logic.LogicError import LogicError
from app.utils import randomString
from app.utils import random_string
def get_extension(filename):
@ -59,7 +59,7 @@ def upload_file(file, file_type, file_type_desc):
file.stream.seek(0)
filename = randomString(10) + "." + ext
filename = random_string(10) + "." + ext
filepath = os.path.join(app.config["UPLOAD_DIR"], filename)
file.save(filepath)

@ -116,7 +116,7 @@ class AuditLogEntry(db.Model):
raise Exception("Unknown permission given to AuditLogEntry.check_perm()")
if perm == Permission.VIEW_AUDIT_DESCRIPTION:
return user.rank.atLeast(UserRank.APPROVER if self.package is not None else UserRank.MODERATOR)
return user.rank.at_least(UserRank.APPROVER if self.package is not None else UserRank.MODERATOR)
else:
raise Exception("Permission {} is not related to audit log entries".format(perm.name))
@ -181,7 +181,7 @@ class ForumTopic(db.Model):
raise Exception("Unknown permission given to ForumTopic.check_perm()")
if perm == Permission.TOPIC_DISCARD:
return self.author == user or user.rank.atLeast(UserRank.EDITOR)
return self.author == user or user.rank.at_least(UserRank.EDITOR)
else:
raise Exception("Permission {} is not related to topics".format(perm.name))

@ -271,7 +271,7 @@ class Dependency(db.Model):
else:
raise Exception("Either meta or package must be given, but not both!")
def getName(self):
def get_name(self):
if self.meta_package:
return self.meta_package.name
elif self.package:
@ -484,7 +484,7 @@ class Package(db.Model):
query = query.filter_by(optional=not is_hard)
deps = query.all()
deps.sort(key=lambda x: x.getName())
deps.sort(key=lambda x: x.get_name())
return deps
def get_sorted_hard_dependencies(self):
@ -654,25 +654,25 @@ class Package(db.Model):
raise Exception("Unknown permission given to Package.check_perm()")
is_owner = user == self.author
is_maintainer = is_owner or user.rank.atLeast(UserRank.EDITOR) or user in self.maintainers
is_approver = user.rank.atLeast(UserRank.APPROVER)
is_maintainer = is_owner or user.rank.at_least(UserRank.EDITOR) or user in self.maintainers
is_approver = user.rank.at_least(UserRank.APPROVER)
if perm == Permission.CREATE_THREAD:
return user.rank.atLeast(UserRank.NEW_MEMBER)
return user.rank.at_least(UserRank.NEW_MEMBER)
# Members can edit their own packages, and editors can edit any packages
elif perm == Permission.MAKE_RELEASE or perm == Permission.ADD_SCREENSHOTS:
return is_maintainer
elif perm == Permission.EDIT_PACKAGE:
return is_maintainer and user.rank.atLeast(UserRank.NEW_MEMBER)
return is_maintainer and user.rank.at_least(UserRank.NEW_MEMBER)
elif perm == Permission.APPROVE_RELEASE:
return (is_maintainer or is_approver) and user.rank.atLeast(UserRank.MEMBER if self.approved else UserRank.NEW_MEMBER)
return (is_maintainer or is_approver) and user.rank.at_least(UserRank.MEMBER if self.approved else UserRank.NEW_MEMBER)
# Anyone can change the package name when not approved, but only editors when approved
elif perm == Permission.CHANGE_NAME:
return not self.approved or user.rank.atLeast(UserRank.EDITOR)
return not self.approved or user.rank.at_least(UserRank.EDITOR)
# Editors can change authors and approve new packages
elif perm == Permission.APPROVE_NEW or perm == Permission.CHANGE_AUTHOR:
@ -680,16 +680,16 @@ class Package(db.Model):
elif perm == Permission.APPROVE_SCREENSHOT:
return (is_maintainer or is_approver) and \
user.rank.atLeast(UserRank.MEMBER if self.approved else UserRank.NEW_MEMBER)
user.rank.at_least(UserRank.MEMBER if self.approved else UserRank.NEW_MEMBER)
elif perm == Permission.EDIT_MAINTAINERS or perm == Permission.DELETE_PACKAGE:
return is_owner or user.rank.atLeast(UserRank.EDITOR)
return is_owner or user.rank.at_least(UserRank.EDITOR)
elif perm == Permission.UNAPPROVE_PACKAGE:
return is_owner or user.rank.atLeast(UserRank.APPROVER)
return is_owner or user.rank.at_least(UserRank.APPROVER)
elif perm == Permission.CHANGE_RELEASE_URL:
return user.rank.atLeast(UserRank.MODERATOR)
return user.rank.at_least(UserRank.MODERATOR)
else:
raise Exception("Permission {} is not related to packages".format(perm.name))
@ -738,7 +738,7 @@ class Package(db.Model):
elif state == PackageState.WIP:
return self.check_perm(user, Permission.EDIT_PACKAGE) and \
(user in self.maintainers or user.rank.atLeast(UserRank.ADMIN))
(user in self.maintainers or user.rank.at_least(UserRank.ADMIN))
return True
@ -1018,10 +1018,10 @@ class PackageRelease(db.Model):
is_maintainer = user == self.package.author or user in self.package.maintainers
if perm == Permission.DELETE_RELEASE:
if user.rank.atLeast(UserRank.ADMIN):
if user.rank.at_least(UserRank.ADMIN):
return True
if not (is_maintainer or user.rank.atLeast(UserRank.EDITOR)):
if not (is_maintainer or user.rank.at_least(UserRank.EDITOR)):
return False
if not self.package.approved or self.task_id is not None:
@ -1033,8 +1033,8 @@ class PackageRelease(db.Model):
return count > 0
elif perm == Permission.APPROVE_RELEASE:
return user.rank.atLeast(UserRank.APPROVER) or \
(is_maintainer and user.rank.atLeast(
return user.rank.at_least(UserRank.APPROVER) or \
(is_maintainer and user.rank.at_least(
UserRank.MEMBER if self.approved else UserRank.NEW_MEMBER))
else:
raise Exception("Permission {} is not related to releases".format(perm.name))

@ -92,21 +92,21 @@ class Thread(db.Model):
if self.package:
isMaintainer = isMaintainer or user in self.package.maintainers
canSee = not self.private or isMaintainer or user.rank.atLeast(UserRank.APPROVER) or user in self.watchers
canSee = not self.private or isMaintainer or user.rank.at_least(UserRank.APPROVER) or user in self.watchers
if perm == Permission.SEE_THREAD:
return canSee
elif perm == Permission.COMMENT_THREAD:
return canSee and (not self.locked or user.rank.atLeast(UserRank.MODERATOR))
return canSee and (not self.locked or user.rank.at_least(UserRank.MODERATOR))
elif perm == Permission.LOCK_THREAD:
return user.rank.atLeast(UserRank.MODERATOR)
return user.rank.at_least(UserRank.MODERATOR)
elif perm == Permission.DELETE_THREAD:
from app.utils.models import get_system_user
return (self.author == get_system_user() and self.package and
user in self.package.maintainers) or user.rank.atLeast(UserRank.MODERATOR)
user in self.package.maintainers) or user.rank.at_least(UserRank.MODERATOR)
else:
raise Exception("Permission {} is not related to threads".format(perm.name))
@ -157,10 +157,10 @@ class ThreadReply(db.Model):
raise Exception("Unknown permission given to ThreadReply.check_perm()")
if perm == Permission.EDIT_REPLY:
return user.rank.atLeast(UserRank.NEW_MEMBER if user == self.author else UserRank.MODERATOR) and not self.thread.locked
return user.rank.at_least(UserRank.NEW_MEMBER if user == self.author else UserRank.MODERATOR) and not self.thread.locked
elif perm == Permission.DELETE_REPLY:
return user.rank.atLeast(UserRank.MODERATOR) and self.thread.first_reply != self
return user.rank.at_least(UserRank.MODERATOR) and self.thread.first_reply != self
else:
raise Exception("Permission {} is not related to threads".format(perm.name))
@ -227,7 +227,7 @@ class PackageReview(db.Model):
name=self.package.name,
reviewer=self.author.username)
def getVoteUrl(self, next_url=None):
def get_vote_url(self, next_url=None):
return url_for("packages.review_vote",
author=self.package.author.username,
name=self.package.name,
@ -248,7 +248,7 @@ class PackageReview(db.Model):
raise Exception("Unknown permission given to PackageReview.check_perm()")
if perm == Permission.DELETE_REVIEW:
return user == self.author or user.rank.atLeast(UserRank.MODERATOR)
return user == self.author or user.rank.at_least(UserRank.MODERATOR)
else:
raise Exception("Permission {} is not related to reviews".format(perm.name))

@ -37,7 +37,7 @@ class UserRank(enum.Enum):
MODERATOR = 8
ADMIN = 9
def atLeast(self, min):
def at_least(self, min):
return self.value >= min.value
def get_title(self):
@ -101,10 +101,10 @@ class Permission(enum.Enum):
self == Permission.APPROVE_RELEASE or \
self == Permission.APPROVE_SCREENSHOT or \
self == Permission.SEE_THREAD:
return user.rank.atLeast(UserRank.APPROVER)
return user.rank.at_least(UserRank.APPROVER)
elif self == Permission.EDIT_TAGS or self == Permission.CREATE_TAG:
return user.rank.atLeast(UserRank.EDITOR)
return user.rank.at_least(UserRank.EDITOR)
else:
raise Exception("Non-global permission checked globally. Use Package.check_perm or User.check_perm instead.")
@ -234,20 +234,20 @@ class User(db.Model, UserMixin):
# Members can edit their own packages, and editors can edit any packages
if perm == Permission.CHANGE_AUTHOR:
return user.rank.atLeast(UserRank.EDITOR)
return user.rank.at_least(UserRank.EDITOR)
elif perm == Permission.CHANGE_USERNAMES:
return user.rank.atLeast(UserRank.MODERATOR)
return user.rank.at_least(UserRank.MODERATOR)
elif perm == Permission.CHANGE_RANK:
return user.rank.atLeast(UserRank.MODERATOR) and not self.rank.atLeast(user.rank)
return user.rank.at_least(UserRank.MODERATOR) and not self.rank.at_least(user.rank)
elif perm == Permission.CHANGE_EMAIL or perm == Permission.CHANGE_PROFILE_URLS:
return user == self or (user.rank.atLeast(UserRank.MODERATOR) and not self.rank.atLeast(user.rank))
return user == self or (user.rank.at_least(UserRank.MODERATOR) and not self.rank.at_least(user.rank))
elif perm == Permission.CHANGE_DISPLAY_NAME:
return user.rank.atLeast(UserRank.NEW_MEMBER if user == self else UserRank.MODERATOR)
return user.rank.at_least(UserRank.NEW_MEMBER if user == self else UserRank.MODERATOR)
elif perm == Permission.CREATE_TOKEN:
if user == self:
return user.rank.atLeast(UserRank.NEW_MEMBER)
return user.rank.at_least(UserRank.NEW_MEMBER)
else:
return user.rank.atLeast(UserRank.MODERATOR) and user.rank.atLeast(self.rank)
return user.rank.at_least(UserRank.MODERATOR) and user.rank.at_least(self.rank)
else:
raise Exception("Permission {} is not related to users".format(perm.name))
@ -255,11 +255,11 @@ class User(db.Model, UserMixin):
from app.models import ThreadReply
factor = 1
if self.rank.atLeast(UserRank.ADMIN):
if self.rank.at_least(UserRank.ADMIN):
return True
elif self.rank.atLeast(UserRank.TRUSTED_MEMBER):
elif self.rank.at_least(UserRank.TRUSTED_MEMBER):
factor = 3
elif self.rank.atLeast(UserRank.MEMBER):
elif self.rank.at_least(UserRank.MEMBER):
factor = 2
one_min_ago = datetime.datetime.utcnow() - datetime.timedelta(minutes=1)
@ -278,11 +278,11 @@ class User(db.Model, UserMixin):
from app.models import Thread
factor = 1
if self.rank.atLeast(UserRank.ADMIN):
if self.rank.at_least(UserRank.ADMIN):
return True
elif self.rank.atLeast(UserRank.TRUSTED_MEMBER):
elif self.rank.at_least(UserRank.TRUSTED_MEMBER):
factor = 5
elif self.rank.atLeast(UserRank.MEMBER):
elif self.rank.at_least(UserRank.MEMBER):
factor = 2
hour_ago = datetime.datetime.utcnow() - datetime.timedelta(hours=1)
@ -293,9 +293,9 @@ class User(db.Model, UserMixin):
from app.models import PackageReview
factor = 1
if self.rank.atLeast(UserRank.ADMIN):
if self.rank.at_least(UserRank.ADMIN):
return True
elif self.rank.atLeast(UserRank.TRUSTED_MEMBER):
elif self.rank.at_least(UserRank.TRUSTED_MEMBER):
factor *= 5
five_mins_ago = datetime.datetime.utcnow() - datetime.timedelta(minutes=5)

@ -23,7 +23,7 @@ from sqlalchemy_searchable import search
from .models import db, PackageType, Package, ForumTopic, License, MinetestRelease, PackageRelease, User, Tag, \
ContentWarning, PackageState, PackageDevState
from .utils import isYes, get_int_or_abort
from .utils import is_yes, get_int_or_abort
class QueryBuilder:
@ -105,10 +105,10 @@ class QueryBuilder:
else:
self.version = None
self.show_discarded = isYes(args.get("show_discarded"))
self.show_discarded = is_yes(args.get("show_discarded"))
self.show_added = args.get("show_added")
if self.show_added is not None:
self.show_added = isYes(self.show_added)
self.show_added = is_yes(self.show_added)
if self.search is not None and self.search.strip() == "":
self.search = None
@ -117,12 +117,12 @@ class QueryBuilder:
if self.game:
self.game = Package.get_by_key(self.game)
def setSortIfNone(self, name, dir="desc"):
def set_sort_if_none(self, name, dir="desc"):
if self.order_by is None:
self.order_by = name
self.order_dir = dir
def getReleases(self):
def get_releases(self):
releases_query = db.session.query(PackageRelease.package_id, func.max(PackageRelease.id)) \
.select_from(PackageRelease).filter(PackageRelease.approved) \
.group_by(PackageRelease.package_id)
@ -136,18 +136,18 @@ class QueryBuilder:
return releases_query.all()
def convertToDictionary(self, packages):
def convert_to_dictionary(self, packages):
releases = {}
for [package_id, release_id] in self.getReleases():
for [package_id, release_id] in self.get_releases():
releases[package_id] = release_id
def toJson(package: Package):
def to_json(package: Package):
release_id = releases.get(package.id)
return package.as_short_dict(current_app.config["BASE_URL"], release_id=release_id, no_load=True)
return [toJson(pkg) for pkg in packages]
return [to_json(pkg) for pkg in packages]
def buildPackageQuery(self):
def build_package_query(self):
if self.order_by == "last_release":
query = db.session.query(Package).select_from(PackageRelease).join(Package) \
.filter_by(state=PackageState.APPROVED)
@ -156,14 +156,14 @@ class QueryBuilder:
query = query.options(subqueryload(Package.main_screenshot), subqueryload(Package.aliases))
query = self.orderPackageQuery(self.filterPackageQuery(query))
query = self.order_package_query(self.filter_package_query(query))
if self.limit:
query = query.limit(self.limit)
return query
def filterPackageQuery(self, query):
def filter_package_query(self, query):
if len(self.types) > 0:
query = query.filter(Package.type.in_(self.types))
@ -207,7 +207,7 @@ class QueryBuilder:
return query
def orderPackageQuery(self, query):
def order_package_query(self, query):
if self.search:
query = search(query, self.search, sort=self.order_by is None)
@ -250,7 +250,7 @@ class QueryBuilder:
return query
def buildTopicQuery(self, show_added=False):
def build_topic_query(self, show_added=False):
query = ForumTopic.query
if not self.show_discarded:

@ -75,11 +75,11 @@ celery = make_celery(app)
CELERYBEAT_SCHEDULE = {
'topic_list_import': {
'task': 'app.tasks.forumtasks.importTopicList',
'task': 'app.tasks.forumtasks.import_topic_list',
'schedule': crontab(minute=1, hour=1), # 0101
},
'package_score_update': {
'task': 'app.tasks.pkgtasks.updatePackageScores',
'task': 'app.tasks.pkgtasks.update_package_scores',
'schedule': crontab(minute=10, hour=1), # 0110
},
'check_for_updates': {

@ -23,7 +23,7 @@ from flask_mail import Message
from app import mail
from app.models import Notification, db, EmailSubscription, User
from app.tasks import celery
from app.utils import abs_url_for, abs_url, randomString
from app.utils import abs_url_for, abs_url, random_string
def get_email_subscription(email):
@ -31,7 +31,7 @@ def get_email_subscription(email):
ret = EmailSubscription.query.filter_by(email=email).first()
if not ret:
ret = EmailSubscription(email)
ret.token = randomString(32)
ret.token = random_string(32)
db.session.add(ret)
db.session.commit()

@ -23,15 +23,15 @@ from urllib.parse import urljoin
from app.models import User, db, PackageType, ForumTopic
from app.tasks import celery
from app.utils import is_username_valid
from app.utils.phpbbparser import getProfile, getTopicsFromForum
from app.utils.phpbbparser import get_profile, get_topics_from_forum
from .usertasks import set_profile_picture_from_url
@celery.task()
def checkForumAccount(forums_username):
def check_forum_account(forums_username):
print("### Checking " + forums_username, file=sys.stderr)
try:
profile = getProfile("https://forum.minetest.net", forums_username)
profile = get_profile("https://forum.minetest.net", forums_username)
except OSError as e:
print(e, file=sys.stderr)
return
@ -42,7 +42,7 @@ def checkForumAccount(forums_username):
user = User.query.filter_by(forums_username=forums_username).first()
# Create user
needsSaving = False
needs_saving = False
if user is None:
user = User(forums_username)
user.forums_username = forums_username
@ -53,14 +53,14 @@ def checkForumAccount(forums_username):
if github_username is not None and github_username.strip() != "":
print("Updated GitHub username for " + user.display_name + " to " + github_username)
user.github_username = github_username
needsSaving = True
needs_saving = True
pic = profile.avatar
if pic and pic.startswith("http"):
pic = None
# Save
if needsSaving:
if needs_saving:
db.session.commit()
if pic:
@ -74,21 +74,21 @@ def checkForumAccount(forums_username):
print(f"####### Queueing", file=sys.stderr)
set_profile_picture_from_url.delay(user.username, pic)
return needsSaving
return needs_saving
@celery.task()
def checkAllForumAccounts():
def check_all_forum_accounts():
query = User.query.filter(User.forums_username.isnot(None))
for user in query.all():
checkForumAccount(user.forums_username)
check_forum_account(user.forums_username)
regex_tag = re.compile(r"\[([a-z0-9_]+)\]")
BANNED_NAMES = ["mod", "game", "old", "outdated", "wip", "api", "beta", "alpha", "git"]
def getNameFromTaglist(taglist):
def get_name_from_taglist(taglist):
for tag in reversed(regex_tag.findall(taglist)):
if len(tag) < 30 and not tag in BANNED_NAMES and \
not re.match(r"^[a-z]?[0-9]+$", tag):
@ -100,15 +100,16 @@ def getNameFromTaglist(taglist):
regex_title = re.compile(r"^((?:\[[^\]]+\] *)*)([^\[]+) *((?:\[[^\]]+\] *)*)[^\[]*$")
def parseTitle(title):
def parse_title(title):
m = regex_title.match(title)
if m is None:
print("Invalid title format: " + title)
return title, getNameFromTaglist(title)
return title, get_name_from_taglist(title)
else:
return m.group(2).strip(), getNameFromTaglist(m.group(3))
return m.group(2).strip(), get_name_from_taglist(m.group(3))
def getLinksFromModSearch():
def get_links_from_mod_search():
links = {}
try:
@ -127,15 +128,16 @@ def getLinksFromModSearch():
return links
@celery.task()
def importTopicList():
links_by_id = getLinksFromModSearch()
def import_topic_list():
links_by_id = get_links_from_mod_search()
info_by_id = {}
getTopicsFromForum(11, out=info_by_id, extra={ 'type': PackageType.MOD, 'wip': False })
getTopicsFromForum(9, out=info_by_id, extra={ 'type': PackageType.MOD, 'wip': True })
getTopicsFromForum(15, out=info_by_id, extra={ 'type': PackageType.GAME, 'wip': False })
getTopicsFromForum(50, out=info_by_id, extra={ 'type': PackageType.GAME, 'wip': True })
get_topics_from_forum(11, out=info_by_id, extra={'type': PackageType.MOD, 'wip': False})
get_topics_from_forum(9, out=info_by_id, extra={'type': PackageType.MOD, 'wip': True})
get_topics_from_forum(15, out=info_by_id, extra={'type': PackageType.GAME, 'wip': False})
get_topics_from_forum(50, out=info_by_id, extra={'type': PackageType.GAME, 'wip': True})
# Caches
username_to_user = {}
@ -182,7 +184,7 @@ def importTopicList():
db.session.add(topic)
# Parse title
title, name = parseTitle(info["title"])
title, name = parse_title(info["title"])
# Get link
link = links_by_id.get(id)

@ -30,7 +30,7 @@ from kombu import uuid
from app.models import AuditSeverity, db, NotificationType, PackageRelease, MetaPackage, Dependency, PackageType, \
MinetestRelease, Package, PackageState, PackageScreenshot, PackageUpdateTrigger, PackageUpdateConfig
from app.tasks import celery, TaskError
from app.utils import randomString, post_bot_message, addSystemNotification, addSystemAuditLog, get_games_from_csv
from app.utils import random_string, post_bot_message, add_system_notification, add_system_audit_log, get_games_from_csv
from app.utils.git import clone_repo, get_latest_tag, get_latest_commit, get_temp_dir
from .minetestcheck import build_tree, MinetestCheckError, ContentType
from app import app
@ -41,7 +41,7 @@ from app.utils.image import get_image_size
@celery.task()
def getMeta(urlstr, author):
def get_meta(urlstr, author):
with clone_repo(urlstr, recursive=True) as repo:
try:
tree = build_tree(repo.working_tree_dir, author=author, repo=urlstr)
@ -82,13 +82,13 @@ def getMeta(urlstr, author):
@celery.task()
def updateAllGameSupport():
def update_all_game_support():
resolver = GameSupportResolver(db.session)
resolver.init_all()
db.session.commit()
def postReleaseCheckUpdate(self, release: PackageRelease, path):
def post_release_check_update(self, release: PackageRelease, path):
try:
tree = build_tree(path, expected_type=ContentType[release.package.type.name],
author=release.package.author.username, name=release.package.name)
@ -97,14 +97,14 @@ def postReleaseCheckUpdate(self, release: PackageRelease, path):
raise MinetestCheckError(f"Expected {tree.relative} to have technical name {release.package.name}, instead has name {tree.name}")
cache = {}
def getMetaPackages(names):
def get_meta_packages(names):
return [ MetaPackage.GetOrCreate(x, cache) for x in names ]
provides = tree.get_mod_names()
package = release.package
package.provides.clear()
package.provides.extend(getMetaPackages(tree.get_mod_names()))
package.provides.extend(get_meta_packages(tree.get_mod_names()))
# Delete all mod name dependencies
package.dependencies.filter(Dependency.meta_package != None).delete()
@ -124,10 +124,10 @@ def postReleaseCheckUpdate(self, release: PackageRelease, path):
raise MinetestCheckError("Game has unresolved hard dependencies: " + deps)
# Add dependencies
for meta in getMetaPackages(depends):
for meta in get_meta_packages(depends):
db.session.add(Dependency(package, meta=meta, optional=False))
for meta in getMetaPackages(optional_depends):
for meta in get_meta_packages(optional_depends):
db.session.add(Dependency(package, meta=meta, optional=True))
# Update min/max
@ -191,7 +191,7 @@ def postReleaseCheckUpdate(self, release: PackageRelease, path):
@celery.task(bind=True)
def checkZipRelease(self, id, path):
def check_zip_release(self, id, path):
release = PackageRelease.query.get(id)
if release is None:
raise TaskError("No such release!")
@ -202,7 +202,7 @@ def checkZipRelease(self, id, path):
with ZipFile(path, 'r') as zip_ref:
zip_ref.extractall(temp)
postReleaseCheckUpdate(self, release, temp)
post_release_check_update(self, release, temp)
release.task_id = None
release.approve(release.package.author)
@ -210,7 +210,7 @@ def checkZipRelease(self, id, path):
@celery.task(bind=True)
def makeVCSRelease(self, id, branch):
def make_vcs_release(self, id, branch):
release = PackageRelease.query.get(id)
if release is None:
raise TaskError("No such release!")
@ -218,9 +218,9 @@ def makeVCSRelease(self, id, branch):
raise TaskError("No package attached to release")
with clone_repo(release.package.repo, ref=branch, recursive=True) as repo:
postReleaseCheckUpdate(self, release, repo.working_tree_dir)
post_release_check_update(self, release, repo.working_tree_dir)
filename = randomString(10) + ".zip"
filename = random_string(10) + ".zip"
destPath = os.path.join(app.config["UPLOAD_DIR"], filename)
assert(not os.path.isfile(destPath))
@ -238,7 +238,7 @@ def makeVCSRelease(self, id, branch):
@celery.task()
def importRepoScreenshot(id):
def import_repo_screenshot(id):
package = Package.query.get(id)
if package is None or package.state == PackageState.DELETED:
raise Exception("Unexpected none package")
@ -248,7 +248,7 @@ def importRepoScreenshot(id):
for ext in ["png", "jpg", "jpeg"]:
sourcePath = repo.working_tree_dir + "/screenshot." + ext
if os.path.isfile(sourcePath):
filename = randomString(10) + "." + ext
filename = random_string(10) + "." + ext
destPath = os.path.join(app.config["UPLOAD_DIR"], filename)
shutil.copyfile(sourcePath, destPath)
@ -313,11 +313,11 @@ def check_update_config_impl(package):
db.session.add(rel)
msg = "Created release {} (Git Update Detection)".format(rel.title)
addSystemAuditLog(AuditSeverity.NORMAL, msg, package.get_url("packages.view"), package)
add_system_audit_log(AuditSeverity.NORMAL, msg, package.get_url("packages.view"), package)
db.session.commit()
makeVCSRelease.apply_async((rel.id, commit), task_id=rel.task_id)
make_vcs_release.apply_async((rel.id, commit), task_id=rel.task_id)
elif config.outdated_at is None:
config.set_outdated()
@ -338,8 +338,8 @@ def check_update_config_impl(package):
.format(tag, msg_last)
for user in package.maintainers:
addSystemNotification(user, NotificationType.BOT,
msg, url_for("todo.view_user", username=user.username, _external=False), package)
add_system_notification(user, NotificationType.BOT,
msg, url_for("todo.view_user", username=user.username, _external=False), package)
config.last_commit = commit
config.last_tag = tag

@ -19,7 +19,7 @@ from app.models import Package, db
from app.tasks import celery
@celery.task()
def updatePackageScores():
def update_package_scores():
Package.query.update({ "score_downloads": Package.score_downloads * 0.95 })
db.session.commit()

@ -23,7 +23,7 @@ from sqlalchemy import or_, and_
from app import app
from app.models import User, db, UserRank, ThreadReply, Package
from app.utils import randomString
from app.utils import random_string
from app.utils.models import create_session
from app.tasks import celery, TaskError
@ -76,7 +76,7 @@ def set_profile_picture_from_url(username: str, url: str):
else:
raise TaskError(f"Unacceptable content-type: {content_type}")
filename = randomString(10) + "." + ext
filename = random_string(10) + "." + ext
filepath = os.path.join(app.config["UPLOAD_DIR"], filename)
with open(filepath, "wb") as f:
size = 0

@ -147,10 +147,10 @@
{{ _("Statistics") }}
</a>
</li>
{% if current_user.rank.atLeast(current_user.rank.EDITOR) or check_global_perm(current_user, "CREATE_TAG") %}
{% if current_user.rank.at_least(current_user.rank.EDITOR) or check_global_perm(current_user, "CREATE_TAG") %}
<li class="dropdown-divider"></li>
{% endif %}
{% if current_user.rank.atLeast(current_user.rank.MODERATOR) %}
{% if current_user.rank.at_least(current_user.rank.MODERATOR) %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('admin.audit') }}">
{{ _("Audit Log") }}
@ -164,7 +164,7 @@
{% endif %}
{% endif %}
{% endif %}
{% if current_user.rank.atLeast(current_user.rank.EDITOR) %}
{% if current_user.rank.at_least(current_user.rank.EDITOR) %}
<li class="nav-item"><a class="nav-link" href="{{ url_for('admin.restore') }}">{{ _("Restore Package") }}</a></li>
{% endif %}
{% if check_global_perm(current_user, "EDIT_TAGS") %}

@ -1,6 +1,6 @@
{% macro render_review_vote(review, current_user, next_url) %}
{% set (positive, negative, is_positive) = review.get_totals(current_user) %}
<form class="-group" method="post" action="{{ review.getVoteUrl(next_url) }}">
<form class="-group" method="post" action="{{ review.get_vote_url(next_url) }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<div class="btn-group">
<button class="btn {% if is_positive == true %}btn-primary{% else %}btn-secondary{% endif %}" name="is_positive" value="yes">

@ -25,7 +25,7 @@
<td class="btn-group">
{% if current_user == topic.author or topic.author.check_perm(current_user, "CHANGE_AUTHOR") %}
<a class="btn btn-primary"
href="{{ url_for('packages.create_edit', 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.get_repo_url(), forums=topic.topic_id, title=topic.title, bname=topic.name) }}">
{{ _("Create") }}
</a>
{% endif %}
@ -61,7 +61,7 @@
{% endif %}
{% if topic.author == current_user or topic.author.check_perm(current_user, "CHANGE_AUTHOR") %}
|
<a href="{{ url_for('packages.create_edit', author=topic.author.username, repo=topic.getRepoURL(), forums=topic.topic_id, title=topic.title, bname=topic.name) }}">
<a href="{{ url_for('packages.create_edit', author=topic.author.username, repo=topic.get_repo_url(), forums=topic.topic_id, title=topic.title, bname=topic.name) }}">
{{ _("Create") }}
</a>
{% endif %}

@ -323,7 +323,7 @@
</p>
{% endif %}
{% if current_user.is_authenticated and current_user.rank.atLeast(current_user.rank.ADMIN) %}
{% if current_user.is_authenticated and current_user.rank.at_least(current_user.rank.ADMIN) %}
<a href="{{ package.get_url('packages.review_votes') }}" class="btn btn-secondary">{{ _("Review Votes") }}</a>
{% endif %}

@ -6,7 +6,7 @@
{% block content %}
<h2 class="mb-4">{{ _("Approval Queue") }}</h2>
{% if canApproveScn and screenshots %}
{% if can_approve_scn and screenshots %}
<div class="card my-4">
<h3 class="card-header">{{ _("Screenshots") }}
<form class="float-right" method="post" action="{{ url_for('todo.view_editor') }}">
@ -40,7 +40,7 @@
{% endif %}
<div class="row">
{% if canApproveNew and (packages or wip_packages) %}
{% if can_approve_new and (packages or wip_packages) %}
<div class="col-sm-6">
<div class="card">
<h3 class="card-header">{{ _("Packages") }}</h3>
@ -69,7 +69,7 @@
</div>
{% endif %}
{% if canApproveRel and releases %}
{% if can_approve_rel and releases %}
<div class="col-sm-6">
<div class="card">
<h3 class="card-header">{{ _("Releases") }}</h3>
@ -159,7 +159,7 @@
<h2 class="mt-5">{{ _("WIP") }}</h2>
{% if canApproveNew and (packages or wip_packages) %}
{% if can_approve_new and (packages or wip_packages) %}
<div class="card">
<h3 class="card-header">WIP Packages</h3>
<div class="list-group list-group-flush" style="max-height: 300px; overflow: hidden auto;">
@ -188,7 +188,7 @@
<div class="mt-5"></div>
{% if current_user.rank.atLeast(current_user.rank.MODERATOR) %}
{% if current_user.rank.at_least(current_user.rank.MODERATOR) %}
<a class="btn btn-secondary float-right" href="{{ url_for('admin.audit') }}">
{{ _("View All") }}
</a>

@ -1,7 +1,7 @@
{% extends "base.html" %}
{% block container %}
{% if current_user.rank.atLeast(current_user.rank.APPROVER) %}
{% if current_user.rank.at_least(current_user.rank.APPROVER) %}
<nav class="pt-4 tabs-container">
<div class="container">
<ul class="nav nav-tabs">
@ -47,7 +47,7 @@
{% endif %}
<main class="container mt-5">
{% if not current_user.rank.atLeast(current_user.rank.APPROVER) %}
{% if not current_user.rank.at_least(current_user.rank.APPROVER) %}
<h1 class="mb-5">{{ self.title() }}</h1>
{% endif %}

@ -22,7 +22,7 @@ Topics to be Added
</div>
<div class="btn-group btn-group-sm">
{% if current_user.rank.atLeast(current_user.rank.APPROVER) %}
{% if current_user.rank.at_least(current_user.rank.APPROVER) %}
{% if n >= 10000 %}
<a class="btn btn-secondary"
href="{{ url_for('todo.topics', q=query, show_discarded=show_discarded, n=100, sort=sort_by) }}">

@ -68,7 +68,7 @@
</tr>
</table>
{% if current_user.rank.atLeast(current_user.rank.MODERATOR) %}
{% if current_user.rank.at_least(current_user.rank.MODERATOR) %}
<a class="btn btn-secondary float-right" href="{{ url_for('admin.audit', username=user.username) }}">
{{ _("View All") }}
</a>
@ -81,7 +81,7 @@
<h3>{{ _("Account Deletion and Deactivation") }}</h3>
{% if current_user.rank.atLeast(current_user.rank.ADMIN) %}
{% if current_user.rank.at_least(current_user.rank.ADMIN) %}
<a class="btn btn-danger" href="{{ url_for('users.delete', username=user.username) }}">
{{ _("Delete or Deactivate") }}</a>
{% else %}

@ -36,7 +36,7 @@
name="deactivate" value="{{ _('Deactivate') }}"
{% endif %}
class="btn btn-danger" />
{% if not can_delete and current_user.rank.atLeast(current_user.rank.ADMIN) %}
{% if not can_delete and current_user.rank.at_least(current_user.rank.ADMIN) %}
<input type="submit" name="delete" value="{{ _('Delete Anyway') }}" class="btn btn-danger ml-3" />
{% endif %}
</div>

@ -39,7 +39,7 @@
<p class="text-danger">{{ _("Doesn't have password") }}</p>
{% endif %}
{% if not user.rank.atLeast(current_user.rank) %}
{% if not user.rank.at_least(current_user.rank) %}
<h3>{{ _("Ban") }}</h3>
{% if user.ban %}
<p>

@ -28,8 +28,8 @@
{{ _("Report") }}
</a>
{% if current_user.is_authenticated and current_user.rank.atLeast(current_user.rank.MODERATOR) %}
{% if not user.rank.atLeast(current_user.rank) %}
{% if current_user.is_authenticated and current_user.rank.at_least(current_user.rank.MODERATOR) %}
{% if not user.rank.at_least(current_user.rank) %}
<a class="btn btn-secondary float-right mr-3" href="{{ url_for('users.modtools', username=user.username) }}">
<i class="fas fa-user-shield mr-1"></i>
{{ _("Moderator Tools") }}
@ -164,7 +164,7 @@
</div>
</div>
{% endfor %}
{% if current_user == user or (current_user.is_authenticated and current_user.rank.atLeast(current_user.rank.ADMIN)) %}
{% if current_user == user or (current_user.is_authenticated and current_user.rank.at_least(current_user.rank.ADMIN)) %}
{% for medal in medals_locked %}
{% set value = medal.progress[0] %}
{% set target = medal.progress[1] %}
@ -202,7 +202,7 @@
{{ _("Create package") }}
</a>
{% endif %}
{% if current_user == user or (current_user.is_authenticated and current_user.rank.atLeast(current_user.rank.EDITOR)) %}
{% if current_user == user or (current_user.is_authenticated and current_user.rank.at_least(current_user.rank.EDITOR)) %}
<a class="float-right btn btn-sm btn-secondary mr-2"
href="{{ url_for('todo.tags', author=user.username) }}">
{{ _("View list of tags") }}

@ -33,27 +33,27 @@ def is_username_valid(username):
re.match(r"^[A-Za-z0-9._-]*$", username) and not re.match(r"^\.*$", username)
def isYes(val):
def is_yes(val):
return val and val.lower() in YESES
def isNo(val):
return val and not isYes(val)
def is_no(val):
return val and not is_yes(val)
def nonEmptyOrNone(str):
def nonempty_or_none(str):
if str is None or str == "":
return None
return str
def shouldReturnJson():
def should_return_json():
return "application/json" in request.accept_mimetypes and \
not "text/html" in request.accept_mimetypes
def randomString(n):
def random_string(n):
return secrets.token_hex(int(n / 2))

@ -26,7 +26,7 @@ from urllib.parse import urlsplit
from git import GitCommandError
from app.tasks import TaskError
from app.utils import randomString
from app.utils import random_string
def generate_git_url(urlstr):
@ -40,7 +40,7 @@ def generate_git_url(urlstr):
@contextlib.contextmanager
def get_temp_dir():
temp = os.path.join(tempfile.gettempdir(), randomString(10))
temp = os.path.join(tempfile.gettempdir(), random_string(10))
yield temp
shutil.rmtree(temp)
@ -50,21 +50,21 @@ def get_temp_dir():
# Throws `TaskError` on failure.
# Caller is responsible for deleting returned directory.
@contextlib.contextmanager
def clone_repo(urlstr, ref=None, recursive=False):
gitDir = os.path.join(tempfile.gettempdir(), randomString(10))
def clone_repo(url_str, ref=None, recursive=False):
git_dir = os.path.join(tempfile.gettempdir(), random_string(10))
try:
gitUrl = generate_git_url(urlstr)
print("Cloning from " + gitUrl)
git_url = generate_git_url(url_str)
print("Cloning from " + git_url)
if ref is None:
repo = git.Repo.clone_from(gitUrl, gitDir,
repo = git.Repo.clone_from(git_url, git_dir,
progress=None, env=None, depth=1, recursive=recursive, kill_after_timeout=15)
else:
assert ref != ""
repo = git.Repo.init(gitDir)
origin = repo.create_remote("origin", url=gitUrl)
repo = git.Repo.init(git_dir)
origin = repo.create_remote("origin", url=git_url)
assert origin.exists()
origin.fetch()
repo.git.checkout(ref)
@ -72,7 +72,7 @@ def clone_repo(urlstr, ref=None, recursive=False):
repo.git.submodule('update', '--init')
yield repo
shutil.rmtree(gitDir)
shutil.rmtree(git_dir)
return
except GitCommandError as e:
@ -83,7 +83,7 @@ def clone_repo(urlstr, ref=None, recursive=False):
err = "Unable to find the reference " + (ref or "?") + "\n" + e.stderr
raise TaskError(err.replace("stderr: ", "") \
.replace("Cloning into '" + gitDir + "'...", "") \
.replace("Cloning into '" + git_dir + "'...", "") \
.strip())

@ -27,7 +27,7 @@ from sqlalchemy.orm import sessionmaker
from app.models import User, NotificationType, Package, UserRank, Notification, db, AuditSeverity, AuditLogEntry, ThreadReply, Thread, PackageState, PackageType, PackageAlias
def getPackageByInfo(author, name):
def get_package_by_info(author, name):
user = User.query.filter_by(username=author).first()
if user is None:
return None
@ -39,6 +39,7 @@ def getPackageByInfo(author, name):
return package
def is_package_page(f):
@wraps(f)
def decorated_function(*args, **kwargs):
@ -48,9 +49,9 @@ def is_package_page(f):
author = kwargs["author"]
name = kwargs["name"]
package = getPackageByInfo(author, name)
package = get_package_by_info(author, name)
if package is None:
package = getPackageByInfo(author, name + "_game")
package = get_package_by_info(author, name + "_game")
if package and package.type == PackageType.GAME:
args = dict(kwargs)
args["name"] = name + "_game"
@ -72,28 +73,28 @@ def is_package_page(f):
return decorated_function
def addNotification(target, causer: User, type: NotificationType, title: str, url: str, package: Package = None):
def add_notification(target, causer: User, type: NotificationType, title: str, url: str, package: Package = None):
try:
iter(target)
for x in target:
addNotification(x, causer, type, title, url, package)
add_notification(x, causer, type, title, url, package)
return
except TypeError:
pass
if target.rank.atLeast(UserRank.NEW_MEMBER) and target != causer:
if target.rank.at_least(UserRank.NEW_MEMBER) and target != causer:
Notification.query.filter_by(user=target, causer=causer, type=type, title=title, url=url, package=package).delete()
notif = Notification(target, causer, type, title, url, package)
db.session.add(notif)
def addAuditLog(severity: AuditSeverity, causer: User, title: str, url: typing.Optional[str],
package: Package = None, description: str = None):
def add_audit_log(severity: AuditSeverity, causer: User, title: str, url: typing.Optional[str],
package: Package = None, description: str = None):
entry = AuditLogEntry(causer, severity, title, url, package, description)
db.session.add(entry)
def clearNotifications(url):
def clear_notifications(url):
if current_user.is_authenticated:
Notification.query.filter_by(user=current_user, url=url).delete()
db.session.commit()
@ -105,12 +106,12 @@ def get_system_user():
return system_user
def addSystemNotification(target, type: NotificationType, title: str, url: str, package: Package = None):
return addNotification(target, get_system_user(), type, title, url, package)
def add_system_notification(target, type: NotificationType, title: str, url: str, package: Package = None):
return add_notification(target, get_system_user(), type, title, url, package)
def addSystemAuditLog(severity: AuditSeverity, title: str, url: str, package=None, description=None):
return addAuditLog(severity, get_system_user(), title, url, package, description)
def add_system_audit_log(severity: AuditSeverity, title: str, url: str, package=None, description=None):
return add_audit_log(severity, get_system_user(), title, url, package, description)
def post_bot_message(package: Package, title: str, message: str):
@ -133,8 +134,7 @@ def post_bot_message(package: Package, title: str, message: str):
reply.comment = "**{}**\n\n{}\n\nThis is an automated message, but you can reply if you need help".format(title, message)
db.session.add(reply)
addNotification(thread.watchers, system_user, NotificationType.BOT,
title, thread.get_view_url(), thread.package)
add_notification(thread.watchers, system_user, NotificationType.BOT, title, thread.get_view_url(), thread.package)
thread.replies.append(reply)

@ -12,9 +12,10 @@ from urllib.parse import urlencode
from bs4 import BeautifulSoup
def urlEncodeNonAscii(b):
def url_encode_non_ascii(b):
return re.sub('[\x80-\xFF]', lambda c: '%%%02x' % ord(c.group(0)), b)
class Profile:
def __init__(self, username):
self.username = username
@ -31,6 +32,7 @@ class Profile:
def __str__(self):
return self.username + "\n" + str(self.signature) + "\n" + str(self.properties)
def __extract_properties(profile, soup):
el = soup.find(id="viewprofile")
if el is None:
@ -66,6 +68,7 @@ def __extract_properties(profile, soup):
elif element and element.name is not None:
print("Unexpected other")
def __extract_signature(soup):
res = soup.find_all("div", class_="signature")
if len(res) != 1:
@ -74,7 +77,7 @@ def __extract_signature(soup):
return str(res[0])
def getProfileURL(url, username):
def get_profile_url(url, username):
url = urlparse.urlparse(url)
# Update path
@ -89,8 +92,8 @@ def getProfileURL(url, username):
return urlparse.urlunparse(url)
def getProfile(url, username):
url = getProfileURL(url, username)
def get_profile(url, username):
url = get_profile_url(url, username)
try:
req = urllib.request.urlopen(url, timeout=15)
@ -114,7 +117,8 @@ def getProfile(url, username):
regex_id = re.compile(r"^.*t=([0-9]+).*$")
def parseForumListPage(id, page, out, extra=None):
def parse_forum_list_page(id, page, out, extra=None):
num_per_page = 30
start = page*num_per_page+1
print(" - Fetching page {} (topics {}-{})".format(page, start, start+num_per_page))
@ -171,15 +175,11 @@ def parseForumListPage(id, page, out, extra=None):
return True
def getTopicsFromForum(id, out, extra=None):
def get_topics_from_forum(id, out, extra=None):
print("Fetching all topics from forum {}".format(id))
page = 0
while parseForumListPage(id, page, out, extra):
while parse_forum_list_page(id, page, out, extra):
page = page + 1
return out
def dumpTitlesToFile(topics, path):
with open(path, "w") as out_file:
for topic in topics.values():
out_file.write(topic["title"] + "\n")

@ -76,7 +76,7 @@ def rank_required(rank):
def decorated_function(*args, **kwargs):
if not current_user.is_authenticated:
return redirect(url_for("users.login"))
if not current_user.rank.atLeast(rank):
if not current_user.rank.at_least(rank):
abort(403)
return f(*args, **kwargs)