From 9c6c13b78a30cb9d800043410799e29631f803d2 Mon Sep 17 00:00:00 2001
From: Joakim Saario
Date: Sun, 21 Aug 2022 22:08:29 +0200
Subject: [PATCH] style: Run pre-commit
---
.gitignore | 1 +
.tx/config | 1 -
aurweb/asgi.py | 104 +--
aurweb/auth/__init__.py | 55 +-
aurweb/auth/creds.py | 15 +-
aurweb/benchmark.py | 6 +-
aurweb/cache.py | 7 +-
aurweb/captcha.py | 18 +-
aurweb/config.py | 7 +-
aurweb/cookies.py | 37 +-
aurweb/db.py | 113 +--
aurweb/defaults.py | 4 +-
aurweb/exceptions.py | 22 +-
aurweb/filters.py | 34 +-
aurweb/git/auth.py | 34 +-
aurweb/git/serve.py | 393 ++++++----
aurweb/git/update.py | 370 +++++----
aurweb/initdb.py | 82 +-
aurweb/l10n.py | 76 +-
aurweb/logging.py | 2 +-
aurweb/models/accepted_term.py | 18 +-
aurweb/models/account_type.py | 8 +-
aurweb/models/api_rate_limit.py | 6 +-
aurweb/models/declarative.py | 17 +-
aurweb/models/group.py | 3 +-
aurweb/models/license.py | 3 +-
aurweb/models/official_provider.py | 9 +-
aurweb/models/package.py | 13 +-
aurweb/models/package_base.py | 27 +-
aurweb/models/package_blacklist.py | 3 +-
aurweb/models/package_comaintainer.py | 27 +-
aurweb/models/package_comment.py | 47 +-
aurweb/models/package_dependency.py | 63 +-
aurweb/models/package_group.py | 24 +-
aurweb/models/package_keyword.py | 14 +-
aurweb/models/package_license.py | 24 +-
aurweb/models/package_notification.py | 23 +-
aurweb/models/package_relation.py | 22 +-
aurweb/models/package_request.py | 46 +-
aurweb/models/package_source.py | 17 +-
aurweb/models/package_vote.py | 26 +-
aurweb/models/request_type.py | 2 +-
aurweb/models/session.py | 15 +-
aurweb/models/ssh_pub_key.py | 9 +-
aurweb/models/term.py | 6 +-
aurweb/models/tu_vote.py | 22 +-
aurweb/models/tu_voteinfo.py | 25 +-
aurweb/models/user.py | 100 +--
aurweb/packages/requests.py | 159 ++--
aurweb/packages/search.py | 7 +-
aurweb/packages/util.py | 96 ++-
aurweb/pkgbase/actions.py | 36 +-
aurweb/pkgbase/util.py | 74 +-
aurweb/pkgbase/validate.py | 27 +-
aurweb/prometheus.py | 24 +-
aurweb/ratelimit.py | 11 +-
aurweb/redis.py | 4 +-
aurweb/routers/__init__.py | 13 +-
aurweb/routers/accounts.py | 391 +++++-----
aurweb/routers/auth.py | 84 +-
aurweb/routers/html.py | 205 +++--
aurweb/routers/packages.py | 213 ++---
aurweb/routers/pkgbase.py | 481 ++++++------
aurweb/routers/requests.py | 36 +-
aurweb/routers/rpc.py | 74 +-
aurweb/routers/rss.py | 31 +-
aurweb/routers/sso.py | 93 ++-
aurweb/routers/trusted_user.py | 240 +++---
aurweb/rpc.py | 216 +++---
aurweb/schema.py | 703 ++++++++++-------
aurweb/scripts/adduser.py | 32 +-
aurweb/scripts/aurblup.py | 35 +-
aurweb/scripts/config.py | 6 +-
aurweb/scripts/mkpkglists.py | 138 ++--
aurweb/scripts/notify.py | 926 ++++++++++++----------
aurweb/scripts/pkgmaint.py | 6 +-
aurweb/scripts/popupdate.py | 43 +-
aurweb/scripts/rendercomment.py | 77 +-
aurweb/scripts/tuvotereminder.py | 8 +-
aurweb/scripts/usermaint.py | 16 +-
aurweb/spawn.py | 129 +--
aurweb/templates.py | 49 +-
aurweb/testing/__init__.py | 3 +-
aurweb/testing/alpm.py | 13 +-
aurweb/testing/email.py | 6 +-
aurweb/testing/filelock.py | 1 -
aurweb/testing/git.py | 1 -
aurweb/testing/html.py | 2 +-
aurweb/testing/requests.py | 23 +-
aurweb/testing/smtp.py | 5 +-
aurweb/time.py | 31 +-
aurweb/users/update.py | 75 +-
aurweb/users/validate.py | 185 +++--
aurweb/util.py | 25 +-
doc/web-auth.md | 1 -
docker-compose.yml | 2 +-
docker/config/nginx.conf | 1 -
migrations/env.py | 5 +-
po/ar.po | 2 +-
po/ast.po | 2 +-
po/az.po | 2 +-
po/az_AZ.po | 2 +-
po/bg.po | 2 +-
po/ca.po | 2 +-
po/ca_ES.po | 2 +-
po/cs.po | 2 +-
po/da.po | 2 +-
po/de.po | 2 +-
po/el.po | 2 +-
po/es.po | 2 +-
po/es_419.po | 2 +-
po/et.po | 2 +-
po/fi.po | 2 +-
po/fi_FI.po | 2 +-
po/fr.po | 2 +-
po/he.po | 2 +-
po/hi_IN.po | 2 +-
po/hr.po | 2 +-
po/hu.po | 2 +-
po/id.po | 2 +-
po/id_ID.po | 2 +-
po/is.po | 2 +-
po/it.po | 2 +-
po/ja.po | 2 +-
po/ko.po | 2 +-
po/lt.po | 2 +-
po/nb.po | 2 +-
po/nb_NO.po | 2 +-
po/nl.po | 2 +-
po/pl.po | 2 +-
po/pt.po | 2 +-
po/pt_BR.po | 2 +-
po/pt_PT.po | 2 +-
po/ro.po | 2 +-
po/ru.po | 2 +-
po/sk.po | 2 +-
po/sr.po | 2 +-
po/sr_RS.po | 2 +-
po/sv_SE.po | 2 +-
po/tr.po | 2 +-
po/uk.po | 2 +-
po/vi.po | 2 +-
po/zh.po | 2 +-
po/zh_CN.po | 2 +-
po/zh_TW.po | 2 +-
schema/gendummydata.py | 75 +-
templates/addvote.html | 1 -
templates/home.html | 6 +-
templates/packages/index.html | 2 +-
templates/partials/account/results.html | 1 -
templates/tu/show.html | 2 +-
test/conftest.py | 13 +-
test/test_accepted_term.py | 15 +-
test/test_account_type.py | 22 +-
test/test_accounts_routes.py | 499 ++++++------
test/test_adduser.py | 41 +-
test/test_api_rate_limit.py | 4 +-
test/test_asgi.py | 51 +-
test/test_aurblup.py | 22 +-
test/test_auth.py | 35 +-
test/test_auth_routes.py | 138 ++--
test/test_ban.py | 2 -
test/test_cache.py | 24 +-
test/test_captcha.py | 14 +-
test/test_config.py | 10 +-
test/test_db.py | 26 +-
test/test_dependency_type.py | 3 +-
test/test_email.py | 7 +-
test/test_filelock.py | 1 -
test/test_filters.py | 4 +-
test/test_group.py | 1 -
test/test_homepage.py | 137 ++--
test/test_html.py | 49 +-
test/test_initdb.py | 5 +-
test/test_l10n.py | 21 +-
test/test_license.py | 1 -
test/test_mkpkglists.py | 57 +-
test/test_notify.py | 127 +--
test/test_official_provider.py | 33 +-
test/test_package.py | 48 +-
test/test_package_base.py | 17 +-
test/test_package_blacklist.py | 1 -
test/test_package_comaintainer.py | 20 +-
test/test_package_comment.py | 55 +-
test/test_package_dependency.py | 27 +-
test/test_package_group.py | 12 +-
test/test_package_keyword.py | 18 +-
test/test_package_license.py | 15 +-
test/test_package_notification.py | 13 +-
test/test_package_relation.py | 31 +-
test/test_package_request.py | 148 ++--
test/test_package_source.py | 12 +-
test/test_package_vote.py | 15 +-
test/test_packages_routes.py | 990 ++++++++++++------------
test/test_packages_util.py | 51 +-
test/test_pkgbase_routes.py | 810 ++++++++++---------
test/test_pkgmaint.py | 22 +-
test/test_ratelimit.py | 23 +-
test/test_redis.py | 4 +-
test/test_rendercomment.py | 40 +-
test/test_requests.py | 337 ++++----
test/test_routes.py | 65 +-
test/test_rpc.py | 534 +++++++------
test/test_rss.py | 31 +-
test/test_session.py | 35 +-
test/test_spawn.py | 23 +-
test/test_ssh_pub_key.py | 25 +-
test/test_templates.py | 110 +--
test/test_term.py | 6 +-
test/test_time.py | 1 -
test/test_trusted_user_routes.py | 361 +++++----
test/test_tu_vote.py | 25 +-
test/test_tu_voteinfo.py | 137 ++--
test/test_tuvotereminder.py | 39 +-
test/test_user.py | 58 +-
test/test_usermaint.py | 11 +-
test/test_util.py | 7 +-
util/fix-coverage | 5 +-
web/html/503.php | 1 -
web/html/addvote.php | 1 -
web/html/comaintainers.php | 2 -
web/html/css/archweb.css | 4 +-
web/html/logout.php | 1 -
web/html/packages.php | 1 -
web/html/pkgbase.php | 1 -
web/html/pkgreq.php | 1 -
web/html/tu.php | 1 -
web/lib/aurjson.class.php | 1 -
web/lib/version.inc.php | 1 -
web/locale/README | 1 -
web/template/comaintainers_form.php | 1 -
web/template/flag_comment.php | 1 -
web/template/header.php | 1 -
web/template/pkgreq_close_form.php | 1 -
web/template/template.phps | 1 -
235 files changed, 7180 insertions(+), 5628 deletions(-)
diff --git a/.gitignore b/.gitignore
index 8388694c..2a3d2106 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+/data/
__pycache__/
*.py[cod]
.vim/
diff --git a/.tx/config b/.tx/config
index 7f53b684..d2553dec 100644
--- a/.tx/config
+++ b/.tx/config
@@ -5,4 +5,3 @@ host = https://www.transifex.com
file_filter = po/.po
source_file = po/aurweb.pot
source_lang = en
-
diff --git a/aurweb/asgi.py b/aurweb/asgi.py
index fa2526ed..ccca3fc5 100644
--- a/aurweb/asgi.py
+++ b/aurweb/asgi.py
@@ -6,11 +6,9 @@ import re
import sys
import traceback
import typing
-
from urllib.parse import quote_plus
import requests
-
from fastapi import FastAPI, HTTPException, Request, Response
from fastapi.responses import RedirectResponse
from fastapi.staticfiles import StaticFiles
@@ -26,7 +24,6 @@ import aurweb.config
import aurweb.filters # noqa: F401
import aurweb.logging
import aurweb.pkgbase.util as pkgbaseutil
-
from aurweb import logging, prometheus, util
from aurweb.auth import BasicAuthBackend
from aurweb.db import get_engine, query
@@ -60,33 +57,33 @@ async def app_startup():
# provided by the user. Docker uses .env's TEST_RECURSION_LIMIT
# when running test suites.
# TODO: Find a proper fix to this issue.
- recursion_limit = int(os.environ.get(
- "TEST_RECURSION_LIMIT", sys.getrecursionlimit() + 1000))
+ recursion_limit = int(
+ os.environ.get("TEST_RECURSION_LIMIT", sys.getrecursionlimit() + 1000)
+ )
sys.setrecursionlimit(recursion_limit)
backend = aurweb.config.get("database", "backend")
if backend not in aurweb.db.DRIVERS:
raise ValueError(
f"The configured database backend ({backend}) is unsupported. "
- f"Supported backends: {str(aurweb.db.DRIVERS.keys())}")
+ f"Supported backends: {str(aurweb.db.DRIVERS.keys())}"
+ )
session_secret = aurweb.config.get("fastapi", "session_secret")
if not session_secret:
raise Exception("[fastapi] session_secret must not be empty")
if not os.environ.get("PROMETHEUS_MULTIPROC_DIR", None):
- logger.warning("$PROMETHEUS_MULTIPROC_DIR is not set, the /metrics "
- "endpoint is disabled.")
+ logger.warning(
+ "$PROMETHEUS_MULTIPROC_DIR is not set, the /metrics "
+ "endpoint is disabled."
+ )
- app.mount("/static/css",
- StaticFiles(directory="web/html/css"),
- name="static_css")
- app.mount("/static/js",
- StaticFiles(directory="web/html/js"),
- name="static_js")
- app.mount("/static/images",
- StaticFiles(directory="web/html/images"),
- name="static_images")
+ app.mount("/static/css", StaticFiles(directory="web/html/css"), name="static_css")
+ app.mount("/static/js", StaticFiles(directory="web/html/js"), name="static_js")
+ app.mount(
+ "/static/images", StaticFiles(directory="web/html/images"), name="static_images"
+ )
# Add application middlewares.
app.add_middleware(AuthenticationMiddleware, backend=BasicAuthBackend())
@@ -95,6 +92,7 @@ async def app_startup():
# Add application routes.
def add_router(module):
app.include_router(module.router)
+
util.apply_all(APP_ROUTES, add_router)
# Initialize the database engine and ORM.
@@ -102,8 +100,8 @@ async def app_startup():
def child_exit(server, worker): # pragma: no cover
- """ This function is required for gunicorn customization
- of prometheus multiprocessing. """
+ """This function is required for gunicorn customization
+ of prometheus multiprocessing."""
multiprocess.mark_process_dead(worker.pid)
@@ -177,9 +175,7 @@ async def internal_server_error(request: Request, exc: Exception) -> Response:
else:
# post
form_data = str(dict(request.state.form_data))
- desc = desc + [
- f"- Data: `{form_data}`"
- ] + ["", f"```{tb}```"]
+ desc = desc + [f"- Data: `{form_data}`"] + ["", f"```{tb}```"]
headers = {"Authorization": f"Bearer {token}"}
data = {
@@ -191,11 +187,12 @@ async def internal_server_error(request: Request, exc: Exception) -> Response:
logger.info(endp)
resp = requests.post(endp, json=data, headers=headers)
if resp.status_code != http.HTTPStatus.CREATED:
- logger.error(
- f"Unable to report exception to {repo}: {resp.text}")
+ logger.error(f"Unable to report exception to {repo}: {resp.text}")
else:
- logger.warning("Unable to report an exception found due to "
- "unset notifications.error-{{project,token}}")
+ logger.warning(
+ "Unable to report an exception found due to "
+ "unset notifications.error-{{project,token}}"
+ )
# Log details about the exception traceback.
logger.error(f"FATAL[{tb_id}]: An unexpected exception has occurred.")
@@ -203,14 +200,17 @@ async def internal_server_error(request: Request, exc: Exception) -> Response:
else:
retval = retval.decode()
- return render_template(request, "errors/500.html", context,
- status_code=http.HTTPStatus.INTERNAL_SERVER_ERROR)
+ return render_template(
+ request,
+ "errors/500.html",
+ context,
+ status_code=http.HTTPStatus.INTERNAL_SERVER_ERROR,
+ )
@app.exception_handler(StarletteHTTPException)
-async def http_exception_handler(request: Request, exc: HTTPException) \
- -> Response:
- """ Handle an HTTPException thrown in a route. """
+async def http_exception_handler(request: Request, exc: HTTPException) -> Response:
+ """Handle an HTTPException thrown in a route."""
phrase = http.HTTPStatus(exc.status_code).phrase
context = make_context(request, phrase)
context["exc"] = exc
@@ -228,16 +228,16 @@ async def http_exception_handler(request: Request, exc: HTTPException) \
pass
try:
- return render_template(request, f"errors/{exc.status_code}.html",
- context, exc.status_code)
+ return render_template(
+ request, f"errors/{exc.status_code}.html", context, exc.status_code
+ )
except TemplateNotFound:
- return render_template(request, "errors/detail.html",
- context, exc.status_code)
+ return render_template(request, "errors/detail.html", context, exc.status_code)
@app.middleware("http")
async def add_security_headers(request: Request, call_next: typing.Callable):
- """ This middleware adds the CSP, XCTO, XFO and RP security
+ """This middleware adds the CSP, XCTO, XFO and RP security
headers to the HTTP response associated with request.
CSP: Content-Security-Policy
@@ -254,7 +254,7 @@ async def add_security_headers(request: Request, call_next: typing.Callable):
nonce = request.user.nonce
csp = "default-src 'self'; "
script_hosts = []
- csp += f"script-src 'self' 'nonce-{nonce}' " + ' '.join(script_hosts)
+ csp += f"script-src 'self' 'nonce-{nonce}' " + " ".join(script_hosts)
# It's fine if css is inlined.
csp += "; style-src 'self' 'unsafe-inline'"
response.headers["Content-Security-Policy"] = csp
@@ -276,17 +276,25 @@ async def add_security_headers(request: Request, call_next: typing.Callable):
@app.middleware("http")
async def check_terms_of_service(request: Request, call_next: typing.Callable):
- """ This middleware function redirects authenticated users if they
- have any outstanding Terms to agree to. """
+ """This middleware function redirects authenticated users if they
+ have any outstanding Terms to agree to."""
if request.user.is_authenticated() and request.url.path != "/tos":
- unaccepted = query(Term).join(AcceptedTerm).filter(
- or_(AcceptedTerm.UsersID != request.user.ID,
- and_(AcceptedTerm.UsersID == request.user.ID,
- AcceptedTerm.TermsID == Term.ID,
- AcceptedTerm.Revision < Term.Revision)))
+ unaccepted = (
+ query(Term)
+ .join(AcceptedTerm)
+ .filter(
+ or_(
+ AcceptedTerm.UsersID != request.user.ID,
+ and_(
+ AcceptedTerm.UsersID == request.user.ID,
+ AcceptedTerm.TermsID == Term.ID,
+ AcceptedTerm.Revision < Term.Revision,
+ ),
+ )
+ )
+ )
if query(Term).count() > unaccepted.count():
- return RedirectResponse(
- "/tos", status_code=int(http.HTTPStatus.SEE_OTHER))
+ return RedirectResponse("/tos", status_code=int(http.HTTPStatus.SEE_OTHER))
return await util.error_or_result(call_next, request)
@@ -301,9 +309,9 @@ async def id_redirect_middleware(request: Request, call_next: typing.Callable):
for k, v in request.query_params.items():
if k != "id":
qs.append(f"{k}={quote_plus(str(v))}")
- qs = str() if not qs else '?' + '&'.join(qs)
+ qs = str() if not qs else "?" + "&".join(qs)
- path = request.url.path.rstrip('/')
+ path = request.url.path.rstrip("/")
return RedirectResponse(f"{path}/{id}{qs}")
return await util.error_or_result(call_next, request)
diff --git a/aurweb/auth/__init__.py b/aurweb/auth/__init__.py
index cb6f3e4d..0c8bba69 100644
--- a/aurweb/auth/__init__.py
+++ b/aurweb/auth/__init__.py
@@ -1,25 +1,22 @@
import functools
-
from http import HTTPStatus
from typing import Callable
import fastapi
-
from fastapi import HTTPException
from fastapi.responses import RedirectResponse
from starlette.authentication import AuthCredentials, AuthenticationBackend
from starlette.requests import HTTPConnection
import aurweb.config
-
from aurweb import db, filters, l10n, time, util
from aurweb.models import Session, User
from aurweb.models.account_type import ACCOUNT_TYPE_ID
class StubQuery:
- """ Acts as a stubbed version of an orm.Query. Typically used
- to masquerade fake records for an AnonymousUser. """
+ """Acts as a stubbed version of an orm.Query. Typically used
+ to masquerade fake records for an AnonymousUser."""
def filter(self, *args):
return StubQuery()
@@ -29,19 +26,21 @@ class StubQuery:
class AnonymousUser:
- """ A stubbed User class used when an unauthenticated User
- makes a request against FastAPI. """
+ """A stubbed User class used when an unauthenticated User
+ makes a request against FastAPI."""
+
# Stub attributes used to mimic a real user.
ID = 0
Username = "N/A"
Email = "N/A"
class AccountType:
- """ A stubbed AccountType static class. In here, we use an ID
+ """A stubbed AccountType static class. In here, we use an ID
and AccountType which do not exist in our constant records.
All records primary keys (AccountType.ID) should be non-zero,
so using a zero here means that we'll never match against a
- real AccountType. """
+ real AccountType."""
+
ID = 0
AccountType = "Anonymous"
@@ -104,11 +103,11 @@ class BasicAuthBackend(AuthenticationBackend):
return unauthenticated
timeout = aurweb.config.getint("options", "login_timeout")
- remembered = ("AURREMEMBER" in conn.cookies
- and bool(conn.cookies.get("AURREMEMBER")))
+ remembered = "AURREMEMBER" in conn.cookies and bool(
+ conn.cookies.get("AURREMEMBER")
+ )
if remembered:
- timeout = aurweb.config.getint("options",
- "persistent_cookie_timeout")
+ timeout = aurweb.config.getint("options", "persistent_cookie_timeout")
# If no session with sid and a LastUpdateTS now or later exists.
now_ts = time.utcnow()
@@ -160,40 +159,45 @@ def _auth_required(auth_goal: bool = True):
# page itself is not directly possible (e.g. submitting a form).
if request.method in ("GET", "HEAD"):
url = request.url.path
- elif (referer := request.headers.get("Referer")):
+ elif referer := request.headers.get("Referer"):
aur = aurweb.config.get("options", "aur_location") + "/"
if not referer.startswith(aur):
_ = l10n.get_translator_for_request(request)
- raise HTTPException(status_code=HTTPStatus.BAD_REQUEST,
- detail=_("Bad Referer header."))
- url = referer[len(aur) - 1:]
+ raise HTTPException(
+ status_code=HTTPStatus.BAD_REQUEST,
+ detail=_("Bad Referer header."),
+ )
+ url = referer[len(aur) - 1 :]
url = "/login?" + filters.urlencode({"next": url})
return RedirectResponse(url, status_code=int(HTTPStatus.SEE_OTHER))
+
return wrapper
return decorator
def requires_auth(func: Callable) -> Callable:
- """ Require an authenticated session for a particular route. """
+ """Require an authenticated session for a particular route."""
@functools.wraps(func)
async def wrapper(*args, **kwargs):
return await _auth_required(True)(func)(*args, **kwargs)
+
return wrapper
def requires_guest(func: Callable) -> Callable:
- """ Require a guest (unauthenticated) session for a particular route. """
+ """Require a guest (unauthenticated) session for a particular route."""
@functools.wraps(func)
async def wrapper(*args, **kwargs):
return await _auth_required(False)(func)(*args, **kwargs)
+
return wrapper
def account_type_required(one_of: set):
- """ A decorator that can be used on FastAPI routes to dictate
+ """A decorator that can be used on FastAPI routes to dictate
that a user belongs to one of the types defined in one_of.
This decorator should be run after an @auth_required(True) is
@@ -211,18 +215,15 @@ def account_type_required(one_of: set):
:return: Return the FastAPI function this decorator wraps.
"""
# Convert any account type string constants to their integer IDs.
- one_of = {
- ACCOUNT_TYPE_ID[atype]
- for atype in one_of
- if isinstance(atype, str)
- }
+ one_of = {ACCOUNT_TYPE_ID[atype] for atype in one_of if isinstance(atype, str)}
def decorator(func):
@functools.wraps(func)
async def wrapper(request: fastapi.Request, *args, **kwargs):
if request.user.AccountTypeID not in one_of:
- return RedirectResponse("/",
- status_code=int(HTTPStatus.SEE_OTHER))
+ return RedirectResponse("/", status_code=int(HTTPStatus.SEE_OTHER))
return await func(request, *args, **kwargs)
+
return wrapper
+
return decorator
diff --git a/aurweb/auth/creds.py b/aurweb/auth/creds.py
index 05b30d5d..baa3b9bf 100644
--- a/aurweb/auth/creds.py
+++ b/aurweb/auth/creds.py
@@ -1,4 +1,9 @@
-from aurweb.models.account_type import DEVELOPER_ID, TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID, USER_ID
+from aurweb.models.account_type import (
+ DEVELOPER_ID,
+ TRUSTED_USER_AND_DEV_ID,
+ TRUSTED_USER_ID,
+ USER_ID,
+)
from aurweb.models.user import User
ACCOUNT_CHANGE_TYPE = 1
@@ -30,7 +35,9 @@ TU_LIST_VOTES = 20
TU_VOTE = 21
PKGBASE_MERGE = 29
-user_developer_or_trusted_user = set([USER_ID, TRUSTED_USER_ID, DEVELOPER_ID, TRUSTED_USER_AND_DEV_ID])
+user_developer_or_trusted_user = set(
+ [USER_ID, TRUSTED_USER_ID, DEVELOPER_ID, TRUSTED_USER_AND_DEV_ID]
+)
trusted_user_or_dev = set([TRUSTED_USER_ID, DEVELOPER_ID, TRUSTED_USER_AND_DEV_ID])
developer = set([DEVELOPER_ID, TRUSTED_USER_AND_DEV_ID])
trusted_user = set([TRUSTED_USER_ID, TRUSTED_USER_AND_DEV_ID])
@@ -67,9 +74,7 @@ cred_filters = {
}
-def has_credential(user: User,
- credential: int,
- approved: list = tuple()):
+def has_credential(user: User, credential: int, approved: list = tuple()):
if user in approved:
return True
diff --git a/aurweb/benchmark.py b/aurweb/benchmark.py
index 7086fb08..a5512acc 100644
--- a/aurweb/benchmark.py
+++ b/aurweb/benchmark.py
@@ -6,16 +6,16 @@ class Benchmark:
self.start()
def _timestamp(self) -> float:
- """ Generate a timestamp. """
+ """Generate a timestamp."""
return float(datetime.utcnow().timestamp())
def start(self) -> int:
- """ Start a benchmark. """
+ """Start a benchmark."""
self.current = self._timestamp()
return self.current
def end(self):
- """ Return the diff between now - start(). """
+ """Return the diff between now - start()."""
n = self._timestamp() - self.current
self.current = float(0)
return n
diff --git a/aurweb/cache.py b/aurweb/cache.py
index 697473b8..1572e2fc 100644
--- a/aurweb/cache.py
+++ b/aurweb/cache.py
@@ -2,9 +2,10 @@ from redis import Redis
from sqlalchemy import orm
-async def db_count_cache(redis: Redis, key: str, query: orm.Query,
- expire: int = None) -> int:
- """ Store and retrieve a query.count() via redis cache.
+async def db_count_cache(
+ redis: Redis, key: str, query: orm.Query, expire: int = None
+) -> int:
+ """Store and retrieve a query.count() via redis cache.
:param redis: Redis handle
:param key: Redis key
diff --git a/aurweb/captcha.py b/aurweb/captcha.py
index 34d99e53..52dfeb31 100644
--- a/aurweb/captcha.py
+++ b/aurweb/captcha.py
@@ -9,7 +9,7 @@ from aurweb.templates import register_filter
def get_captcha_salts():
- """ Produce salts based on the current user count. """
+ """Produce salts based on the current user count."""
count = query(User).count()
salts = []
for i in range(0, 6):
@@ -18,19 +18,19 @@ def get_captcha_salts():
def get_captcha_token(salt):
- """ Produce a token for the CAPTCHA salt. """
+ """Produce a token for the CAPTCHA salt."""
return hashlib.md5(salt.encode()).hexdigest()[:3]
def get_captcha_challenge(salt):
- """ Get a CAPTCHA challenge string (shell command) for a salt. """
+ """Get a CAPTCHA challenge string (shell command) for a salt."""
token = get_captcha_token(salt)
return f"LC_ALL=C pacman -V|sed -r 's#[0-9]+#{token}#g'|md5sum|cut -c1-6"
def get_captcha_answer(token):
- """ Compute the answer via md5 of the real template text, return the
- first six digits of the hexadecimal hash. """
+ """Compute the answer via md5 of the real template text, return the
+ first six digits of the hexadecimal hash."""
text = r"""
.--. Pacman v%s.%s.%s - libalpm v%s.%s.%s
/ _.-' .-. .-. .-. Copyright (C) %s-%s Pacman Development Team
@@ -38,14 +38,16 @@ def get_captcha_answer(token):
'--'
This program may be freely redistributed under
the terms of the GNU General Public License.
-""" % tuple([token] * 10)
+""" % tuple(
+ [token] * 10
+ )
return hashlib.md5((text + "\n").encode()).hexdigest()[:6]
@register_filter("captcha_salt")
@pass_context
def captcha_salt_filter(context):
- """ Returns the most recent CAPTCHA salt in the list of salts. """
+ """Returns the most recent CAPTCHA salt in the list of salts."""
salts = get_captcha_salts()
return salts[0]
@@ -53,5 +55,5 @@ def captcha_salt_filter(context):
@register_filter("captcha_cmdline")
@pass_context
def captcha_cmdline_filter(context, salt):
- """ Returns a CAPTCHA challenge for a given salt. """
+ """Returns a CAPTCHA challenge for a given salt."""
return get_captcha_challenge(salt)
diff --git a/aurweb/config.py b/aurweb/config.py
index 6069910f..4f97020c 100644
--- a/aurweb/config.py
+++ b/aurweb/config.py
@@ -1,6 +1,5 @@
import configparser
import os
-
from typing import Any
# Publicly visible version of aurweb. This is used to display
@@ -15,8 +14,8 @@ def _get_parser():
global _parser
if not _parser:
- path = os.environ.get('AUR_CONFIG', '/etc/aurweb/config')
- defaults = os.environ.get('AUR_CONFIG_DEFAULTS', path + '.defaults')
+ path = os.environ.get("AUR_CONFIG", "/etc/aurweb/config")
+ defaults = os.environ.get("AUR_CONFIG_DEFAULTS", path + ".defaults")
_parser = configparser.RawConfigParser()
_parser.optionxform = lambda option: option
@@ -29,7 +28,7 @@ def _get_parser():
def rehash():
- """ Globally rehash the configuration parser. """
+ """Globally rehash the configuration parser."""
global _parser
_parser = None
_get_parser()
diff --git a/aurweb/cookies.py b/aurweb/cookies.py
index 58d14515..841e9adc 100644
--- a/aurweb/cookies.py
+++ b/aurweb/cookies.py
@@ -5,7 +5,7 @@ from aurweb import config
def samesite() -> str:
- """ Produce cookie SameSite value.
+ """Produce cookie SameSite value.
Currently this is hard-coded to return "lax"
@@ -15,7 +15,7 @@ def samesite() -> str:
def timeout(extended: bool) -> int:
- """ Produce a session timeout based on `remember_me`.
+ """Produce a session timeout based on `remember_me`.
This method returns one of AUR_CONFIG's options.persistent_cookie_timeout
and options.login_timeout based on the `extended` argument.
@@ -35,10 +35,14 @@ def timeout(extended: bool) -> int:
return timeout
-def update_response_cookies(request: Request, response: Response,
- aurtz: str = None, aurlang: str = None,
- aursid: str = None) -> Response:
- """ Update session cookies. This method is particularly useful
+def update_response_cookies(
+ request: Request,
+ response: Response,
+ aurtz: str = None,
+ aurlang: str = None,
+ aursid: str = None,
+) -> Response:
+ """Update session cookies. This method is particularly useful
when updating a cookie which was already set.
The AURSID cookie's expiration is based on the AURREMEMBER cookie,
@@ -53,14 +57,21 @@ def update_response_cookies(request: Request, response: Response,
"""
secure = config.getboolean("options", "disable_http_login")
if aurtz:
- response.set_cookie("AURTZ", aurtz, secure=secure, httponly=secure,
- samesite=samesite())
+ response.set_cookie(
+ "AURTZ", aurtz, secure=secure, httponly=secure, samesite=samesite()
+ )
if aurlang:
- response.set_cookie("AURLANG", aurlang, secure=secure, httponly=secure,
- samesite=samesite())
+ response.set_cookie(
+ "AURLANG", aurlang, secure=secure, httponly=secure, samesite=samesite()
+ )
if aursid:
remember_me = bool(request.cookies.get("AURREMEMBER", False))
- response.set_cookie("AURSID", aursid, secure=secure, httponly=secure,
- max_age=timeout(remember_me),
- samesite=samesite())
+ response.set_cookie(
+ "AURSID",
+ aursid,
+ secure=secure,
+ httponly=secure,
+ max_age=timeout(remember_me),
+ samesite=samesite(),
+ )
return response
diff --git a/aurweb/db.py b/aurweb/db.py
index 94514d35..7425d928 100644
--- a/aurweb/db.py
+++ b/aurweb/db.py
@@ -1,15 +1,14 @@
# Supported database drivers.
-DRIVERS = {
- "mysql": "mysql+mysqldb"
-}
+DRIVERS = {"mysql": "mysql+mysqldb"}
def make_random_value(table: str, column: str, length: int):
- """ Generate a unique, random value for a string column in a table.
+ """Generate a unique, random value for a string column in a table.
:return: A unique string that is not in the database
"""
import aurweb.util
+
string = aurweb.util.make_random_string(length)
while query(table).filter(column == string).first():
string = aurweb.util.make_random_string(length)
@@ -37,8 +36,7 @@ def test_name() -> str:
import aurweb.config
- db = os.environ.get("PYTEST_CURRENT_TEST",
- aurweb.config.get("database", "name"))
+ db = os.environ.get("PYTEST_CURRENT_TEST", aurweb.config.get("database", "name"))
return db.split(":")[0]
@@ -57,6 +55,7 @@ def name() -> str:
return dbname
import hashlib
+
sha1 = hashlib.sha1(dbname.encode()).hexdigest()
return "db" + sha1
@@ -67,7 +66,7 @@ _sessions = dict()
def get_session(engine=None):
- """ Return aurweb.db's global session. """
+ """Return aurweb.db's global session."""
dbname = name()
global _sessions
@@ -78,7 +77,8 @@ def get_session(engine=None):
engine = get_engine()
Session = scoped_session(
- sessionmaker(autocommit=True, autoflush=False, bind=engine))
+ sessionmaker(autocommit=True, autoflush=False, bind=engine)
+ )
_sessions[dbname] = Session()
return _sessions.get(dbname)
@@ -138,25 +138,26 @@ def delete(model) -> None:
def delete_all(iterable) -> None:
- """ Delete each instance found in `iterable`. """
+ """Delete each instance found in `iterable`."""
import aurweb.util
+
session_ = get_session()
aurweb.util.apply_all(iterable, session_.delete)
def rollback() -> None:
- """ Rollback the database session. """
+ """Rollback the database session."""
get_session().rollback()
def add(model):
- """ Add `model` to the database session. """
+ """Add `model` to the database session."""
get_session().add(model)
return model
def begin():
- """ Begin an SQLAlchemy SessionTransaction. """
+ """Begin an SQLAlchemy SessionTransaction."""
return get_session().begin()
@@ -167,62 +168,62 @@ def get_sqlalchemy_url():
:return: sqlalchemy.engine.url.URL
"""
import sqlalchemy
-
from sqlalchemy.engine.url import URL
import aurweb.config
constructor = URL
- parts = sqlalchemy.__version__.split('.')
+ parts = sqlalchemy.__version__.split(".")
major = int(parts[0])
minor = int(parts[1])
if major == 1 and minor >= 4: # pragma: no cover
constructor = URL.create
- aur_db_backend = aurweb.config.get('database', 'backend')
- if aur_db_backend == 'mysql':
+ aur_db_backend = aurweb.config.get("database", "backend")
+ if aur_db_backend == "mysql":
param_query = {}
port = aurweb.config.get_with_fallback("database", "port", None)
if not port:
- param_query["unix_socket"] = aurweb.config.get(
- "database", "socket")
+ param_query["unix_socket"] = aurweb.config.get("database", "socket")
return constructor(
DRIVERS.get(aur_db_backend),
- username=aurweb.config.get('database', 'user'),
- password=aurweb.config.get_with_fallback('database', 'password',
- fallback=None),
- host=aurweb.config.get('database', 'host'),
+ username=aurweb.config.get("database", "user"),
+ password=aurweb.config.get_with_fallback(
+ "database", "password", fallback=None
+ ),
+ host=aurweb.config.get("database", "host"),
database=name(),
port=port,
- query=param_query
+ query=param_query,
)
- elif aur_db_backend == 'sqlite':
+ elif aur_db_backend == "sqlite":
return constructor(
- 'sqlite',
- database=aurweb.config.get('database', 'name'),
+ "sqlite",
+ database=aurweb.config.get("database", "name"),
)
else:
- raise ValueError('unsupported database backend')
+ raise ValueError("unsupported database backend")
def sqlite_regexp(regex, item) -> bool: # pragma: no cover
- """ Method which mimics SQL's REGEXP for SQLite. """
+ """Method which mimics SQL's REGEXP for SQLite."""
import re
+
return bool(re.search(regex, str(item)))
def setup_sqlite(engine) -> None: # pragma: no cover
- """ Perform setup for an SQLite engine. """
+ """Perform setup for an SQLite engine."""
from sqlalchemy import event
@event.listens_for(engine, "connect")
def do_begin(conn, record):
import functools
+
create_deterministic_function = functools.partial(
- conn.create_function,
- deterministic=True
+ conn.create_function, deterministic=True
)
create_deterministic_function("REGEXP", 2, sqlite_regexp)
@@ -256,11 +257,9 @@ def get_engine(dbname: str = None, echo: bool = False):
if is_sqlite: # pragma: no cover
connect_args["check_same_thread"] = False
- kwargs = {
- "echo": echo,
- "connect_args": connect_args
- }
+ kwargs = {"echo": echo, "connect_args": connect_args}
from sqlalchemy import create_engine
+
_engines[dbname] = create_engine(get_sqlalchemy_url(), **kwargs)
if is_sqlite: # pragma: no cover
@@ -281,7 +280,7 @@ def pop_engine(dbname: str) -> None:
def kill_engine() -> None:
- """ Close the current session and dispose of the engine. """
+ """Close the current session and dispose of the engine."""
dbname = name()
session = get_session()
@@ -317,6 +316,7 @@ class ConnectionExecutor:
self._paramstyle = "format"
elif backend == "sqlite":
import sqlite3
+
self._paramstyle = sqlite3.paramstyle
def paramstyle(self):
@@ -325,12 +325,12 @@ class ConnectionExecutor:
def execute(self, query, params=()): # pragma: no cover
# TODO: SQLite support has been removed in FastAPI. It remains
# here to fund its support for PHP until it is removed.
- if self._paramstyle in ('format', 'pyformat'):
- query = query.replace('%', '%%').replace('?', '%s')
- elif self._paramstyle == 'qmark':
+ if self._paramstyle in ("format", "pyformat"):
+ query = query.replace("%", "%%").replace("?", "%s")
+ elif self._paramstyle == "qmark":
pass
else:
- raise ValueError('unsupported paramstyle')
+ raise ValueError("unsupported paramstyle")
cur = self._conn.cursor()
cur.execute(query, params)
@@ -350,32 +350,35 @@ class Connection:
def __init__(self):
import aurweb.config
- aur_db_backend = aurweb.config.get('database', 'backend')
- if aur_db_backend == 'mysql':
+ aur_db_backend = aurweb.config.get("database", "backend")
+
+ if aur_db_backend == "mysql":
import MySQLdb
- aur_db_host = aurweb.config.get('database', 'host')
+
+ aur_db_host = aurweb.config.get("database", "host")
aur_db_name = name()
- aur_db_user = aurweb.config.get('database', 'user')
- aur_db_pass = aurweb.config.get_with_fallback(
- 'database', 'password', str())
- aur_db_socket = aurweb.config.get('database', 'socket')
- self._conn = MySQLdb.connect(host=aur_db_host,
- user=aur_db_user,
- passwd=aur_db_pass,
- db=aur_db_name,
- unix_socket=aur_db_socket)
- elif aur_db_backend == 'sqlite': # pragma: no cover
+ aur_db_user = aurweb.config.get("database", "user")
+ aur_db_pass = aurweb.config.get_with_fallback("database", "password", str())
+ aur_db_socket = aurweb.config.get("database", "socket")
+ self._conn = MySQLdb.connect(
+ host=aur_db_host,
+ user=aur_db_user,
+ passwd=aur_db_pass,
+ db=aur_db_name,
+ unix_socket=aur_db_socket,
+ )
+ elif aur_db_backend == "sqlite": # pragma: no cover
# TODO: SQLite support has been removed in FastAPI. It remains
# here to fund its support for PHP until it is removed.
import math
import sqlite3
- aur_db_name = aurweb.config.get('database', 'name')
+ aur_db_name = aurweb.config.get("database", "name")
self._conn = sqlite3.connect(aur_db_name)
self._conn.create_function("POWER", 2, math.pow)
else:
- raise ValueError('unsupported database backend')
+ raise ValueError("unsupported database backend")
self._conn = ConnectionExecutor(self._conn, aur_db_backend)
diff --git a/aurweb/defaults.py b/aurweb/defaults.py
index 91ba367a..84d91c55 100644
--- a/aurweb/defaults.py
+++ b/aurweb/defaults.py
@@ -17,8 +17,8 @@ RPC_SEARCH_BY = "name-desc"
def fallback_pp(per_page: int) -> int:
- """ If `per_page` is a valid value in PP_WHITELIST, return it.
- Otherwise, return defaults.PP. """
+ """If `per_page` is a valid value in PP_WHITELIST, return it.
+ Otherwise, return defaults.PP."""
if per_page not in PP_WHITELIST:
return PP
return per_page
diff --git a/aurweb/exceptions.py b/aurweb/exceptions.py
index 30a3df08..e24eb607 100644
--- a/aurweb/exceptions.py
+++ b/aurweb/exceptions.py
@@ -1,5 +1,4 @@
import functools
-
from typing import Any, Callable
import fastapi
@@ -19,61 +18,61 @@ class BannedException(AurwebException):
class PermissionDeniedException(AurwebException):
def __init__(self, user):
- msg = 'permission denied: {:s}'.format(user)
+ msg = "permission denied: {:s}".format(user)
super(PermissionDeniedException, self).__init__(msg)
class BrokenUpdateHookException(AurwebException):
def __init__(self, cmd):
- msg = 'broken update hook: {:s}'.format(cmd)
+ msg = "broken update hook: {:s}".format(cmd)
super(BrokenUpdateHookException, self).__init__(msg)
class InvalidUserException(AurwebException):
def __init__(self, user):
- msg = 'unknown user: {:s}'.format(user)
+ msg = "unknown user: {:s}".format(user)
super(InvalidUserException, self).__init__(msg)
class InvalidPackageBaseException(AurwebException):
def __init__(self, pkgbase):
- msg = 'package base not found: {:s}'.format(pkgbase)
+ msg = "package base not found: {:s}".format(pkgbase)
super(InvalidPackageBaseException, self).__init__(msg)
class InvalidRepositoryNameException(AurwebException):
def __init__(self, pkgbase):
- msg = 'invalid repository name: {:s}'.format(pkgbase)
+ msg = "invalid repository name: {:s}".format(pkgbase)
super(InvalidRepositoryNameException, self).__init__(msg)
class PackageBaseExistsException(AurwebException):
def __init__(self, pkgbase):
- msg = 'package base already exists: {:s}'.format(pkgbase)
+ msg = "package base already exists: {:s}".format(pkgbase)
super(PackageBaseExistsException, self).__init__(msg)
class InvalidReasonException(AurwebException):
def __init__(self, reason):
- msg = 'invalid reason: {:s}'.format(reason)
+ msg = "invalid reason: {:s}".format(reason)
super(InvalidReasonException, self).__init__(msg)
class InvalidCommentException(AurwebException):
def __init__(self, comment):
- msg = 'comment is too short: {:s}'.format(comment)
+ msg = "comment is too short: {:s}".format(comment)
super(InvalidCommentException, self).__init__(msg)
class AlreadyVotedException(AurwebException):
def __init__(self, comment):
- msg = 'already voted for package base: {:s}'.format(comment)
+ msg = "already voted for package base: {:s}".format(comment)
super(AlreadyVotedException, self).__init__(msg)
class NotVotedException(AurwebException):
def __init__(self, comment):
- msg = 'missing vote for package base: {:s}'.format(comment)
+ msg = "missing vote for package base: {:s}".format(comment)
super(NotVotedException, self).__init__(msg)
@@ -109,4 +108,5 @@ def handle_form_exceptions(route: Callable) -> fastapi.Response:
async def wrapper(request: fastapi.Request, *args, **kwargs):
request.state.form_data = await request.form()
return await route(request, *args, **kwargs)
+
return wrapper
diff --git a/aurweb/filters.py b/aurweb/filters.py
index 22f65024..893f21af 100644
--- a/aurweb/filters.py
+++ b/aurweb/filters.py
@@ -1,6 +1,5 @@
import copy
import math
-
from datetime import datetime
from typing import Any, Union
from urllib.parse import quote_plus, urlencode
@@ -8,19 +7,16 @@ from zoneinfo import ZoneInfo
import fastapi
import paginate
-
from jinja2 import pass_context
import aurweb.models
-
from aurweb import config, l10n
from aurweb.templates import register_filter, register_function
@register_filter("pager_nav")
@pass_context
-def pager_nav(context: dict[str, Any],
- page: int, total: int, prefix: str) -> str:
+def pager_nav(context: dict[str, Any], page: int, total: int, prefix: str) -> str:
page = int(page) # Make sure this is an int.
pp = context.get("PP", 50)
@@ -43,10 +39,9 @@ def pager_nav(context: dict[str, Any],
return f"{prefix}?{qs}"
# Use the paginate module to produce our linkage.
- pager = paginate.Page([], page=page + 1,
- items_per_page=pp,
- item_count=total,
- url_maker=create_url)
+ pager = paginate.Page(
+ [], page=page + 1, items_per_page=pp, item_count=total, url_maker=create_url
+ )
return pager.pager(
link_attr={"class": "page"},
@@ -56,7 +51,8 @@ def pager_nav(context: dict[str, Any],
symbol_first="« First",
symbol_previous="‹ Previous",
symbol_next="Next ›",
- symbol_last="Last »")
+ symbol_last="Last »",
+ )
@register_function("config_getint")
@@ -72,16 +68,15 @@ def do_round(f: float) -> int:
@register_filter("tr")
@pass_context
def tr(context: dict[str, Any], value: str):
- """ A translation filter; example: {{ "Hello" | tr("de") }}. """
+ """A translation filter; example: {{ "Hello" | tr("de") }}."""
_ = l10n.get_translator_for_request(context.get("request"))
return _(value)
@register_filter("tn")
@pass_context
-def tn(context: dict[str, Any], count: int,
- singular: str, plural: str) -> str:
- """ A singular and plural translation filter.
+def tn(context: dict[str, Any], count: int, singular: str, plural: str) -> str:
+ """A singular and plural translation filter.
Example:
{{ some_integer | tn("singular %d", "plural %d") }}
@@ -108,7 +103,7 @@ def as_timezone(dt: datetime, timezone: str):
@register_filter("extend_query")
def extend_query(query: dict[str, Any], *additions) -> dict[str, Any]:
- """ Add additional key value pairs to query. """
+ """Add additional key value pairs to query."""
q = copy.copy(query)
for k, v in list(additions):
q[k] = v
@@ -123,19 +118,19 @@ def to_qs(query: dict[str, Any]) -> str:
@register_filter("get_vote")
def get_vote(voteinfo, request: fastapi.Request):
from aurweb.models import TUVote
+
return voteinfo.tu_votes.filter(TUVote.User == request.user).first()
@register_filter("number_format")
def number_format(value: float, places: int):
- """ A converter function similar to PHP's number_format. """
+ """A converter function similar to PHP's number_format."""
return f"{value:.{places}f}"
@register_filter("account_url")
@pass_context
-def account_url(context: dict[str, Any],
- user: "aurweb.models.user.User") -> str:
+def account_url(context: dict[str, Any], user: "aurweb.models.user.User") -> str:
base = aurweb.config.get("options", "aur_location")
return f"{base}/account/{user.Username}"
@@ -152,8 +147,7 @@ def ceil(*args, **kwargs) -> int:
@register_function("date_strftime")
@pass_context
-def date_strftime(context: dict[str, Any], dt: Union[int, datetime], fmt: str) \
- -> str:
+def date_strftime(context: dict[str, Any], dt: Union[int, datetime], fmt: str) -> str:
if isinstance(dt, int):
dt = timestamp_to_datetime(dt)
tz = context.get("timezone")
diff --git a/aurweb/git/auth.py b/aurweb/git/auth.py
index abecd276..759fce89 100755
--- a/aurweb/git/auth.py
+++ b/aurweb/git/auth.py
@@ -9,12 +9,12 @@ import aurweb.db
def format_command(env_vars, command, ssh_opts, ssh_key):
- environment = ''
+ environment = ""
for key, var in env_vars.items():
- environment += '{}={} '.format(key, shlex.quote(var))
+ environment += "{}={} ".format(key, shlex.quote(var))
command = shlex.quote(command)
- command = '{}{}'.format(environment, command)
+ command = "{}{}".format(environment, command)
# The command is being substituted into an authorized_keys line below,
# so we need to escape the double quotes.
@@ -24,10 +24,10 @@ def format_command(env_vars, command, ssh_opts, ssh_key):
def main():
- valid_keytypes = aurweb.config.get('auth', 'valid-keytypes').split()
- username_regex = aurweb.config.get('auth', 'username-regex')
- git_serve_cmd = aurweb.config.get('auth', 'git-serve-cmd')
- ssh_opts = aurweb.config.get('auth', 'ssh-options')
+ valid_keytypes = aurweb.config.get("auth", "valid-keytypes").split()
+ username_regex = aurweb.config.get("auth", "username-regex")
+ git_serve_cmd = aurweb.config.get("auth", "git-serve-cmd")
+ ssh_opts = aurweb.config.get("auth", "ssh-options")
keytype = sys.argv[1]
keytext = sys.argv[2]
@@ -36,11 +36,13 @@ def main():
conn = aurweb.db.Connection()
- cur = conn.execute("SELECT Users.Username, Users.AccountTypeID FROM Users "
- "INNER JOIN SSHPubKeys ON SSHPubKeys.UserID = Users.ID "
- "WHERE SSHPubKeys.PubKey = ? AND Users.Suspended = 0 "
- "AND NOT Users.Passwd = ''",
- (keytype + " " + keytext,))
+ cur = conn.execute(
+ "SELECT Users.Username, Users.AccountTypeID FROM Users "
+ "INNER JOIN SSHPubKeys ON SSHPubKeys.UserID = Users.ID "
+ "WHERE SSHPubKeys.PubKey = ? AND Users.Suspended = 0 "
+ "AND NOT Users.Passwd = ''",
+ (keytype + " " + keytext,),
+ )
row = cur.fetchone()
if not row or cur.fetchone():
@@ -51,13 +53,13 @@ def main():
exit(1)
env_vars = {
- 'AUR_USER': user,
- 'AUR_PRIVILEGED': '1' if account_type > 1 else '0',
+ "AUR_USER": user,
+ "AUR_PRIVILEGED": "1" if account_type > 1 else "0",
}
- key = keytype + ' ' + keytext
+ key = keytype + " " + keytext
print(format_command(env_vars, git_serve_cmd, ssh_opts, key))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/aurweb/git/serve.py b/aurweb/git/serve.py
index b91f1a13..a12b6d6e 100755
--- a/aurweb/git/serve.py
+++ b/aurweb/git/serve.py
@@ -11,16 +11,16 @@ import aurweb.config
import aurweb.db
import aurweb.exceptions
-notify_cmd = aurweb.config.get('notifications', 'notify-cmd')
+notify_cmd = aurweb.config.get("notifications", "notify-cmd")
-repo_path = aurweb.config.get('serve', 'repo-path')
-repo_regex = aurweb.config.get('serve', 'repo-regex')
-git_shell_cmd = aurweb.config.get('serve', 'git-shell-cmd')
-git_update_cmd = aurweb.config.get('serve', 'git-update-cmd')
-ssh_cmdline = aurweb.config.get('serve', 'ssh-cmdline')
+repo_path = aurweb.config.get("serve", "repo-path")
+repo_regex = aurweb.config.get("serve", "repo-regex")
+git_shell_cmd = aurweb.config.get("serve", "git-shell-cmd")
+git_update_cmd = aurweb.config.get("serve", "git-update-cmd")
+ssh_cmdline = aurweb.config.get("serve", "ssh-cmdline")
-enable_maintenance = aurweb.config.getboolean('options', 'enable-maintenance')
-maintenance_exc = aurweb.config.get('options', 'maintenance-exceptions').split()
+enable_maintenance = aurweb.config.getboolean("options", "enable-maintenance")
+maintenance_exc = aurweb.config.get("options", "maintenance-exceptions").split()
def pkgbase_from_name(pkgbase):
@@ -43,10 +43,12 @@ def list_repos(user):
if userid == 0:
raise aurweb.exceptions.InvalidUserException(user)
- cur = conn.execute("SELECT Name, PackagerUID FROM PackageBases " +
- "WHERE MaintainerUID = ?", [userid])
+ cur = conn.execute(
+ "SELECT Name, PackagerUID FROM PackageBases " + "WHERE MaintainerUID = ?",
+ [userid],
+ )
for row in cur:
- print((' ' if row[1] else '*') + row[0])
+ print((" " if row[1] else "*") + row[0])
conn.close()
@@ -64,15 +66,18 @@ def create_pkgbase(pkgbase, user):
raise aurweb.exceptions.InvalidUserException(user)
now = int(time.time())
- cur = conn.execute("INSERT INTO PackageBases (Name, SubmittedTS, " +
- "ModifiedTS, SubmitterUID, MaintainerUID, " +
- "FlaggerComment) VALUES (?, ?, ?, ?, ?, '')",
- [pkgbase, now, now, userid, userid])
+ cur = conn.execute(
+ "INSERT INTO PackageBases (Name, SubmittedTS, "
+ + "ModifiedTS, SubmitterUID, MaintainerUID, "
+ + "FlaggerComment) VALUES (?, ?, ?, ?, ?, '')",
+ [pkgbase, now, now, userid, userid],
+ )
pkgbase_id = cur.lastrowid
- cur = conn.execute("INSERT INTO PackageNotifications " +
- "(PackageBaseID, UserID) VALUES (?, ?)",
- [pkgbase_id, userid])
+ cur = conn.execute(
+ "INSERT INTO PackageNotifications " + "(PackageBaseID, UserID) VALUES (?, ?)",
+ [pkgbase_id, userid],
+ )
conn.commit()
conn.close()
@@ -85,8 +90,10 @@ def pkgbase_adopt(pkgbase, user, privileged):
conn = aurweb.db.Connection()
- cur = conn.execute("SELECT ID FROM PackageBases WHERE ID = ? AND " +
- "MaintainerUID IS NULL", [pkgbase_id])
+ cur = conn.execute(
+ "SELECT ID FROM PackageBases WHERE ID = ? AND " + "MaintainerUID IS NULL",
+ [pkgbase_id],
+ )
if not privileged and not cur.fetchone():
raise aurweb.exceptions.PermissionDeniedException(user)
@@ -95,19 +102,25 @@ def pkgbase_adopt(pkgbase, user, privileged):
if userid == 0:
raise aurweb.exceptions.InvalidUserException(user)
- cur = conn.execute("UPDATE PackageBases SET MaintainerUID = ? " +
- "WHERE ID = ?", [userid, pkgbase_id])
+ cur = conn.execute(
+ "UPDATE PackageBases SET MaintainerUID = ? " + "WHERE ID = ?",
+ [userid, pkgbase_id],
+ )
- cur = conn.execute("SELECT COUNT(*) FROM PackageNotifications WHERE " +
- "PackageBaseID = ? AND UserID = ?",
- [pkgbase_id, userid])
+ cur = conn.execute(
+ "SELECT COUNT(*) FROM PackageNotifications WHERE "
+ + "PackageBaseID = ? AND UserID = ?",
+ [pkgbase_id, userid],
+ )
if cur.fetchone()[0] == 0:
- cur = conn.execute("INSERT INTO PackageNotifications " +
- "(PackageBaseID, UserID) VALUES (?, ?)",
- [pkgbase_id, userid])
+ cur = conn.execute(
+ "INSERT INTO PackageNotifications "
+ + "(PackageBaseID, UserID) VALUES (?, ?)",
+ [pkgbase_id, userid],
+ )
conn.commit()
- subprocess.Popen((notify_cmd, 'adopt', str(userid), str(pkgbase_id)))
+ subprocess.Popen((notify_cmd, "adopt", str(userid), str(pkgbase_id)))
conn.close()
@@ -115,13 +128,16 @@ def pkgbase_adopt(pkgbase, user, privileged):
def pkgbase_get_comaintainers(pkgbase):
conn = aurweb.db.Connection()
- cur = conn.execute("SELECT UserName FROM PackageComaintainers " +
- "INNER JOIN Users " +
- "ON Users.ID = PackageComaintainers.UsersID " +
- "INNER JOIN PackageBases " +
- "ON PackageBases.ID = PackageComaintainers.PackageBaseID " +
- "WHERE PackageBases.Name = ? " +
- "ORDER BY Priority ASC", [pkgbase])
+ cur = conn.execute(
+ "SELECT UserName FROM PackageComaintainers "
+ + "INNER JOIN Users "
+ + "ON Users.ID = PackageComaintainers.UsersID "
+ + "INNER JOIN PackageBases "
+ + "ON PackageBases.ID = PackageComaintainers.PackageBaseID "
+ + "WHERE PackageBases.Name = ? "
+ + "ORDER BY Priority ASC",
+ [pkgbase],
+ )
return [row[0] for row in cur.fetchall()]
@@ -140,8 +156,7 @@ def pkgbase_set_comaintainers(pkgbase, userlist, user, privileged):
uids_old = set()
for olduser in userlist_old:
- cur = conn.execute("SELECT ID FROM Users WHERE Username = ?",
- [olduser])
+ cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [olduser])
userid = cur.fetchone()[0]
if userid == 0:
raise aurweb.exceptions.InvalidUserException(user)
@@ -149,8 +164,7 @@ def pkgbase_set_comaintainers(pkgbase, userlist, user, privileged):
uids_new = set()
for newuser in userlist:
- cur = conn.execute("SELECT ID FROM Users WHERE Username = ?",
- [newuser])
+ cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [newuser])
userid = cur.fetchone()[0]
if userid == 0:
raise aurweb.exceptions.InvalidUserException(user)
@@ -162,24 +176,33 @@ def pkgbase_set_comaintainers(pkgbase, userlist, user, privileged):
i = 1
for userid in uids_new:
if userid in uids_add:
- cur = conn.execute("INSERT INTO PackageComaintainers " +
- "(PackageBaseID, UsersID, Priority) " +
- "VALUES (?, ?, ?)", [pkgbase_id, userid, i])
- subprocess.Popen((notify_cmd, 'comaintainer-add', str(userid),
- str(pkgbase_id)))
+ cur = conn.execute(
+ "INSERT INTO PackageComaintainers "
+ + "(PackageBaseID, UsersID, Priority) "
+ + "VALUES (?, ?, ?)",
+ [pkgbase_id, userid, i],
+ )
+ subprocess.Popen(
+ (notify_cmd, "comaintainer-add", str(userid), str(pkgbase_id))
+ )
else:
- cur = conn.execute("UPDATE PackageComaintainers " +
- "SET Priority = ? " +
- "WHERE PackageBaseID = ? AND UsersID = ?",
- [i, pkgbase_id, userid])
+ cur = conn.execute(
+ "UPDATE PackageComaintainers "
+ + "SET Priority = ? "
+ + "WHERE PackageBaseID = ? AND UsersID = ?",
+ [i, pkgbase_id, userid],
+ )
i += 1
for userid in uids_rem:
- cur = conn.execute("DELETE FROM PackageComaintainers " +
- "WHERE PackageBaseID = ? AND UsersID = ?",
- [pkgbase_id, userid])
- subprocess.Popen((notify_cmd, 'comaintainer-remove',
- str(userid), str(pkgbase_id)))
+ cur = conn.execute(
+ "DELETE FROM PackageComaintainers "
+ + "WHERE PackageBaseID = ? AND UsersID = ?",
+ [pkgbase_id, userid],
+ )
+ subprocess.Popen(
+ (notify_cmd, "comaintainer-remove", str(userid), str(pkgbase_id))
+ )
conn.commit()
conn.close()
@@ -188,18 +211,21 @@ def pkgbase_set_comaintainers(pkgbase, userlist, user, privileged):
def pkgreq_by_pkgbase(pkgbase_id, reqtype):
conn = aurweb.db.Connection()
- cur = conn.execute("SELECT PackageRequests.ID FROM PackageRequests " +
- "INNER JOIN RequestTypes ON " +
- "RequestTypes.ID = PackageRequests.ReqTypeID " +
- "WHERE PackageRequests.Status = 0 " +
- "AND PackageRequests.PackageBaseID = ? " +
- "AND RequestTypes.Name = ?", [pkgbase_id, reqtype])
+ cur = conn.execute(
+ "SELECT PackageRequests.ID FROM PackageRequests "
+ + "INNER JOIN RequestTypes ON "
+ + "RequestTypes.ID = PackageRequests.ReqTypeID "
+ + "WHERE PackageRequests.Status = 0 "
+ + "AND PackageRequests.PackageBaseID = ? "
+ + "AND RequestTypes.Name = ?",
+ [pkgbase_id, reqtype],
+ )
return [row[0] for row in cur.fetchall()]
def pkgreq_close(reqid, user, reason, comments, autoclose=False):
- statusmap = {'accepted': 2, 'rejected': 3}
+ statusmap = {"accepted": 2, "rejected": 3}
if reason not in statusmap:
raise aurweb.exceptions.InvalidReasonException(reason)
status = statusmap[reason]
@@ -215,16 +241,20 @@ def pkgreq_close(reqid, user, reason, comments, autoclose=False):
raise aurweb.exceptions.InvalidUserException(user)
now = int(time.time())
- conn.execute("UPDATE PackageRequests SET Status = ?, ClosedTS = ?, " +
- "ClosedUID = ?, ClosureComment = ? " +
- "WHERE ID = ?", [status, now, userid, comments, reqid])
+ conn.execute(
+ "UPDATE PackageRequests SET Status = ?, ClosedTS = ?, "
+ + "ClosedUID = ?, ClosureComment = ? "
+ + "WHERE ID = ?",
+ [status, now, userid, comments, reqid],
+ )
conn.commit()
conn.close()
if not userid:
userid = 0
- subprocess.Popen((notify_cmd, 'request-close', str(userid), str(reqid),
- reason)).wait()
+ subprocess.Popen(
+ (notify_cmd, "request-close", str(userid), str(reqid), reason)
+ ).wait()
def pkgbase_disown(pkgbase, user, privileged):
@@ -239,9 +269,9 @@ def pkgbase_disown(pkgbase, user, privileged):
# TODO: Support disowning package bases via package request.
# Scan through pending orphan requests and close them.
- comment = 'The user {:s} disowned the package.'.format(user)
- for reqid in pkgreq_by_pkgbase(pkgbase_id, 'orphan'):
- pkgreq_close(reqid, user, 'accepted', comment, True)
+ comment = "The user {:s} disowned the package.".format(user)
+ for reqid in pkgreq_by_pkgbase(pkgbase_id, "orphan"):
+ pkgreq_close(reqid, user, "accepted", comment, True)
comaintainers = []
new_maintainer_userid = None
@@ -254,14 +284,17 @@ def pkgbase_disown(pkgbase, user, privileged):
comaintainers = pkgbase_get_comaintainers(pkgbase)
if len(comaintainers) > 0:
new_maintainer = comaintainers[0]
- cur = conn.execute("SELECT ID FROM Users WHERE Username = ?",
- [new_maintainer])
+ cur = conn.execute(
+ "SELECT ID FROM Users WHERE Username = ?", [new_maintainer]
+ )
new_maintainer_userid = cur.fetchone()[0]
comaintainers.remove(new_maintainer)
pkgbase_set_comaintainers(pkgbase, comaintainers, user, privileged)
- cur = conn.execute("UPDATE PackageBases SET MaintainerUID = ? " +
- "WHERE ID = ?", [new_maintainer_userid, pkgbase_id])
+ cur = conn.execute(
+ "UPDATE PackageBases SET MaintainerUID = ? " + "WHERE ID = ?",
+ [new_maintainer_userid, pkgbase_id],
+ )
conn.commit()
@@ -270,7 +303,7 @@ def pkgbase_disown(pkgbase, user, privileged):
if userid == 0:
raise aurweb.exceptions.InvalidUserException(user)
- subprocess.Popen((notify_cmd, 'disown', str(userid), str(pkgbase_id)))
+ subprocess.Popen((notify_cmd, "disown", str(userid), str(pkgbase_id)))
conn.close()
@@ -290,14 +323,16 @@ def pkgbase_flag(pkgbase, user, comment):
raise aurweb.exceptions.InvalidUserException(user)
now = int(time.time())
- conn.execute("UPDATE PackageBases SET " +
- "OutOfDateTS = ?, FlaggerUID = ?, FlaggerComment = ? " +
- "WHERE ID = ? AND OutOfDateTS IS NULL",
- [now, userid, comment, pkgbase_id])
+ conn.execute(
+ "UPDATE PackageBases SET "
+ + "OutOfDateTS = ?, FlaggerUID = ?, FlaggerComment = ? "
+ + "WHERE ID = ? AND OutOfDateTS IS NULL",
+ [now, userid, comment, pkgbase_id],
+ )
conn.commit()
- subprocess.Popen((notify_cmd, 'flag', str(userid), str(pkgbase_id)))
+ subprocess.Popen((notify_cmd, "flag", str(userid), str(pkgbase_id)))
def pkgbase_unflag(pkgbase, user):
@@ -313,12 +348,15 @@ def pkgbase_unflag(pkgbase, user):
raise aurweb.exceptions.InvalidUserException(user)
if user in pkgbase_get_comaintainers(pkgbase):
- conn.execute("UPDATE PackageBases SET OutOfDateTS = NULL " +
- "WHERE ID = ?", [pkgbase_id])
+ conn.execute(
+ "UPDATE PackageBases SET OutOfDateTS = NULL " + "WHERE ID = ?", [pkgbase_id]
+ )
else:
- conn.execute("UPDATE PackageBases SET OutOfDateTS = NULL " +
- "WHERE ID = ? AND (MaintainerUID = ? OR FlaggerUID = ?)",
- [pkgbase_id, userid, userid])
+ conn.execute(
+ "UPDATE PackageBases SET OutOfDateTS = NULL "
+ + "WHERE ID = ? AND (MaintainerUID = ? OR FlaggerUID = ?)",
+ [pkgbase_id, userid, userid],
+ )
conn.commit()
@@ -335,17 +373,24 @@ def pkgbase_vote(pkgbase, user):
if userid == 0:
raise aurweb.exceptions.InvalidUserException(user)
- cur = conn.execute("SELECT COUNT(*) FROM PackageVotes " +
- "WHERE UsersID = ? AND PackageBaseID = ?",
- [userid, pkgbase_id])
+ cur = conn.execute(
+ "SELECT COUNT(*) FROM PackageVotes "
+ + "WHERE UsersID = ? AND PackageBaseID = ?",
+ [userid, pkgbase_id],
+ )
if cur.fetchone()[0] > 0:
raise aurweb.exceptions.AlreadyVotedException(pkgbase)
now = int(time.time())
- conn.execute("INSERT INTO PackageVotes (UsersID, PackageBaseID, VoteTS) " +
- "VALUES (?, ?, ?)", [userid, pkgbase_id, now])
- conn.execute("UPDATE PackageBases SET NumVotes = NumVotes + 1 " +
- "WHERE ID = ?", [pkgbase_id])
+ conn.execute(
+ "INSERT INTO PackageVotes (UsersID, PackageBaseID, VoteTS) "
+ + "VALUES (?, ?, ?)",
+ [userid, pkgbase_id, now],
+ )
+ conn.execute(
+ "UPDATE PackageBases SET NumVotes = NumVotes + 1 " + "WHERE ID = ?",
+ [pkgbase_id],
+ )
conn.commit()
@@ -361,16 +406,22 @@ def pkgbase_unvote(pkgbase, user):
if userid == 0:
raise aurweb.exceptions.InvalidUserException(user)
- cur = conn.execute("SELECT COUNT(*) FROM PackageVotes " +
- "WHERE UsersID = ? AND PackageBaseID = ?",
- [userid, pkgbase_id])
+ cur = conn.execute(
+ "SELECT COUNT(*) FROM PackageVotes "
+ + "WHERE UsersID = ? AND PackageBaseID = ?",
+ [userid, pkgbase_id],
+ )
if cur.fetchone()[0] == 0:
raise aurweb.exceptions.NotVotedException(pkgbase)
- conn.execute("DELETE FROM PackageVotes WHERE UsersID = ? AND " +
- "PackageBaseID = ?", [userid, pkgbase_id])
- conn.execute("UPDATE PackageBases SET NumVotes = NumVotes - 1 " +
- "WHERE ID = ?", [pkgbase_id])
+ conn.execute(
+ "DELETE FROM PackageVotes WHERE UsersID = ? AND " + "PackageBaseID = ?",
+ [userid, pkgbase_id],
+ )
+ conn.execute(
+ "UPDATE PackageBases SET NumVotes = NumVotes - 1 " + "WHERE ID = ?",
+ [pkgbase_id],
+ )
conn.commit()
@@ -381,11 +432,12 @@ def pkgbase_set_keywords(pkgbase, keywords):
conn = aurweb.db.Connection()
- conn.execute("DELETE FROM PackageKeywords WHERE PackageBaseID = ?",
- [pkgbase_id])
+ conn.execute("DELETE FROM PackageKeywords WHERE PackageBaseID = ?", [pkgbase_id])
for keyword in keywords:
- conn.execute("INSERT INTO PackageKeywords (PackageBaseID, Keyword) " +
- "VALUES (?, ?)", [pkgbase_id, keyword])
+ conn.execute(
+ "INSERT INTO PackageKeywords (PackageBaseID, Keyword) " + "VALUES (?, ?)",
+ [pkgbase_id, keyword],
+ )
conn.commit()
conn.close()
@@ -394,24 +446,30 @@ def pkgbase_set_keywords(pkgbase, keywords):
def pkgbase_has_write_access(pkgbase, user):
conn = aurweb.db.Connection()
- cur = conn.execute("SELECT COUNT(*) FROM PackageBases " +
- "LEFT JOIN PackageComaintainers " +
- "ON PackageComaintainers.PackageBaseID = PackageBases.ID " +
- "INNER JOIN Users " +
- "ON Users.ID = PackageBases.MaintainerUID " +
- "OR PackageBases.MaintainerUID IS NULL " +
- "OR Users.ID = PackageComaintainers.UsersID " +
- "WHERE Name = ? AND Username = ?", [pkgbase, user])
+ cur = conn.execute(
+ "SELECT COUNT(*) FROM PackageBases "
+ + "LEFT JOIN PackageComaintainers "
+ + "ON PackageComaintainers.PackageBaseID = PackageBases.ID "
+ + "INNER JOIN Users "
+ + "ON Users.ID = PackageBases.MaintainerUID "
+ + "OR PackageBases.MaintainerUID IS NULL "
+ + "OR Users.ID = PackageComaintainers.UsersID "
+ + "WHERE Name = ? AND Username = ?",
+ [pkgbase, user],
+ )
return cur.fetchone()[0] > 0
def pkgbase_has_full_access(pkgbase, user):
conn = aurweb.db.Connection()
- cur = conn.execute("SELECT COUNT(*) FROM PackageBases " +
- "INNER JOIN Users " +
- "ON Users.ID = PackageBases.MaintainerUID " +
- "WHERE Name = ? AND Username = ?", [pkgbase, user])
+ cur = conn.execute(
+ "SELECT COUNT(*) FROM PackageBases "
+ + "INNER JOIN Users "
+ + "ON Users.ID = PackageBases.MaintainerUID "
+ + "WHERE Name = ? AND Username = ?",
+ [pkgbase, user],
+ )
return cur.fetchone()[0] > 0
@@ -419,9 +477,11 @@ def log_ssh_login(user, remote_addr):
conn = aurweb.db.Connection()
now = int(time.time())
- conn.execute("UPDATE Users SET LastSSHLogin = ?, " +
- "LastSSHLoginIPAddress = ? WHERE Username = ?",
- [now, remote_addr, user])
+ conn.execute(
+ "UPDATE Users SET LastSSHLogin = ?, "
+ + "LastSSHLoginIPAddress = ? WHERE Username = ?",
+ [now, remote_addr, user],
+ )
conn.commit()
conn.close()
@@ -430,8 +490,7 @@ def log_ssh_login(user, remote_addr):
def bans_match(remote_addr):
conn = aurweb.db.Connection()
- cur = conn.execute("SELECT COUNT(*) FROM Bans WHERE IPAddress = ?",
- [remote_addr])
+ cur = conn.execute("SELECT COUNT(*) FROM Bans WHERE IPAddress = ?", [remote_addr])
return cur.fetchone()[0] > 0
@@ -458,13 +517,13 @@ def usage(cmds):
def checkarg_atleast(cmdargv, *argdesc):
if len(cmdargv) - 1 < len(argdesc):
- msg = 'missing {:s}'.format(argdesc[len(cmdargv) - 1])
+ msg = "missing {:s}".format(argdesc[len(cmdargv) - 1])
raise aurweb.exceptions.InvalidArgumentsException(msg)
def checkarg_atmost(cmdargv, *argdesc):
if len(cmdargv) - 1 > len(argdesc):
- raise aurweb.exceptions.InvalidArgumentsException('too many arguments')
+ raise aurweb.exceptions.InvalidArgumentsException("too many arguments")
def checkarg(cmdargv, *argdesc):
@@ -480,23 +539,23 @@ def serve(action, cmdargv, user, privileged, remote_addr): # noqa: C901
raise aurweb.exceptions.BannedException
log_ssh_login(user, remote_addr)
- if action == 'git' and cmdargv[1] in ('upload-pack', 'receive-pack'):
- action = action + '-' + cmdargv[1]
+ if action == "git" and cmdargv[1] in ("upload-pack", "receive-pack"):
+ action = action + "-" + cmdargv[1]
del cmdargv[1]
- if action == 'git-upload-pack' or action == 'git-receive-pack':
- checkarg(cmdargv, 'path')
+ if action == "git-upload-pack" or action == "git-receive-pack":
+ checkarg(cmdargv, "path")
- path = cmdargv[1].rstrip('/')
- if not path.startswith('/'):
- path = '/' + path
- if not path.endswith('.git'):
- path = path + '.git'
+ path = cmdargv[1].rstrip("/")
+ if not path.startswith("/"):
+ path = "/" + path
+ if not path.endswith(".git"):
+ path = path + ".git"
pkgbase = path[1:-4]
if not re.match(repo_regex, pkgbase):
raise aurweb.exceptions.InvalidRepositoryNameException(pkgbase)
- if action == 'git-receive-pack' and pkgbase_exists(pkgbase):
+ if action == "git-receive-pack" and pkgbase_exists(pkgbase):
if not privileged and not pkgbase_has_write_access(pkgbase, user):
raise aurweb.exceptions.PermissionDeniedException(user)
@@ -507,65 +566,67 @@ def serve(action, cmdargv, user, privileged, remote_addr): # noqa: C901
os.environ["AUR_PKGBASE"] = pkgbase
os.environ["GIT_NAMESPACE"] = pkgbase
cmd = action + " '" + repo_path + "'"
- os.execl(git_shell_cmd, git_shell_cmd, '-c', cmd)
- elif action == 'set-keywords':
- checkarg_atleast(cmdargv, 'repository name')
+ os.execl(git_shell_cmd, git_shell_cmd, "-c", cmd)
+ elif action == "set-keywords":
+ checkarg_atleast(cmdargv, "repository name")
pkgbase_set_keywords(cmdargv[1], cmdargv[2:])
- elif action == 'list-repos':
+ elif action == "list-repos":
checkarg(cmdargv)
list_repos(user)
- elif action == 'setup-repo':
- checkarg(cmdargv, 'repository name')
- warn('{:s} is deprecated. '
- 'Use `git push` to create new repositories.'.format(action))
+ elif action == "setup-repo":
+ checkarg(cmdargv, "repository name")
+ warn(
+ "{:s} is deprecated. "
+ "Use `git push` to create new repositories.".format(action)
+ )
create_pkgbase(cmdargv[1], user)
- elif action == 'restore':
- checkarg(cmdargv, 'repository name')
+ elif action == "restore":
+ checkarg(cmdargv, "repository name")
pkgbase = cmdargv[1]
create_pkgbase(pkgbase, user)
os.environ["AUR_USER"] = user
os.environ["AUR_PKGBASE"] = pkgbase
- os.execl(git_update_cmd, git_update_cmd, 'restore')
- elif action == 'adopt':
- checkarg(cmdargv, 'repository name')
+ os.execl(git_update_cmd, git_update_cmd, "restore")
+ elif action == "adopt":
+ checkarg(cmdargv, "repository name")
pkgbase = cmdargv[1]
pkgbase_adopt(pkgbase, user, privileged)
- elif action == 'disown':
- checkarg(cmdargv, 'repository name')
+ elif action == "disown":
+ checkarg(cmdargv, "repository name")
pkgbase = cmdargv[1]
pkgbase_disown(pkgbase, user, privileged)
- elif action == 'flag':
- checkarg(cmdargv, 'repository name', 'comment')
+ elif action == "flag":
+ checkarg(cmdargv, "repository name", "comment")
pkgbase = cmdargv[1]
comment = cmdargv[2]
pkgbase_flag(pkgbase, user, comment)
- elif action == 'unflag':
- checkarg(cmdargv, 'repository name')
+ elif action == "unflag":
+ checkarg(cmdargv, "repository name")
pkgbase = cmdargv[1]
pkgbase_unflag(pkgbase, user)
- elif action == 'vote':
- checkarg(cmdargv, 'repository name')
+ elif action == "vote":
+ checkarg(cmdargv, "repository name")
pkgbase = cmdargv[1]
pkgbase_vote(pkgbase, user)
- elif action == 'unvote':
- checkarg(cmdargv, 'repository name')
+ elif action == "unvote":
+ checkarg(cmdargv, "repository name")
pkgbase = cmdargv[1]
pkgbase_unvote(pkgbase, user)
- elif action == 'set-comaintainers':
- checkarg_atleast(cmdargv, 'repository name')
+ elif action == "set-comaintainers":
+ checkarg_atleast(cmdargv, "repository name")
pkgbase = cmdargv[1]
userlist = cmdargv[2:]
pkgbase_set_comaintainers(pkgbase, userlist, user, privileged)
- elif action == 'help':
+ elif action == "help":
cmds = {
"adopt ": "Adopt a package base.",
"disown ": "Disown a package base.",
@@ -584,21 +645,21 @@ def serve(action, cmdargv, user, privileged, remote_addr): # noqa: C901
}
usage(cmds)
else:
- msg = 'invalid command: {:s}'.format(action)
+ msg = "invalid command: {:s}".format(action)
raise aurweb.exceptions.InvalidArgumentsException(msg)
def main():
- user = os.environ.get('AUR_USER')
- privileged = (os.environ.get('AUR_PRIVILEGED', '0') == '1')
- ssh_cmd = os.environ.get('SSH_ORIGINAL_COMMAND')
- ssh_client = os.environ.get('SSH_CLIENT')
+ user = os.environ.get("AUR_USER")
+ privileged = os.environ.get("AUR_PRIVILEGED", "0") == "1"
+ ssh_cmd = os.environ.get("SSH_ORIGINAL_COMMAND")
+ ssh_client = os.environ.get("SSH_CLIENT")
if not ssh_cmd:
die_with_help("Interactive shell is disabled.")
cmdargv = shlex.split(ssh_cmd)
action = cmdargv[0]
- remote_addr = ssh_client.split(' ')[0] if ssh_client else None
+ remote_addr = ssh_client.split(" ")[0] if ssh_client else None
try:
serve(action, cmdargv, user, privileged, remote_addr)
@@ -607,10 +668,10 @@ def main():
except aurweb.exceptions.BannedException:
die("The SSH interface is disabled for your IP address.")
except aurweb.exceptions.InvalidArgumentsException as e:
- die_with_help('{:s}: {}'.format(action, e))
+ die_with_help("{:s}: {}".format(action, e))
except aurweb.exceptions.AurwebException as e:
- die('{:s}: {}'.format(action, e))
+ die("{:s}: {}".format(action, e))
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/aurweb/git/update.py b/aurweb/git/update.py
index 2424bf6c..94a8d623 100755
--- a/aurweb/git/update.py
+++ b/aurweb/git/update.py
@@ -13,23 +13,23 @@ import srcinfo.utils
import aurweb.config
import aurweb.db
-notify_cmd = aurweb.config.get('notifications', 'notify-cmd')
+notify_cmd = aurweb.config.get("notifications", "notify-cmd")
-repo_path = aurweb.config.get('serve', 'repo-path')
-repo_regex = aurweb.config.get('serve', 'repo-regex')
+repo_path = aurweb.config.get("serve", "repo-path")
+repo_regex = aurweb.config.get("serve", "repo-regex")
-max_blob_size = aurweb.config.getint('update', 'max-blob-size')
+max_blob_size = aurweb.config.getint("update", "max-blob-size")
def size_humanize(num):
- for unit in ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB']:
+ for unit in ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB"]:
if abs(num) < 2048.0:
if isinstance(num, int):
return "{}{}".format(num, unit)
else:
return "{:.2f}{}".format(num, unit)
num /= 1024.0
- return "{:.2f}{}".format(num, 'YiB')
+ return "{:.2f}{}".format(num, "YiB")
def extract_arch_fields(pkginfo, field):
@@ -39,18 +39,18 @@ def extract_arch_fields(pkginfo, field):
for val in pkginfo[field]:
values.append({"value": val, "arch": None})
- for arch in pkginfo['arch']:
- if field + '_' + arch in pkginfo:
- for val in pkginfo[field + '_' + arch]:
+ for arch in pkginfo["arch"]:
+ if field + "_" + arch in pkginfo:
+ for val in pkginfo[field + "_" + arch]:
values.append({"value": val, "arch": arch})
return values
def parse_dep(depstring):
- dep, _, desc = depstring.partition(': ')
- depname = re.sub(r'(<|=|>).*', '', dep)
- depcond = dep[len(depname):]
+ dep, _, desc = depstring.partition(": ")
+ depname = re.sub(r"(<|=|>).*", "", dep)
+ depcond = dep[len(depname) :]
return (depname, desc, depcond)
@@ -60,15 +60,18 @@ def create_pkgbase(conn, pkgbase, user):
userid = cur.fetchone()[0]
now = int(time.time())
- cur = conn.execute("INSERT INTO PackageBases (Name, SubmittedTS, " +
- "ModifiedTS, SubmitterUID, MaintainerUID, " +
- "FlaggerComment) VALUES (?, ?, ?, ?, ?, '')",
- [pkgbase, now, now, userid, userid])
+ cur = conn.execute(
+ "INSERT INTO PackageBases (Name, SubmittedTS, "
+ + "ModifiedTS, SubmitterUID, MaintainerUID, "
+ + "FlaggerComment) VALUES (?, ?, ?, ?, ?, '')",
+ [pkgbase, now, now, userid, userid],
+ )
pkgbase_id = cur.lastrowid
- cur = conn.execute("INSERT INTO PackageNotifications " +
- "(PackageBaseID, UserID) VALUES (?, ?)",
- [pkgbase_id, userid])
+ cur = conn.execute(
+ "INSERT INTO PackageNotifications " + "(PackageBaseID, UserID) VALUES (?, ?)",
+ [pkgbase_id, userid],
+ )
conn.commit()
@@ -77,9 +80,10 @@ def create_pkgbase(conn, pkgbase, user):
def save_metadata(metadata, conn, user): # noqa: C901
# Obtain package base ID and previous maintainer.
- pkgbase = metadata['pkgbase']
- cur = conn.execute("SELECT ID, MaintainerUID FROM PackageBases "
- "WHERE Name = ?", [pkgbase])
+ pkgbase = metadata["pkgbase"]
+ cur = conn.execute(
+ "SELECT ID, MaintainerUID FROM PackageBases " "WHERE Name = ?", [pkgbase]
+ )
(pkgbase_id, maintainer_uid) = cur.fetchone()
was_orphan = not maintainer_uid
@@ -89,119 +93,142 @@ def save_metadata(metadata, conn, user): # noqa: C901
# Update package base details and delete current packages.
now = int(time.time())
- conn.execute("UPDATE PackageBases SET ModifiedTS = ?, " +
- "PackagerUID = ?, OutOfDateTS = NULL WHERE ID = ?",
- [now, user_id, pkgbase_id])
- conn.execute("UPDATE PackageBases SET MaintainerUID = ? " +
- "WHERE ID = ? AND MaintainerUID IS NULL",
- [user_id, pkgbase_id])
- for table in ('Sources', 'Depends', 'Relations', 'Licenses', 'Groups'):
- conn.execute("DELETE FROM Package" + table + " WHERE EXISTS (" +
- "SELECT * FROM Packages " +
- "WHERE Packages.PackageBaseID = ? AND " +
- "Package" + table + ".PackageID = Packages.ID)",
- [pkgbase_id])
+ conn.execute(
+ "UPDATE PackageBases SET ModifiedTS = ?, "
+ + "PackagerUID = ?, OutOfDateTS = NULL WHERE ID = ?",
+ [now, user_id, pkgbase_id],
+ )
+ conn.execute(
+ "UPDATE PackageBases SET MaintainerUID = ? "
+ + "WHERE ID = ? AND MaintainerUID IS NULL",
+ [user_id, pkgbase_id],
+ )
+ for table in ("Sources", "Depends", "Relations", "Licenses", "Groups"):
+ conn.execute(
+ "DELETE FROM Package"
+ + table
+ + " WHERE EXISTS ("
+ + "SELECT * FROM Packages "
+ + "WHERE Packages.PackageBaseID = ? AND "
+ + "Package"
+ + table
+ + ".PackageID = Packages.ID)",
+ [pkgbase_id],
+ )
conn.execute("DELETE FROM Packages WHERE PackageBaseID = ?", [pkgbase_id])
for pkgname in srcinfo.utils.get_package_names(metadata):
pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata)
- if 'epoch' in pkginfo and int(pkginfo['epoch']) > 0:
- ver = '{:d}:{:s}-{:s}'.format(int(pkginfo['epoch']),
- pkginfo['pkgver'],
- pkginfo['pkgrel'])
+ if "epoch" in pkginfo and int(pkginfo["epoch"]) > 0:
+ ver = "{:d}:{:s}-{:s}".format(
+ int(pkginfo["epoch"]), pkginfo["pkgver"], pkginfo["pkgrel"]
+ )
else:
- ver = '{:s}-{:s}'.format(pkginfo['pkgver'], pkginfo['pkgrel'])
+ ver = "{:s}-{:s}".format(pkginfo["pkgver"], pkginfo["pkgrel"])
- for field in ('pkgdesc', 'url'):
+ for field in ("pkgdesc", "url"):
if field not in pkginfo:
pkginfo[field] = None
# Create a new package.
- cur = conn.execute("INSERT INTO Packages (PackageBaseID, Name, " +
- "Version, Description, URL) " +
- "VALUES (?, ?, ?, ?, ?)",
- [pkgbase_id, pkginfo['pkgname'], ver,
- pkginfo['pkgdesc'], pkginfo['url']])
+ cur = conn.execute(
+ "INSERT INTO Packages (PackageBaseID, Name, "
+ + "Version, Description, URL) "
+ + "VALUES (?, ?, ?, ?, ?)",
+ [pkgbase_id, pkginfo["pkgname"], ver, pkginfo["pkgdesc"], pkginfo["url"]],
+ )
conn.commit()
pkgid = cur.lastrowid
# Add package sources.
- for source_info in extract_arch_fields(pkginfo, 'source'):
- conn.execute("INSERT INTO PackageSources (PackageID, Source, " +
- "SourceArch) VALUES (?, ?, ?)",
- [pkgid, source_info['value'], source_info['arch']])
+ for source_info in extract_arch_fields(pkginfo, "source"):
+ conn.execute(
+ "INSERT INTO PackageSources (PackageID, Source, "
+ + "SourceArch) VALUES (?, ?, ?)",
+ [pkgid, source_info["value"], source_info["arch"]],
+ )
# Add package dependencies.
- for deptype in ('depends', 'makedepends',
- 'checkdepends', 'optdepends'):
- cur = conn.execute("SELECT ID FROM DependencyTypes WHERE Name = ?",
- [deptype])
+ for deptype in ("depends", "makedepends", "checkdepends", "optdepends"):
+ cur = conn.execute(
+ "SELECT ID FROM DependencyTypes WHERE Name = ?", [deptype]
+ )
deptypeid = cur.fetchone()[0]
for dep_info in extract_arch_fields(pkginfo, deptype):
- depname, depdesc, depcond = parse_dep(dep_info['value'])
- deparch = dep_info['arch']
- conn.execute("INSERT INTO PackageDepends (PackageID, " +
- "DepTypeID, DepName, DepDesc, DepCondition, " +
- "DepArch) VALUES (?, ?, ?, ?, ?, ?)",
- [pkgid, deptypeid, depname, depdesc, depcond,
- deparch])
+ depname, depdesc, depcond = parse_dep(dep_info["value"])
+ deparch = dep_info["arch"]
+ conn.execute(
+ "INSERT INTO PackageDepends (PackageID, "
+ + "DepTypeID, DepName, DepDesc, DepCondition, "
+ + "DepArch) VALUES (?, ?, ?, ?, ?, ?)",
+ [pkgid, deptypeid, depname, depdesc, depcond, deparch],
+ )
# Add package relations (conflicts, provides, replaces).
- for reltype in ('conflicts', 'provides', 'replaces'):
- cur = conn.execute("SELECT ID FROM RelationTypes WHERE Name = ?",
- [reltype])
+ for reltype in ("conflicts", "provides", "replaces"):
+ cur = conn.execute("SELECT ID FROM RelationTypes WHERE Name = ?", [reltype])
reltypeid = cur.fetchone()[0]
for rel_info in extract_arch_fields(pkginfo, reltype):
- relname, _, relcond = parse_dep(rel_info['value'])
- relarch = rel_info['arch']
- conn.execute("INSERT INTO PackageRelations (PackageID, " +
- "RelTypeID, RelName, RelCondition, RelArch) " +
- "VALUES (?, ?, ?, ?, ?)",
- [pkgid, reltypeid, relname, relcond, relarch])
+ relname, _, relcond = parse_dep(rel_info["value"])
+ relarch = rel_info["arch"]
+ conn.execute(
+ "INSERT INTO PackageRelations (PackageID, "
+ + "RelTypeID, RelName, RelCondition, RelArch) "
+ + "VALUES (?, ?, ?, ?, ?)",
+ [pkgid, reltypeid, relname, relcond, relarch],
+ )
# Add package licenses.
- if 'license' in pkginfo:
- for license in pkginfo['license']:
- cur = conn.execute("SELECT ID FROM Licenses WHERE Name = ?",
- [license])
+ if "license" in pkginfo:
+ for license in pkginfo["license"]:
+ cur = conn.execute("SELECT ID FROM Licenses WHERE Name = ?", [license])
row = cur.fetchone()
if row:
licenseid = row[0]
else:
- cur = conn.execute("INSERT INTO Licenses (Name) " +
- "VALUES (?)", [license])
+ cur = conn.execute(
+ "INSERT INTO Licenses (Name) " + "VALUES (?)", [license]
+ )
conn.commit()
licenseid = cur.lastrowid
- conn.execute("INSERT INTO PackageLicenses (PackageID, " +
- "LicenseID) VALUES (?, ?)",
- [pkgid, licenseid])
+ conn.execute(
+ "INSERT INTO PackageLicenses (PackageID, "
+ + "LicenseID) VALUES (?, ?)",
+ [pkgid, licenseid],
+ )
# Add package groups.
- if 'groups' in pkginfo:
- for group in pkginfo['groups']:
- cur = conn.execute("SELECT ID FROM `Groups` WHERE Name = ?",
- [group])
+ if "groups" in pkginfo:
+ for group in pkginfo["groups"]:
+ cur = conn.execute("SELECT ID FROM `Groups` WHERE Name = ?", [group])
row = cur.fetchone()
if row:
groupid = row[0]
else:
- cur = conn.execute("INSERT INTO `Groups` (Name) VALUES (?)",
- [group])
+ cur = conn.execute(
+ "INSERT INTO `Groups` (Name) VALUES (?)", [group]
+ )
conn.commit()
groupid = cur.lastrowid
- conn.execute("INSERT INTO PackageGroups (PackageID, "
- "GroupID) VALUES (?, ?)", [pkgid, groupid])
+ conn.execute(
+ "INSERT INTO PackageGroups (PackageID, " "GroupID) VALUES (?, ?)",
+ [pkgid, groupid],
+ )
# Add user to notification list on adoption.
if was_orphan:
- cur = conn.execute("SELECT COUNT(*) FROM PackageNotifications WHERE " +
- "PackageBaseID = ? AND UserID = ?",
- [pkgbase_id, user_id])
+ cur = conn.execute(
+ "SELECT COUNT(*) FROM PackageNotifications WHERE "
+ + "PackageBaseID = ? AND UserID = ?",
+ [pkgbase_id, user_id],
+ )
if cur.fetchone()[0] == 0:
- conn.execute("INSERT INTO PackageNotifications " +
- "(PackageBaseID, UserID) VALUES (?, ?)",
- [pkgbase_id, user_id])
+ conn.execute(
+ "INSERT INTO PackageNotifications "
+ + "(PackageBaseID, UserID) VALUES (?, ?)",
+ [pkgbase_id, user_id],
+ )
conn.commit()
@@ -212,7 +239,7 @@ def update_notify(conn, user, pkgbase_id):
user_id = int(cur.fetchone()[0])
# Execute the notification script.
- subprocess.Popen((notify_cmd, 'update', str(user_id), str(pkgbase_id)))
+ subprocess.Popen((notify_cmd, "update", str(user_id), str(pkgbase_id)))
def die(msg):
@@ -225,8 +252,7 @@ def warn(msg):
def die_commit(msg, commit):
- sys.stderr.write("error: The following error " +
- "occurred when parsing commit\n")
+ sys.stderr.write("error: The following error " + "occurred when parsing commit\n")
sys.stderr.write("error: {:s}:\n".format(commit))
sys.stderr.write("error: {:s}\n".format(msg))
exit(1)
@@ -237,16 +263,15 @@ def main(): # noqa: C901
user = os.environ.get("AUR_USER")
pkgbase = os.environ.get("AUR_PKGBASE")
- privileged = (os.environ.get("AUR_PRIVILEGED", '0') == '1')
- allow_overwrite = (os.environ.get("AUR_OVERWRITE", '0') == '1') and privileged
+ privileged = os.environ.get("AUR_PRIVILEGED", "0") == "1"
+ allow_overwrite = (os.environ.get("AUR_OVERWRITE", "0") == "1") and privileged
warn_or_die = warn if privileged else die
if len(sys.argv) == 2 and sys.argv[1] == "restore":
- if 'refs/heads/' + pkgbase not in repo.listall_references():
- die('{:s}: repository not found: {:s}'.format(sys.argv[1],
- pkgbase))
+ if "refs/heads/" + pkgbase not in repo.listall_references():
+ die("{:s}: repository not found: {:s}".format(sys.argv[1], pkgbase))
refname = "refs/heads/master"
- branchref = 'refs/heads/' + pkgbase
+ branchref = "refs/heads/" + pkgbase
sha1_old = sha1_new = repo.lookup_reference(branchref).target
elif len(sys.argv) == 4:
refname, sha1_old, sha1_new = sys.argv[1:4]
@@ -272,7 +297,7 @@ def main(): # noqa: C901
# Validate all new commits.
for commit in walker:
- for fname in ('.SRCINFO', 'PKGBUILD'):
+ for fname in (".SRCINFO", "PKGBUILD"):
if fname not in commit.tree:
die_commit("missing {:s}".format(fname), str(commit.id))
@@ -280,99 +305,115 @@ def main(): # noqa: C901
blob = repo[treeobj.id]
if isinstance(blob, pygit2.Tree):
- die_commit("the repository must not contain subdirectories",
- str(commit.id))
+ die_commit(
+ "the repository must not contain subdirectories", str(commit.id)
+ )
if not isinstance(blob, pygit2.Blob):
- die_commit("not a blob object: {:s}".format(treeobj),
- str(commit.id))
+ die_commit("not a blob object: {:s}".format(treeobj), str(commit.id))
if blob.size > max_blob_size:
- die_commit("maximum blob size ({:s}) exceeded".format(
- size_humanize(max_blob_size)), str(commit.id))
+ die_commit(
+ "maximum blob size ({:s}) exceeded".format(
+ size_humanize(max_blob_size)
+ ),
+ str(commit.id),
+ )
- metadata_raw = repo[commit.tree['.SRCINFO'].id].data.decode()
+ metadata_raw = repo[commit.tree[".SRCINFO"].id].data.decode()
(metadata, errors) = srcinfo.parse.parse_srcinfo(metadata_raw)
if errors:
- sys.stderr.write("error: The following errors occurred "
- "when parsing .SRCINFO in commit\n")
+ sys.stderr.write(
+ "error: The following errors occurred "
+ "when parsing .SRCINFO in commit\n"
+ )
sys.stderr.write("error: {:s}:\n".format(str(commit.id)))
for error in errors:
- for err in error['error']:
- sys.stderr.write("error: line {:d}: {:s}\n".format(
- error['line'], err))
+ for err in error["error"]:
+ sys.stderr.write(
+ "error: line {:d}: {:s}\n".format(error["line"], err)
+ )
exit(1)
try:
- metadata_pkgbase = metadata['pkgbase']
+ metadata_pkgbase = metadata["pkgbase"]
except KeyError:
- die_commit('invalid .SRCINFO, does not contain a pkgbase (is the file empty?)',
- str(commit.id))
+ die_commit(
+ "invalid .SRCINFO, does not contain a pkgbase (is the file empty?)",
+ str(commit.id),
+ )
if not re.match(repo_regex, metadata_pkgbase):
- die_commit('invalid pkgbase: {:s}'.format(metadata_pkgbase),
- str(commit.id))
+ die_commit("invalid pkgbase: {:s}".format(metadata_pkgbase), str(commit.id))
- if not metadata['packages']:
- die_commit('missing pkgname entry', str(commit.id))
+ if not metadata["packages"]:
+ die_commit("missing pkgname entry", str(commit.id))
- for pkgname in set(metadata['packages'].keys()):
+ for pkgname in set(metadata["packages"].keys()):
pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata)
- for field in ('pkgver', 'pkgrel', 'pkgname'):
+ for field in ("pkgver", "pkgrel", "pkgname"):
if field not in pkginfo:
- die_commit('missing mandatory field: {:s}'.format(field),
- str(commit.id))
+ die_commit(
+ "missing mandatory field: {:s}".format(field), str(commit.id)
+ )
- if 'epoch' in pkginfo and not pkginfo['epoch'].isdigit():
- die_commit('invalid epoch: {:s}'.format(pkginfo['epoch']),
- str(commit.id))
+ if "epoch" in pkginfo and not pkginfo["epoch"].isdigit():
+ die_commit(
+ "invalid epoch: {:s}".format(pkginfo["epoch"]), str(commit.id)
+ )
- if not re.match(r'[a-z0-9][a-z0-9\.+_-]*$', pkginfo['pkgname']):
- die_commit('invalid package name: {:s}'.format(
- pkginfo['pkgname']), str(commit.id))
+ if not re.match(r"[a-z0-9][a-z0-9\.+_-]*$", pkginfo["pkgname"]):
+ die_commit(
+ "invalid package name: {:s}".format(pkginfo["pkgname"]),
+ str(commit.id),
+ )
- max_len = {'pkgname': 255, 'pkgdesc': 255, 'url': 8000}
+ max_len = {"pkgname": 255, "pkgdesc": 255, "url": 8000}
for field in max_len.keys():
if field in pkginfo and len(pkginfo[field]) > max_len[field]:
- die_commit('{:s} field too long: {:s}'.format(field,
- pkginfo[field]), str(commit.id))
+ die_commit(
+ "{:s} field too long: {:s}".format(field, pkginfo[field]),
+ str(commit.id),
+ )
- for field in ('install', 'changelog'):
+ for field in ("install", "changelog"):
if field in pkginfo and not pkginfo[field] in commit.tree:
- die_commit('missing {:s} file: {:s}'.format(field,
- pkginfo[field]), str(commit.id))
+ die_commit(
+ "missing {:s} file: {:s}".format(field, pkginfo[field]),
+ str(commit.id),
+ )
- for field in extract_arch_fields(pkginfo, 'source'):
- fname = field['value']
+ for field in extract_arch_fields(pkginfo, "source"):
+ fname = field["value"]
if len(fname) > 8000:
- die_commit('source entry too long: {:s}'.format(fname),
- str(commit.id))
+ die_commit(
+ "source entry too long: {:s}".format(fname), str(commit.id)
+ )
if "://" in fname or "lp:" in fname:
continue
if fname not in commit.tree:
- die_commit('missing source file: {:s}'.format(fname),
- str(commit.id))
+ die_commit(
+ "missing source file: {:s}".format(fname), str(commit.id)
+ )
# Display a warning if .SRCINFO is unchanged.
if sha1_old not in ("0000000000000000000000000000000000000000", sha1_new):
- srcinfo_id_old = repo[sha1_old].tree['.SRCINFO'].id
- srcinfo_id_new = repo[sha1_new].tree['.SRCINFO'].id
+ srcinfo_id_old = repo[sha1_old].tree[".SRCINFO"].id
+ srcinfo_id_new = repo[sha1_new].tree[".SRCINFO"].id
if srcinfo_id_old == srcinfo_id_new:
- warn(".SRCINFO unchanged. "
- "The package database will not be updated!")
+ warn(".SRCINFO unchanged. " "The package database will not be updated!")
# Read .SRCINFO from the HEAD commit.
- metadata_raw = repo[repo[sha1_new].tree['.SRCINFO'].id].data.decode()
+ metadata_raw = repo[repo[sha1_new].tree[".SRCINFO"].id].data.decode()
(metadata, errors) = srcinfo.parse.parse_srcinfo(metadata_raw)
# Ensure that the package base name matches the repository name.
- metadata_pkgbase = metadata['pkgbase']
+ metadata_pkgbase = metadata["pkgbase"]
if metadata_pkgbase != pkgbase:
- die('invalid pkgbase: {:s}, expected {:s}'.format(metadata_pkgbase,
- pkgbase))
+ die("invalid pkgbase: {:s}, expected {:s}".format(metadata_pkgbase, pkgbase))
# Ensure that packages are neither blacklisted nor overwritten.
- pkgbase = metadata['pkgbase']
+ pkgbase = metadata["pkgbase"]
cur = conn.execute("SELECT ID FROM PackageBases WHERE Name = ?", [pkgbase])
row = cur.fetchone()
pkgbase_id = row[0] if row else 0
@@ -385,18 +426,23 @@ def main(): # noqa: C901
for pkgname in srcinfo.utils.get_package_names(metadata):
pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata)
- pkgname = pkginfo['pkgname']
+ pkgname = pkginfo["pkgname"]
if pkgname in blacklist:
- warn_or_die('package is blacklisted: {:s}'.format(pkgname))
+ warn_or_die("package is blacklisted: {:s}".format(pkgname))
if pkgname in providers:
- warn_or_die('package already provided by [{:s}]: {:s}'.format(
- providers[pkgname], pkgname))
+ warn_or_die(
+ "package already provided by [{:s}]: {:s}".format(
+ providers[pkgname], pkgname
+ )
+ )
- cur = conn.execute("SELECT COUNT(*) FROM Packages WHERE Name = ? " +
- "AND PackageBaseID <> ?", [pkgname, pkgbase_id])
+ cur = conn.execute(
+ "SELECT COUNT(*) FROM Packages WHERE Name = ? " + "AND PackageBaseID <> ?",
+ [pkgname, pkgbase_id],
+ )
if cur.fetchone()[0] > 0:
- die('cannot overwrite package: {:s}'.format(pkgname))
+ die("cannot overwrite package: {:s}".format(pkgname))
# Create a new package base if it does not exist yet.
if pkgbase_id == 0:
@@ -407,7 +453,7 @@ def main(): # noqa: C901
# Create (or update) a branch with the name of the package base for better
# accessibility.
- branchref = 'refs/heads/' + pkgbase
+ branchref = "refs/heads/" + pkgbase
repo.create_reference(branchref, sha1_new, True)
# Work around a Git bug: The HEAD ref is not updated when using
@@ -415,7 +461,7 @@ def main(): # noqa: C901
# mainline. See
# http://git.661346.n2.nabble.com/PATCH-receive-pack-Create-a-HEAD-ref-for-ref-namespace-td7632149.html
# for details.
- headref = 'refs/namespaces/' + pkgbase + '/HEAD'
+ headref = "refs/namespaces/" + pkgbase + "/HEAD"
repo.create_reference(headref, sha1_new, True)
# Send package update notifications.
@@ -426,5 +472,5 @@ def main(): # noqa: C901
conn.close()
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/aurweb/initdb.py b/aurweb/initdb.py
index a4a9f621..ded4330d 100644
--- a/aurweb/initdb.py
+++ b/aurweb/initdb.py
@@ -9,28 +9,40 @@ import aurweb.schema
def feed_initial_data(conn):
- conn.execute(aurweb.schema.AccountTypes.insert(), [
- {'ID': 1, 'AccountType': 'User'},
- {'ID': 2, 'AccountType': 'Trusted User'},
- {'ID': 3, 'AccountType': 'Developer'},
- {'ID': 4, 'AccountType': 'Trusted User & Developer'},
- ])
- conn.execute(aurweb.schema.DependencyTypes.insert(), [
- {'ID': 1, 'Name': 'depends'},
- {'ID': 2, 'Name': 'makedepends'},
- {'ID': 3, 'Name': 'checkdepends'},
- {'ID': 4, 'Name': 'optdepends'},
- ])
- conn.execute(aurweb.schema.RelationTypes.insert(), [
- {'ID': 1, 'Name': 'conflicts'},
- {'ID': 2, 'Name': 'provides'},
- {'ID': 3, 'Name': 'replaces'},
- ])
- conn.execute(aurweb.schema.RequestTypes.insert(), [
- {'ID': 1, 'Name': 'deletion'},
- {'ID': 2, 'Name': 'orphan'},
- {'ID': 3, 'Name': 'merge'},
- ])
+ conn.execute(
+ aurweb.schema.AccountTypes.insert(),
+ [
+ {"ID": 1, "AccountType": "User"},
+ {"ID": 2, "AccountType": "Trusted User"},
+ {"ID": 3, "AccountType": "Developer"},
+ {"ID": 4, "AccountType": "Trusted User & Developer"},
+ ],
+ )
+ conn.execute(
+ aurweb.schema.DependencyTypes.insert(),
+ [
+ {"ID": 1, "Name": "depends"},
+ {"ID": 2, "Name": "makedepends"},
+ {"ID": 3, "Name": "checkdepends"},
+ {"ID": 4, "Name": "optdepends"},
+ ],
+ )
+ conn.execute(
+ aurweb.schema.RelationTypes.insert(),
+ [
+ {"ID": 1, "Name": "conflicts"},
+ {"ID": 2, "Name": "provides"},
+ {"ID": 3, "Name": "replaces"},
+ ],
+ )
+ conn.execute(
+ aurweb.schema.RequestTypes.insert(),
+ [
+ {"ID": 1, "Name": "deletion"},
+ {"ID": 2, "Name": "orphan"},
+ {"ID": 3, "Name": "merge"},
+ ],
+ )
def run(args):
@@ -40,8 +52,8 @@ def run(args):
# the last step and leave the database in an inconsistent state. The
# configuration is loaded lazily, so we query it to force its loading.
if args.use_alembic:
- alembic_config = alembic.config.Config('alembic.ini')
- alembic_config.get_main_option('script_location')
+ alembic_config = alembic.config.Config("alembic.ini")
+ alembic_config.get_main_option("script_location")
alembic_config.attributes["configure_logger"] = False
engine = aurweb.db.get_engine(echo=(args.verbose >= 1))
@@ -51,17 +63,21 @@ def run(args):
conn.close()
if args.use_alembic:
- alembic.command.stamp(alembic_config, 'head')
+ alembic.command.stamp(alembic_config, "head")
-if __name__ == '__main__':
+if __name__ == "__main__":
parser = argparse.ArgumentParser(
- prog='python -m aurweb.initdb',
- description='Initialize the aurweb database.')
- parser.add_argument('-v', '--verbose', action='count', default=0,
- help='increase verbosity')
- parser.add_argument('--no-alembic',
- help='disable Alembic migrations support',
- dest='use_alembic', action='store_false')
+ prog="python -m aurweb.initdb", description="Initialize the aurweb database."
+ )
+ parser.add_argument(
+ "-v", "--verbose", action="count", default=0, help="increase verbosity"
+ )
+ parser.add_argument(
+ "--no-alembic",
+ help="disable Alembic migrations support",
+ dest="use_alembic",
+ action="store_false",
+ )
args = parser.parse_args()
run(args)
diff --git a/aurweb/l10n.py b/aurweb/l10n.py
index 4998d8ee..2ef2c43e 100644
--- a/aurweb/l10n.py
+++ b/aurweb/l10n.py
@@ -1,43 +1,44 @@
import gettext
-
from collections import OrderedDict
from fastapi import Request
import aurweb.config
-SUPPORTED_LANGUAGES = OrderedDict({
- "ar": "العربية",
- "ast": "Asturianu",
- "ca": "Català",
- "cs": "Český",
- "da": "Dansk",
- "de": "Deutsch",
- "el": "Ελληνικά",
- "en": "English",
- "es": "Español",
- "es_419": "Español (Latinoamérica)",
- "fi": "Suomi",
- "fr": "Français",
- "he": "עברית",
- "hr": "Hrvatski",
- "hu": "Magyar",
- "it": "Italiano",
- "ja": "日本語",
- "nb": "Norsk",
- "nl": "Nederlands",
- "pl": "Polski",
- "pt_BR": "Português (Brasil)",
- "pt_PT": "Português (Portugal)",
- "ro": "Română",
- "ru": "Русский",
- "sk": "Slovenčina",
- "sr": "Srpski",
- "tr": "Türkçe",
- "uk": "Українська",
- "zh_CN": "简体中文",
- "zh_TW": "正體中文"
-})
+SUPPORTED_LANGUAGES = OrderedDict(
+ {
+ "ar": "العربية",
+ "ast": "Asturianu",
+ "ca": "Català",
+ "cs": "Český",
+ "da": "Dansk",
+ "de": "Deutsch",
+ "el": "Ελληνικά",
+ "en": "English",
+ "es": "Español",
+ "es_419": "Español (Latinoamérica)",
+ "fi": "Suomi",
+ "fr": "Français",
+ "he": "עברית",
+ "hr": "Hrvatski",
+ "hu": "Magyar",
+ "it": "Italiano",
+ "ja": "日本語",
+ "nb": "Norsk",
+ "nl": "Nederlands",
+ "pl": "Polski",
+ "pt_BR": "Português (Brasil)",
+ "pt_PT": "Português (Portugal)",
+ "ro": "Română",
+ "ru": "Русский",
+ "sk": "Slovenčina",
+ "sr": "Srpski",
+ "tr": "Türkçe",
+ "uk": "Українська",
+ "zh_CN": "简体中文",
+ "zh_TW": "正體中文",
+ }
+)
RIGHT_TO_LEFT_LANGUAGES = ("he", "ar")
@@ -45,15 +46,14 @@ RIGHT_TO_LEFT_LANGUAGES = ("he", "ar")
class Translator:
def __init__(self):
- self._localedir = aurweb.config.get('options', 'localedir')
+ self._localedir = aurweb.config.get("options", "localedir")
self._translator = {}
def get_translator(self, lang: str):
if lang not in self._translator:
- self._translator[lang] = gettext.translation("aurweb",
- self._localedir,
- languages=[lang],
- fallback=True)
+ self._translator[lang] = gettext.translation(
+ "aurweb", self._localedir, languages=[lang], fallback=True
+ )
return self._translator.get(lang)
def translate(self, s: str, lang: str):
diff --git a/aurweb/logging.py b/aurweb/logging.py
index 116421e4..d90edfdd 100644
--- a/aurweb/logging.py
+++ b/aurweb/logging.py
@@ -15,7 +15,7 @@ logging.getLogger("root").addHandler(logging.NullHandler())
def get_logger(name: str) -> logging.Logger:
- """ A logging.getLogger wrapper. Importing this function and
+ """A logging.getLogger wrapper. Importing this function and
using it to get a module-local logger ensures that logging.conf
initialization is performed wherever loggers are used.
diff --git a/aurweb/models/accepted_term.py b/aurweb/models/accepted_term.py
index 0f9b187e..022075e8 100644
--- a/aurweb/models/accepted_term.py
+++ b/aurweb/models/accepted_term.py
@@ -13,12 +13,16 @@ class AcceptedTerm(Base):
__mapper_args__ = {"primary_key": [__table__.c.TermsID]}
User = relationship(
- _User, backref=backref("accepted_terms", lazy="dynamic"),
- foreign_keys=[__table__.c.UsersID])
+ _User,
+ backref=backref("accepted_terms", lazy="dynamic"),
+ foreign_keys=[__table__.c.UsersID],
+ )
Term = relationship(
- _Term, backref=backref("accepted_terms", lazy="dynamic"),
- foreign_keys=[__table__.c.TermsID])
+ _Term,
+ backref=backref("accepted_terms", lazy="dynamic"),
+ foreign_keys=[__table__.c.TermsID],
+ )
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -27,10 +31,12 @@ class AcceptedTerm(Base):
raise IntegrityError(
statement="Foreign key UsersID cannot be null.",
orig="AcceptedTerms.UserID",
- params=("NULL"))
+ params=("NULL"),
+ )
if not self.Term and not self.TermsID:
raise IntegrityError(
statement="Foreign key TermID cannot be null.",
orig="AcceptedTerms.TermID",
- params=("NULL"))
+ params=("NULL"),
+ )
diff --git a/aurweb/models/account_type.py b/aurweb/models/account_type.py
index a849df02..315800a7 100644
--- a/aurweb/models/account_type.py
+++ b/aurweb/models/account_type.py
@@ -16,7 +16,7 @@ ACCOUNT_TYPE_ID = {
USER: USER_ID,
TRUSTED_USER: TRUSTED_USER_ID,
DEVELOPER: DEVELOPER_ID,
- TRUSTED_USER_AND_DEV: TRUSTED_USER_AND_DEV_ID
+ TRUSTED_USER_AND_DEV: TRUSTED_USER_AND_DEV_ID,
}
# Reversed ACCOUNT_TYPE_ID mapping.
@@ -24,7 +24,8 @@ ACCOUNT_TYPE_NAME = {v: k for k, v in ACCOUNT_TYPE_ID.items()}
class AccountType(Base):
- """ An ORM model of a single AccountTypes record. """
+ """An ORM model of a single AccountTypes record."""
+
__table__ = schema.AccountTypes
__tablename__ = __table__.name
__mapper_args__ = {"primary_key": [__table__.c.ID]}
@@ -36,5 +37,4 @@ class AccountType(Base):
return str(self.AccountType)
def __repr__(self):
- return "" % (
- self.ID, str(self))
+ return "" % (self.ID, str(self))
diff --git a/aurweb/models/api_rate_limit.py b/aurweb/models/api_rate_limit.py
index 19b656df..ce195a80 100644
--- a/aurweb/models/api_rate_limit.py
+++ b/aurweb/models/api_rate_limit.py
@@ -16,10 +16,12 @@ class ApiRateLimit(Base):
raise IntegrityError(
statement="Column Requests cannot be null.",
orig="ApiRateLimit.Requests",
- params=("NULL"))
+ params=("NULL"),
+ )
if self.WindowStart is None:
raise IntegrityError(
statement="Column WindowStart cannot be null.",
orig="ApiRateLimit.WindowStart",
- params=("NULL"))
+ params=("NULL"),
+ )
diff --git a/aurweb/models/declarative.py b/aurweb/models/declarative.py
index 20ddd20c..22df31c7 100644
--- a/aurweb/models/declarative.py
+++ b/aurweb/models/declarative.py
@@ -6,26 +6,19 @@ from aurweb import util
def to_dict(model):
- return {
- c.name: getattr(model, c.name)
- for c in model.__table__.columns
- }
+ return {c.name: getattr(model, c.name) for c in model.__table__.columns}
def to_json(model, indent: int = None):
- return json.dumps({
- k: util.jsonify(v)
- for k, v in to_dict(model).items()
- }, indent=indent)
+ return json.dumps(
+ {k: util.jsonify(v) for k, v in to_dict(model).items()}, indent=indent
+ )
Base = declarative_base()
# Setup __table_args__ applicable to every table.
-Base.__table_args__ = {
- "autoload": False,
- "extend_existing": True
-}
+Base.__table_args__ = {"autoload": False, "extend_existing": True}
# Setup Base.as_dict and Base.json.
#
diff --git a/aurweb/models/group.py b/aurweb/models/group.py
index 0275ed94..a6870db6 100644
--- a/aurweb/models/group.py
+++ b/aurweb/models/group.py
@@ -15,4 +15,5 @@ class Group(Base):
raise IntegrityError(
statement="Column Name cannot be null.",
orig="Groups.Name",
- params=("NULL"))
+ params=("NULL"),
+ )
diff --git a/aurweb/models/license.py b/aurweb/models/license.py
index 86aeaa86..f2b02a87 100644
--- a/aurweb/models/license.py
+++ b/aurweb/models/license.py
@@ -16,4 +16,5 @@ class License(Base):
raise IntegrityError(
statement="Column Name cannot be null.",
orig="Licenses.Name",
- params=("NULL"))
+ params=("NULL"),
+ )
diff --git a/aurweb/models/official_provider.py b/aurweb/models/official_provider.py
index e111569e..0da9f76c 100644
--- a/aurweb/models/official_provider.py
+++ b/aurweb/models/official_provider.py
@@ -21,16 +21,19 @@ class OfficialProvider(Base):
raise IntegrityError(
statement="Column Name cannot be null.",
orig="OfficialProviders.Name",
- params=("NULL"))
+ params=("NULL"),
+ )
if not self.Repo:
raise IntegrityError(
statement="Column Repo cannot be null.",
orig="OfficialProviders.Repo",
- params=("NULL"))
+ params=("NULL"),
+ )
if not self.Provides:
raise IntegrityError(
statement="Column Provides cannot be null.",
orig="OfficialProviders.Provides",
- params=("NULL"))
+ params=("NULL"),
+ )
diff --git a/aurweb/models/package.py b/aurweb/models/package.py
index 64c6a195..e98029f3 100644
--- a/aurweb/models/package.py
+++ b/aurweb/models/package.py
@@ -12,9 +12,10 @@ class Package(Base):
__mapper_args__ = {"primary_key": [__table__.c.ID]}
PackageBase = relationship(
- _PackageBase, backref=backref("packages", lazy="dynamic",
- cascade="all, delete"),
- foreign_keys=[__table__.c.PackageBaseID])
+ _PackageBase,
+ backref=backref("packages", lazy="dynamic", cascade="all, delete"),
+ foreign_keys=[__table__.c.PackageBaseID],
+ )
# No Package instances are official packages.
is_official = False
@@ -26,10 +27,12 @@ class Package(Base):
raise IntegrityError(
statement="Foreign key PackageBaseID cannot be null.",
orig="Packages.PackageBaseID",
- params=("NULL"))
+ params=("NULL"),
+ )
if self.Name is None:
raise IntegrityError(
statement="Column Name cannot be null.",
orig="Packages.Name",
- params=("NULL"))
+ params=("NULL"),
+ )
diff --git a/aurweb/models/package_base.py b/aurweb/models/package_base.py
index 37ad63ce..bf80233d 100644
--- a/aurweb/models/package_base.py
+++ b/aurweb/models/package_base.py
@@ -12,20 +12,28 @@ class PackageBase(Base):
__mapper_args__ = {"primary_key": [__table__.c.ID]}
Flagger = relationship(
- _User, backref=backref("flagged_bases", lazy="dynamic"),
- foreign_keys=[__table__.c.FlaggerUID])
+ _User,
+ backref=backref("flagged_bases", lazy="dynamic"),
+ foreign_keys=[__table__.c.FlaggerUID],
+ )
Submitter = relationship(
- _User, backref=backref("submitted_bases", lazy="dynamic"),
- foreign_keys=[__table__.c.SubmitterUID])
+ _User,
+ backref=backref("submitted_bases", lazy="dynamic"),
+ foreign_keys=[__table__.c.SubmitterUID],
+ )
Maintainer = relationship(
- _User, backref=backref("maintained_bases", lazy="dynamic"),
- foreign_keys=[__table__.c.MaintainerUID])
+ _User,
+ backref=backref("maintained_bases", lazy="dynamic"),
+ foreign_keys=[__table__.c.MaintainerUID],
+ )
Packager = relationship(
- _User, backref=backref("package_bases", lazy="dynamic"),
- foreign_keys=[__table__.c.PackagerUID])
+ _User,
+ backref=backref("package_bases", lazy="dynamic"),
+ foreign_keys=[__table__.c.PackagerUID],
+ )
# A set used to check for floatable values.
TO_FLOAT = {"Popularity"}
@@ -37,7 +45,8 @@ class PackageBase(Base):
raise IntegrityError(
statement="Column Name cannot be null.",
orig="PackageBases.Name",
- params=("NULL"))
+ params=("NULL"),
+ )
# If no SubmittedTS/ModifiedTS is provided on creation, set them
# here to the current utc timestamp.
diff --git a/aurweb/models/package_blacklist.py b/aurweb/models/package_blacklist.py
index 0f8f0cee..7f6e75ea 100644
--- a/aurweb/models/package_blacklist.py
+++ b/aurweb/models/package_blacklist.py
@@ -16,4 +16,5 @@ class PackageBlacklist(Base):
raise IntegrityError(
statement="Column Name cannot be null.",
orig="PackageBlacklist.Name",
- params=("NULL"))
+ params=("NULL"),
+ )
diff --git a/aurweb/models/package_comaintainer.py b/aurweb/models/package_comaintainer.py
index b5cdcf38..4bd7f6b3 100644
--- a/aurweb/models/package_comaintainer.py
+++ b/aurweb/models/package_comaintainer.py
@@ -10,19 +10,19 @@ from aurweb.models.user import User as _User
class PackageComaintainer(Base):
__table__ = schema.PackageComaintainers
__tablename__ = __table__.name
- __mapper_args__ = {
- "primary_key": [__table__.c.UsersID, __table__.c.PackageBaseID]
- }
+ __mapper_args__ = {"primary_key": [__table__.c.UsersID, __table__.c.PackageBaseID]}
User = relationship(
- _User, backref=backref("comaintained", lazy="dynamic",
- cascade="all, delete"),
- foreign_keys=[__table__.c.UsersID])
+ _User,
+ backref=backref("comaintained", lazy="dynamic", cascade="all, delete"),
+ foreign_keys=[__table__.c.UsersID],
+ )
PackageBase = relationship(
- _PackageBase, backref=backref("comaintainers", lazy="dynamic",
- cascade="all, delete"),
- foreign_keys=[__table__.c.PackageBaseID])
+ _PackageBase,
+ backref=backref("comaintainers", lazy="dynamic", cascade="all, delete"),
+ foreign_keys=[__table__.c.PackageBaseID],
+ )
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -31,16 +31,19 @@ class PackageComaintainer(Base):
raise IntegrityError(
statement="Foreign key UsersID cannot be null.",
orig="PackageComaintainers.UsersID",
- params=("NULL"))
+ params=("NULL"),
+ )
if not self.PackageBase and not self.PackageBaseID:
raise IntegrityError(
statement="Foreign key PackageBaseID cannot be null.",
orig="PackageComaintainers.PackageBaseID",
- params=("NULL"))
+ params=("NULL"),
+ )
if not self.Priority:
raise IntegrityError(
statement="Column Priority cannot be null.",
orig="PackageComaintainers.Priority",
- params=("NULL"))
+ params=("NULL"),
+ )
diff --git a/aurweb/models/package_comment.py b/aurweb/models/package_comment.py
index 7ab1f218..64b339a0 100644
--- a/aurweb/models/package_comment.py
+++ b/aurweb/models/package_comment.py
@@ -13,21 +13,28 @@ class PackageComment(Base):
__mapper_args__ = {"primary_key": [__table__.c.ID]}
PackageBase = relationship(
- _PackageBase, backref=backref("comments", lazy="dynamic",
- cascade="all, delete"),
- foreign_keys=[__table__.c.PackageBaseID])
+ _PackageBase,
+ backref=backref("comments", lazy="dynamic", cascade="all, delete"),
+ foreign_keys=[__table__.c.PackageBaseID],
+ )
User = relationship(
- _User, backref=backref("package_comments", lazy="dynamic"),
- foreign_keys=[__table__.c.UsersID])
+ _User,
+ backref=backref("package_comments", lazy="dynamic"),
+ foreign_keys=[__table__.c.UsersID],
+ )
Editor = relationship(
- _User, backref=backref("edited_comments", lazy="dynamic"),
- foreign_keys=[__table__.c.EditedUsersID])
+ _User,
+ backref=backref("edited_comments", lazy="dynamic"),
+ foreign_keys=[__table__.c.EditedUsersID],
+ )
Deleter = relationship(
- _User, backref=backref("deleted_comments", lazy="dynamic"),
- foreign_keys=[__table__.c.DelUsersID])
+ _User,
+ backref=backref("deleted_comments", lazy="dynamic"),
+ foreign_keys=[__table__.c.DelUsersID],
+ )
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -36,27 +43,31 @@ class PackageComment(Base):
raise IntegrityError(
statement="Foreign key PackageBaseID cannot be null.",
orig="PackageComments.PackageBaseID",
- params=("NULL"))
+ params=("NULL"),
+ )
if not self.User and not self.UsersID:
raise IntegrityError(
statement="Foreign key UsersID cannot be null.",
orig="PackageComments.UsersID",
- params=("NULL"))
+ params=("NULL"),
+ )
if self.Comments is None:
raise IntegrityError(
statement="Column Comments cannot be null.",
orig="PackageComments.Comments",
- params=("NULL"))
+ params=("NULL"),
+ )
if self.RenderedComment is None:
self.RenderedComment = str()
def maintainers(self):
- return list(filter(
- lambda e: e is not None,
- [self.PackageBase.Maintainer] + [
- c.User for c in self.PackageBase.comaintainers
- ]
- ))
+ return list(
+ filter(
+ lambda e: e is not None,
+ [self.PackageBase.Maintainer]
+ + [c.User for c in self.PackageBase.comaintainers],
+ )
+ )
diff --git a/aurweb/models/package_dependency.py b/aurweb/models/package_dependency.py
index 67a7717f..587ba68d 100644
--- a/aurweb/models/package_dependency.py
+++ b/aurweb/models/package_dependency.py
@@ -22,14 +22,16 @@ class PackageDependency(Base):
}
Package = relationship(
- _Package, backref=backref("package_dependencies", lazy="dynamic",
- cascade="all, delete"),
- foreign_keys=[__table__.c.PackageID])
+ _Package,
+ backref=backref("package_dependencies", lazy="dynamic", cascade="all, delete"),
+ foreign_keys=[__table__.c.PackageID],
+ )
DependencyType = relationship(
_DependencyType,
backref=backref("package_dependencies", lazy="dynamic"),
- foreign_keys=[__table__.c.DepTypeID])
+ foreign_keys=[__table__.c.DepTypeID],
+ )
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -38,43 +40,58 @@ class PackageDependency(Base):
raise IntegrityError(
statement="Foreign key PackageID cannot be null.",
orig="PackageDependencies.PackageID",
- params=("NULL"))
+ params=("NULL"),
+ )
if not self.DependencyType and not self.DepTypeID:
raise IntegrityError(
statement="Foreign key DepTypeID cannot be null.",
orig="PackageDependencies.DepTypeID",
- params=("NULL"))
+ params=("NULL"),
+ )
if self.DepName is None:
raise IntegrityError(
statement="Column DepName cannot be null.",
orig="PackageDependencies.DepName",
- params=("NULL"))
+ params=("NULL"),
+ )
def is_package(self) -> bool:
pkg = db.query(_Package).filter(_Package.Name == self.DepName).exists()
- official = db.query(_OfficialProvider).filter(
- _OfficialProvider.Name == self.DepName).exists()
+ official = (
+ db.query(_OfficialProvider)
+ .filter(_OfficialProvider.Name == self.DepName)
+ .exists()
+ )
return db.query(pkg).scalar() or db.query(official).scalar()
def provides(self) -> list[PackageRelation]:
from aurweb.models.relation_type import PROVIDES_ID
- rels = db.query(PackageRelation).join(_Package).filter(
- and_(PackageRelation.RelTypeID == PROVIDES_ID,
- PackageRelation.RelName == self.DepName)
- ).with_entities(
- _Package.Name,
- literal(False).label("is_official")
- ).order_by(_Package.Name.asc())
+ rels = (
+ db.query(PackageRelation)
+ .join(_Package)
+ .filter(
+ and_(
+ PackageRelation.RelTypeID == PROVIDES_ID,
+ PackageRelation.RelName == self.DepName,
+ )
+ )
+ .with_entities(_Package.Name, literal(False).label("is_official"))
+ .order_by(_Package.Name.asc())
+ )
- official_rels = db.query(_OfficialProvider).filter(
- and_(_OfficialProvider.Provides == self.DepName,
- _OfficialProvider.Name != self.DepName)
- ).with_entities(
- _OfficialProvider.Name,
- literal(True).label("is_official")
- ).order_by(_OfficialProvider.Name.asc())
+ official_rels = (
+ db.query(_OfficialProvider)
+ .filter(
+ and_(
+ _OfficialProvider.Provides == self.DepName,
+ _OfficialProvider.Name != self.DepName,
+ )
+ )
+ .with_entities(_OfficialProvider.Name, literal(True).label("is_official"))
+ .order_by(_OfficialProvider.Name.asc())
+ )
return rels.union(official_rels).all()
diff --git a/aurweb/models/package_group.py b/aurweb/models/package_group.py
index dd212051..4e7c55ee 100644
--- a/aurweb/models/package_group.py
+++ b/aurweb/models/package_group.py
@@ -10,19 +10,19 @@ from aurweb.models.package import Package as _Package
class PackageGroup(Base):
__table__ = schema.PackageGroups
__tablename__ = __table__.name
- __mapper_args__ = {
- "primary_key": [__table__.c.PackageID, __table__.c.GroupID]
- }
+ __mapper_args__ = {"primary_key": [__table__.c.PackageID, __table__.c.GroupID]}
Package = relationship(
- _Package, backref=backref("package_groups", lazy="dynamic",
- cascade="all, delete"),
- foreign_keys=[__table__.c.PackageID])
+ _Package,
+ backref=backref("package_groups", lazy="dynamic", cascade="all, delete"),
+ foreign_keys=[__table__.c.PackageID],
+ )
Group = relationship(
- _Group, backref=backref("package_groups", lazy="dynamic",
- cascade="all, delete"),
- foreign_keys=[__table__.c.GroupID])
+ _Group,
+ backref=backref("package_groups", lazy="dynamic", cascade="all, delete"),
+ foreign_keys=[__table__.c.GroupID],
+ )
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -31,10 +31,12 @@ class PackageGroup(Base):
raise IntegrityError(
statement="Primary key PackageID cannot be null.",
orig="PackageGroups.PackageID",
- params=("NULL"))
+ params=("NULL"),
+ )
if not self.Group and not self.GroupID:
raise IntegrityError(
statement="Primary key GroupID cannot be null.",
orig="PackageGroups.GroupID",
- params=("NULL"))
+ params=("NULL"),
+ )
diff --git a/aurweb/models/package_keyword.py b/aurweb/models/package_keyword.py
index 581aafdc..dfacd7c0 100644
--- a/aurweb/models/package_keyword.py
+++ b/aurweb/models/package_keyword.py
@@ -9,14 +9,13 @@ from aurweb.models.package_base import PackageBase as _PackageBase
class PackageKeyword(Base):
__table__ = schema.PackageKeywords
__tablename__ = __table__.name
- __mapper_args__ = {
- "primary_key": [__table__.c.PackageBaseID, __table__.c.Keyword]
- }
+ __mapper_args__ = {"primary_key": [__table__.c.PackageBaseID, __table__.c.Keyword]}
PackageBase = relationship(
- _PackageBase, backref=backref("keywords", lazy="dynamic",
- cascade="all, delete"),
- foreign_keys=[__table__.c.PackageBaseID])
+ _PackageBase,
+ backref=backref("keywords", lazy="dynamic", cascade="all, delete"),
+ foreign_keys=[__table__.c.PackageBaseID],
+ )
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -25,4 +24,5 @@ class PackageKeyword(Base):
raise IntegrityError(
statement="Primary key PackageBaseID cannot be null.",
orig="PackageKeywords.PackageBaseID",
- params=("NULL"))
+ params=("NULL"),
+ )
diff --git a/aurweb/models/package_license.py b/aurweb/models/package_license.py
index 43dd0339..c421defe 100644
--- a/aurweb/models/package_license.py
+++ b/aurweb/models/package_license.py
@@ -10,19 +10,19 @@ from aurweb.models.package import Package as _Package
class PackageLicense(Base):
__table__ = schema.PackageLicenses
__tablename__ = __table__.name
- __mapper_args__ = {
- "primary_key": [__table__.c.PackageID, __table__.c.LicenseID]
- }
+ __mapper_args__ = {"primary_key": [__table__.c.PackageID, __table__.c.LicenseID]}
Package = relationship(
- _Package, backref=backref("package_licenses", lazy="dynamic",
- cascade="all, delete"),
- foreign_keys=[__table__.c.PackageID])
+ _Package,
+ backref=backref("package_licenses", lazy="dynamic", cascade="all, delete"),
+ foreign_keys=[__table__.c.PackageID],
+ )
License = relationship(
- _License, backref=backref("package_licenses", lazy="dynamic",
- cascade="all, delete"),
- foreign_keys=[__table__.c.LicenseID])
+ _License,
+ backref=backref("package_licenses", lazy="dynamic", cascade="all, delete"),
+ foreign_keys=[__table__.c.LicenseID],
+ )
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -31,10 +31,12 @@ class PackageLicense(Base):
raise IntegrityError(
statement="Primary key PackageID cannot be null.",
orig="PackageLicenses.PackageID",
- params=("NULL"))
+ params=("NULL"),
+ )
if not self.License and not self.LicenseID:
raise IntegrityError(
statement="Primary key LicenseID cannot be null.",
orig="PackageLicenses.LicenseID",
- params=("NULL"))
+ params=("NULL"),
+ )
diff --git a/aurweb/models/package_notification.py b/aurweb/models/package_notification.py
index 327b92a6..7d5489d4 100644
--- a/aurweb/models/package_notification.py
+++ b/aurweb/models/package_notification.py
@@ -10,20 +10,19 @@ from aurweb.models.user import User as _User
class PackageNotification(Base):
__table__ = schema.PackageNotifications
__tablename__ = __table__.name
- __mapper_args__ = {
- "primary_key": [__table__.c.UserID, __table__.c.PackageBaseID]
- }
+ __mapper_args__ = {"primary_key": [__table__.c.UserID, __table__.c.PackageBaseID]}
User = relationship(
- _User, backref=backref("notifications", lazy="dynamic",
- cascade="all, delete"),
- foreign_keys=[__table__.c.UserID])
+ _User,
+ backref=backref("notifications", lazy="dynamic", cascade="all, delete"),
+ foreign_keys=[__table__.c.UserID],
+ )
PackageBase = relationship(
_PackageBase,
- backref=backref("notifications", lazy="dynamic",
- cascade="all, delete"),
- foreign_keys=[__table__.c.PackageBaseID])
+ backref=backref("notifications", lazy="dynamic", cascade="all, delete"),
+ foreign_keys=[__table__.c.PackageBaseID],
+ )
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -32,10 +31,12 @@ class PackageNotification(Base):
raise IntegrityError(
statement="Foreign key UserID cannot be null.",
orig="PackageNotifications.UserID",
- params=("NULL"))
+ params=("NULL"),
+ )
if not self.PackageBase and not self.PackageBaseID:
raise IntegrityError(
statement="Foreign key PackageBaseID cannot be null.",
orig="PackageNotifications.PackageBaseID",
- params=("NULL"))
+ params=("NULL"),
+ )
diff --git a/aurweb/models/package_relation.py b/aurweb/models/package_relation.py
index 4910934d..60988a56 100644
--- a/aurweb/models/package_relation.py
+++ b/aurweb/models/package_relation.py
@@ -19,13 +19,16 @@ class PackageRelation(Base):
}
Package = relationship(
- _Package, backref=backref("package_relations", lazy="dynamic",
- cascade="all, delete"),
- foreign_keys=[__table__.c.PackageID])
+ _Package,
+ backref=backref("package_relations", lazy="dynamic", cascade="all, delete"),
+ foreign_keys=[__table__.c.PackageID],
+ )
RelationType = relationship(
- _RelationType, backref=backref("package_relations", lazy="dynamic"),
- foreign_keys=[__table__.c.RelTypeID])
+ _RelationType,
+ backref=backref("package_relations", lazy="dynamic"),
+ foreign_keys=[__table__.c.RelTypeID],
+ )
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -34,16 +37,19 @@ class PackageRelation(Base):
raise IntegrityError(
statement="Foreign key PackageID cannot be null.",
orig="PackageRelations.PackageID",
- params=("NULL"))
+ params=("NULL"),
+ )
if not self.RelationType and not self.RelTypeID:
raise IntegrityError(
statement="Foreign key RelTypeID cannot be null.",
orig="PackageRelations.RelTypeID",
- params=("NULL"))
+ params=("NULL"),
+ )
if not self.RelName:
raise IntegrityError(
statement="Column RelName cannot be null.",
orig="PackageRelations.RelName",
- params=("NULL"))
+ params=("NULL"),
+ )
diff --git a/aurweb/models/package_request.py b/aurweb/models/package_request.py
index 9669ec46..31071df4 100644
--- a/aurweb/models/package_request.py
+++ b/aurweb/models/package_request.py
@@ -25,26 +25,34 @@ class PackageRequest(Base):
__mapper_args__ = {"primary_key": [__table__.c.ID]}
RequestType = relationship(
- _RequestType, backref=backref("package_requests", lazy="dynamic"),
- foreign_keys=[__table__.c.ReqTypeID])
+ _RequestType,
+ backref=backref("package_requests", lazy="dynamic"),
+ foreign_keys=[__table__.c.ReqTypeID],
+ )
User = relationship(
- _User, backref=backref("package_requests", lazy="dynamic"),
- foreign_keys=[__table__.c.UsersID])
+ _User,
+ backref=backref("package_requests", lazy="dynamic"),
+ foreign_keys=[__table__.c.UsersID],
+ )
PackageBase = relationship(
- _PackageBase, backref=backref("requests", lazy="dynamic"),
- foreign_keys=[__table__.c.PackageBaseID])
+ _PackageBase,
+ backref=backref("requests", lazy="dynamic"),
+ foreign_keys=[__table__.c.PackageBaseID],
+ )
Closer = relationship(
- _User, backref=backref("closed_requests", lazy="dynamic"),
- foreign_keys=[__table__.c.ClosedUID])
+ _User,
+ backref=backref("closed_requests", lazy="dynamic"),
+ foreign_keys=[__table__.c.ClosedUID],
+ )
STATUS_DISPLAY = {
PENDING_ID: PENDING,
CLOSED_ID: CLOSED,
ACCEPTED_ID: ACCEPTED,
- REJECTED_ID: REJECTED
+ REJECTED_ID: REJECTED,
}
def __init__(self, **kwargs):
@@ -54,38 +62,44 @@ class PackageRequest(Base):
raise IntegrityError(
statement="Foreign key ReqTypeID cannot be null.",
orig="PackageRequests.ReqTypeID",
- params=("NULL"))
+ params=("NULL"),
+ )
if not self.PackageBase and not self.PackageBaseID:
raise IntegrityError(
statement="Foreign key PackageBaseID cannot be null.",
orig="PackageRequests.PackageBaseID",
- params=("NULL"))
+ params=("NULL"),
+ )
if not self.PackageBaseName:
raise IntegrityError(
statement="Column PackageBaseName cannot be null.",
orig="PackageRequests.PackageBaseName",
- params=("NULL"))
+ params=("NULL"),
+ )
if not self.User and not self.UsersID:
raise IntegrityError(
statement="Foreign key UsersID cannot be null.",
orig="PackageRequests.UsersID",
- params=("NULL"))
+ params=("NULL"),
+ )
if self.Comments is None:
raise IntegrityError(
statement="Column Comments cannot be null.",
orig="PackageRequests.Comments",
- params=("NULL"))
+ params=("NULL"),
+ )
if self.ClosureComment is None:
raise IntegrityError(
statement="Column ClosureComment cannot be null.",
orig="PackageRequests.ClosureComment",
- params=("NULL"))
+ params=("NULL"),
+ )
def status_display(self) -> str:
- """ Return a display string for the Status column. """
+ """Return a display string for the Status column."""
return self.STATUS_DISPLAY[self.Status]
diff --git a/aurweb/models/package_source.py b/aurweb/models/package_source.py
index 4ea1645b..a6d0f958 100644
--- a/aurweb/models/package_source.py
+++ b/aurweb/models/package_source.py
@@ -9,17 +9,13 @@ from aurweb.models.package import Package as _Package
class PackageSource(Base):
__table__ = schema.PackageSources
__tablename__ = __table__.name
- __mapper_args__ = {
- "primary_key": [
- __table__.c.PackageID,
- __table__.c.Source
- ]
- }
+ __mapper_args__ = {"primary_key": [__table__.c.PackageID, __table__.c.Source]}
Package = relationship(
- _Package, backref=backref("package_sources", lazy="dynamic",
- cascade="all, delete"),
- foreign_keys=[__table__.c.PackageID])
+ _Package,
+ backref=backref("package_sources", lazy="dynamic", cascade="all, delete"),
+ foreign_keys=[__table__.c.PackageID],
+ )
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -28,7 +24,8 @@ class PackageSource(Base):
raise IntegrityError(
statement="Foreign key PackageID cannot be null.",
orig="PackageSources.PackageID",
- params=("NULL"))
+ params=("NULL"),
+ )
if not self.Source:
self.Source = "/dev/null"
diff --git a/aurweb/models/package_vote.py b/aurweb/models/package_vote.py
index 8da88210..fa769bb6 100644
--- a/aurweb/models/package_vote.py
+++ b/aurweb/models/package_vote.py
@@ -10,18 +10,19 @@ from aurweb.models.user import User as _User
class PackageVote(Base):
__table__ = schema.PackageVotes
__tablename__ = __table__.name
- __mapper_args__ = {
- "primary_key": [__table__.c.UsersID, __table__.c.PackageBaseID]
- }
+ __mapper_args__ = {"primary_key": [__table__.c.UsersID, __table__.c.PackageBaseID]}
User = relationship(
- _User, backref=backref("package_votes", lazy="dynamic"),
- foreign_keys=[__table__.c.UsersID])
+ _User,
+ backref=backref("package_votes", lazy="dynamic"),
+ foreign_keys=[__table__.c.UsersID],
+ )
PackageBase = relationship(
- _PackageBase, backref=backref("package_votes", lazy="dynamic",
- cascade="all, delete"),
- foreign_keys=[__table__.c.PackageBaseID])
+ _PackageBase,
+ backref=backref("package_votes", lazy="dynamic", cascade="all, delete"),
+ foreign_keys=[__table__.c.PackageBaseID],
+ )
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -30,16 +31,19 @@ class PackageVote(Base):
raise IntegrityError(
statement="Foreign key UsersID cannot be null.",
orig="PackageVotes.UsersID",
- params=("NULL"))
+ params=("NULL"),
+ )
if not self.PackageBase and not self.PackageBaseID:
raise IntegrityError(
statement="Foreign key PackageBaseID cannot be null.",
orig="PackageVotes.PackageBaseID",
- params=("NULL"))
+ params=("NULL"),
+ )
if not self.VoteTS:
raise IntegrityError(
statement="Column VoteTS cannot be null.",
orig="PackageVotes.VoteTS",
- params=("NULL"))
+ params=("NULL"),
+ )
diff --git a/aurweb/models/request_type.py b/aurweb/models/request_type.py
index cabab3d2..1853b0be 100644
--- a/aurweb/models/request_type.py
+++ b/aurweb/models/request_type.py
@@ -16,5 +16,5 @@ class RequestType(Base):
__mapper_args__ = {"primary_key": [__table__.c.ID]}
def name_display(self) -> str:
- """ Return the Name column with its first char capitalized. """
+ """Return the Name column with its first char capitalized."""
return self.Name.title()
diff --git a/aurweb/models/session.py b/aurweb/models/session.py
index 37ab4bce..d3d69f8c 100644
--- a/aurweb/models/session.py
+++ b/aurweb/models/session.py
@@ -12,8 +12,10 @@ class Session(Base):
__mapper_args__ = {"primary_key": [__table__.c.UsersID]}
User = relationship(
- _User, backref=backref("session", uselist=False),
- foreign_keys=[__table__.c.UsersID])
+ _User,
+ backref=backref("session", uselist=False),
+ foreign_keys=[__table__.c.UsersID],
+ )
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -29,10 +31,13 @@ class Session(Base):
user_exists = db.query(_User).filter(_User.ID == uid).exists()
if not db.query(user_exists).scalar():
raise IntegrityError(
- statement=("Foreign key UsersID cannot be null and "
- "must be a valid user's ID."),
+ statement=(
+ "Foreign key UsersID cannot be null and "
+ "must be a valid user's ID."
+ ),
orig="Sessions.UsersID",
- params=("NULL"))
+ params=("NULL"),
+ )
def generate_unique_sid():
diff --git a/aurweb/models/ssh_pub_key.py b/aurweb/models/ssh_pub_key.py
index 53c8c3ac..a2af34f4 100644
--- a/aurweb/models/ssh_pub_key.py
+++ b/aurweb/models/ssh_pub_key.py
@@ -12,16 +12,17 @@ class SSHPubKey(Base):
__mapper_args__ = {"primary_key": [__table__.c.Fingerprint]}
User = relationship(
- "User", backref=backref("ssh_pub_keys", lazy="dynamic"),
- foreign_keys=[__table__.c.UserID])
+ "User",
+ backref=backref("ssh_pub_keys", lazy="dynamic"),
+ foreign_keys=[__table__.c.UserID],
+ )
def __init__(self, **kwargs):
super().__init__(**kwargs)
def get_fingerprint(pubkey: str) -> str:
- proc = Popen(["ssh-keygen", "-l", "-f", "-"], stdin=PIPE, stdout=PIPE,
- stderr=PIPE)
+ proc = Popen(["ssh-keygen", "-l", "-f", "-"], stdin=PIPE, stdout=PIPE, stderr=PIPE)
out, _ = proc.communicate(pubkey.encode())
if proc.returncode:
raise ValueError("The SSH public key is invalid.")
diff --git a/aurweb/models/term.py b/aurweb/models/term.py
index 59534bbc..3aad9884 100644
--- a/aurweb/models/term.py
+++ b/aurweb/models/term.py
@@ -16,10 +16,12 @@ class Term(Base):
raise IntegrityError(
statement="Column Description cannot be null.",
orig="Terms.Description",
- params=("NULL"))
+ params=("NULL"),
+ )
if not self.URL:
raise IntegrityError(
statement="Column URL cannot be null.",
orig="Terms.URL",
- params=("NULL"))
+ params=("NULL"),
+ )
diff --git a/aurweb/models/tu_vote.py b/aurweb/models/tu_vote.py
index efb23b19..412915e2 100644
--- a/aurweb/models/tu_vote.py
+++ b/aurweb/models/tu_vote.py
@@ -10,17 +10,19 @@ from aurweb.models.user import User as _User
class TUVote(Base):
__table__ = schema.TU_Votes
__tablename__ = __table__.name
- __mapper_args__ = {
- "primary_key": [__table__.c.VoteID, __table__.c.UserID]
- }
+ __mapper_args__ = {"primary_key": [__table__.c.VoteID, __table__.c.UserID]}
VoteInfo = relationship(
- _TUVoteInfo, backref=backref("tu_votes", lazy="dynamic"),
- foreign_keys=[__table__.c.VoteID])
+ _TUVoteInfo,
+ backref=backref("tu_votes", lazy="dynamic"),
+ foreign_keys=[__table__.c.VoteID],
+ )
User = relationship(
- _User, backref=backref("tu_votes", lazy="dynamic"),
- foreign_keys=[__table__.c.UserID])
+ _User,
+ backref=backref("tu_votes", lazy="dynamic"),
+ foreign_keys=[__table__.c.UserID],
+ )
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -29,10 +31,12 @@ class TUVote(Base):
raise IntegrityError(
statement="Foreign key VoteID cannot be null.",
orig="TU_Votes.VoteID",
- params=("NULL"))
+ params=("NULL"),
+ )
if not self.User and not self.UserID:
raise IntegrityError(
statement="Foreign key UserID cannot be null.",
orig="TU_Votes.UserID",
- params=("NULL"))
+ params=("NULL"),
+ )
diff --git a/aurweb/models/tu_voteinfo.py b/aurweb/models/tu_voteinfo.py
index 7934a772..63fcee23 100644
--- a/aurweb/models/tu_voteinfo.py
+++ b/aurweb/models/tu_voteinfo.py
@@ -14,8 +14,10 @@ class TUVoteInfo(Base):
__mapper_args__ = {"primary_key": [__table__.c.ID]}
Submitter = relationship(
- _User, backref=backref("tu_voteinfo_set", lazy="dynamic"),
- foreign_keys=[__table__.c.SubmitterID])
+ _User,
+ backref=backref("tu_voteinfo_set", lazy="dynamic"),
+ foreign_keys=[__table__.c.SubmitterID],
+ )
def __init__(self, **kwargs):
# Default Quorum, Yes, No and Abstain columns to 0.
@@ -29,40 +31,45 @@ class TUVoteInfo(Base):
raise IntegrityError(
statement="Column Agenda cannot be null.",
orig="TU_VoteInfo.Agenda",
- params=("NULL"))
+ params=("NULL"),
+ )
if self.User is None:
raise IntegrityError(
statement="Column User cannot be null.",
orig="TU_VoteInfo.User",
- params=("NULL"))
+ params=("NULL"),
+ )
if self.Submitted is None:
raise IntegrityError(
statement="Column Submitted cannot be null.",
orig="TU_VoteInfo.Submitted",
- params=("NULL"))
+ params=("NULL"),
+ )
if self.End is None:
raise IntegrityError(
statement="Column End cannot be null.",
orig="TU_VoteInfo.End",
- params=("NULL"))
+ params=("NULL"),
+ )
if not self.Submitter:
raise IntegrityError(
statement="Foreign key SubmitterID cannot be null.",
orig="TU_VoteInfo.SubmitterID",
- params=("NULL"))
+ params=("NULL"),
+ )
def __setattr__(self, key: str, value: typing.Any):
- """ Customize setattr to stringify any Quorum keys given. """
+ """Customize setattr to stringify any Quorum keys given."""
if key == "Quorum":
value = str(value)
return super().__setattr__(key, value)
def __getattribute__(self, key: str):
- """ Customize getattr to floatify any fetched Quorum values. """
+ """Customize getattr to floatify any fetched Quorum values."""
attr = super().__getattribute__(key)
if key == "Quorum":
return float(attr)
diff --git a/aurweb/models/user.py b/aurweb/models/user.py
index 3fa72a85..0404c77a 100644
--- a/aurweb/models/user.py
+++ b/aurweb/models/user.py
@@ -1,9 +1,7 @@
import hashlib
-
from typing import Set
import bcrypt
-
from fastapi import Request
from sqlalchemy import or_
from sqlalchemy.exc import IntegrityError
@@ -12,7 +10,6 @@ from sqlalchemy.orm import backref, relationship
import aurweb.config
import aurweb.models.account_type
import aurweb.schema
-
from aurweb import db, logging, schema, time, util
from aurweb.models.account_type import AccountType as _AccountType
from aurweb.models.ban import is_banned
@@ -24,7 +21,8 @@ SALT_ROUNDS_DEFAULT = 12
class User(Base):
- """ An ORM model of a single Users record. """
+ """An ORM model of a single Users record."""
+
__table__ = schema.Users
__tablename__ = __table__.name
__mapper_args__ = {"primary_key": [__table__.c.ID]}
@@ -33,7 +31,8 @@ class User(Base):
_AccountType,
backref=backref("users", lazy="dynamic"),
foreign_keys=[__table__.c.AccountTypeID],
- uselist=False)
+ uselist=False,
+ )
# High-level variables used to track authentication (not in DB).
authenticated = False
@@ -41,50 +40,50 @@ class User(Base):
# Make this static to the class just in case SQLAlchemy ever
# does something to bypass our constructor.
- salt_rounds = aurweb.config.getint("options", "salt_rounds",
- SALT_ROUNDS_DEFAULT)
+ salt_rounds = aurweb.config.getint("options", "salt_rounds", SALT_ROUNDS_DEFAULT)
def __init__(self, Passwd: str = str(), **kwargs):
super().__init__(**kwargs, Passwd=str())
# Run this again in the constructor in case we rehashed config.
- self.salt_rounds = aurweb.config.getint("options", "salt_rounds",
- SALT_ROUNDS_DEFAULT)
+ self.salt_rounds = aurweb.config.getint(
+ "options", "salt_rounds", SALT_ROUNDS_DEFAULT
+ )
if Passwd:
self.update_password(Passwd)
def update_password(self, password):
self.Passwd = bcrypt.hashpw(
- password.encode(),
- bcrypt.gensalt(rounds=self.salt_rounds)).decode()
+ password.encode(), bcrypt.gensalt(rounds=self.salt_rounds)
+ ).decode()
@staticmethod
def minimum_passwd_length():
return aurweb.config.getint("options", "passwd_min_len")
def is_authenticated(self):
- """ Return internal authenticated state. """
+ """Return internal authenticated state."""
return self.authenticated
def valid_password(self, password: str):
- """ Check authentication against a given password. """
+ """Check authentication against a given password."""
if password is None:
return False
password_is_valid = False
try:
- password_is_valid = bcrypt.checkpw(password.encode(),
- self.Passwd.encode())
+ password_is_valid = bcrypt.checkpw(password.encode(), self.Passwd.encode())
except ValueError:
pass
# If our Salt column is not empty, we're using a legacy password.
if not password_is_valid and self.Salt != str():
# Try to login with legacy method.
- password_is_valid = hashlib.md5(
- f"{self.Salt}{password}".encode()
- ).hexdigest() == self.Passwd
+ password_is_valid = (
+ hashlib.md5(f"{self.Salt}{password}".encode()).hexdigest()
+ == self.Passwd
+ )
# We got here, we passed the legacy authentication.
# Update the password to our modern hash style.
@@ -96,9 +95,8 @@ class User(Base):
def _login_approved(self, request: Request):
return not is_banned(request) and not self.Suspended
- def login(self, request: Request, password: str,
- session_time: int = 0) -> str:
- """ Login and authenticate a request. """
+ def login(self, request: Request, password: str, session_time: int = 0) -> str:
+ """Login and authenticate a request."""
from aurweb import db
from aurweb.models.session import Session, generate_unique_sid
@@ -127,9 +125,9 @@ class User(Base):
self.LastLoginIPAddress = request.client.host
if not self.session:
sid = generate_unique_sid()
- self.session = db.create(Session, User=self,
- SessionID=sid,
- LastUpdateTS=now_ts)
+ self.session = db.create(
+ Session, User=self, SessionID=sid, LastUpdateTS=now_ts
+ )
else:
last_updated = self.session.LastUpdateTS
if last_updated and last_updated < now_ts:
@@ -148,9 +146,9 @@ class User(Base):
return self.session.SessionID
- def has_credential(self, credential: Set[int],
- approved: list["User"] = list()):
+ def has_credential(self, credential: Set[int], approved: list["User"] = list()):
from aurweb.auth.creds import has_credential
+
return has_credential(self, credential, approved)
def logout(self, request: Request):
@@ -162,18 +160,18 @@ class User(Base):
def is_trusted_user(self):
return self.AccountType.ID in {
aurweb.models.account_type.TRUSTED_USER_ID,
- aurweb.models.account_type.TRUSTED_USER_AND_DEV_ID
+ aurweb.models.account_type.TRUSTED_USER_AND_DEV_ID,
}
def is_developer(self):
return self.AccountType.ID in {
aurweb.models.account_type.DEVELOPER_ID,
- aurweb.models.account_type.TRUSTED_USER_AND_DEV_ID
+ aurweb.models.account_type.TRUSTED_USER_AND_DEV_ID,
}
def is_elevated(self):
- """ A User is 'elevated' when they have either a
- Trusted User or Developer AccountType. """
+ """A User is 'elevated' when they have either a
+ Trusted User or Developer AccountType."""
return self.AccountType.ID in {
aurweb.models.account_type.TRUSTED_USER_ID,
aurweb.models.account_type.DEVELOPER_ID,
@@ -196,18 +194,22 @@ class User(Base):
:return: Boolean indicating whether `self` can edit `target`
"""
from aurweb.auth import creds
+
has_cred = self.has_credential(creds.ACCOUNT_EDIT, approved=[target])
return has_cred and self.AccountTypeID >= target.AccountTypeID
def voted_for(self, package) -> bool:
- """ Has this User voted for package? """
+ """Has this User voted for package?"""
from aurweb.models.package_vote import PackageVote
- return bool(package.PackageBase.package_votes.filter(
- PackageVote.UsersID == self.ID
- ).scalar())
+
+ return bool(
+ package.PackageBase.package_votes.filter(
+ PackageVote.UsersID == self.ID
+ ).scalar()
+ )
def notified(self, package) -> bool:
- """ Is this User being notified about package (or package base)?
+ """Is this User being notified about package (or package base)?
:param package: Package or PackageBase instance
:return: Boolean indicating state of package notification
@@ -225,12 +227,14 @@ class User(Base):
# Run an exists() query where a pkgbase-related
# PackageNotification exists for self (a user).
- return bool(db.query(
- query.filter(PackageNotification.UserID == self.ID).exists()
- ).scalar())
+ return bool(
+ db.query(
+ query.filter(PackageNotification.UserID == self.ID).exists()
+ ).scalar()
+ )
def packages(self):
- """ Returns an ORM query to Package objects owned by this user.
+ """Returns an ORM query to Package objects owned by this user.
This should really be replaced with an internal ORM join
configured for the User model. This has not been done yet
@@ -241,16 +245,24 @@ class User(Base):
"""
from aurweb.models.package import Package
from aurweb.models.package_base import PackageBase
- return db.query(Package).join(PackageBase).filter(
- or_(
- PackageBase.PackagerUID == self.ID,
- PackageBase.MaintainerUID == self.ID
+
+ return (
+ db.query(Package)
+ .join(PackageBase)
+ .filter(
+ or_(
+ PackageBase.PackagerUID == self.ID,
+ PackageBase.MaintainerUID == self.ID,
+ )
)
)
def __repr__(self):
return "" % (
- self.ID, str(self.AccountType), self.Username)
+ self.ID,
+ str(self.AccountType),
+ self.Username,
+ )
def __str__(self) -> str:
return self.Username
diff --git a/aurweb/packages/requests.py b/aurweb/packages/requests.py
index 42026a33..7309a880 100644
--- a/aurweb/packages/requests.py
+++ b/aurweb/packages/requests.py
@@ -7,46 +7,55 @@ from aurweb import config, db, l10n, time, util
from aurweb.exceptions import InvariantError
from aurweb.models import PackageBase, PackageRequest, User
from aurweb.models.package_request import ACCEPTED_ID, PENDING_ID, REJECTED_ID
-from aurweb.models.request_type import DELETION, DELETION_ID, MERGE, MERGE_ID, ORPHAN, ORPHAN_ID
+from aurweb.models.request_type import (
+ DELETION,
+ DELETION_ID,
+ MERGE,
+ MERGE_ID,
+ ORPHAN,
+ ORPHAN_ID,
+)
from aurweb.scripts import notify
class ClosureFactory:
- """ A factory class used to autogenerate closure comments. """
+ """A factory class used to autogenerate closure comments."""
- REQTYPE_NAMES = {
- DELETION_ID: DELETION,
- MERGE_ID: MERGE,
- ORPHAN_ID: ORPHAN
- }
+ REQTYPE_NAMES = {DELETION_ID: DELETION, MERGE_ID: MERGE, ORPHAN_ID: ORPHAN}
- def _deletion_closure(self, requester: User,
- pkgbase: PackageBase,
- target: PackageBase = None):
- return (f"[Autogenerated] Accepted deletion for {pkgbase.Name}.")
+ def _deletion_closure(
+ self, requester: User, pkgbase: PackageBase, target: PackageBase = None
+ ):
+ return f"[Autogenerated] Accepted deletion for {pkgbase.Name}."
- def _merge_closure(self, requester: User,
- pkgbase: PackageBase,
- target: PackageBase = None):
- return (f"[Autogenerated] Accepted merge for {pkgbase.Name} "
- f"into {target.Name}.")
+ def _merge_closure(
+ self, requester: User, pkgbase: PackageBase, target: PackageBase = None
+ ):
+ return (
+ f"[Autogenerated] Accepted merge for {pkgbase.Name} " f"into {target.Name}."
+ )
- def _orphan_closure(self, requester: User,
- pkgbase: PackageBase,
- target: PackageBase = None):
- return (f"[Autogenerated] Accepted orphan for {pkgbase.Name}.")
+ def _orphan_closure(
+ self, requester: User, pkgbase: PackageBase, target: PackageBase = None
+ ):
+ return f"[Autogenerated] Accepted orphan for {pkgbase.Name}."
- def _rejected_merge_closure(self, requester: User,
- pkgbase: PackageBase,
- target: PackageBase = None):
- return (f"[Autogenerated] Another request to merge {pkgbase.Name} "
- f"into {target.Name} has rendered this request invalid.")
+ def _rejected_merge_closure(
+ self, requester: User, pkgbase: PackageBase, target: PackageBase = None
+ ):
+ return (
+ f"[Autogenerated] Another request to merge {pkgbase.Name} "
+ f"into {target.Name} has rendered this request invalid."
+ )
- def get_closure(self, reqtype_id: int,
- requester: User,
- pkgbase: PackageBase,
- target: PackageBase = None,
- status: int = ACCEPTED_ID) -> str:
+ def get_closure(
+ self,
+ reqtype_id: int,
+ requester: User,
+ pkgbase: PackageBase,
+ target: PackageBase = None,
+ status: int = ACCEPTED_ID,
+ ) -> str:
"""
Return a closure comment handled by this class.
@@ -69,8 +78,9 @@ class ClosureFactory:
return handler(requester, pkgbase, target)
-def update_closure_comment(pkgbase: PackageBase, reqtype_id: int,
- comments: str, target: PackageBase = None) -> None:
+def update_closure_comment(
+ pkgbase: PackageBase, reqtype_id: int, comments: str, target: PackageBase = None
+) -> None:
"""
Update all pending requests related to `pkgbase` with a closure comment.
@@ -90,8 +100,10 @@ def update_closure_comment(pkgbase: PackageBase, reqtype_id: int,
return
query = pkgbase.requests.filter(
- and_(PackageRequest.ReqTypeID == reqtype_id,
- PackageRequest.Status == PENDING_ID))
+ and_(
+ PackageRequest.ReqTypeID == reqtype_id, PackageRequest.Status == PENDING_ID
+ )
+ )
if reqtype_id == MERGE_ID:
query = query.filter(PackageRequest.MergeBaseName == target.Name)
@@ -100,9 +112,8 @@ def update_closure_comment(pkgbase: PackageBase, reqtype_id: int,
def verify_orphan_request(user: User, pkgbase: PackageBase):
- """ Verify that an undue orphan request exists in `requests`. """
- requests = pkgbase.requests.filter(
- PackageRequest.ReqTypeID == ORPHAN_ID)
+ """Verify that an undue orphan request exists in `requests`."""
+ requests = pkgbase.requests.filter(PackageRequest.ReqTypeID == ORPHAN_ID)
for pkgreq in requests:
idle_time = config.getint("options", "request_idle_time")
time_delta = time.utcnow() - pkgreq.RequestTS
@@ -115,9 +126,13 @@ def verify_orphan_request(user: User, pkgbase: PackageBase):
return False
-def close_pkgreq(pkgreq: PackageRequest, closer: User,
- pkgbase: PackageBase, target: Optional[PackageBase],
- status: int) -> None:
+def close_pkgreq(
+ pkgreq: PackageRequest,
+ closer: User,
+ pkgbase: PackageBase,
+ target: Optional[PackageBase],
+ status: int,
+) -> None:
"""
Close a package request with `pkgreq`.Status == `status`.
@@ -130,16 +145,15 @@ def close_pkgreq(pkgreq: PackageRequest, closer: User,
now = time.utcnow()
pkgreq.Status = status
pkgreq.Closer = closer
- pkgreq.ClosureComment = (
- pkgreq.ClosureComment or ClosureFactory().get_closure(
- pkgreq.ReqTypeID, closer, pkgbase, target, status)
+ pkgreq.ClosureComment = pkgreq.ClosureComment or ClosureFactory().get_closure(
+ pkgreq.ReqTypeID, closer, pkgbase, target, status
)
pkgreq.ClosedTS = now
-def handle_request(request: Request, reqtype_id: int,
- pkgbase: PackageBase,
- target: PackageBase = None) -> list[notify.Notification]:
+def handle_request(
+ request: Request, reqtype_id: int, pkgbase: PackageBase, target: PackageBase = None
+) -> list[notify.Notification]:
"""
Handle package requests before performing an action.
@@ -165,17 +179,20 @@ def handle_request(request: Request, reqtype_id: int,
if reqtype_id == ORPHAN_ID:
if not verify_orphan_request(request.user, pkgbase):
_ = l10n.get_translator_for_request(request)
- raise InvariantError(_(
- "No due existing orphan requests to accept for %s."
- ) % pkgbase.Name)
+ raise InvariantError(
+ _("No due existing orphan requests to accept for %s.") % pkgbase.Name
+ )
# Produce a base query for requests related to `pkgbase`, based
# on ReqTypeID matching `reqtype_id`, pending status and a correct
# PackagBaseName column.
query: orm.Query = pkgbase.requests.filter(
- and_(PackageRequest.ReqTypeID == reqtype_id,
- PackageRequest.Status == PENDING_ID,
- PackageRequest.PackageBaseName == pkgbase.Name))
+ and_(
+ PackageRequest.ReqTypeID == reqtype_id,
+ PackageRequest.Status == PENDING_ID,
+ PackageRequest.PackageBaseName == pkgbase.Name,
+ )
+ )
# Build a query for records we should accept. For merge requests,
# this is specific to a matching MergeBaseName. For others, this
@@ -183,8 +200,7 @@ def handle_request(request: Request, reqtype_id: int,
accept_query: orm.Query = query
if target:
# If a `target` was supplied, filter by MergeBaseName
- accept_query = query.filter(
- PackageRequest.MergeBaseName == target.Name)
+ accept_query = query.filter(PackageRequest.MergeBaseName == target.Name)
# Build an accept list out of `accept_query`.
to_accept: list[PackageRequest] = accept_query.all()
@@ -203,14 +219,16 @@ def handle_request(request: Request, reqtype_id: int,
if not to_accept:
utcnow = time.utcnow()
with db.begin():
- pkgreq = db.create(PackageRequest,
- ReqTypeID=reqtype_id,
- RequestTS=utcnow,
- User=request.user,
- PackageBase=pkgbase,
- PackageBaseName=pkgbase.Name,
- Comments="Autogenerated by aurweb.",
- ClosureComment=str())
+ pkgreq = db.create(
+ PackageRequest,
+ ReqTypeID=reqtype_id,
+ RequestTS=utcnow,
+ User=request.user,
+ PackageBase=pkgbase,
+ PackageBaseName=pkgbase.Name,
+ Comments="Autogenerated by aurweb.",
+ ClosureComment=str(),
+ )
# If it's a merge request, set MergeBaseName to `target`.Name.
if pkgreq.ReqTypeID == MERGE_ID:
@@ -222,15 +240,20 @@ def handle_request(request: Request, reqtype_id: int,
# Update requests with their new status and closures.
with db.begin():
- util.apply_all(to_accept, lambda p: close_pkgreq(
- p, request.user, pkgbase, target, ACCEPTED_ID))
- util.apply_all(to_reject, lambda p: close_pkgreq(
- p, request.user, pkgbase, target, REJECTED_ID))
+ util.apply_all(
+ to_accept,
+ lambda p: close_pkgreq(p, request.user, pkgbase, target, ACCEPTED_ID),
+ )
+ util.apply_all(
+ to_reject,
+ lambda p: close_pkgreq(p, request.user, pkgbase, target, REJECTED_ID),
+ )
# Create RequestCloseNotifications for all requests involved.
- for pkgreq in (to_accept + to_reject):
+ for pkgreq in to_accept + to_reject:
notif = notify.RequestCloseNotification(
- request.user.ID, pkgreq.ID, pkgreq.status_display())
+ request.user.ID, pkgreq.ID, pkgreq.status_display()
+ )
notifs.append(notif)
# Return notifications to the caller for sending.
diff --git a/aurweb/packages/search.py b/aurweb/packages/search.py
index 5ba72652..224212d1 100644
--- a/aurweb/packages/search.py
+++ b/aurweb/packages/search.py
@@ -4,7 +4,12 @@ from sqlalchemy import and_, case, or_, orm
from aurweb import db, models
from aurweb.models import Package, PackageBase, User
-from aurweb.models.dependency_type import CHECKDEPENDS_ID, DEPENDS_ID, MAKEDEPENDS_ID, OPTDEPENDS_ID
+from aurweb.models.dependency_type import (
+ CHECKDEPENDS_ID,
+ DEPENDS_ID,
+ MAKEDEPENDS_ID,
+ OPTDEPENDS_ID,
+)
from aurweb.models.package_comaintainer import PackageComaintainer
from aurweb.models.package_keyword import PackageKeyword
from aurweb.models.package_notification import PackageNotification
diff --git a/aurweb/packages/util.py b/aurweb/packages/util.py
index bd173065..1ae7f9fe 100644
--- a/aurweb/packages/util.py
+++ b/aurweb/packages/util.py
@@ -3,7 +3,6 @@ from http import HTTPStatus
from typing import Tuple, Union
import orjson
-
from fastapi import HTTPException
from sqlalchemy import orm
@@ -43,10 +42,10 @@ def dep_optdepends_extra(dep: models.PackageDependency) -> str:
@register_filter("dep_extra")
def dep_extra(dep: models.PackageDependency) -> str:
- """ Some dependency types have extra text added to their
+ """Some dependency types have extra text added to their
display. This function provides that output. However, it
**assumes** that the dep passed is bound to a valid one
- of: depends, makedepends, checkdepends or optdepends. """
+ of: depends, makedepends, checkdepends or optdepends."""
f = globals().get(f"dep_{dep.DependencyType.Name}_extra")
return f(dep)
@@ -61,13 +60,13 @@ def dep_extra_desc(dep: models.PackageDependency) -> str:
@register_filter("pkgname_link")
def pkgname_link(pkgname: str) -> str:
- record = db.query(Package).filter(
- Package.Name == pkgname).exists()
+ record = db.query(Package).filter(Package.Name == pkgname).exists()
if db.query(record).scalar():
return f"/packages/{pkgname}"
- official = db.query(OfficialProvider).filter(
- OfficialProvider.Name == pkgname).exists()
+ official = (
+ db.query(OfficialProvider).filter(OfficialProvider.Name == pkgname).exists()
+ )
if db.query(official).scalar():
base = "/".join([OFFICIAL_BASE, "packages"])
return f"{base}/?q={pkgname}"
@@ -83,17 +82,15 @@ def package_link(package: Union[Package, OfficialProvider]) -> str:
@register_filter("provides_markup")
def provides_markup(provides: Providers) -> str:
- return ", ".join([
- f'{pkg.Name}'
- for pkg in provides
- ])
+ return ", ".join(
+ [f'{pkg.Name}' for pkg in provides]
+ )
def get_pkg_or_base(
- name: str,
- cls: Union[models.Package, models.PackageBase] = models.PackageBase) \
- -> Union[models.Package, models.PackageBase]:
- """ Get a PackageBase instance by its name or raise a 404 if
+ name: str, cls: Union[models.Package, models.PackageBase] = models.PackageBase
+) -> Union[models.Package, models.PackageBase]:
+ """Get a PackageBase instance by its name or raise a 404 if
it can't be found in the database.
:param name: {Package,PackageBase}.Name
@@ -109,8 +106,7 @@ def get_pkg_or_base(
return instance
-def get_pkgbase_comment(pkgbase: models.PackageBase, id: int) \
- -> models.PackageComment:
+def get_pkgbase_comment(pkgbase: models.PackageBase, id: int) -> models.PackageComment:
comment = pkgbase.comments.filter(models.PackageComment.ID == id).first()
if not comment:
raise HTTPException(status_code=HTTPStatus.NOT_FOUND)
@@ -122,9 +118,8 @@ def out_of_date(packages: orm.Query) -> orm.Query:
return packages.filter(models.PackageBase.OutOfDateTS.isnot(None))
-def updated_packages(limit: int = 0,
- cache_ttl: int = 600) -> list[models.Package]:
- """ Return a list of valid Package objects ordered by their
+def updated_packages(limit: int = 0, cache_ttl: int = 600) -> list[models.Package]:
+ """Return a list of valid Package objects ordered by their
ModifiedTS column in descending order from cache, after setting
the cache when no key yet exists.
@@ -139,10 +134,11 @@ def updated_packages(limit: int = 0,
return orjson.loads(packages)
with db.begin():
- query = db.query(models.Package).join(models.PackageBase).filter(
- models.PackageBase.PackagerUID.isnot(None)
- ).order_by(
- models.PackageBase.ModifiedTS.desc()
+ query = (
+ db.query(models.Package)
+ .join(models.PackageBase)
+ .filter(models.PackageBase.PackagerUID.isnot(None))
+ .order_by(models.PackageBase.ModifiedTS.desc())
)
if limit:
@@ -152,13 +148,13 @@ def updated_packages(limit: int = 0,
for pkg in query:
# For each Package returned by the query, append a dict
# containing Package columns we're interested in.
- packages.append({
- "Name": pkg.Name,
- "Version": pkg.Version,
- "PackageBase": {
- "ModifiedTS": pkg.PackageBase.ModifiedTS
+ packages.append(
+ {
+ "Name": pkg.Name,
+ "Version": pkg.Version,
+ "PackageBase": {"ModifiedTS": pkg.PackageBase.ModifiedTS},
}
- })
+ )
# Store the JSON serialization of the package_updates key into Redis.
redis.set("package_updates", orjson.dumps(packages))
@@ -168,9 +164,8 @@ def updated_packages(limit: int = 0,
return packages
-def query_voted(query: list[models.Package],
- user: models.User) -> dict[int, bool]:
- """ Produce a dictionary of package base ID keys to boolean values,
+def query_voted(query: list[models.Package], user: models.User) -> dict[int, bool]:
+ """Produce a dictionary of package base ID keys to boolean values,
which indicate whether or not the package base has a vote record
related to user.
@@ -180,20 +175,18 @@ def query_voted(query: list[models.Package],
"""
output = defaultdict(bool)
query_set = {pkg.PackageBaseID for pkg in query}
- voted = db.query(models.PackageVote).join(
- models.PackageBase,
- models.PackageBase.ID.in_(query_set)
- ).filter(
- models.PackageVote.UsersID == user.ID
+ voted = (
+ db.query(models.PackageVote)
+ .join(models.PackageBase, models.PackageBase.ID.in_(query_set))
+ .filter(models.PackageVote.UsersID == user.ID)
)
for vote in voted:
output[vote.PackageBase.ID] = True
return output
-def query_notified(query: list[models.Package],
- user: models.User) -> dict[int, bool]:
- """ Produce a dictionary of package base ID keys to boolean values,
+def query_notified(query: list[models.Package], user: models.User) -> dict[int, bool]:
+ """Produce a dictionary of package base ID keys to boolean values,
which indicate whether or not the package base has a notification
record related to user.
@@ -203,19 +196,17 @@ def query_notified(query: list[models.Package],
"""
output = defaultdict(bool)
query_set = {pkg.PackageBaseID for pkg in query}
- notified = db.query(models.PackageNotification).join(
- models.PackageBase,
- models.PackageBase.ID.in_(query_set)
- ).filter(
- models.PackageNotification.UserID == user.ID
+ notified = (
+ db.query(models.PackageNotification)
+ .join(models.PackageBase, models.PackageBase.ID.in_(query_set))
+ .filter(models.PackageNotification.UserID == user.ID)
)
for notif in notified:
output[notif.PackageBase.ID] = True
return output
-def pkg_required(pkgname: str, provides: list[str]) \
- -> list[PackageDependency]:
+def pkg_required(pkgname: str, provides: list[str]) -> list[PackageDependency]:
"""
Get dependencies that match a string in `[pkgname] + provides`.
@@ -225,9 +216,12 @@ def pkg_required(pkgname: str, provides: list[str]) \
:return: List of PackageDependency instances
"""
targets = set([pkgname] + provides)
- query = db.query(PackageDependency).join(Package).filter(
- PackageDependency.DepName.in_(targets)
- ).order_by(Package.Name.asc())
+ query = (
+ db.query(PackageDependency)
+ .join(Package)
+ .filter(PackageDependency.DepName.in_(targets))
+ .order_by(Package.Name.asc())
+ )
return query
diff --git a/aurweb/pkgbase/actions.py b/aurweb/pkgbase/actions.py
index 27143d51..4834f8dd 100644
--- a/aurweb/pkgbase/actions.py
+++ b/aurweb/pkgbase/actions.py
@@ -14,15 +14,15 @@ logger = logging.get_logger(__name__)
def pkgbase_notify_instance(request: Request, pkgbase: PackageBase) -> None:
- notif = db.query(pkgbase.notifications.filter(
- PackageNotification.UserID == request.user.ID
- ).exists()).scalar()
+ notif = db.query(
+ pkgbase.notifications.filter(
+ PackageNotification.UserID == request.user.ID
+ ).exists()
+ ).scalar()
has_cred = request.user.has_credential(creds.PKGBASE_NOTIFY)
if has_cred and not notif:
with db.begin():
- db.create(PackageNotification,
- PackageBase=pkgbase,
- User=request.user)
+ db.create(PackageNotification, PackageBase=pkgbase, User=request.user)
def pkgbase_unnotify_instance(request: Request, pkgbase: PackageBase) -> None:
@@ -36,8 +36,11 @@ def pkgbase_unnotify_instance(request: Request, pkgbase: PackageBase) -> None:
def pkgbase_unflag_instance(request: Request, pkgbase: PackageBase) -> None:
- has_cred = request.user.has_credential(creds.PKGBASE_UNFLAG, approved=[
- pkgbase.Flagger, pkgbase.Maintainer] + [c.User for c in pkgbase.comaintainers])
+ has_cred = request.user.has_credential(
+ creds.PKGBASE_UNFLAG,
+ approved=[pkgbase.Flagger, pkgbase.Maintainer]
+ + [c.User for c in pkgbase.comaintainers],
+ )
if has_cred:
with db.begin():
pkgbase.OutOfDateTS = None
@@ -93,9 +96,9 @@ def pkgbase_adopt_instance(request: Request, pkgbase: PackageBase) -> None:
notif.send()
-def pkgbase_delete_instance(request: Request, pkgbase: PackageBase,
- comments: str = str()) \
- -> list[notify.Notification]:
+def pkgbase_delete_instance(
+ request: Request, pkgbase: PackageBase, comments: str = str()
+) -> list[notify.Notification]:
notifs = handle_request(request, DELETION_ID, pkgbase) + [
notify.DeleteNotification(request.user.ID, pkgbase.ID)
]
@@ -107,8 +110,9 @@ def pkgbase_delete_instance(request: Request, pkgbase: PackageBase,
return notifs
-def pkgbase_merge_instance(request: Request, pkgbase: PackageBase,
- target: PackageBase, comments: str = str()) -> None:
+def pkgbase_merge_instance(
+ request: Request, pkgbase: PackageBase, target: PackageBase, comments: str = str()
+) -> None:
pkgbasename = str(pkgbase.Name)
# Create notifications.
@@ -144,8 +148,10 @@ def pkgbase_merge_instance(request: Request, pkgbase: PackageBase,
db.delete(pkgbase)
# Log this out for accountability purposes.
- logger.info(f"Trusted User '{request.user.Username}' merged "
- f"'{pkgbasename}' into '{target.Name}'.")
+ logger.info(
+ f"Trusted User '{request.user.Username}' merged "
+ f"'{pkgbasename}' into '{target.Name}'."
+ )
# Send notifications.
util.apply_all(notifs, lambda n: n.send())
diff --git a/aurweb/pkgbase/util.py b/aurweb/pkgbase/util.py
index 63621d63..223c3013 100644
--- a/aurweb/pkgbase/util.py
+++ b/aurweb/pkgbase/util.py
@@ -10,19 +10,23 @@ from aurweb.models.package_comment import PackageComment
from aurweb.models.package_request import PENDING_ID, PackageRequest
from aurweb.models.package_vote import PackageVote
from aurweb.scripts import notify
-from aurweb.templates import make_context as _make_context
-from aurweb.templates import make_variable_context as _make_variable_context
+from aurweb.templates import (
+ make_context as _make_context,
+ make_variable_context as _make_variable_context,
+)
-async def make_variable_context(request: Request, pkgbase: PackageBase) \
- -> dict[str, Any]:
+async def make_variable_context(
+ request: Request, pkgbase: PackageBase
+) -> dict[str, Any]:
ctx = await _make_variable_context(request, pkgbase.Name)
return make_context(request, pkgbase, ctx)
-def make_context(request: Request, pkgbase: PackageBase,
- context: dict[str, Any] = None) -> dict[str, Any]:
- """ Make a basic context for package or pkgbase.
+def make_context(
+ request: Request, pkgbase: PackageBase, context: dict[str, Any] = None
+) -> dict[str, Any]:
+ """Make a basic context for package or pkgbase.
:param request: FastAPI request
:param pkgbase: PackageBase instance
@@ -34,14 +38,16 @@ def make_context(request: Request, pkgbase: PackageBase,
# Per page and offset.
offset, per_page = util.sanitize_params(
request.query_params.get("O", defaults.O),
- request.query_params.get("PP", defaults.COMMENTS_PER_PAGE))
+ request.query_params.get("PP", defaults.COMMENTS_PER_PAGE),
+ )
context["O"] = offset
context["PP"] = per_page
context["git_clone_uri_anon"] = config.get("options", "git_clone_uri_anon")
context["git_clone_uri_priv"] = config.get("options", "git_clone_uri_priv")
context["pkgbase"] = pkgbase
context["comaintainers"] = [
- c.User for c in pkgbase.comaintainers.order_by(
+ c.User
+ for c in pkgbase.comaintainers.order_by(
PackageComaintainer.Priority.asc()
).all()
]
@@ -53,9 +59,11 @@ def make_context(request: Request, pkgbase: PackageBase,
context["comments_total"] = pkgbase.comments.order_by(
PackageComment.CommentTS.desc()
).count()
- context["comments"] = pkgbase.comments.order_by(
- PackageComment.CommentTS.desc()
- ).limit(per_page).offset(offset)
+ context["comments"] = (
+ pkgbase.comments.order_by(PackageComment.CommentTS.desc())
+ .limit(per_page)
+ .offset(offset)
+ )
context["pinned_comments"] = pkgbase.comments.filter(
PackageComment.PinnedTS != 0
).order_by(PackageComment.CommentTS.desc())
@@ -70,15 +78,15 @@ def make_context(request: Request, pkgbase: PackageBase,
).scalar()
context["requests"] = pkgbase.requests.filter(
- and_(PackageRequest.Status == PENDING_ID,
- PackageRequest.ClosedTS.is_(None))
+ and_(PackageRequest.Status == PENDING_ID, PackageRequest.ClosedTS.is_(None))
).count()
return context
-def remove_comaintainer(comaint: PackageComaintainer) \
- -> notify.ComaintainerRemoveNotification:
+def remove_comaintainer(
+ comaint: PackageComaintainer,
+) -> notify.ComaintainerRemoveNotification:
"""
Remove a PackageComaintainer.
@@ -107,9 +115,9 @@ def remove_comaintainers(pkgbase: PackageBase, usernames: list[str]) -> None:
"""
notifications = []
with db.begin():
- comaintainers = pkgbase.comaintainers.join(User).filter(
- User.Username.in_(usernames)
- ).all()
+ comaintainers = (
+ pkgbase.comaintainers.join(User).filter(User.Username.in_(usernames)).all()
+ )
notifications = [
notify.ComaintainerRemoveNotification(co.User.ID, pkgbase.ID)
for co in comaintainers
@@ -133,23 +141,23 @@ def latest_priority(pkgbase: PackageBase) -> int:
"""
# Order comaintainers related to pkgbase by Priority DESC.
- record = pkgbase.comaintainers.order_by(
- PackageComaintainer.Priority.desc()).first()
+ record = pkgbase.comaintainers.order_by(PackageComaintainer.Priority.desc()).first()
# Use Priority column if record exists, otherwise 0.
return record.Priority if record else 0
class NoopComaintainerNotification:
- """ A noop notification stub used as an error-state return value. """
+ """A noop notification stub used as an error-state return value."""
def send(self) -> None:
- """ noop """
+ """noop"""
return
-def add_comaintainer(pkgbase: PackageBase, comaintainer: User) \
- -> notify.ComaintainerAddNotification:
+def add_comaintainer(
+ pkgbase: PackageBase, comaintainer: User
+) -> notify.ComaintainerAddNotification:
"""
Add a new comaintainer to `pkgbase`.
@@ -165,14 +173,19 @@ def add_comaintainer(pkgbase: PackageBase, comaintainer: User) \
new_prio = latest_priority(pkgbase) + 1
with db.begin():
- db.create(PackageComaintainer, PackageBase=pkgbase,
- User=comaintainer, Priority=new_prio)
+ db.create(
+ PackageComaintainer,
+ PackageBase=pkgbase,
+ User=comaintainer,
+ Priority=new_prio,
+ )
return notify.ComaintainerAddNotification(comaintainer.ID, pkgbase.ID)
-def add_comaintainers(request: Request, pkgbase: PackageBase,
- usernames: list[str]) -> None:
+def add_comaintainers(
+ request: Request, pkgbase: PackageBase, usernames: list[str]
+) -> None:
"""
Add comaintainers to `pkgbase`.
@@ -216,7 +229,6 @@ def rotate_comaintainers(pkgbase: PackageBase) -> None:
:param pkgbase: PackageBase instance
"""
- comaintainers = pkgbase.comaintainers.order_by(
- PackageComaintainer.Priority.asc())
+ comaintainers = pkgbase.comaintainers.order_by(PackageComaintainer.Priority.asc())
for i, comaint in enumerate(comaintainers):
comaint.Priority = i + 1
diff --git a/aurweb/pkgbase/validate.py b/aurweb/pkgbase/validate.py
index baefc415..3c50e578 100644
--- a/aurweb/pkgbase/validate.py
+++ b/aurweb/pkgbase/validate.py
@@ -5,9 +5,13 @@ from aurweb.exceptions import ValidationError
from aurweb.models import PackageBase
-def request(pkgbase: PackageBase,
- type: str, comments: str, merge_into: str,
- context: dict[str, Any]) -> None:
+def request(
+ pkgbase: PackageBase,
+ type: str,
+ comments: str,
+ merge_into: str,
+ context: dict[str, Any],
+) -> None:
if not comments:
raise ValidationError(["The comment field must not be empty."])
@@ -15,21 +19,16 @@ def request(pkgbase: PackageBase,
# Perform merge-related checks.
if not merge_into:
# TODO: This error needs to be translated.
- raise ValidationError(
- ['The "Merge into" field must not be empty.'])
+ raise ValidationError(['The "Merge into" field must not be empty.'])
- target = db.query(PackageBase).filter(
- PackageBase.Name == merge_into
- ).first()
+ target = db.query(PackageBase).filter(PackageBase.Name == merge_into).first()
if not target:
# TODO: This error needs to be translated.
- raise ValidationError([
- "The package base you want to merge into does not exist."
- ])
+ raise ValidationError(
+ ["The package base you want to merge into does not exist."]
+ )
db.refresh(target)
if target.ID == pkgbase.ID:
# TODO: This error needs to be translated.
- raise ValidationError([
- "You cannot merge a package base into itself."
- ])
+ raise ValidationError(["You cannot merge a package base into itself."])
diff --git a/aurweb/prometheus.py b/aurweb/prometheus.py
index 227d46ed..0bbea4be 100644
--- a/aurweb/prometheus.py
+++ b/aurweb/prometheus.py
@@ -19,8 +19,9 @@ def instrumentator():
# Their license is included in LICENSES/starlette_exporter.
# The code has been modified to remove child route checks
# (since we don't have any) and to stay within an 80-width limit.
-def get_matching_route_path(scope: dict[Any, Any], routes: list[Route],
- route_name: Optional[str] = None) -> str:
+def get_matching_route_path(
+ scope: dict[Any, Any], routes: list[Route], route_name: Optional[str] = None
+) -> str:
"""
Find a matching route and return its original path string
@@ -34,7 +35,7 @@ def get_matching_route_path(scope: dict[Any, Any], routes: list[Route],
if match == Match.FULL:
route_name = route.path
- '''
+ """
# This path exists in the original function's code, but we
# don't need it (currently), so it's been removed to avoid
# useless test coverage.
@@ -47,7 +48,7 @@ def get_matching_route_path(scope: dict[Any, Any], routes: list[Route],
route_name = None
else:
route_name += child_route_name
- '''
+ """
return route_name
elif match == Match.PARTIAL and route_name is None:
@@ -55,9 +56,11 @@ def get_matching_route_path(scope: dict[Any, Any], routes: list[Route],
def http_requests_total() -> Callable[[Info], None]:
- metric = Counter("http_requests_total",
- "Number of HTTP requests.",
- labelnames=("method", "path", "status"))
+ metric = Counter(
+ "http_requests_total",
+ "Number of HTTP requests.",
+ labelnames=("method", "path", "status"),
+ )
def instrumentation(info: Info) -> None:
if info.request.method.lower() in ("head", "options"): # pragma: no cover
@@ -79,13 +82,13 @@ def http_requests_total() -> Callable[[Info], None]:
if hasattr(app, "root_path"):
app_root_path = getattr(app, "root_path")
if root_path.startswith(app_root_path):
- root_path = root_path[len(app_root_path):]
+ root_path = root_path[len(app_root_path) :]
base_scope = {
"type": scope.get("type"),
"path": root_path + scope.get("path"),
"path_params": scope.get("path_params", {}),
- "method": scope.get("method")
+ "method": scope.get("method"),
}
method = scope.get("method")
@@ -102,7 +105,8 @@ def http_api_requests_total() -> Callable[[Info], None]:
metric = Counter(
"http_api_requests",
"Number of times an RPC API type has been requested.",
- labelnames=("type", "status"))
+ labelnames=("type", "status"),
+ )
def instrumentation(info: Info) -> None:
if info.request.method.lower() in ("head", "options"): # pragma: no cover
diff --git a/aurweb/ratelimit.py b/aurweb/ratelimit.py
index 86063f5d..cb08cdf5 100644
--- a/aurweb/ratelimit.py
+++ b/aurweb/ratelimit.py
@@ -38,8 +38,7 @@ def _update_ratelimit_db(request: Request):
now = time.utcnow()
time_to_delete = now - window_length
- records = db.query(ApiRateLimit).filter(
- ApiRateLimit.WindowStart < time_to_delete)
+ records = db.query(ApiRateLimit).filter(ApiRateLimit.WindowStart < time_to_delete)
with db.begin():
db.delete_all(records)
@@ -47,9 +46,7 @@ def _update_ratelimit_db(request: Request):
record = db.query(ApiRateLimit, ApiRateLimit.IP == host).first()
with db.begin():
if not record:
- record = db.create(ApiRateLimit,
- WindowStart=now,
- IP=host, Requests=1)
+ record = db.create(ApiRateLimit, WindowStart=now, IP=host, Requests=1)
else:
record.Requests += 1
@@ -58,7 +55,7 @@ def _update_ratelimit_db(request: Request):
def update_ratelimit(request: Request, pipeline: Pipeline):
- """ Update the ratelimit stored in Redis or the database depending
+ """Update the ratelimit stored in Redis or the database depending
on AUR_CONFIG's [options] cache setting.
This Redis-capable function is slightly different than most. If Redis
@@ -75,7 +72,7 @@ def update_ratelimit(request: Request, pipeline: Pipeline):
def check_ratelimit(request: Request):
- """ Increment and check to see if request has exceeded their rate limit.
+ """Increment and check to see if request has exceeded their rate limit.
:param request: FastAPI request
:returns: True if the request host has exceeded the rate limit else False
diff --git a/aurweb/redis.py b/aurweb/redis.py
index e29b8e37..af179b9b 100644
--- a/aurweb/redis.py
+++ b/aurweb/redis.py
@@ -1,9 +1,7 @@
import fakeredis
-
from redis import ConnectionPool, Redis
import aurweb.config
-
from aurweb import logging
logger = logging.get_logger(__name__)
@@ -11,7 +9,7 @@ pool = None
class FakeConnectionPool:
- """ A fake ConnectionPool class which holds an internal reference
+ """A fake ConnectionPool class which holds an internal reference
to a fakeredis handle.
We normally deal with Redis by keeping its ConnectionPool globally
diff --git a/aurweb/routers/__init__.py b/aurweb/routers/__init__.py
index da79e38f..f77bce4f 100644
--- a/aurweb/routers/__init__.py
+++ b/aurweb/routers/__init__.py
@@ -3,7 +3,18 @@ API routers for FastAPI.
See https://fastapi.tiangolo.com/tutorial/bigger-applications/
"""
-from . import accounts, auth, html, packages, pkgbase, requests, rpc, rss, sso, trusted_user
+from . import (
+ accounts,
+ auth,
+ html,
+ packages,
+ pkgbase,
+ requests,
+ rpc,
+ rss,
+ sso,
+ trusted_user,
+)
"""
aurweb application routes. This constant can be any iterable
diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py
index dcac72b0..db05955a 100644
--- a/aurweb/routers/accounts.py
+++ b/aurweb/routers/accounts.py
@@ -1,6 +1,5 @@
import copy
import typing
-
from http import HTTPStatus
from typing import Any
@@ -9,7 +8,6 @@ from fastapi.responses import HTMLResponse, RedirectResponse
from sqlalchemy import and_, or_
import aurweb.config
-
from aurweb import cookies, db, l10n, logging, models, util
from aurweb.auth import account_type_required, requires_auth, requires_guest
from aurweb.captcha import get_captcha_salts
@@ -37,21 +35,23 @@ async def passreset(request: Request):
@router.post("/passreset", response_class=HTMLResponse)
@handle_form_exceptions
@requires_guest
-async def passreset_post(request: Request,
- user: str = Form(...),
- resetkey: str = Form(default=None),
- password: str = Form(default=None),
- confirm: str = Form(default=None)):
+async def passreset_post(
+ request: Request,
+ user: str = Form(...),
+ resetkey: str = Form(default=None),
+ password: str = Form(default=None),
+ confirm: str = Form(default=None),
+):
context = await make_variable_context(request, "Password Reset")
# The user parameter being required, we can match against
criteria = or_(models.User.Username == user, models.User.Email == user)
- db_user = db.query(models.User,
- and_(criteria, models.User.Suspended == 0)).first()
+ db_user = db.query(models.User, and_(criteria, models.User.Suspended == 0)).first()
if db_user is None:
context["errors"] = ["Invalid e-mail."]
- return render_template(request, "passreset.html", context,
- status_code=HTTPStatus.NOT_FOUND)
+ return render_template(
+ request, "passreset.html", context, status_code=HTTPStatus.NOT_FOUND
+ )
db.refresh(db_user)
if resetkey:
@@ -59,29 +59,34 @@ async def passreset_post(request: Request,
if not db_user.ResetKey or resetkey != db_user.ResetKey:
context["errors"] = ["Invalid e-mail."]
- return render_template(request, "passreset.html", context,
- status_code=HTTPStatus.NOT_FOUND)
+ return render_template(
+ request, "passreset.html", context, status_code=HTTPStatus.NOT_FOUND
+ )
if not user or not password:
context["errors"] = ["Missing a required field."]
- return render_template(request, "passreset.html", context,
- status_code=HTTPStatus.BAD_REQUEST)
+ return render_template(
+ request, "passreset.html", context, status_code=HTTPStatus.BAD_REQUEST
+ )
if password != confirm:
# If the provided password does not match the provided confirm.
context["errors"] = ["Password fields do not match."]
- return render_template(request, "passreset.html", context,
- status_code=HTTPStatus.BAD_REQUEST)
+ return render_template(
+ request, "passreset.html", context, status_code=HTTPStatus.BAD_REQUEST
+ )
if len(password) < models.User.minimum_passwd_length():
# Translate the error here, which simplifies error output
# in the jinja2 template.
_ = get_translator_for_request(request)
- context["errors"] = [_(
- "Your password must be at least %s characters.") % (
- str(models.User.minimum_passwd_length()))]
- return render_template(request, "passreset.html", context,
- status_code=HTTPStatus.BAD_REQUEST)
+ context["errors"] = [
+ _("Your password must be at least %s characters.")
+ % (str(models.User.minimum_passwd_length()))
+ ]
+ return render_template(
+ request, "passreset.html", context, status_code=HTTPStatus.BAD_REQUEST
+ )
# We got to this point; everything matched up. Update the password
# and remove the ResetKey.
@@ -92,8 +97,9 @@ async def passreset_post(request: Request,
db_user.update_password(password)
# Render ?step=complete.
- return RedirectResponse(url="/passreset?step=complete",
- status_code=HTTPStatus.SEE_OTHER)
+ return RedirectResponse(
+ url="/passreset?step=complete", status_code=HTTPStatus.SEE_OTHER
+ )
# If we got here, we continue with issuing a resetkey for the user.
resetkey = generate_resetkey()
@@ -103,13 +109,13 @@ async def passreset_post(request: Request,
ResetKeyNotification(db_user.ID).send()
# Render ?step=confirm.
- return RedirectResponse(url="/passreset?step=confirm",
- status_code=HTTPStatus.SEE_OTHER)
+ return RedirectResponse(
+ url="/passreset?step=confirm", status_code=HTTPStatus.SEE_OTHER
+ )
-def process_account_form(request: Request, user: models.User,
- args: dict[str, Any]):
- """ Process an account form. All fields are optional and only checks
+def process_account_form(request: Request, user: models.User, args: dict[str, Any]):
+ """Process an account form. All fields are optional and only checks
requirements in the case they are present.
```
@@ -146,7 +152,7 @@ def process_account_form(request: Request, user: models.User,
validate.username_in_use,
validate.email_in_use,
validate.invalid_account_type,
- validate.invalid_captcha
+ validate.invalid_captcha,
]
try:
@@ -158,11 +164,10 @@ def process_account_form(request: Request, user: models.User,
return (True, [])
-def make_account_form_context(context: dict,
- request: Request,
- user: models.User,
- args: dict):
- """ Modify a FastAPI context and add attributes for the account form.
+def make_account_form_context(
+ context: dict, request: Request, user: models.User, args: dict
+):
+ """Modify a FastAPI context and add attributes for the account form.
:param context: FastAPI context
:param request: FastAPI request
@@ -173,15 +178,17 @@ def make_account_form_context(context: dict,
# Do not modify the original context.
context = copy.copy(context)
- context["account_types"] = list(filter(
- lambda e: request.user.AccountTypeID >= e[0],
- [
- (at.USER_ID, f"Normal {at.USER}"),
- (at.TRUSTED_USER_ID, at.TRUSTED_USER),
- (at.DEVELOPER_ID, at.DEVELOPER),
- (at.TRUSTED_USER_AND_DEV_ID, at.TRUSTED_USER_AND_DEV)
- ]
- ))
+ context["account_types"] = list(
+ filter(
+ lambda e: request.user.AccountTypeID >= e[0],
+ [
+ (at.USER_ID, f"Normal {at.USER}"),
+ (at.TRUSTED_USER_ID, at.TRUSTED_USER),
+ (at.DEVELOPER_ID, at.DEVELOPER),
+ (at.TRUSTED_USER_AND_DEV_ID, at.TRUSTED_USER_AND_DEV),
+ ],
+ )
+ )
if request.user.is_authenticated():
context["username"] = args.get("U", user.Username)
@@ -229,24 +236,24 @@ def make_account_form_context(context: dict,
@router.get("/register", response_class=HTMLResponse)
@requires_guest
-async def account_register(request: Request,
- U: str = Form(default=str()), # Username
- E: str = Form(default=str()), # Email
- H: str = Form(default=False), # Hide Email
- BE: str = Form(default=None), # Backup Email
- R: str = Form(default=None), # Real Name
- HP: str = Form(default=None), # Homepage
- I: str = Form(default=None), # IRC Nick
- K: str = Form(default=None), # PGP Key FP
- L: str = Form(default=aurweb.config.get(
- "options", "default_lang")),
- TZ: str = Form(default=aurweb.config.get(
- "options", "default_timezone")),
- PK: str = Form(default=None),
- CN: bool = Form(default=False), # Comment Notify
- CU: bool = Form(default=False), # Update Notify
- CO: bool = Form(default=False), # Owner Notify
- captcha: str = Form(default=str())):
+async def account_register(
+ request: Request,
+ U: str = Form(default=str()), # Username
+ E: str = Form(default=str()), # Email
+ H: str = Form(default=False), # Hide Email
+ BE: str = Form(default=None), # Backup Email
+ R: str = Form(default=None), # Real Name
+ HP: str = Form(default=None), # Homepage
+ I: str = Form(default=None), # IRC Nick
+ K: str = Form(default=None), # PGP Key FP
+ L: str = Form(default=aurweb.config.get("options", "default_lang")),
+ TZ: str = Form(default=aurweb.config.get("options", "default_timezone")),
+ PK: str = Form(default=None),
+ CN: bool = Form(default=False), # Comment Notify
+ CU: bool = Form(default=False), # Update Notify
+ CO: bool = Form(default=False), # Owner Notify
+ captcha: str = Form(default=str()),
+):
context = await make_variable_context(request, "Register")
context["captcha_salt"] = get_captcha_salts()[0]
context = make_account_form_context(context, request, None, dict())
@@ -256,32 +263,32 @@ async def account_register(request: Request,
@router.post("/register", response_class=HTMLResponse)
@handle_form_exceptions
@requires_guest
-async def account_register_post(request: Request,
- U: str = Form(default=str()), # Username
- E: str = Form(default=str()), # Email
- H: str = Form(default=False), # Hide Email
- BE: str = Form(default=None), # Backup Email
- R: str = Form(default=''), # Real Name
- HP: str = Form(default=None), # Homepage
- I: str = Form(default=None), # IRC Nick
- K: str = Form(default=None), # PGP Key
- L: str = Form(default=aurweb.config.get(
- "options", "default_lang")),
- TZ: str = Form(default=aurweb.config.get(
- "options", "default_timezone")),
- PK: str = Form(default=str()), # SSH PubKey
- CN: bool = Form(default=False),
- UN: bool = Form(default=False),
- ON: bool = Form(default=False),
- captcha: str = Form(default=None),
- captcha_salt: str = Form(...)):
+async def account_register_post(
+ request: Request,
+ U: str = Form(default=str()), # Username
+ E: str = Form(default=str()), # Email
+ H: str = Form(default=False), # Hide Email
+ BE: str = Form(default=None), # Backup Email
+ R: str = Form(default=""), # Real Name
+ HP: str = Form(default=None), # Homepage
+ I: str = Form(default=None), # IRC Nick
+ K: str = Form(default=None), # PGP Key
+ L: str = Form(default=aurweb.config.get("options", "default_lang")),
+ TZ: str = Form(default=aurweb.config.get("options", "default_timezone")),
+ PK: str = Form(default=str()), # SSH PubKey
+ CN: bool = Form(default=False),
+ UN: bool = Form(default=False),
+ ON: bool = Form(default=False),
+ captcha: str = Form(default=None),
+ captcha_salt: str = Form(...),
+):
context = await make_variable_context(request, "Register")
args = dict(await request.form())
args["K"] = args.get("K", str()).replace(" ", "")
K = args.get("K")
# Force "H" into a boolean.
- args["H"] = H = (args.get("H", str()) == "on")
+ args["H"] = H = args.get("H", str()) == "on"
context = make_account_form_context(context, request, None, args)
ok, errors = process_account_form(request, request.user, args)
@@ -289,30 +296,45 @@ async def account_register_post(request: Request,
# If the field values given do not meet the requirements,
# return HTTP 400 with an error.
context["errors"] = errors
- return render_template(request, "register.html", context,
- status_code=HTTPStatus.BAD_REQUEST)
+ return render_template(
+ request, "register.html", context, status_code=HTTPStatus.BAD_REQUEST
+ )
if not captcha:
context["errors"] = ["The CAPTCHA is missing."]
- return render_template(request, "register.html", context,
- status_code=HTTPStatus.BAD_REQUEST)
+ return render_template(
+ request, "register.html", context, status_code=HTTPStatus.BAD_REQUEST
+ )
# Create a user with no password with a resetkey, then send
# an email off about it.
resetkey = generate_resetkey()
# By default, we grab the User account type to associate with.
- atype = db.query(models.AccountType,
- models.AccountType.AccountType == "User").first()
+ atype = db.query(
+ models.AccountType, models.AccountType.AccountType == "User"
+ ).first()
# Create a user given all parameters available.
with db.begin():
- user = db.create(models.User, Username=U,
- Email=E, HideEmail=H, BackupEmail=BE,
- RealName=R, Homepage=HP, IRCNick=I, PGPKey=K,
- LangPreference=L, Timezone=TZ, CommentNotify=CN,
- UpdateNotify=UN, OwnershipNotify=ON,
- ResetKey=resetkey, AccountType=atype)
+ user = db.create(
+ models.User,
+ Username=U,
+ Email=E,
+ HideEmail=H,
+ BackupEmail=BE,
+ RealName=R,
+ Homepage=HP,
+ IRCNick=I,
+ PGPKey=K,
+ LangPreference=L,
+ Timezone=TZ,
+ CommentNotify=CN,
+ UpdateNotify=UN,
+ OwnershipNotify=ON,
+ ResetKey=resetkey,
+ AccountType=atype,
+ )
# If a PK was given and either one does not exist or the given
# PK mismatches the existing user's SSHPubKey.PubKey.
@@ -323,8 +345,9 @@ async def account_register_post(request: Request,
pk = " ".join(k)
fprint = get_fingerprint(pk)
with db.begin():
- db.create(models.SSHPubKey, UserID=user.ID,
- PubKey=pk, Fingerprint=fprint)
+ db.create(
+ models.SSHPubKey, UserID=user.ID, PubKey=pk, Fingerprint=fprint
+ )
# Send a reset key notification to the new user.
WelcomeNotification(user.ID).send()
@@ -334,8 +357,9 @@ async def account_register_post(request: Request,
return render_template(request, "register.html", context)
-def cannot_edit(request: Request, user: models.User) \
- -> typing.Optional[RedirectResponse]:
+def cannot_edit(
+ request: Request, user: models.User
+) -> typing.Optional[RedirectResponse]:
"""
Decide if `request.user` cannot edit `user`.
@@ -373,31 +397,30 @@ async def account_edit(request: Request, username: str):
@router.post("/account/{username}/edit", response_class=HTMLResponse)
@handle_form_exceptions
@requires_auth
-async def account_edit_post(request: Request,
- username: str,
- U: str = Form(default=str()), # Username
- J: bool = Form(default=False),
- E: str = Form(default=str()), # Email
- H: str = Form(default=False), # Hide Email
- BE: str = Form(default=None), # Backup Email
- R: str = Form(default=None), # Real Name
- HP: str = Form(default=None), # Homepage
- I: str = Form(default=None), # IRC Nick
- K: str = Form(default=None), # PGP Key
- L: str = Form(aurweb.config.get(
- "options", "default_lang")),
- TZ: str = Form(aurweb.config.get(
- "options", "default_timezone")),
- P: str = Form(default=str()), # New Password
- C: str = Form(default=None), # Password Confirm
- PK: str = Form(default=None), # PubKey
- CN: bool = Form(default=False), # Comment Notify
- UN: bool = Form(default=False), # Update Notify
- ON: bool = Form(default=False), # Owner Notify
- T: int = Form(default=None),
- passwd: str = Form(default=str())):
- user = db.query(models.User).filter(
- models.User.Username == username).first()
+async def account_edit_post(
+ request: Request,
+ username: str,
+ U: str = Form(default=str()), # Username
+ J: bool = Form(default=False),
+ E: str = Form(default=str()), # Email
+ H: str = Form(default=False), # Hide Email
+ BE: str = Form(default=None), # Backup Email
+ R: str = Form(default=None), # Real Name
+ HP: str = Form(default=None), # Homepage
+ I: str = Form(default=None), # IRC Nick
+ K: str = Form(default=None), # PGP Key
+ L: str = Form(aurweb.config.get("options", "default_lang")),
+ TZ: str = Form(aurweb.config.get("options", "default_timezone")),
+ P: str = Form(default=str()), # New Password
+ C: str = Form(default=None), # Password Confirm
+ PK: str = Form(default=None), # PubKey
+ CN: bool = Form(default=False), # Comment Notify
+ UN: bool = Form(default=False), # Update Notify
+ ON: bool = Form(default=False), # Owner Notify
+ T: int = Form(default=None),
+ passwd: str = Form(default=str()),
+):
+ user = db.query(models.User).filter(models.User.Username == username).first()
response = cannot_edit(request, user)
if response:
return response
@@ -416,13 +439,15 @@ async def account_edit_post(request: Request,
if not passwd:
context["errors"] = ["Invalid password."]
- return render_template(request, "account/edit.html", context,
- status_code=HTTPStatus.BAD_REQUEST)
+ return render_template(
+ request, "account/edit.html", context, status_code=HTTPStatus.BAD_REQUEST
+ )
if not ok:
context["errors"] = errors
- return render_template(request, "account/edit.html", context,
- status_code=HTTPStatus.BAD_REQUEST)
+ return render_template(
+ request, "account/edit.html", context, status_code=HTTPStatus.BAD_REQUEST
+ )
updates = [
update.simple,
@@ -430,7 +455,7 @@ async def account_edit_post(request: Request,
update.timezone,
update.ssh_pubkey,
update.account_type,
- update.password
+ update.password,
]
for f in updates:
@@ -441,18 +466,17 @@ async def account_edit_post(request: Request,
# Update cookies with requests, in case they were changed.
response = render_template(request, "account/edit.html", context)
- return cookies.update_response_cookies(request, response,
- aurtz=TZ, aurlang=L)
+ return cookies.update_response_cookies(request, response, aurtz=TZ, aurlang=L)
@router.get("/account/{username}")
async def account(request: Request, username: str):
_ = l10n.get_translator_for_request(request)
- context = await make_variable_context(
- request, _("Account") + " " + username)
+ context = await make_variable_context(request, _("Account") + " " + username)
if not request.user.is_authenticated():
- return render_template(request, "account/show.html", context,
- status_code=HTTPStatus.UNAUTHORIZED)
+ return render_template(
+ request, "account/show.html", context, status_code=HTTPStatus.UNAUTHORIZED
+ )
# Get related User record, if possible.
user = get_user_by_name(username)
@@ -460,11 +484,10 @@ async def account(request: Request, username: str):
# Format PGPKey for display with a space between each 4 characters.
k = user.PGPKey or str()
- context["pgp_key"] = " ".join([k[i:i + 4] for i in range(0, len(k), 4)])
+ context["pgp_key"] = " ".join([k[i : i + 4] for i in range(0, len(k), 4)])
login_ts = None
- session = db.query(models.Session).filter(
- models.Session.UsersID == user.ID).first()
+ session = db.query(models.Session).filter(models.Session.UsersID == user.ID).first()
if session:
login_ts = user.session.LastUpdateTS
context["login_ts"] = login_ts
@@ -480,15 +503,14 @@ async def account_comments(request: Request, username: str):
context = make_context(request, "Accounts")
context["username"] = username
context["comments"] = user.package_comments.order_by(
- models.PackageComment.CommentTS.desc())
+ models.PackageComment.CommentTS.desc()
+ )
return render_template(request, "account/comments.html", context)
@router.get("/accounts")
@requires_auth
-@account_type_required({at.TRUSTED_USER,
- at.DEVELOPER,
- at.TRUSTED_USER_AND_DEV})
+@account_type_required({at.TRUSTED_USER, at.DEVELOPER, at.TRUSTED_USER_AND_DEV})
async def accounts(request: Request):
context = make_context(request, "Accounts")
return render_template(request, "account/search.html", context)
@@ -497,19 +519,19 @@ async def accounts(request: Request):
@router.post("/accounts")
@handle_form_exceptions
@requires_auth
-@account_type_required({at.TRUSTED_USER,
- at.DEVELOPER,
- at.TRUSTED_USER_AND_DEV})
-async def accounts_post(request: Request,
- O: int = Form(default=0), # Offset
- SB: str = Form(default=str()), # Sort By
- U: str = Form(default=str()), # Username
- T: str = Form(default=str()), # Account Type
- S: bool = Form(default=False), # Suspended
- E: str = Form(default=str()), # Email
- R: str = Form(default=str()), # Real Name
- I: str = Form(default=str()), # IRC Nick
- K: str = Form(default=str())): # PGP Key
+@account_type_required({at.TRUSTED_USER, at.DEVELOPER, at.TRUSTED_USER_AND_DEV})
+async def accounts_post(
+ request: Request,
+ O: int = Form(default=0), # Offset
+ SB: str = Form(default=str()), # Sort By
+ U: str = Form(default=str()), # Username
+ T: str = Form(default=str()), # Account Type
+ S: bool = Form(default=False), # Suspended
+ E: str = Form(default=str()), # Email
+ R: str = Form(default=str()), # Real Name
+ I: str = Form(default=str()), # IRC Nick
+ K: str = Form(default=str()),
+): # PGP Key
context = await make_variable_context(request, "Accounts")
context["pp"] = pp = 50 # Hits per page.
@@ -534,7 +556,7 @@ async def accounts_post(request: Request,
"u": at.USER_ID,
"t": at.TRUSTED_USER_ID,
"d": at.DEVELOPER_ID,
- "td": at.TRUSTED_USER_AND_DEV_ID
+ "td": at.TRUSTED_USER_AND_DEV_ID,
}
account_type_id = account_types.get(T, None)
@@ -545,7 +567,8 @@ async def accounts_post(request: Request,
# Populate this list with any additional statements to
# be ANDed together.
statements = [
- v for k, v in [
+ v
+ for k, v in [
(account_type_id is not None, models.AccountType.ID == account_type_id),
(bool(U), models.User.Username.like(f"%{U}%")),
(bool(S), models.User.Suspended == S),
@@ -553,7 +576,8 @@ async def accounts_post(request: Request,
(bool(R), models.User.RealName.like(f"%{R}%")),
(bool(I), models.User.IRCNick.like(f"%{I}%")),
(bool(K), models.User.PGPKey.like(f"%{K}%")),
- ] if k
+ ]
+ if k
]
# Filter the query by coe-mbining all statements added above into
@@ -571,9 +595,7 @@ async def accounts_post(request: Request,
return render_template(request, "account/index.html", context)
-def render_terms_of_service(request: Request,
- context: dict,
- terms: typing.Iterable):
+def render_terms_of_service(request: Request, context: dict, terms: typing.Iterable):
if not terms:
return RedirectResponse("/", status_code=HTTPStatus.SEE_OTHER)
context["unaccepted_terms"] = terms
@@ -585,14 +607,21 @@ def render_terms_of_service(request: Request,
async def terms_of_service(request: Request):
# Query the database for terms that were previously accepted,
# but now have a bumped Revision that needs to be accepted.
- diffs = db.query(models.Term).join(models.AcceptedTerm).filter(
- models.AcceptedTerm.Revision < models.Term.Revision).all()
+ diffs = (
+ db.query(models.Term)
+ .join(models.AcceptedTerm)
+ .filter(models.AcceptedTerm.Revision < models.Term.Revision)
+ .all()
+ )
# Query the database for any terms that have not yet been accepted.
- unaccepted = db.query(models.Term).filter(
- ~models.Term.ID.in_(db.query(models.AcceptedTerm.TermsID))).all()
+ unaccepted = (
+ db.query(models.Term)
+ .filter(~models.Term.ID.in_(db.query(models.AcceptedTerm.TermsID)))
+ .all()
+ )
- for record in (diffs + unaccepted):
+ for record in diffs + unaccepted:
db.refresh(record)
# Translate the 'Terms of Service' part of our page title.
@@ -607,16 +636,22 @@ async def terms_of_service(request: Request):
@router.post("/tos")
@handle_form_exceptions
@requires_auth
-async def terms_of_service_post(request: Request,
- accept: bool = Form(default=False)):
+async def terms_of_service_post(request: Request, accept: bool = Form(default=False)):
# Query the database for terms that were previously accepted,
# but now have a bumped Revision that needs to be accepted.
- diffs = db.query(models.Term).join(models.AcceptedTerm).filter(
- models.AcceptedTerm.Revision < models.Term.Revision).all()
+ diffs = (
+ db.query(models.Term)
+ .join(models.AcceptedTerm)
+ .filter(models.AcceptedTerm.Revision < models.Term.Revision)
+ .all()
+ )
# Query the database for any terms that have not yet been accepted.
- unaccepted = db.query(models.Term).filter(
- ~models.Term.ID.in_(db.query(models.AcceptedTerm.TermsID))).all()
+ unaccepted = (
+ db.query(models.Term)
+ .filter(~models.Term.ID.in_(db.query(models.AcceptedTerm.TermsID)))
+ .all()
+ )
if not accept:
# Translate the 'Terms of Service' part of our page title.
@@ -628,7 +663,8 @@ async def terms_of_service_post(request: Request,
# them instead of reiterating the process in terms_of_service.
accept_needed = sorted(unaccepted + diffs)
return render_terms_of_service(
- request, context, util.apply_all(accept_needed, db.refresh))
+ request, context, util.apply_all(accept_needed, db.refresh)
+ )
with db.begin():
# For each term we found, query for the matching accepted term
@@ -636,13 +672,18 @@ async def terms_of_service_post(request: Request,
for term in diffs:
db.refresh(term)
accepted_term = request.user.accepted_terms.filter(
- models.AcceptedTerm.TermsID == term.ID).first()
+ models.AcceptedTerm.TermsID == term.ID
+ ).first()
accepted_term.Revision = term.Revision
# For each term that was never accepted, accept it!
for term in unaccepted:
db.refresh(term)
- db.create(models.AcceptedTerm, User=request.user,
- Term=term, Revision=term.Revision)
+ db.create(
+ models.AcceptedTerm,
+ User=request.user,
+ Term=term,
+ Revision=term.Revision,
+ )
return RedirectResponse("/", status_code=HTTPStatus.SEE_OTHER)
diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py
index 50cec419..3f94952e 100644
--- a/aurweb/routers/auth.py
+++ b/aurweb/routers/auth.py
@@ -5,7 +5,6 @@ from fastapi.responses import HTMLResponse, RedirectResponse
from sqlalchemy import or_
import aurweb.config
-
from aurweb import cookies, db
from aurweb.auth import requires_auth, requires_guest
from aurweb.exceptions import handle_form_exceptions
@@ -17,7 +16,7 @@ router = APIRouter()
async def login_template(request: Request, next: str, errors: list = None):
- """ Provide login-specific template context to render_template. """
+ """Provide login-specific template context to render_template."""
context = await make_variable_context(request, "Login", next)
context["errors"] = errors
context["url_base"] = f"{request.url.scheme}://{request.url.netloc}"
@@ -32,55 +31,73 @@ async def login_get(request: Request, next: str = "/"):
@router.post("/login", response_class=HTMLResponse)
@handle_form_exceptions
@requires_guest
-async def login_post(request: Request,
- next: str = Form(...),
- user: str = Form(default=str()),
- passwd: str = Form(default=str()),
- remember_me: bool = Form(default=False)):
+async def login_post(
+ request: Request,
+ next: str = Form(...),
+ user: str = Form(default=str()),
+ passwd: str = Form(default=str()),
+ remember_me: bool = Form(default=False),
+):
# TODO: Once the Origin header gets broader adoption, this code can be
# slightly simplified to use it.
login_path = aurweb.config.get("options", "aur_location") + "/login"
referer = request.headers.get("Referer")
if not referer or not referer.startswith(login_path):
_ = get_translator_for_request(request)
- raise HTTPException(status_code=HTTPStatus.BAD_REQUEST,
- detail=_("Bad Referer header."))
+ raise HTTPException(
+ status_code=HTTPStatus.BAD_REQUEST, detail=_("Bad Referer header.")
+ )
with db.begin():
- user = db.query(User).filter(
- or_(User.Username == user, User.Email == user)
- ).first()
+ user = (
+ db.query(User)
+ .filter(or_(User.Username == user, User.Email == user))
+ .first()
+ )
if not user:
- return await login_template(request, next,
- errors=["Bad username or password."])
+ return await login_template(request, next, errors=["Bad username or password."])
if user.Suspended:
- return await login_template(request, next,
- errors=["Account Suspended"])
+ return await login_template(request, next, errors=["Account Suspended"])
cookie_timeout = cookies.timeout(remember_me)
sid = user.login(request, passwd, cookie_timeout)
if not sid:
- return await login_template(request, next,
- errors=["Bad username or password."])
+ return await login_template(request, next, errors=["Bad username or password."])
- response = RedirectResponse(url=next,
- status_code=HTTPStatus.SEE_OTHER)
+ response = RedirectResponse(url=next, status_code=HTTPStatus.SEE_OTHER)
secure = aurweb.config.getboolean("options", "disable_http_login")
- response.set_cookie("AURSID", sid, max_age=cookie_timeout,
- secure=secure, httponly=secure,
- samesite=cookies.samesite())
- response.set_cookie("AURTZ", user.Timezone,
- secure=secure, httponly=secure,
- samesite=cookies.samesite())
- response.set_cookie("AURLANG", user.LangPreference,
- secure=secure, httponly=secure,
- samesite=cookies.samesite())
- response.set_cookie("AURREMEMBER", remember_me,
- secure=secure, httponly=secure,
- samesite=cookies.samesite())
+ response.set_cookie(
+ "AURSID",
+ sid,
+ max_age=cookie_timeout,
+ secure=secure,
+ httponly=secure,
+ samesite=cookies.samesite(),
+ )
+ response.set_cookie(
+ "AURTZ",
+ user.Timezone,
+ secure=secure,
+ httponly=secure,
+ samesite=cookies.samesite(),
+ )
+ response.set_cookie(
+ "AURLANG",
+ user.LangPreference,
+ secure=secure,
+ httponly=secure,
+ samesite=cookies.samesite(),
+ )
+ response.set_cookie(
+ "AURREMEMBER",
+ remember_me,
+ secure=secure,
+ httponly=secure,
+ samesite=cookies.samesite(),
+ )
return response
@@ -93,8 +110,7 @@ async def logout(request: Request, next: str = Form(default="/")):
# Use 303 since we may be handling a post request, that'll get it
# to redirect to a get request.
- response = RedirectResponse(url=next,
- status_code=HTTPStatus.SEE_OTHER)
+ response = RedirectResponse(url=next, status_code=HTTPStatus.SEE_OTHER)
response.delete_cookie("AURSID")
response.delete_cookie("AURTZ")
return response
diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py
index d31a32c7..2148d535 100644
--- a/aurweb/routers/html.py
+++ b/aurweb/routers/html.py
@@ -2,17 +2,20 @@
decorators in some way; more complex routes should be defined in their
own modules and imported here. """
import os
-
from http import HTTPStatus
from fastapi import APIRouter, Form, HTTPException, Request, Response
from fastapi.responses import HTMLResponse, RedirectResponse
-from prometheus_client import CONTENT_TYPE_LATEST, CollectorRegistry, generate_latest, multiprocess
+from prometheus_client import (
+ CONTENT_TYPE_LATEST,
+ CollectorRegistry,
+ generate_latest,
+ multiprocess,
+)
from sqlalchemy import and_, case, or_
import aurweb.config
import aurweb.models.package_request
-
from aurweb import cookies, db, logging, models, time, util
from aurweb.cache import db_count_cache
from aurweb.exceptions import handle_form_exceptions
@@ -27,17 +30,19 @@ router = APIRouter()
@router.get("/favicon.ico")
async def favicon(request: Request):
- """ Some browsers attempt to find a website's favicon via root uri at
- /favicon.ico, so provide a redirection here to our static icon. """
+ """Some browsers attempt to find a website's favicon via root uri at
+ /favicon.ico, so provide a redirection here to our static icon."""
return RedirectResponse("/static/images/favicon.ico")
@router.post("/language", response_class=RedirectResponse)
@handle_form_exceptions
-async def language(request: Request,
- set_lang: str = Form(...),
- next: str = Form(...),
- q: str = Form(default=None)):
+async def language(
+ request: Request,
+ set_lang: str = Form(...),
+ next: str = Form(...),
+ q: str = Form(default=None),
+):
"""
A POST route used to set a session's language.
@@ -45,7 +50,7 @@ async def language(request: Request,
setting the language on any page, we want to preserve query
parameters across the redirect.
"""
- if next[0] != '/':
+ if next[0] != "/":
return HTMLResponse(b"Invalid 'next' parameter.", status_code=400)
query_string = "?" + q if q else str()
@@ -56,20 +61,21 @@ async def language(request: Request,
request.user.LangPreference = set_lang
# In any case, set the response's AURLANG cookie that never expires.
- response = RedirectResponse(url=f"{next}{query_string}",
- status_code=HTTPStatus.SEE_OTHER)
+ response = RedirectResponse(
+ url=f"{next}{query_string}", status_code=HTTPStatus.SEE_OTHER
+ )
secure = aurweb.config.getboolean("options", "disable_http_login")
- response.set_cookie("AURLANG", set_lang,
- secure=secure, httponly=secure,
- samesite=cookies.samesite())
+ response.set_cookie(
+ "AURLANG", set_lang, secure=secure, httponly=secure, samesite=cookies.samesite()
+ )
return response
@router.get("/", response_class=HTMLResponse)
async def index(request: Request):
- """ Homepage route. """
+ """Homepage route."""
context = make_context(request, "Home")
- context['ssh_fingerprints'] = util.get_ssh_fingerprints()
+ context["ssh_fingerprints"] = util.get_ssh_fingerprints()
bases = db.query(models.PackageBase)
@@ -79,24 +85,33 @@ async def index(request: Request):
# Package statistics.
query = bases.filter(models.PackageBase.PackagerUID.isnot(None))
context["package_count"] = await db_count_cache(
- redis, "package_count", query, expire=cache_expire)
+ redis, "package_count", query, expire=cache_expire
+ )
query = bases.filter(
- and_(models.PackageBase.MaintainerUID.is_(None),
- models.PackageBase.PackagerUID.isnot(None))
+ and_(
+ models.PackageBase.MaintainerUID.is_(None),
+ models.PackageBase.PackagerUID.isnot(None),
+ )
)
context["orphan_count"] = await db_count_cache(
- redis, "orphan_count", query, expire=cache_expire)
+ redis, "orphan_count", query, expire=cache_expire
+ )
query = db.query(models.User)
context["user_count"] = await db_count_cache(
- redis, "user_count", query, expire=cache_expire)
+ redis, "user_count", query, expire=cache_expire
+ )
query = query.filter(
- or_(models.User.AccountTypeID == TRUSTED_USER_ID,
- models.User.AccountTypeID == TRUSTED_USER_AND_DEV_ID))
+ or_(
+ models.User.AccountTypeID == TRUSTED_USER_ID,
+ models.User.AccountTypeID == TRUSTED_USER_AND_DEV_ID,
+ )
+ )
context["trusted_user_count"] = await db_count_cache(
- redis, "trusted_user_count", query, expire=cache_expire)
+ redis, "trusted_user_count", query, expire=cache_expire
+ )
# Current timestamp.
now = time.utcnow()
@@ -106,31 +121,40 @@ async def index(request: Request):
one_hour = 3600
updated = bases.filter(
- and_(models.PackageBase.ModifiedTS - models.PackageBase.SubmittedTS >= one_hour,
- models.PackageBase.PackagerUID.isnot(None))
+ and_(
+ models.PackageBase.ModifiedTS - models.PackageBase.SubmittedTS >= one_hour,
+ models.PackageBase.PackagerUID.isnot(None),
+ )
)
query = bases.filter(
- and_(models.PackageBase.SubmittedTS >= seven_days_ago,
- models.PackageBase.PackagerUID.isnot(None))
+ and_(
+ models.PackageBase.SubmittedTS >= seven_days_ago,
+ models.PackageBase.PackagerUID.isnot(None),
+ )
)
context["seven_days_old_added"] = await db_count_cache(
- redis, "seven_days_old_added", query, expire=cache_expire)
+ redis, "seven_days_old_added", query, expire=cache_expire
+ )
query = updated.filter(models.PackageBase.ModifiedTS >= seven_days_ago)
context["seven_days_old_updated"] = await db_count_cache(
- redis, "seven_days_old_updated", query, expire=cache_expire)
+ redis, "seven_days_old_updated", query, expire=cache_expire
+ )
year = seven_days * 52 # Fifty two weeks worth: one year.
year_ago = now - year
query = updated.filter(models.PackageBase.ModifiedTS >= year_ago)
context["year_old_updated"] = await db_count_cache(
- redis, "year_old_updated", query, expire=cache_expire)
+ redis, "year_old_updated", query, expire=cache_expire
+ )
query = bases.filter(
- models.PackageBase.ModifiedTS - models.PackageBase.SubmittedTS < 3600)
+ models.PackageBase.ModifiedTS - models.PackageBase.SubmittedTS < 3600
+ )
context["never_updated"] = await db_count_cache(
- redis, "never_updated", query, expire=cache_expire)
+ redis, "never_updated", query, expire=cache_expire
+ )
# Get the 15 most recently updated packages.
context["package_updates"] = updated_packages(15, cache_expire)
@@ -140,78 +164,92 @@ async def index(request: Request):
# the dashboard display.
packages = db.query(models.Package).join(models.PackageBase)
- maintained = packages.join(
- models.PackageComaintainer,
- models.PackageComaintainer.PackageBaseID == models.PackageBase.ID,
- isouter=True
- ).join(
- models.User,
- or_(models.PackageBase.MaintainerUID == models.User.ID,
- models.PackageComaintainer.UsersID == models.User.ID)
- ).filter(
- models.User.ID == request.user.ID
+ maintained = (
+ packages.join(
+ models.PackageComaintainer,
+ models.PackageComaintainer.PackageBaseID == models.PackageBase.ID,
+ isouter=True,
+ )
+ .join(
+ models.User,
+ or_(
+ models.PackageBase.MaintainerUID == models.User.ID,
+ models.PackageComaintainer.UsersID == models.User.ID,
+ ),
+ )
+ .filter(models.User.ID == request.user.ID)
)
# Packages maintained by the user that have been flagged.
- context["flagged_packages"] = maintained.filter(
- models.PackageBase.OutOfDateTS.isnot(None)
- ).order_by(
- models.PackageBase.ModifiedTS.desc(), models.Package.Name.asc()
- ).limit(50).all()
+ context["flagged_packages"] = (
+ maintained.filter(models.PackageBase.OutOfDateTS.isnot(None))
+ .order_by(models.PackageBase.ModifiedTS.desc(), models.Package.Name.asc())
+ .limit(50)
+ .all()
+ )
# Flagged packages that request.user has voted for.
context["flagged_packages_voted"] = query_voted(
- context.get("flagged_packages"), request.user)
+ context.get("flagged_packages"), request.user
+ )
# Flagged packages that request.user is being notified about.
context["flagged_packages_notified"] = query_notified(
- context.get("flagged_packages"), request.user)
+ context.get("flagged_packages"), request.user
+ )
- archive_time = aurweb.config.getint('options', 'request_archive_time')
+ archive_time = aurweb.config.getint("options", "request_archive_time")
start = now - archive_time
# Package requests created by request.user.
- context["package_requests"] = request.user.package_requests.filter(
- models.PackageRequest.RequestTS >= start
- ).order_by(
- # Order primarily by the Status column being PENDING_ID,
- # and secondarily by RequestTS; both in descending order.
- case([(models.PackageRequest.Status == PENDING_ID, 1)],
- else_=0).desc(),
- models.PackageRequest.RequestTS.desc()
- ).limit(50).all()
+ context["package_requests"] = (
+ request.user.package_requests.filter(
+ models.PackageRequest.RequestTS >= start
+ )
+ .order_by(
+ # Order primarily by the Status column being PENDING_ID,
+ # and secondarily by RequestTS; both in descending order.
+ case([(models.PackageRequest.Status == PENDING_ID, 1)], else_=0).desc(),
+ models.PackageRequest.RequestTS.desc(),
+ )
+ .limit(50)
+ .all()
+ )
# Packages that the request user maintains or comaintains.
- context["packages"] = maintained.filter(
- models.User.ID == models.PackageBase.MaintainerUID
- ).order_by(
- models.PackageBase.ModifiedTS.desc(), models.Package.Name.desc()
- ).limit(50).all()
+ context["packages"] = (
+ maintained.filter(models.User.ID == models.PackageBase.MaintainerUID)
+ .order_by(models.PackageBase.ModifiedTS.desc(), models.Package.Name.desc())
+ .limit(50)
+ .all()
+ )
# Packages that request.user has voted for.
- context["packages_voted"] = query_voted(
- context.get("packages"), request.user)
+ context["packages_voted"] = query_voted(context.get("packages"), request.user)
# Packages that request.user is being notified about.
context["packages_notified"] = query_notified(
- context.get("packages"), request.user)
+ context.get("packages"), request.user
+ )
# Any packages that the request user comaintains.
- context["comaintained"] = packages.join(
- models.PackageComaintainer
- ).filter(
- models.PackageComaintainer.UsersID == request.user.ID
- ).order_by(
- models.PackageBase.ModifiedTS.desc(), models.Package.Name.desc()
- ).limit(50).all()
+ context["comaintained"] = (
+ packages.join(models.PackageComaintainer)
+ .filter(models.PackageComaintainer.UsersID == request.user.ID)
+ .order_by(models.PackageBase.ModifiedTS.desc(), models.Package.Name.desc())
+ .limit(50)
+ .all()
+ )
# Comaintained packages that request.user has voted for.
context["comaintained_voted"] = query_voted(
- context.get("comaintained"), request.user)
+ context.get("comaintained"), request.user
+ )
# Comaintained packages that request.user is being notified about.
context["comaintained_notified"] = query_notified(
- context.get("comaintained"), request.user)
+ context.get("comaintained"), request.user
+ )
return render_template(request, "index.html", context)
@@ -232,16 +270,15 @@ async def archive_sha256(request: Request, archive: str):
@router.get("/metrics")
async def metrics(request: Request):
if not os.environ.get("PROMETHEUS_MULTIPROC_DIR", None):
- return Response("Prometheus metrics are not enabled.",
- status_code=HTTPStatus.SERVICE_UNAVAILABLE)
+ return Response(
+ "Prometheus metrics are not enabled.",
+ status_code=HTTPStatus.SERVICE_UNAVAILABLE,
+ )
registry = CollectorRegistry()
multiprocess.MultiProcessCollector(registry)
data = generate_latest(registry)
- headers = {
- "Content-Type": CONTENT_TYPE_LATEST,
- "Content-Length": str(len(data))
- }
+ headers = {"Content-Type": CONTENT_TYPE_LATEST, "Content-Length": str(len(data))}
return Response(data, headers=headers)
diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py
index 7bf4e3d4..55d2abf5 100644
--- a/aurweb/routers/packages.py
+++ b/aurweb/routers/packages.py
@@ -5,7 +5,6 @@ from typing import Any
from fastapi import APIRouter, Form, Query, Request, Response
import aurweb.filters # noqa: F401
-
from aurweb import config, db, defaults, logging, models, util
from aurweb.auth import creds, requires_auth
from aurweb.exceptions import InvariantError, handle_form_exceptions
@@ -13,23 +12,24 @@ from aurweb.models.relation_type import CONFLICTS_ID, PROVIDES_ID, REPLACES_ID
from aurweb.packages import util as pkgutil
from aurweb.packages.search import PackageSearch
from aurweb.packages.util import get_pkg_or_base
-from aurweb.pkgbase import actions as pkgbase_actions
-from aurweb.pkgbase import util as pkgbaseutil
+from aurweb.pkgbase import actions as pkgbase_actions, util as pkgbaseutil
from aurweb.templates import make_context, make_variable_context, render_template
logger = logging.get_logger(__name__)
router = APIRouter()
-async def packages_get(request: Request, context: dict[str, Any],
- status_code: HTTPStatus = HTTPStatus.OK):
+async def packages_get(
+ request: Request, context: dict[str, Any], status_code: HTTPStatus = HTTPStatus.OK
+):
# Query parameters used in this request.
context["q"] = dict(request.query_params)
# Per page and offset.
offset, per_page = util.sanitize_params(
request.query_params.get("O", defaults.O),
- request.query_params.get("PP", defaults.PP))
+ request.query_params.get("PP", defaults.PP),
+ )
context["O"] = offset
# Limit PP to options.max_search_results
@@ -82,8 +82,7 @@ async def packages_get(request: Request, context: dict[str, Any],
if submit == "Orphans":
# If the user clicked the "Orphans" button, we only want
# orphaned packages.
- search.query = search.query.filter(
- models.PackageBase.MaintainerUID.is_(None))
+ search.query = search.query.filter(models.PackageBase.MaintainerUID.is_(None))
# Collect search result count here; we've applied our keywords.
# Including more query operations below, like ordering, will
@@ -94,26 +93,31 @@ async def packages_get(request: Request, context: dict[str, Any],
search.sort_by(sort_by, sort_order)
# Insert search results into the context.
- results = search.results().with_entities(
- models.Package.ID,
- models.Package.Name,
- models.Package.PackageBaseID,
- models.Package.Version,
- models.Package.Description,
- models.PackageBase.Popularity,
- models.PackageBase.NumVotes,
- models.PackageBase.OutOfDateTS,
- models.User.Username.label("Maintainer"),
- models.PackageVote.PackageBaseID.label("Voted"),
- models.PackageNotification.PackageBaseID.label("Notify")
- ).group_by(models.Package.Name)
+ results = (
+ search.results()
+ .with_entities(
+ models.Package.ID,
+ models.Package.Name,
+ models.Package.PackageBaseID,
+ models.Package.Version,
+ models.Package.Description,
+ models.PackageBase.Popularity,
+ models.PackageBase.NumVotes,
+ models.PackageBase.OutOfDateTS,
+ models.User.Username.label("Maintainer"),
+ models.PackageVote.PackageBaseID.label("Voted"),
+ models.PackageNotification.PackageBaseID.label("Notify"),
+ )
+ .group_by(models.Package.Name)
+ )
packages = results.limit(per_page).offset(offset)
context["packages"] = packages
context["packages_count"] = num_packages
- return render_template(request, "packages/index.html", context,
- status_code=status_code)
+ return render_template(
+ request, "packages/index.html", context, status_code=status_code
+ )
@router.get("/packages")
@@ -123,9 +127,12 @@ async def packages(request: Request) -> Response:
@router.get("/packages/{name}")
-async def package(request: Request, name: str,
- all_deps: bool = Query(default=False),
- all_reqs: bool = Query(default=False)) -> Response:
+async def package(
+ request: Request,
+ name: str,
+ all_deps: bool = Query(default=False),
+ all_reqs: bool = Query(default=False),
+) -> Response:
"""
Get a package by name.
@@ -156,26 +163,21 @@ async def package(request: Request, name: str,
# Add our base information.
context = await pkgbaseutil.make_variable_context(request, pkgbase)
- context.update(
- {
- "all_deps": all_deps,
- "all_reqs": all_reqs
- }
- )
+ context.update({"all_deps": all_deps, "all_reqs": all_reqs})
context["package"] = pkg
# Package sources.
context["sources"] = pkg.package_sources.order_by(
- models.PackageSource.Source.asc()).all()
+ models.PackageSource.Source.asc()
+ ).all()
# Listing metadata.
context["max_listing"] = max_listing = 20
# Package dependencies.
deps = pkg.package_dependencies.order_by(
- models.PackageDependency.DepTypeID.asc(),
- models.PackageDependency.DepName.asc()
+ models.PackageDependency.DepTypeID.asc(), models.PackageDependency.DepName.asc()
)
context["depends_count"] = deps.count()
if not all_deps:
@@ -183,8 +185,7 @@ async def package(request: Request, name: str,
context["dependencies"] = deps.all()
# Package requirements (other packages depend on this one).
- reqs = pkgutil.pkg_required(
- pkg.Name, [p.RelName for p in rels_data.get("p", [])])
+ reqs = pkgutil.pkg_required(pkg.Name, [p.RelName for p in rels_data.get("p", [])])
context["reqs_count"] = reqs.count()
if not all_reqs:
reqs = reqs.limit(max_listing)
@@ -210,8 +211,7 @@ async def package(request: Request, name: str,
return render_template(request, "packages/show.html", context)
-async def packages_unflag(request: Request, package_ids: list[int] = [],
- **kwargs):
+async def packages_unflag(request: Request, package_ids: list[int] = [], **kwargs):
if not package_ids:
return (False, ["You did not select any packages to unflag."])
@@ -220,11 +220,11 @@ async def packages_unflag(request: Request, package_ids: list[int] = [],
bases = set()
package_ids = set(package_ids) # Convert this to a set for O(1).
- packages = db.query(models.Package).filter(
- models.Package.ID.in_(package_ids)).all()
+ packages = db.query(models.Package).filter(models.Package.ID.in_(package_ids)).all()
for pkg in packages:
has_cred = request.user.has_credential(
- creds.PKGBASE_UNFLAG, approved=[pkg.PackageBase.Flagger])
+ creds.PKGBASE_UNFLAG, approved=[pkg.PackageBase.Flagger]
+ )
if not has_cred:
return (False, ["You did not select any packages to unflag."])
@@ -236,20 +236,17 @@ async def packages_unflag(request: Request, package_ids: list[int] = [],
return (True, ["The selected packages have been unflagged."])
-async def packages_notify(request: Request, package_ids: list[int] = [],
- **kwargs):
+async def packages_notify(request: Request, package_ids: list[int] = [], **kwargs):
# In cases where we encounter errors with the request, we'll
# use this error tuple as a return value.
# TODO: This error does not yet have a translation.
- error_tuple = (False,
- ["You did not select any packages to be notified about."])
+ error_tuple = (False, ["You did not select any packages to be notified about."])
if not package_ids:
return error_tuple
bases = set()
package_ids = set(package_ids)
- packages = db.query(models.Package).filter(
- models.Package.ID.in_(package_ids)).all()
+ packages = db.query(models.Package).filter(models.Package.ID.in_(package_ids)).all()
for pkg in packages:
if pkg.PackageBase not in bases:
@@ -257,9 +254,11 @@ async def packages_notify(request: Request, package_ids: list[int] = [],
# Perform some checks on what the user selected for notify.
for pkgbase in bases:
- notif = db.query(pkgbase.notifications.filter(
- models.PackageNotification.UserID == request.user.ID
- ).exists()).scalar()
+ notif = db.query(
+ pkgbase.notifications.filter(
+ models.PackageNotification.UserID == request.user.ID
+ ).exists()
+ ).scalar()
has_cred = request.user.has_credential(creds.PKGBASE_NOTIFY)
# If the request user either does not have credentials
@@ -275,23 +274,20 @@ async def packages_notify(request: Request, package_ids: list[int] = [],
return (True, ["The selected packages' notifications have been enabled."])
-async def packages_unnotify(request: Request, package_ids: list[int] = [],
- **kwargs):
+async def packages_unnotify(request: Request, package_ids: list[int] = [], **kwargs):
if not package_ids:
# TODO: This error does not yet have a translation.
- return (False,
- ["You did not select any packages for notification removal."])
+ return (False, ["You did not select any packages for notification removal."])
# TODO: This error does not yet have a translation.
error_tuple = (
False,
- ["A package you selected does not have notifications enabled."]
+ ["A package you selected does not have notifications enabled."],
)
bases = set()
package_ids = set(package_ids)
- packages = db.query(models.Package).filter(
- models.Package.ID.in_(package_ids)).all()
+ packages = db.query(models.Package).filter(models.Package.ID.in_(package_ids)).all()
for pkg in packages:
if pkg.PackageBase not in bases:
@@ -299,9 +295,11 @@ async def packages_unnotify(request: Request, package_ids: list[int] = [],
# Perform some checks on what the user selected for notify.
for pkgbase in bases:
- notif = db.query(pkgbase.notifications.filter(
- models.PackageNotification.UserID == request.user.ID
- ).exists()).scalar()
+ notif = db.query(
+ pkgbase.notifications.filter(
+ models.PackageNotification.UserID == request.user.ID
+ ).exists()
+ ).scalar()
if not notif:
return error_tuple
@@ -312,19 +310,24 @@ async def packages_unnotify(request: Request, package_ids: list[int] = [],
return (True, ["The selected packages' notifications have been removed."])
-async def packages_adopt(request: Request, package_ids: list[int] = [],
- confirm: bool = False, **kwargs):
+async def packages_adopt(
+ request: Request, package_ids: list[int] = [], confirm: bool = False, **kwargs
+):
if not package_ids:
return (False, ["You did not select any packages to adopt."])
if not confirm:
- return (False, ["The selected packages have not been adopted, "
- "check the confirmation checkbox."])
+ return (
+ False,
+ [
+ "The selected packages have not been adopted, "
+ "check the confirmation checkbox."
+ ],
+ )
bases = set()
package_ids = set(package_ids)
- packages = db.query(models.Package).filter(
- models.Package.ID.in_(package_ids)).all()
+ packages = db.query(models.Package).filter(models.Package.ID.in_(package_ids)).all()
for pkg in packages:
if pkg.PackageBase not in bases:
@@ -335,8 +338,10 @@ async def packages_adopt(request: Request, package_ids: list[int] = [],
has_cred = request.user.has_credential(creds.PKGBASE_ADOPT)
if not (has_cred or not pkgbase.Maintainer):
# TODO: This error needs to be translated.
- return (False, ["You are not allowed to adopt one of the "
- "packages you selected."])
+ return (
+ False,
+ ["You are not allowed to adopt one of the " "packages you selected."],
+ )
# Now, really adopt the bases.
for pkgbase in bases:
@@ -345,8 +350,7 @@ async def packages_adopt(request: Request, package_ids: list[int] = [],
return (True, ["The selected packages have been adopted."])
-def disown_all(request: Request, pkgbases: list[models.PackageBase]) \
- -> list[str]:
+def disown_all(request: Request, pkgbases: list[models.PackageBase]) -> list[str]:
errors = []
for pkgbase in pkgbases:
try:
@@ -356,19 +360,24 @@ def disown_all(request: Request, pkgbases: list[models.PackageBase]) \
return errors
-async def packages_disown(request: Request, package_ids: list[int] = [],
- confirm: bool = False, **kwargs):
+async def packages_disown(
+ request: Request, package_ids: list[int] = [], confirm: bool = False, **kwargs
+):
if not package_ids:
return (False, ["You did not select any packages to disown."])
if not confirm:
- return (False, ["The selected packages have not been disowned, "
- "check the confirmation checkbox."])
+ return (
+ False,
+ [
+ "The selected packages have not been disowned, "
+ "check the confirmation checkbox."
+ ],
+ )
bases = set()
package_ids = set(package_ids)
- packages = db.query(models.Package).filter(
- models.Package.ID.in_(package_ids)).all()
+ packages = db.query(models.Package).filter(models.Package.ID.in_(package_ids)).all()
for pkg in packages:
if pkg.PackageBase not in bases:
@@ -376,12 +385,15 @@ async def packages_disown(request: Request, package_ids: list[int] = [],
# Check that the user has credentials for every package they selected.
for pkgbase in bases:
- has_cred = request.user.has_credential(creds.PKGBASE_DISOWN,
- approved=[pkgbase.Maintainer])
+ has_cred = request.user.has_credential(
+ creds.PKGBASE_DISOWN, approved=[pkgbase.Maintainer]
+ )
if not has_cred:
# TODO: This error needs to be translated.
- return (False, ["You are not allowed to disown one "
- "of the packages you selected."])
+ return (
+ False,
+ ["You are not allowed to disown one " "of the packages you selected."],
+ )
# Now, disown all the bases if we can.
if errors := disown_all(request, bases):
@@ -390,23 +402,31 @@ async def packages_disown(request: Request, package_ids: list[int] = [],
return (True, ["The selected packages have been disowned."])
-async def packages_delete(request: Request, package_ids: list[int] = [],
- confirm: bool = False, merge_into: str = str(),
- **kwargs):
+async def packages_delete(
+ request: Request,
+ package_ids: list[int] = [],
+ confirm: bool = False,
+ merge_into: str = str(),
+ **kwargs,
+):
if not package_ids:
return (False, ["You did not select any packages to delete."])
if not confirm:
- return (False, ["The selected packages have not been deleted, "
- "check the confirmation checkbox."])
+ return (
+ False,
+ [
+ "The selected packages have not been deleted, "
+ "check the confirmation checkbox."
+ ],
+ )
if not request.user.has_credential(creds.PKGBASE_DELETE):
return (False, ["You do not have permission to delete packages."])
# set-ify package_ids and query the database for related records.
package_ids = set(package_ids)
- packages = db.query(models.Package).filter(
- models.Package.ID.in_(package_ids)).all()
+ packages = db.query(models.Package).filter(models.Package.ID.in_(package_ids)).all()
if len(packages) != len(package_ids):
# Let the user know there was an issue with their input: they have
@@ -422,12 +442,15 @@ async def packages_delete(request: Request, package_ids: list[int] = [],
notifs += pkgbase_actions.pkgbase_delete_instance(request, pkgbase)
# Log out the fact that this happened for accountability.
- logger.info(f"Privileged user '{request.user.Username}' deleted the "
- f"following package bases: {str(deleted_bases)}.")
+ logger.info(
+ f"Privileged user '{request.user.Username}' deleted the "
+ f"following package bases: {str(deleted_bases)}."
+ )
util.apply_all(notifs, lambda n: n.send())
return (True, ["The selected packages have been deleted."])
+
# A mapping of action string -> callback functions used within the
# `packages_post` route below. We expect any action callback to
# return a tuple in the format: (succeeded: bool, message: list[str]).
@@ -444,10 +467,12 @@ PACKAGE_ACTIONS = {
@router.post("/packages")
@handle_form_exceptions
@requires_auth
-async def packages_post(request: Request,
- IDs: list[int] = Form(default=[]),
- action: str = Form(default=str()),
- confirm: bool = Form(default=False)):
+async def packages_post(
+ request: Request,
+ IDs: list[int] = Form(default=[]),
+ action: str = Form(default=str()),
+ confirm: bool = Form(default=False),
+):
# If an invalid action is specified, just render GET /packages
# with an BAD_REQUEST status_code.
diff --git a/aurweb/routers/pkgbase.py b/aurweb/routers/pkgbase.py
index 1f09cfc8..913e3955 100644
--- a/aurweb/routers/pkgbase.py
+++ b/aurweb/routers/pkgbase.py
@@ -16,9 +16,7 @@ from aurweb.models.package_vote import PackageVote
from aurweb.models.request_type import DELETION_ID, MERGE_ID, ORPHAN_ID
from aurweb.packages.requests import update_closure_comment
from aurweb.packages.util import get_pkg_or_base, get_pkgbase_comment
-from aurweb.pkgbase import actions
-from aurweb.pkgbase import util as pkgbaseutil
-from aurweb.pkgbase import validate
+from aurweb.pkgbase import actions, util as pkgbaseutil, validate
from aurweb.scripts import notify, popupdate
from aurweb.scripts.rendercomment import update_comment_render_fastapi
from aurweb.templates import make_variable_context, render_template
@@ -44,8 +42,9 @@ async def pkgbase(request: Request, name: str) -> Response:
packages = pkgbase.packages.all()
pkg = packages[0]
if len(packages) == 1 and pkg.Name == pkgbase.Name:
- return RedirectResponse(f"/packages/{pkg.Name}",
- status_code=int(HTTPStatus.SEE_OTHER))
+ return RedirectResponse(
+ f"/packages/{pkg.Name}", status_code=int(HTTPStatus.SEE_OTHER)
+ )
# Add our base information.
context = pkgbaseutil.make_context(request, pkgbase)
@@ -69,8 +68,7 @@ async def pkgbase_voters(request: Request, name: str) -> Response:
pkgbase = get_pkg_or_base(name, PackageBase)
if not request.user.has_credential(creds.PKGBASE_LIST_VOTERS):
- return RedirectResponse(f"/pkgbase/{name}",
- status_code=HTTPStatus.SEE_OTHER)
+ return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER)
context = templates.make_context(request, "Voters")
context["pkgbase"] = pkgbase
@@ -82,8 +80,7 @@ async def pkgbase_flag_comment(request: Request, name: str):
pkgbase = get_pkg_or_base(name, PackageBase)
if pkgbase.OutOfDateTS is None:
- return RedirectResponse(f"/pkgbase/{name}",
- status_code=HTTPStatus.SEE_OTHER)
+ return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER)
context = templates.make_context(request, "Flag Comment")
context["pkgbase"] = pkgbase
@@ -92,13 +89,15 @@ async def pkgbase_flag_comment(request: Request, name: str):
@router.post("/pkgbase/{name}/keywords")
@handle_form_exceptions
-async def pkgbase_keywords(request: Request, name: str,
- keywords: str = Form(default=str())):
+async def pkgbase_keywords(
+ request: Request, name: str, keywords: str = Form(default=str())
+):
pkgbase = get_pkg_or_base(name, PackageBase)
approved = [pkgbase.Maintainer] + [c.User for c in pkgbase.comaintainers]
- has_cred = creds.has_credential(request.user, creds.PKGBASE_SET_KEYWORDS,
- approved=approved)
+ has_cred = creds.has_credential(
+ request.user, creds.PKGBASE_SET_KEYWORDS, approved=approved
+ )
if not has_cred:
return Response(status_code=HTTPStatus.UNAUTHORIZED)
@@ -108,15 +107,14 @@ async def pkgbase_keywords(request: Request, name: str,
# Delete all keywords which are not supplied by the user.
with db.begin():
- other_keywords = pkgbase.keywords.filter(
- ~PackageKeyword.Keyword.in_(keywords))
- other_keyword_strings = set(
- kwd.Keyword.lower() for kwd in other_keywords)
+ other_keywords = pkgbase.keywords.filter(~PackageKeyword.Keyword.in_(keywords))
+ other_keyword_strings = set(kwd.Keyword.lower() for kwd in other_keywords)
existing_keywords = set(
- kwd.Keyword.lower() for kwd in
- pkgbase.keywords.filter(
- ~PackageKeyword.Keyword.in_(other_keyword_strings))
+ kwd.Keyword.lower()
+ for kwd in pkgbase.keywords.filter(
+ ~PackageKeyword.Keyword.in_(other_keyword_strings)
+ )
)
db.delete_all(other_keywords)
@@ -124,8 +122,7 @@ async def pkgbase_keywords(request: Request, name: str,
for keyword in new_keywords:
db.create(PackageKeyword, PackageBase=pkgbase, Keyword=keyword)
- return RedirectResponse(f"/pkgbase/{name}",
- status_code=HTTPStatus.SEE_OTHER)
+ return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER)
@router.get("/pkgbase/{name}/flag")
@@ -135,8 +132,7 @@ async def pkgbase_flag_get(request: Request, name: str):
has_cred = request.user.has_credential(creds.PKGBASE_FLAG)
if not has_cred or pkgbase.OutOfDateTS is not None:
- return RedirectResponse(f"/pkgbase/{name}",
- status_code=HTTPStatus.SEE_OTHER)
+ return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER)
context = templates.make_context(request, "Flag Package Out-Of-Date")
context["pkgbase"] = pkgbase
@@ -146,17 +142,20 @@ async def pkgbase_flag_get(request: Request, name: str):
@router.post("/pkgbase/{name}/flag")
@handle_form_exceptions
@requires_auth
-async def pkgbase_flag_post(request: Request, name: str,
- comments: str = Form(default=str())):
+async def pkgbase_flag_post(
+ request: Request, name: str, comments: str = Form(default=str())
+):
pkgbase = get_pkg_or_base(name, PackageBase)
if not comments:
context = templates.make_context(request, "Flag Package Out-Of-Date")
context["pkgbase"] = pkgbase
- context["errors"] = ["The selected packages have not been flagged, "
- "please enter a comment."]
- return render_template(request, "pkgbase/flag.html", context,
- status_code=HTTPStatus.BAD_REQUEST)
+ context["errors"] = [
+ "The selected packages have not been flagged, " "please enter a comment."
+ ]
+ return render_template(
+ request, "pkgbase/flag.html", context, status_code=HTTPStatus.BAD_REQUEST
+ )
has_cred = request.user.has_credential(creds.PKGBASE_FLAG)
if has_cred and not pkgbase.OutOfDateTS:
@@ -168,18 +167,19 @@ async def pkgbase_flag_post(request: Request, name: str,
notify.FlagNotification(request.user.ID, pkgbase.ID).send()
- return RedirectResponse(f"/pkgbase/{name}",
- status_code=HTTPStatus.SEE_OTHER)
+ return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER)
@router.post("/pkgbase/{name}/comments")
@handle_form_exceptions
@requires_auth
async def pkgbase_comments_post(
- request: Request, name: str,
- comment: str = Form(default=str()),
- enable_notifications: bool = Form(default=False)):
- """ Add a new comment via POST request. """
+ request: Request,
+ name: str,
+ comment: str = Form(default=str()),
+ enable_notifications: bool = Form(default=False),
+):
+ """Add a new comment via POST request."""
pkgbase = get_pkg_or_base(name, PackageBase)
if not comment:
@@ -189,29 +189,34 @@ async def pkgbase_comments_post(
# update the db record.
now = time.utcnow()
with db.begin():
- comment = db.create(PackageComment, User=request.user,
- PackageBase=pkgbase,
- Comments=comment, RenderedComment=str(),
- CommentTS=now)
+ comment = db.create(
+ PackageComment,
+ User=request.user,
+ PackageBase=pkgbase,
+ Comments=comment,
+ RenderedComment=str(),
+ CommentTS=now,
+ )
if enable_notifications and not request.user.notified(pkgbase):
- db.create(PackageNotification,
- User=request.user,
- PackageBase=pkgbase)
+ db.create(PackageNotification, User=request.user, PackageBase=pkgbase)
update_comment_render_fastapi(comment)
notif = notify.CommentNotification(request.user.ID, pkgbase.ID, comment.ID)
notif.send()
# Redirect to the pkgbase page.
- return RedirectResponse(f"/pkgbase/{pkgbase.Name}#comment-{comment.ID}",
- status_code=HTTPStatus.SEE_OTHER)
+ return RedirectResponse(
+ f"/pkgbase/{pkgbase.Name}#comment-{comment.ID}",
+ status_code=HTTPStatus.SEE_OTHER,
+ )
@router.get("/pkgbase/{name}/comments/{id}/form")
@requires_auth
-async def pkgbase_comment_form(request: Request, name: str, id: int,
- next: str = Query(default=None)):
+async def pkgbase_comment_form(
+ request: Request, name: str, id: int, next: str = Query(default=None)
+):
"""
Produce a comment form for comment {id}.
@@ -244,14 +249,16 @@ async def pkgbase_comment_form(request: Request, name: str, id: int,
context["next"] = next
form = templates.render_raw_template(
- request, "partials/packages/comment_form.html", context)
+ request, "partials/packages/comment_form.html", context
+ )
return JSONResponse({"form": form})
@router.get("/pkgbase/{name}/comments/{id}/edit")
@requires_auth
-async def pkgbase_comment_edit(request: Request, name: str, id: int,
- next: str = Form(default=None)):
+async def pkgbase_comment_edit(
+ request: Request, name: str, id: int, next: str = Form(default=None)
+):
"""
Render the non-javascript edit form.
@@ -276,11 +283,14 @@ async def pkgbase_comment_edit(request: Request, name: str, id: int,
@handle_form_exceptions
@requires_auth
async def pkgbase_comment_post(
- request: Request, name: str, id: int,
- comment: str = Form(default=str()),
- enable_notifications: bool = Form(default=False),
- next: str = Form(default=None)):
- """ Edit an existing comment. """
+ request: Request,
+ name: str,
+ id: int,
+ comment: str = Form(default=str()),
+ enable_notifications: bool = Form(default=False),
+ next: str = Form(default=None),
+):
+ """Edit an existing comment."""
pkgbase = get_pkg_or_base(name, PackageBase)
db_comment = get_pkgbase_comment(pkgbase, id)
@@ -302,24 +312,24 @@ async def pkgbase_comment_post(
PackageNotification.PackageBaseID == pkgbase.ID
).first()
if enable_notifications and not db_notif:
- db.create(PackageNotification,
- User=request.user,
- PackageBase=pkgbase)
+ db.create(PackageNotification, User=request.user, PackageBase=pkgbase)
update_comment_render_fastapi(db_comment)
if not next:
next = f"/pkgbase/{pkgbase.Name}"
# Redirect to the pkgbase page anchored to the updated comment.
- return RedirectResponse(f"{next}#comment-{db_comment.ID}",
- status_code=HTTPStatus.SEE_OTHER)
+ return RedirectResponse(
+ f"{next}#comment-{db_comment.ID}", status_code=HTTPStatus.SEE_OTHER
+ )
@router.post("/pkgbase/{name}/comments/{id}/pin")
@handle_form_exceptions
@requires_auth
-async def pkgbase_comment_pin(request: Request, name: str, id: int,
- next: str = Form(default=None)):
+async def pkgbase_comment_pin(
+ request: Request, name: str, id: int, next: str = Form(default=None)
+):
"""
Pin a comment.
@@ -332,13 +342,15 @@ async def pkgbase_comment_pin(request: Request, name: str, id: int,
pkgbase = get_pkg_or_base(name, PackageBase)
comment = get_pkgbase_comment(pkgbase, id)
- has_cred = request.user.has_credential(creds.COMMENT_PIN,
- approved=comment.maintainers())
+ has_cred = request.user.has_credential(
+ creds.COMMENT_PIN, approved=comment.maintainers()
+ )
if not has_cred:
_ = l10n.get_translator_for_request(request)
raise HTTPException(
status_code=HTTPStatus.UNAUTHORIZED,
- detail=_("You are not allowed to pin this comment."))
+ detail=_("You are not allowed to pin this comment."),
+ )
now = time.utcnow()
with db.begin():
@@ -353,8 +365,9 @@ async def pkgbase_comment_pin(request: Request, name: str, id: int,
@router.post("/pkgbase/{name}/comments/{id}/unpin")
@handle_form_exceptions
@requires_auth
-async def pkgbase_comment_unpin(request: Request, name: str, id: int,
- next: str = Form(default=None)):
+async def pkgbase_comment_unpin(
+ request: Request, name: str, id: int, next: str = Form(default=None)
+):
"""
Unpin a comment.
@@ -367,13 +380,15 @@ async def pkgbase_comment_unpin(request: Request, name: str, id: int,
pkgbase = get_pkg_or_base(name, PackageBase)
comment = get_pkgbase_comment(pkgbase, id)
- has_cred = request.user.has_credential(creds.COMMENT_PIN,
- approved=comment.maintainers())
+ has_cred = request.user.has_credential(
+ creds.COMMENT_PIN, approved=comment.maintainers()
+ )
if not has_cred:
_ = l10n.get_translator_for_request(request)
raise HTTPException(
status_code=HTTPStatus.UNAUTHORIZED,
- detail=_("You are not allowed to unpin this comment."))
+ detail=_("You are not allowed to unpin this comment."),
+ )
with db.begin():
comment.PinnedTS = 0
@@ -387,8 +402,9 @@ async def pkgbase_comment_unpin(request: Request, name: str, id: int,
@router.post("/pkgbase/{name}/comments/{id}/delete")
@handle_form_exceptions
@requires_auth
-async def pkgbase_comment_delete(request: Request, name: str, id: int,
- next: str = Form(default=None)):
+async def pkgbase_comment_delete(
+ request: Request, name: str, id: int, next: str = Form(default=None)
+):
"""
Delete a comment.
@@ -405,13 +421,13 @@ async def pkgbase_comment_delete(request: Request, name: str, id: int,
pkgbase = get_pkg_or_base(name, PackageBase)
comment = get_pkgbase_comment(pkgbase, id)
- authorized = request.user.has_credential(creds.COMMENT_DELETE,
- [comment.User])
+ authorized = request.user.has_credential(creds.COMMENT_DELETE, [comment.User])
if not authorized:
_ = l10n.get_translator_for_request(request)
raise HTTPException(
status_code=HTTPStatus.UNAUTHORIZED,
- detail=_("You are not allowed to delete this comment."))
+ detail=_("You are not allowed to delete this comment."),
+ )
now = time.utcnow()
with db.begin():
@@ -427,8 +443,9 @@ async def pkgbase_comment_delete(request: Request, name: str, id: int,
@router.post("/pkgbase/{name}/comments/{id}/undelete")
@handle_form_exceptions
@requires_auth
-async def pkgbase_comment_undelete(request: Request, name: str, id: int,
- next: str = Form(default=None)):
+async def pkgbase_comment_undelete(
+ request: Request, name: str, id: int, next: str = Form(default=None)
+):
"""
Undelete a comment.
@@ -445,13 +462,15 @@ async def pkgbase_comment_undelete(request: Request, name: str, id: int,
pkgbase = get_pkg_or_base(name, PackageBase)
comment = get_pkgbase_comment(pkgbase, id)
- has_cred = request.user.has_credential(creds.COMMENT_UNDELETE,
- approved=[comment.User])
+ has_cred = request.user.has_credential(
+ creds.COMMENT_UNDELETE, approved=[comment.User]
+ )
if not has_cred:
_ = l10n.get_translator_for_request(request)
raise HTTPException(
status_code=HTTPStatus.UNAUTHORIZED,
- detail=_("You are not allowed to undelete this comment."))
+ detail=_("You are not allowed to undelete this comment."),
+ )
with db.begin():
comment.Deleter = None
@@ -469,23 +488,17 @@ async def pkgbase_comment_undelete(request: Request, name: str, id: int,
async def pkgbase_vote(request: Request, name: str):
pkgbase = get_pkg_or_base(name, PackageBase)
- vote = pkgbase.package_votes.filter(
- PackageVote.UsersID == request.user.ID
- ).first()
+ vote = pkgbase.package_votes.filter(PackageVote.UsersID == request.user.ID).first()
has_cred = request.user.has_credential(creds.PKGBASE_VOTE)
if has_cred and not vote:
now = time.utcnow()
with db.begin():
- db.create(PackageVote,
- User=request.user,
- PackageBase=pkgbase,
- VoteTS=now)
+ db.create(PackageVote, User=request.user, PackageBase=pkgbase, VoteTS=now)
# Update NumVotes/Popularity.
popupdate.run_single(pkgbase)
- return RedirectResponse(f"/pkgbase/{name}",
- status_code=HTTPStatus.SEE_OTHER)
+ return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER)
@router.post("/pkgbase/{name}/unvote")
@@ -494,9 +507,7 @@ async def pkgbase_vote(request: Request, name: str):
async def pkgbase_unvote(request: Request, name: str):
pkgbase = get_pkg_or_base(name, PackageBase)
- vote = pkgbase.package_votes.filter(
- PackageVote.UsersID == request.user.ID
- ).first()
+ vote = pkgbase.package_votes.filter(PackageVote.UsersID == request.user.ID).first()
has_cred = request.user.has_credential(creds.PKGBASE_VOTE)
if has_cred and vote:
with db.begin():
@@ -505,8 +516,7 @@ async def pkgbase_unvote(request: Request, name: str):
# Update NumVotes/Popularity.
popupdate.run_single(pkgbase)
- return RedirectResponse(f"/pkgbase/{name}",
- status_code=HTTPStatus.SEE_OTHER)
+ return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER)
@router.post("/pkgbase/{name}/notify")
@@ -515,8 +525,7 @@ async def pkgbase_unvote(request: Request, name: str):
async def pkgbase_notify(request: Request, name: str):
pkgbase = get_pkg_or_base(name, PackageBase)
actions.pkgbase_notify_instance(request, pkgbase)
- return RedirectResponse(f"/pkgbase/{name}",
- status_code=HTTPStatus.SEE_OTHER)
+ return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER)
@router.post("/pkgbase/{name}/unnotify")
@@ -525,8 +534,7 @@ async def pkgbase_notify(request: Request, name: str):
async def pkgbase_unnotify(request: Request, name: str):
pkgbase = get_pkg_or_base(name, PackageBase)
actions.pkgbase_unnotify_instance(request, pkgbase)
- return RedirectResponse(f"/pkgbase/{name}",
- status_code=HTTPStatus.SEE_OTHER)
+ return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER)
@router.post("/pkgbase/{name}/unflag")
@@ -535,20 +543,19 @@ async def pkgbase_unnotify(request: Request, name: str):
async def pkgbase_unflag(request: Request, name: str):
pkgbase = get_pkg_or_base(name, PackageBase)
actions.pkgbase_unflag_instance(request, pkgbase)
- return RedirectResponse(f"/pkgbase/{name}",
- status_code=HTTPStatus.SEE_OTHER)
+ return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER)
@router.get("/pkgbase/{name}/disown")
@requires_auth
-async def pkgbase_disown_get(request: Request, name: str,
- next: str = Query(default=str())):
+async def pkgbase_disown_get(
+ request: Request, name: str, next: str = Query(default=str())
+):
pkgbase = get_pkg_or_base(name, PackageBase)
comaints = {c.User for c in pkgbase.comaintainers}
approved = [pkgbase.Maintainer] + list(comaints)
- has_cred = request.user.has_credential(creds.PKGBASE_DISOWN,
- approved=approved)
+ has_cred = request.user.has_credential(creds.PKGBASE_DISOWN, approved=approved)
if not has_cred:
return RedirectResponse(f"/pkgbase/{name}", HTTPStatus.SEE_OTHER)
@@ -563,27 +570,33 @@ async def pkgbase_disown_get(request: Request, name: str,
@router.post("/pkgbase/{name}/disown")
@handle_form_exceptions
@requires_auth
-async def pkgbase_disown_post(request: Request, name: str,
- comments: str = Form(default=str()),
- confirm: bool = Form(default=False),
- next: str = Form(default=str())):
+async def pkgbase_disown_post(
+ request: Request,
+ name: str,
+ comments: str = Form(default=str()),
+ confirm: bool = Form(default=False),
+ next: str = Form(default=str()),
+):
pkgbase = get_pkg_or_base(name, PackageBase)
comaints = {c.User for c in pkgbase.comaintainers}
approved = [pkgbase.Maintainer] + list(comaints)
- has_cred = request.user.has_credential(creds.PKGBASE_DISOWN,
- approved=approved)
+ has_cred = request.user.has_credential(creds.PKGBASE_DISOWN, approved=approved)
if not has_cred:
- return RedirectResponse(f"/pkgbase/{name}",
- HTTPStatus.SEE_OTHER)
+ return RedirectResponse(f"/pkgbase/{name}", HTTPStatus.SEE_OTHER)
context = templates.make_context(request, "Disown Package")
context["pkgbase"] = pkgbase
if not confirm:
- context["errors"] = [("The selected packages have not been disowned, "
- "check the confirmation checkbox.")]
- return render_template(request, "pkgbase/disown.html", context,
- status_code=HTTPStatus.BAD_REQUEST)
+ context["errors"] = [
+ (
+ "The selected packages have not been disowned, "
+ "check the confirmation checkbox."
+ )
+ ]
+ return render_template(
+ request, "pkgbase/disown.html", context, status_code=HTTPStatus.BAD_REQUEST
+ )
if request.user != pkgbase.Maintainer and request.user not in comaints:
with db.begin():
@@ -593,8 +606,9 @@ async def pkgbase_disown_post(request: Request, name: str,
actions.pkgbase_disown_instance(request, pkgbase)
except InvariantError as exc:
context["errors"] = [str(exc)]
- return render_template(request, "pkgbase/disown.html", context,
- status_code=HTTPStatus.BAD_REQUEST)
+ return render_template(
+ request, "pkgbase/disown.html", context, status_code=HTTPStatus.BAD_REQUEST
+ )
if not next:
next = f"/pkgbase/{name}"
@@ -615,8 +629,7 @@ async def pkgbase_adopt_post(request: Request, name: str):
# if no maintainer currently exists.
actions.pkgbase_adopt_instance(request, pkgbase)
- return RedirectResponse(f"/pkgbase/{name}",
- status_code=HTTPStatus.SEE_OTHER)
+ return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER)
@router.get("/pkgbase/{name}/comaintainers")
@@ -627,20 +640,20 @@ async def pkgbase_comaintainers(request: Request, name: str) -> Response:
# Unauthorized users (Non-TU/Dev and not the pkgbase maintainer)
# get redirected to the package base's page.
- has_creds = request.user.has_credential(creds.PKGBASE_EDIT_COMAINTAINERS,
- approved=[pkgbase.Maintainer])
+ has_creds = request.user.has_credential(
+ creds.PKGBASE_EDIT_COMAINTAINERS, approved=[pkgbase.Maintainer]
+ )
if not has_creds:
- return RedirectResponse(f"/pkgbase/{name}",
- status_code=HTTPStatus.SEE_OTHER)
+ return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER)
# Add our base information.
context = templates.make_context(request, "Manage Co-maintainers")
- context.update({
- "pkgbase": pkgbase,
- "comaintainers": [
- c.User.Username for c in pkgbase.comaintainers
- ]
- })
+ context.update(
+ {
+ "pkgbase": pkgbase,
+ "comaintainers": [c.User.Username for c in pkgbase.comaintainers],
+ }
+ )
return render_template(request, "pkgbase/comaintainers.html", context)
@@ -648,50 +661,52 @@ async def pkgbase_comaintainers(request: Request, name: str) -> Response:
@router.post("/pkgbase/{name}/comaintainers")
@handle_form_exceptions
@requires_auth
-async def pkgbase_comaintainers_post(request: Request, name: str,
- users: str = Form(default=str())) \
- -> Response:
+async def pkgbase_comaintainers_post(
+ request: Request, name: str, users: str = Form(default=str())
+) -> Response:
# Get the PackageBase.
pkgbase = get_pkg_or_base(name, PackageBase)
# Unauthorized users (Non-TU/Dev and not the pkgbase maintainer)
# get redirected to the package base's page.
- has_creds = request.user.has_credential(creds.PKGBASE_EDIT_COMAINTAINERS,
- approved=[pkgbase.Maintainer])
+ has_creds = request.user.has_credential(
+ creds.PKGBASE_EDIT_COMAINTAINERS, approved=[pkgbase.Maintainer]
+ )
if not has_creds:
- return RedirectResponse(f"/pkgbase/{name}",
- status_code=HTTPStatus.SEE_OTHER)
+ return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER)
users = {e.strip() for e in users.split("\n") if bool(e.strip())}
records = {c.User.Username for c in pkgbase.comaintainers}
users_to_rm = records.difference(users)
pkgbaseutil.remove_comaintainers(pkgbase, users_to_rm)
- logger.debug(f"{request.user} removed comaintainers from "
- f"{pkgbase.Name}: {users_to_rm}")
+ logger.debug(
+ f"{request.user} removed comaintainers from " f"{pkgbase.Name}: {users_to_rm}"
+ )
users_to_add = users.difference(records)
error = pkgbaseutil.add_comaintainers(request, pkgbase, users_to_add)
if error:
context = templates.make_context(request, "Manage Co-maintainers")
context["pkgbase"] = pkgbase
- context["comaintainers"] = [
- c.User.Username for c in pkgbase.comaintainers
- ]
+ context["comaintainers"] = [c.User.Username for c in pkgbase.comaintainers]
context["errors"] = [error]
return render_template(request, "pkgbase/comaintainers.html", context)
- logger.debug(f"{request.user} added comaintainers to "
- f"{pkgbase.Name}: {users_to_add}")
+ logger.debug(
+ f"{request.user} added comaintainers to " f"{pkgbase.Name}: {users_to_add}"
+ )
- return RedirectResponse(f"/pkgbase/{pkgbase.Name}",
- status_code=HTTPStatus.SEE_OTHER)
+ return RedirectResponse(
+ f"/pkgbase/{pkgbase.Name}", status_code=HTTPStatus.SEE_OTHER
+ )
@router.get("/pkgbase/{name}/request")
@requires_auth
-async def pkgbase_request(request: Request, name: str,
- next: str = Query(default=str())):
+async def pkgbase_request(
+ request: Request, name: str, next: str = Query(default=str())
+):
pkgbase = get_pkg_or_base(name, PackageBase)
context = await make_variable_context(request, "Submit Request")
context["pkgbase"] = pkgbase
@@ -702,28 +717,28 @@ async def pkgbase_request(request: Request, name: str,
@router.post("/pkgbase/{name}/request")
@handle_form_exceptions
@requires_auth
-async def pkgbase_request_post(request: Request, name: str,
- type: str = Form(...),
- merge_into: str = Form(default=None),
- comments: str = Form(default=str()),
- next: str = Form(default=str())):
+async def pkgbase_request_post(
+ request: Request,
+ name: str,
+ type: str = Form(...),
+ merge_into: str = Form(default=None),
+ comments: str = Form(default=str()),
+ next: str = Form(default=str()),
+):
pkgbase = get_pkg_or_base(name, PackageBase)
# Create our render context.
context = await make_variable_context(request, "Submit Request")
context["pkgbase"] = pkgbase
- types = {
- "deletion": DELETION_ID,
- "merge": MERGE_ID,
- "orphan": ORPHAN_ID
- }
+ types = {"deletion": DELETION_ID, "merge": MERGE_ID, "orphan": ORPHAN_ID}
if type not in types:
# In the case that someone crafted a POST request with an invalid
# type, just return them to the request form with BAD_REQUEST status.
- return render_template(request, "pkgbase/request.html", context,
- status_code=HTTPStatus.BAD_REQUEST)
+ return render_template(
+ request, "pkgbase/request.html", context, status_code=HTTPStatus.BAD_REQUEST
+ )
try:
validate.request(pkgbase, type, comments, merge_into, context)
@@ -735,20 +750,26 @@ async def pkgbase_request_post(request: Request, name: str,
# All good. Create a new PackageRequest based on the given type.
now = time.utcnow()
with db.begin():
- pkgreq = db.create(PackageRequest,
- ReqTypeID=types.get(type),
- User=request.user,
- RequestTS=now,
- PackageBase=pkgbase,
- PackageBaseName=pkgbase.Name,
- MergeBaseName=merge_into,
- Comments=comments,
- ClosureComment=str())
+ pkgreq = db.create(
+ PackageRequest,
+ ReqTypeID=types.get(type),
+ User=request.user,
+ RequestTS=now,
+ PackageBase=pkgbase,
+ PackageBaseName=pkgbase.Name,
+ MergeBaseName=merge_into,
+ Comments=comments,
+ ClosureComment=str(),
+ )
# Prepare notification object.
notif = notify.RequestOpenNotification(
- request.user.ID, pkgreq.ID, type,
- pkgreq.PackageBase.ID, merge_into=merge_into or None)
+ request.user.ID,
+ pkgreq.ID,
+ type,
+ pkgreq.PackageBase.ID,
+ merge_into=merge_into or None,
+ )
# Send the notification now that we're out of the DB scope.
notif.send()
@@ -767,13 +788,13 @@ async def pkgbase_request_post(request: Request, name: str,
pkgbase.Maintainer = None
pkgreq.Status = ACCEPTED_ID
notif = notify.RequestCloseNotification(
- request.user.ID, pkgreq.ID, pkgreq.status_display())
+ request.user.ID, pkgreq.ID, pkgreq.status_display()
+ )
notif.send()
logger.debug(f"New request #{pkgreq.ID} is marked for auto-orphan.")
elif type == "deletion" and is_maintainer and outdated:
# This request should be auto-accepted.
- notifs = actions.pkgbase_delete_instance(
- request, pkgbase, comments=comments)
+ notifs = actions.pkgbase_delete_instance(request, pkgbase, comments=comments)
util.apply_all(notifs, lambda n: n.send())
logger.debug(f"New request #{pkgreq.ID} is marked for auto-deletion.")
@@ -783,11 +804,11 @@ async def pkgbase_request_post(request: Request, name: str,
@router.get("/pkgbase/{name}/delete")
@requires_auth
-async def pkgbase_delete_get(request: Request, name: str,
- next: str = Query(default=str())):
+async def pkgbase_delete_get(
+ request: Request, name: str, next: str = Query(default=str())
+):
if not request.user.has_credential(creds.PKGBASE_DELETE):
- return RedirectResponse(f"/pkgbase/{name}",
- status_code=HTTPStatus.SEE_OTHER)
+ return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER)
context = templates.make_context(request, "Package Deletion")
context["pkgbase"] = get_pkg_or_base(name, PackageBase)
@@ -798,53 +819,60 @@ async def pkgbase_delete_get(request: Request, name: str,
@router.post("/pkgbase/{name}/delete")
@handle_form_exceptions
@requires_auth
-async def pkgbase_delete_post(request: Request, name: str,
- confirm: bool = Form(default=False),
- comments: str = Form(default=str()),
- next: str = Form(default="/packages")):
+async def pkgbase_delete_post(
+ request: Request,
+ name: str,
+ confirm: bool = Form(default=False),
+ comments: str = Form(default=str()),
+ next: str = Form(default="/packages"),
+):
pkgbase = get_pkg_or_base(name, PackageBase)
if not request.user.has_credential(creds.PKGBASE_DELETE):
- return RedirectResponse(f"/pkgbase/{name}",
- status_code=HTTPStatus.SEE_OTHER)
+ return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER)
if not confirm:
context = templates.make_context(request, "Package Deletion")
context["pkgbase"] = pkgbase
- context["errors"] = [("The selected packages have not been deleted, "
- "check the confirmation checkbox.")]
- return render_template(request, "pkgbase/delete.html", context,
- status_code=HTTPStatus.BAD_REQUEST)
+ context["errors"] = [
+ (
+ "The selected packages have not been deleted, "
+ "check the confirmation checkbox."
+ )
+ ]
+ return render_template(
+ request, "pkgbase/delete.html", context, status_code=HTTPStatus.BAD_REQUEST
+ )
if comments:
# Update any existing deletion requests' ClosureComment.
with db.begin():
requests = pkgbase.requests.filter(
- and_(PackageRequest.Status == PENDING_ID,
- PackageRequest.ReqTypeID == DELETION_ID)
+ and_(
+ PackageRequest.Status == PENDING_ID,
+ PackageRequest.ReqTypeID == DELETION_ID,
+ )
)
for pkgreq in requests:
pkgreq.ClosureComment = comments
- notifs = actions.pkgbase_delete_instance(
- request, pkgbase, comments=comments)
+ notifs = actions.pkgbase_delete_instance(request, pkgbase, comments=comments)
util.apply_all(notifs, lambda n: n.send())
return RedirectResponse(next, status_code=HTTPStatus.SEE_OTHER)
@router.get("/pkgbase/{name}/merge")
@requires_auth
-async def pkgbase_merge_get(request: Request, name: str,
- into: str = Query(default=str()),
- next: str = Query(default=str())):
+async def pkgbase_merge_get(
+ request: Request,
+ name: str,
+ into: str = Query(default=str()),
+ next: str = Query(default=str()),
+):
pkgbase = get_pkg_or_base(name, PackageBase)
context = templates.make_context(request, "Package Merging")
- context.update({
- "pkgbase": pkgbase,
- "into": into,
- "next": next
- })
+ context.update({"pkgbase": pkgbase, "into": into, "next": next})
status_code = HTTPStatus.OK
# TODO: Lookup errors from credential instead of hardcoding them.
@@ -852,51 +880,58 @@ async def pkgbase_merge_get(request: Request, name: str,
# Perhaps additionally: bad_credential_status_code(creds.PKGBASE_MERGE).
# Don't take these examples verbatim. We should find good naming.
if not request.user.has_credential(creds.PKGBASE_MERGE):
- context["errors"] = [
- "Only Trusted Users and Developers can merge packages."]
+ context["errors"] = ["Only Trusted Users and Developers can merge packages."]
status_code = HTTPStatus.UNAUTHORIZED
- return render_template(request, "pkgbase/merge.html", context,
- status_code=status_code)
+ return render_template(
+ request, "pkgbase/merge.html", context, status_code=status_code
+ )
@router.post("/pkgbase/{name}/merge")
@handle_form_exceptions
@requires_auth
-async def pkgbase_merge_post(request: Request, name: str,
- into: str = Form(default=str()),
- comments: str = Form(default=str()),
- confirm: bool = Form(default=False),
- next: str = Form(default=str())):
+async def pkgbase_merge_post(
+ request: Request,
+ name: str,
+ into: str = Form(default=str()),
+ comments: str = Form(default=str()),
+ confirm: bool = Form(default=False),
+ next: str = Form(default=str()),
+):
pkgbase = get_pkg_or_base(name, PackageBase)
context = await make_variable_context(request, "Package Merging")
context["pkgbase"] = pkgbase
# TODO: Lookup errors from credential instead of hardcoding them.
if not request.user.has_credential(creds.PKGBASE_MERGE):
- context["errors"] = [
- "Only Trusted Users and Developers can merge packages."]
- return render_template(request, "pkgbase/merge.html", context,
- status_code=HTTPStatus.UNAUTHORIZED)
+ context["errors"] = ["Only Trusted Users and Developers can merge packages."]
+ return render_template(
+ request, "pkgbase/merge.html", context, status_code=HTTPStatus.UNAUTHORIZED
+ )
if not confirm:
- context["errors"] = ["The selected packages have not been deleted, "
- "check the confirmation checkbox."]
- return render_template(request, "pkgbase/merge.html", context,
- status_code=HTTPStatus.BAD_REQUEST)
+ context["errors"] = [
+ "The selected packages have not been deleted, "
+ "check the confirmation checkbox."
+ ]
+ return render_template(
+ request, "pkgbase/merge.html", context, status_code=HTTPStatus.BAD_REQUEST
+ )
try:
target = get_pkg_or_base(into, PackageBase)
except HTTPException:
- context["errors"] = [
- "Cannot find package to merge votes and comments into."]
- return render_template(request, "pkgbase/merge.html", context,
- status_code=HTTPStatus.BAD_REQUEST)
+ context["errors"] = ["Cannot find package to merge votes and comments into."]
+ return render_template(
+ request, "pkgbase/merge.html", context, status_code=HTTPStatus.BAD_REQUEST
+ )
if pkgbase == target:
context["errors"] = ["Cannot merge a package base with itself."]
- return render_template(request, "pkgbase/merge.html", context,
- status_code=HTTPStatus.BAD_REQUEST)
+ return render_template(
+ request, "pkgbase/merge.html", context, status_code=HTTPStatus.BAD_REQUEST
+ )
with db.begin():
update_closure_comment(pkgbase, MERGE_ID, comments, target=target)
diff --git a/aurweb/routers/requests.py b/aurweb/routers/requests.py
index 086aa3bc..c7935575 100644
--- a/aurweb/routers/requests.py
+++ b/aurweb/routers/requests.py
@@ -18,9 +18,11 @@ router = APIRouter()
@router.get("/requests")
@requires_auth
-async def requests(request: Request,
- O: int = Query(default=defaults.O),
- PP: int = Query(default=defaults.PP)):
+async def requests(
+ request: Request,
+ O: int = Query(default=defaults.O),
+ PP: int = Query(default=defaults.PP),
+):
context = make_context(request, "Requests")
context["q"] = dict(request.query_params)
@@ -30,8 +32,7 @@ async def requests(request: Request,
context["PP"] = PP
# A PackageRequest query, with left inner joined User and RequestType.
- query = db.query(PackageRequest).join(
- User, User.ID == PackageRequest.UsersID)
+ query = db.query(PackageRequest).join(User, User.ID == PackageRequest.UsersID)
# If the request user is not elevated (TU or Dev), then
# filter PackageRequests which are owned by the request user.
@@ -39,12 +40,17 @@ async def requests(request: Request,
query = query.filter(PackageRequest.UsersID == request.user.ID)
context["total"] = query.count()
- context["results"] = query.order_by(
- # Order primarily by the Status column being PENDING_ID,
- # and secondarily by RequestTS; both in descending order.
- case([(PackageRequest.Status == PENDING_ID, 1)], else_=0).desc(),
- PackageRequest.RequestTS.desc()
- ).limit(PP).offset(O).all()
+ context["results"] = (
+ query.order_by(
+ # Order primarily by the Status column being PENDING_ID,
+ # and secondarily by RequestTS; both in descending order.
+ case([(PackageRequest.Status == PENDING_ID, 1)], else_=0).desc(),
+ PackageRequest.RequestTS.desc(),
+ )
+ .limit(PP)
+ .offset(O)
+ .all()
+ )
return render_template(request, "requests.html", context)
@@ -66,8 +72,9 @@ async def request_close(request: Request, id: int):
@router.post("/requests/{id}/close")
@handle_form_exceptions
@requires_auth
-async def request_close_post(request: Request, id: int,
- comments: str = Form(default=str())):
+async def request_close_post(
+ request: Request, id: int, comments: str = Form(default=str())
+):
pkgreq = get_pkgreq_by_id(id)
# `pkgreq`.User can close their own request.
@@ -87,7 +94,8 @@ async def request_close_post(request: Request, id: int,
pkgreq.Status = REJECTED_ID
notify_ = notify.RequestCloseNotification(
- request.user.ID, pkgreq.ID, pkgreq.status_display())
+ request.user.ID, pkgreq.ID, pkgreq.status_display()
+ )
notify_.send()
return RedirectResponse("/requests", status_code=HTTPStatus.SEE_OTHER)
diff --git a/aurweb/routers/rpc.py b/aurweb/routers/rpc.py
index ff58063f..a0cf5019 100644
--- a/aurweb/routers/rpc.py
+++ b/aurweb/routers/rpc.py
@@ -1,12 +1,10 @@
import hashlib
import re
-
from http import HTTPStatus
from typing import Optional
from urllib.parse import unquote
import orjson
-
from fastapi import APIRouter, Form, Query, Request, Response
from fastapi.responses import JSONResponse
@@ -19,7 +17,7 @@ router = APIRouter()
def parse_args(request: Request):
- """ Handle legacy logic of 'arg' and 'arg[]' query parameter handling.
+ """Handle legacy logic of 'arg' and 'arg[]' query parameter handling.
When 'arg' appears as the last argument given to the query string,
that argument is used by itself as one single argument, regardless
@@ -39,9 +37,7 @@ def parse_args(request: Request):
# Create a list of (key, value) pairs of the given 'arg' and 'arg[]'
# query parameters from last to first.
query = list(reversed(unquote(request.url.query).split("&")))
- parts = [
- e.split("=", 1) for e in query if e.startswith(("arg=", "arg[]="))
- ]
+ parts = [e.split("=", 1) for e in query if e.startswith(("arg=", "arg[]="))]
args = []
if parts:
@@ -63,24 +59,28 @@ def parse_args(request: Request):
return args
-JSONP_EXPR = re.compile(r'^[a-zA-Z0-9()_.]{1,128}$')
+JSONP_EXPR = re.compile(r"^[a-zA-Z0-9()_.]{1,128}$")
-async def rpc_request(request: Request,
- v: Optional[int] = None,
- type: Optional[str] = None,
- by: Optional[str] = defaults.RPC_SEARCH_BY,
- arg: Optional[str] = None,
- args: Optional[list[str]] = [],
- callback: Optional[str] = None):
+async def rpc_request(
+ request: Request,
+ v: Optional[int] = None,
+ type: Optional[str] = None,
+ by: Optional[str] = defaults.RPC_SEARCH_BY,
+ arg: Optional[str] = None,
+ args: Optional[list[str]] = [],
+ callback: Optional[str] = None,
+):
# Create a handle to our RPC class.
rpc = RPC(version=v, type=type)
# If ratelimit was exceeded, return a 429 Too Many Requests.
if check_ratelimit(request):
- return JSONResponse(rpc.error("Rate limit reached"),
- status_code=int(HTTPStatus.TOO_MANY_REQUESTS))
+ return JSONResponse(
+ rpc.error("Rate limit reached"),
+ status_code=int(HTTPStatus.TOO_MANY_REQUESTS),
+ )
# If `callback` was provided, produce a text/javascript response
# valid for the jsonp callback. Otherwise, by default, return
@@ -115,15 +115,11 @@ async def rpc_request(request: Request,
# The ETag header expects quotes to surround any identifier.
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
- headers = {
- "Content-Type": content_type,
- "ETag": f'"{etag}"'
- }
+ headers = {"Content-Type": content_type, "ETag": f'"{etag}"'}
if_none_match = request.headers.get("If-None-Match", str())
- if if_none_match and if_none_match.strip("\t\n\r\" ") == etag:
- return Response(headers=headers,
- status_code=int(HTTPStatus.NOT_MODIFIED))
+ if if_none_match and if_none_match.strip('\t\n\r" ') == etag:
+ return Response(headers=headers, status_code=int(HTTPStatus.NOT_MODIFIED))
if callback:
content = f"/**/{callback}({content.decode()})"
@@ -135,13 +131,15 @@ async def rpc_request(request: Request,
@router.get("/rpc.php") # Temporary! Remove on 03/04
@router.get("/rpc/")
@router.get("/rpc")
-async def rpc(request: Request,
- v: Optional[int] = Query(default=None),
- type: Optional[str] = Query(default=None),
- by: Optional[str] = Query(default=defaults.RPC_SEARCH_BY),
- arg: Optional[str] = Query(default=None),
- args: Optional[list[str]] = Query(default=[], alias="arg[]"),
- callback: Optional[str] = Query(default=None)):
+async def rpc(
+ request: Request,
+ v: Optional[int] = Query(default=None),
+ type: Optional[str] = Query(default=None),
+ by: Optional[str] = Query(default=defaults.RPC_SEARCH_BY),
+ arg: Optional[str] = Query(default=None),
+ args: Optional[list[str]] = Query(default=[], alias="arg[]"),
+ callback: Optional[str] = Query(default=None),
+):
if not request.url.query:
return documentation()
return await rpc_request(request, v, type, by, arg, args, callback)
@@ -152,11 +150,13 @@ async def rpc(request: Request,
@router.post("/rpc/")
@router.post("/rpc")
@handle_form_exceptions
-async def rpc_post(request: Request,
- v: Optional[int] = Form(default=None),
- type: Optional[str] = Form(default=None),
- by: Optional[str] = Form(default=defaults.RPC_SEARCH_BY),
- arg: Optional[str] = Form(default=None),
- args: Optional[list[str]] = Form(default=[], alias="arg[]"),
- callback: Optional[str] = Form(default=None)):
+async def rpc_post(
+ request: Request,
+ v: Optional[int] = Form(default=None),
+ type: Optional[str] = Form(default=None),
+ by: Optional[str] = Form(default=defaults.RPC_SEARCH_BY),
+ arg: Optional[str] = Form(default=None),
+ args: Optional[list[str]] = Form(default=[], alias="arg[]"),
+ callback: Optional[str] = Form(default=None),
+):
return await rpc_request(request, v, type, by, arg, args, callback)
diff --git a/aurweb/routers/rss.py b/aurweb/routers/rss.py
index 0996f3cd..ee85b738 100644
--- a/aurweb/routers/rss.py
+++ b/aurweb/routers/rss.py
@@ -10,9 +10,8 @@ from aurweb.models import Package, PackageBase
router = APIRouter()
-def make_rss_feed(request: Request, packages: list,
- date_attr: str):
- """ Create an RSS Feed string for some packages.
+def make_rss_feed(request: Request, packages: list, date_attr: str):
+ """Create an RSS Feed string for some packages.
:param request: A FastAPI request
:param packages: A list of packages to add to the RSS feed
@@ -26,10 +25,12 @@ def make_rss_feed(request: Request, packages: list,
base = f"{request.url.scheme}://{request.url.netloc}"
feed.link(href=base, rel="alternate")
feed.link(href=f"{base}/rss", rel="self")
- feed.image(title="AUR Newest Packages",
- url=f"{base}/static/css/archnavbar/aurlogo.png",
- link=base,
- description="AUR Newest Packages Feed")
+ feed.image(
+ title="AUR Newest Packages",
+ url=f"{base}/static/css/archnavbar/aurlogo.png",
+ link=base,
+ description="AUR Newest Packages Feed",
+ )
for pkg in packages:
entry = feed.add_entry(order="append")
@@ -53,8 +54,12 @@ def make_rss_feed(request: Request, packages: list,
@router.get("/rss/")
async def rss(request: Request):
- packages = db.query(Package).join(PackageBase).order_by(
- PackageBase.SubmittedTS.desc()).limit(100)
+ packages = (
+ db.query(Package)
+ .join(PackageBase)
+ .order_by(PackageBase.SubmittedTS.desc())
+ .limit(100)
+ )
feed = make_rss_feed(request, packages, "SubmittedTS")
response = Response(feed, media_type="application/rss+xml")
@@ -69,8 +74,12 @@ async def rss(request: Request):
@router.get("/rss/modified")
async def rss_modified(request: Request):
- packages = db.query(Package).join(PackageBase).order_by(
- PackageBase.ModifiedTS.desc()).limit(100)
+ packages = (
+ db.query(Package)
+ .join(PackageBase)
+ .order_by(PackageBase.ModifiedTS.desc())
+ .limit(100)
+ )
feed = make_rss_feed(request, packages, "ModifiedTS")
response = Response(feed, media_type="application/rss+xml")
diff --git a/aurweb/routers/sso.py b/aurweb/routers/sso.py
index eff1c63f..e1356cfb 100644
--- a/aurweb/routers/sso.py
+++ b/aurweb/routers/sso.py
@@ -1,11 +1,9 @@
import time
import uuid
-
from http import HTTPStatus
from urllib.parse import urlencode
import fastapi
-
from authlib.integrations.starlette_client import OAuth, OAuthError
from fastapi import Depends, HTTPException
from fastapi.responses import RedirectResponse
@@ -14,7 +12,6 @@ from starlette.requests import Request
import aurweb.config
import aurweb.db
-
from aurweb import util
from aurweb.l10n import get_translator_for_request
from aurweb.schema import Bans, Sessions, Users
@@ -43,14 +40,18 @@ async def login(request: Request, redirect: str = None):
The `redirect` argument is a query parameter specifying the post-login
redirect URL.
"""
- authenticate_url = aurweb.config.get("options", "aur_location") + "/sso/authenticate"
+ authenticate_url = (
+ aurweb.config.get("options", "aur_location") + "/sso/authenticate"
+ )
if redirect:
authenticate_url = authenticate_url + "?" + urlencode([("redirect", redirect)])
return await oauth.sso.authorize_redirect(request, authenticate_url, prompt="login")
def is_account_suspended(conn, user_id):
- row = conn.execute(select([Users.c.Suspended]).where(Users.c.ID == user_id)).fetchone()
+ row = conn.execute(
+ select([Users.c.Suspended]).where(Users.c.ID == user_id)
+ ).fetchone()
return row is not None and bool(row[0])
@@ -60,23 +61,27 @@ def open_session(request, conn, user_id):
"""
if is_account_suspended(conn, user_id):
_ = get_translator_for_request(request)
- raise HTTPException(status_code=HTTPStatus.FORBIDDEN,
- detail=_('Account suspended'))
+ raise HTTPException(
+ status_code=HTTPStatus.FORBIDDEN, detail=_("Account suspended")
+ )
# TODO This is a terrible message because it could imply the attempt at
# logging in just caused the suspension.
sid = uuid.uuid4().hex
- conn.execute(Sessions.insert().values(
- UsersID=user_id,
- SessionID=sid,
- LastUpdateTS=time.time(),
- ))
+ conn.execute(
+ Sessions.insert().values(
+ UsersID=user_id,
+ SessionID=sid,
+ LastUpdateTS=time.time(),
+ )
+ )
# Update user’s last login information.
- conn.execute(Users.update()
- .where(Users.c.ID == user_id)
- .values(LastLogin=int(time.time()),
- LastLoginIPAddress=request.client.host))
+ conn.execute(
+ Users.update()
+ .where(Users.c.ID == user_id)
+ .values(LastLogin=int(time.time()), LastLoginIPAddress=request.client.host)
+ )
return sid
@@ -98,7 +103,9 @@ def is_aur_url(url):
@router.get("/sso/authenticate")
-async def authenticate(request: Request, redirect: str = None, conn=Depends(aurweb.db.connect)):
+async def authenticate(
+ request: Request, redirect: str = None, conn=Depends(aurweb.db.connect)
+):
"""
Receive an OpenID Connect ID token, validate it, then process it to create
an new AUR session.
@@ -107,9 +114,12 @@ async def authenticate(request: Request, redirect: str = None, conn=Depends(aurw
_ = get_translator_for_request(request)
raise HTTPException(
status_code=HTTPStatus.FORBIDDEN,
- detail=_('The login form is currently disabled for your IP address, '
- 'probably due to sustained spam attacks. Sorry for the '
- 'inconvenience.'))
+ detail=_(
+ "The login form is currently disabled for your IP address, "
+ "probably due to sustained spam attacks. Sorry for the "
+ "inconvenience."
+ ),
+ )
try:
token = await oauth.sso.authorize_access_token(request)
@@ -120,30 +130,41 @@ async def authenticate(request: Request, redirect: str = None, conn=Depends(aurw
_ = get_translator_for_request(request)
raise HTTPException(
status_code=HTTPStatus.BAD_REQUEST,
- detail=_('Bad OAuth token. Please retry logging in from the start.'))
+ detail=_("Bad OAuth token. Please retry logging in from the start."),
+ )
sub = user.get("sub") # this is the SSO account ID in JWT terminology
if not sub:
_ = get_translator_for_request(request)
- raise HTTPException(status_code=HTTPStatus.BAD_REQUEST,
- detail=_("JWT is missing its `sub` field."))
+ raise HTTPException(
+ status_code=HTTPStatus.BAD_REQUEST,
+ detail=_("JWT is missing its `sub` field."),
+ )
- aur_accounts = conn.execute(select([Users.c.ID]).where(Users.c.SSOAccountID == sub)) \
- .fetchall()
+ aur_accounts = conn.execute(
+ select([Users.c.ID]).where(Users.c.SSOAccountID == sub)
+ ).fetchall()
if not aur_accounts:
return "Sorry, we don’t seem to know you Sir " + sub
elif len(aur_accounts) == 1:
sid = open_session(request, conn, aur_accounts[0][Users.c.ID])
- response = RedirectResponse(redirect if redirect and is_aur_url(redirect) else "/")
+ response = RedirectResponse(
+ redirect if redirect and is_aur_url(redirect) else "/"
+ )
secure_cookies = aurweb.config.getboolean("options", "disable_http_login")
- response.set_cookie(key="AURSID", value=sid, httponly=True,
- secure=secure_cookies)
+ response.set_cookie(
+ key="AURSID", value=sid, httponly=True, secure=secure_cookies
+ )
if "id_token" in token:
# We save the id_token for the SSO logout. It’s not too important
# though, so if we can’t find it, we can live without it.
- response.set_cookie(key="SSO_ID_TOKEN", value=token["id_token"],
- path="/sso/", httponly=True,
- secure=secure_cookies)
+ response.set_cookie(
+ key="SSO_ID_TOKEN",
+ value=token["id_token"],
+ path="/sso/",
+ httponly=True,
+ secure=secure_cookies,
+ )
return util.add_samesite_fields(response, "strict")
else:
# We’ve got a severe integrity violation.
@@ -165,8 +186,12 @@ async def logout(request: Request):
return RedirectResponse("/")
metadata = await oauth.sso.load_server_metadata()
- query = urlencode({'post_logout_redirect_uri': aurweb.config.get('options', 'aur_location'),
- 'id_token_hint': id_token})
- response = RedirectResponse(metadata["end_session_endpoint"] + '?' + query)
+ query = urlencode(
+ {
+ "post_logout_redirect_uri": aurweb.config.get("options", "aur_location"),
+ "id_token_hint": id_token,
+ }
+ )
+ response = RedirectResponse(metadata["end_session_endpoint"] + "?" + query)
response.delete_cookie("SSO_ID_TOKEN", path="/sso/")
return response
diff --git a/aurweb/routers/trusted_user.py b/aurweb/routers/trusted_user.py
index e1267409..a84bb6bd 100644
--- a/aurweb/routers/trusted_user.py
+++ b/aurweb/routers/trusted_user.py
@@ -1,6 +1,5 @@
import html
import typing
-
from http import HTTPStatus
from typing import Any
@@ -30,33 +29,36 @@ ADDVOTE_SPECIFICS = {
"add_tu": (7 * 24 * 60 * 60, 0.66),
"remove_tu": (7 * 24 * 60 * 60, 0.75),
"remove_inactive_tu": (5 * 24 * 60 * 60, 0.66),
- "bylaws": (7 * 24 * 60 * 60, 0.75)
+ "bylaws": (7 * 24 * 60 * 60, 0.75),
}
def populate_trusted_user_counts(context: dict[str, Any]) -> None:
tu_query = db.query(User).filter(
- or_(User.AccountTypeID == TRUSTED_USER_ID,
- User.AccountTypeID == TRUSTED_USER_AND_DEV_ID)
+ or_(
+ User.AccountTypeID == TRUSTED_USER_ID,
+ User.AccountTypeID == TRUSTED_USER_AND_DEV_ID,
+ )
)
context["trusted_user_count"] = tu_query.count()
# In case any records have a None InactivityTS.
active_tu_query = tu_query.filter(
- or_(User.InactivityTS.is_(None),
- User.InactivityTS == 0)
+ or_(User.InactivityTS.is_(None), User.InactivityTS == 0)
)
context["active_trusted_user_count"] = active_tu_query.count()
@router.get("/tu")
@requires_auth
-async def trusted_user(request: Request,
- coff: int = 0, # current offset
- cby: str = "desc", # current by
- poff: int = 0, # past offset
- pby: str = "desc"): # past by
- """ Proposal listings. """
+async def trusted_user(
+ request: Request,
+ coff: int = 0, # current offset
+ cby: str = "desc", # current by
+ poff: int = 0, # past offset
+ pby: str = "desc",
+): # past by
+ """Proposal listings."""
if not request.user.has_credential(creds.TU_LIST_VOTES):
return RedirectResponse("/", status_code=HTTPStatus.SEE_OTHER)
@@ -81,40 +83,47 @@ async def trusted_user(request: Request,
past_by = "desc"
context["past_by"] = past_by
- current_votes = db.query(models.TUVoteInfo).filter(
- models.TUVoteInfo.End > ts).order_by(
- models.TUVoteInfo.Submitted.desc())
+ current_votes = (
+ db.query(models.TUVoteInfo)
+ .filter(models.TUVoteInfo.End > ts)
+ .order_by(models.TUVoteInfo.Submitted.desc())
+ )
context["current_votes_count"] = current_votes.count()
current_votes = current_votes.limit(pp).offset(current_off)
- context["current_votes"] = reversed(current_votes.all()) \
- if current_by == "asc" else current_votes.all()
+ context["current_votes"] = (
+ reversed(current_votes.all()) if current_by == "asc" else current_votes.all()
+ )
context["current_off"] = current_off
- past_votes = db.query(models.TUVoteInfo).filter(
- models.TUVoteInfo.End <= ts).order_by(
- models.TUVoteInfo.Submitted.desc())
+ past_votes = (
+ db.query(models.TUVoteInfo)
+ .filter(models.TUVoteInfo.End <= ts)
+ .order_by(models.TUVoteInfo.Submitted.desc())
+ )
context["past_votes_count"] = past_votes.count()
past_votes = past_votes.limit(pp).offset(past_off)
- context["past_votes"] = reversed(past_votes.all()) \
- if past_by == "asc" else past_votes.all()
+ context["past_votes"] = (
+ reversed(past_votes.all()) if past_by == "asc" else past_votes.all()
+ )
context["past_off"] = past_off
last_vote = func.max(models.TUVote.VoteID).label("LastVote")
- last_votes_by_tu = db.query(models.TUVote).join(models.User).join(
- models.TUVoteInfo,
- models.TUVoteInfo.ID == models.TUVote.VoteID
- ).filter(
- and_(models.TUVote.VoteID == models.TUVoteInfo.ID,
- models.User.ID == models.TUVote.UserID,
- models.TUVoteInfo.End < ts,
- or_(models.User.AccountTypeID == 2,
- models.User.AccountTypeID == 4))
- ).with_entities(
- models.TUVote.UserID,
- last_vote,
- models.User.Username
- ).group_by(models.TUVote.UserID).order_by(
- last_vote.desc(), models.User.Username.asc())
+ last_votes_by_tu = (
+ db.query(models.TUVote)
+ .join(models.User)
+ .join(models.TUVoteInfo, models.TUVoteInfo.ID == models.TUVote.VoteID)
+ .filter(
+ and_(
+ models.TUVote.VoteID == models.TUVoteInfo.ID,
+ models.User.ID == models.TUVote.UserID,
+ models.TUVoteInfo.End < ts,
+ or_(models.User.AccountTypeID == 2, models.User.AccountTypeID == 4),
+ )
+ )
+ .with_entities(models.TUVote.UserID, last_vote, models.User.Username)
+ .group_by(models.TUVote.UserID)
+ .order_by(last_vote.desc(), models.User.Username.asc())
+ )
context["last_votes_by_tu"] = last_votes_by_tu.all()
context["current_by_next"] = "asc" if current_by == "desc" else "desc"
@@ -126,18 +135,22 @@ async def trusted_user(request: Request,
"coff": current_off,
"cby": current_by,
"poff": past_off,
- "pby": past_by
+ "pby": past_by,
}
return render_template(request, "tu/index.html", context)
-def render_proposal(request: Request, context: dict, proposal: int,
- voteinfo: models.TUVoteInfo,
- voters: typing.Iterable[models.User],
- vote: models.TUVote,
- status_code: HTTPStatus = HTTPStatus.OK):
- """ Render a single TU proposal. """
+def render_proposal(
+ request: Request,
+ context: dict,
+ proposal: int,
+ voteinfo: models.TUVoteInfo,
+ voters: typing.Iterable[models.User],
+ vote: models.TUVote,
+ status_code: HTTPStatus = HTTPStatus.OK,
+):
+ """Render a single TU proposal."""
context["proposal"] = proposal
context["voteinfo"] = voteinfo
context["voters"] = voters.all()
@@ -146,8 +159,9 @@ def render_proposal(request: Request, context: dict, proposal: int,
participation = (total / voteinfo.ActiveTUs) if voteinfo.ActiveTUs else 0
context["participation"] = participation
- accepted = (voteinfo.Yes > voteinfo.ActiveTUs / 2) or \
- (participation > voteinfo.Quorum and voteinfo.Yes > voteinfo.No)
+ accepted = (voteinfo.Yes > voteinfo.ActiveTUs / 2) or (
+ participation > voteinfo.Quorum and voteinfo.Yes > voteinfo.No
+ )
context["accepted"] = accepted
can_vote = voters.filter(models.TUVote.User == request.user).first() is None
@@ -159,8 +173,7 @@ def render_proposal(request: Request, context: dict, proposal: int,
context["vote"] = vote
context["has_voted"] = vote is not None
- return render_template(request, "tu/show.html", context,
- status_code=status_code)
+ return render_template(request, "tu/show.html", context, status_code=status_code)
@router.get("/tu/{proposal}")
@@ -172,16 +185,27 @@ async def trusted_user_proposal(request: Request, proposal: int):
context = await make_variable_context(request, "Trusted User")
proposal = int(proposal)
- voteinfo = db.query(models.TUVoteInfo).filter(
- models.TUVoteInfo.ID == proposal).first()
+ voteinfo = (
+ db.query(models.TUVoteInfo).filter(models.TUVoteInfo.ID == proposal).first()
+ )
if not voteinfo:
raise HTTPException(status_code=HTTPStatus.NOT_FOUND)
- voters = db.query(models.User).join(models.TUVote).filter(
- models.TUVote.VoteID == voteinfo.ID)
- vote = db.query(models.TUVote).filter(
- and_(models.TUVote.UserID == request.user.ID,
- models.TUVote.VoteID == voteinfo.ID)).first()
+ voters = (
+ db.query(models.User)
+ .join(models.TUVote)
+ .filter(models.TUVote.VoteID == voteinfo.ID)
+ )
+ vote = (
+ db.query(models.TUVote)
+ .filter(
+ and_(
+ models.TUVote.UserID == request.user.ID,
+ models.TUVote.VoteID == voteinfo.ID,
+ )
+ )
+ .first()
+ )
if not request.user.has_credential(creds.TU_VOTE):
context["error"] = "Only Trusted Users are allowed to vote."
if voteinfo.User == request.user.Username:
@@ -196,24 +220,36 @@ async def trusted_user_proposal(request: Request, proposal: int):
@router.post("/tu/{proposal}")
@handle_form_exceptions
@requires_auth
-async def trusted_user_proposal_post(request: Request, proposal: int,
- decision: str = Form(...)):
+async def trusted_user_proposal_post(
+ request: Request, proposal: int, decision: str = Form(...)
+):
if not request.user.has_credential(creds.TU_LIST_VOTES):
return RedirectResponse("/tu", status_code=HTTPStatus.SEE_OTHER)
context = await make_variable_context(request, "Trusted User")
proposal = int(proposal) # Make sure it's an int.
- voteinfo = db.query(models.TUVoteInfo).filter(
- models.TUVoteInfo.ID == proposal).first()
+ voteinfo = (
+ db.query(models.TUVoteInfo).filter(models.TUVoteInfo.ID == proposal).first()
+ )
if not voteinfo:
raise HTTPException(status_code=HTTPStatus.NOT_FOUND)
- voters = db.query(models.User).join(models.TUVote).filter(
- models.TUVote.VoteID == voteinfo.ID)
- vote = db.query(models.TUVote).filter(
- and_(models.TUVote.UserID == request.user.ID,
- models.TUVote.VoteID == voteinfo.ID)).first()
+ voters = (
+ db.query(models.User)
+ .join(models.TUVote)
+ .filter(models.TUVote.VoteID == voteinfo.ID)
+ )
+ vote = (
+ db.query(models.TUVote)
+ .filter(
+ and_(
+ models.TUVote.UserID == request.user.ID,
+ models.TUVote.VoteID == voteinfo.ID,
+ )
+ )
+ .first()
+ )
status_code = HTTPStatus.OK
if not request.user.has_credential(creds.TU_VOTE):
@@ -227,16 +263,15 @@ async def trusted_user_proposal_post(request: Request, proposal: int,
status_code = HTTPStatus.BAD_REQUEST
if status_code != HTTPStatus.OK:
- return render_proposal(request, context, proposal,
- voteinfo, voters, vote,
- status_code=status_code)
+ return render_proposal(
+ request, context, proposal, voteinfo, voters, vote, status_code=status_code
+ )
if decision in {"Yes", "No", "Abstain"}:
# Increment whichever decision was given to us.
setattr(voteinfo, decision, getattr(voteinfo, decision) + 1)
else:
- return Response("Invalid 'decision' value.",
- status_code=HTTPStatus.BAD_REQUEST)
+ return Response("Invalid 'decision' value.", status_code=HTTPStatus.BAD_REQUEST)
with db.begin():
vote = db.create(models.TUVote, User=request.user, VoteInfo=voteinfo)
@@ -247,8 +282,9 @@ async def trusted_user_proposal_post(request: Request, proposal: int,
@router.get("/addvote")
@requires_auth
-async def trusted_user_addvote(request: Request, user: str = str(),
- type: str = "add_tu", agenda: str = str()):
+async def trusted_user_addvote(
+ request: Request, user: str = str(), type: str = "add_tu", agenda: str = str()
+):
if not request.user.has_credential(creds.TU_ADD_VOTE):
return RedirectResponse("/tu", status_code=HTTPStatus.SEE_OTHER)
@@ -268,10 +304,12 @@ async def trusted_user_addvote(request: Request, user: str = str(),
@router.post("/addvote")
@handle_form_exceptions
@requires_auth
-async def trusted_user_addvote_post(request: Request,
- user: str = Form(default=str()),
- type: str = Form(default=str()),
- agenda: str = Form(default=str())):
+async def trusted_user_addvote_post(
+ request: Request,
+ user: str = Form(default=str()),
+ type: str = Form(default=str()),
+ agenda: str = Form(default=str()),
+):
if not request.user.has_credential(creds.TU_ADD_VOTE):
return RedirectResponse("/tu", status_code=HTTPStatus.SEE_OTHER)
@@ -283,26 +321,29 @@ async def trusted_user_addvote_post(request: Request,
context["agenda"] = agenda
def render_addvote(context, status_code):
- """ Simplify render_template a bit for this test. """
+ """Simplify render_template a bit for this test."""
return render_template(request, "addvote.html", context, status_code)
# Alright, get some database records, if we can.
if type != "bylaws":
- user_record = db.query(models.User).filter(
- models.User.Username == user).first()
+ user_record = db.query(models.User).filter(models.User.Username == user).first()
if user_record is None:
context["error"] = "Username does not exist."
return render_addvote(context, HTTPStatus.NOT_FOUND)
utcnow = time.utcnow()
- voteinfo = db.query(models.TUVoteInfo).filter(
- and_(models.TUVoteInfo.User == user,
- models.TUVoteInfo.End > utcnow)).count()
+ voteinfo = (
+ db.query(models.TUVoteInfo)
+ .filter(
+ and_(models.TUVoteInfo.User == user, models.TUVoteInfo.End > utcnow)
+ )
+ .count()
+ )
if voteinfo:
_ = l10n.get_translator_for_request(request)
- context["error"] = _(
- "%s already has proposal running for them.") % (
- html.escape(user),)
+ context["error"] = _("%s already has proposal running for them.") % (
+ html.escape(user),
+ )
return render_addvote(context, HTTPStatus.BAD_REQUEST)
if type not in ADDVOTE_SPECIFICS:
@@ -323,16 +364,27 @@ async def trusted_user_addvote_post(request: Request,
# Create a new TUVoteInfo (proposal)!
with db.begin():
- active_tus = db.query(User).filter(
- and_(User.Suspended == 0,
- User.InactivityTS.isnot(None),
- User.AccountTypeID.in_(types))
- ).count()
- voteinfo = db.create(models.TUVoteInfo, User=user,
- Agenda=html.escape(agenda),
- Submitted=timestamp, End=(timestamp + duration),
- Quorum=quorum, ActiveTUs=active_tus,
- Submitter=request.user)
+ active_tus = (
+ db.query(User)
+ .filter(
+ and_(
+ User.Suspended == 0,
+ User.InactivityTS.isnot(None),
+ User.AccountTypeID.in_(types),
+ )
+ )
+ .count()
+ )
+ voteinfo = db.create(
+ models.TUVoteInfo,
+ User=user,
+ Agenda=html.escape(agenda),
+ Submitted=timestamp,
+ End=(timestamp + duration),
+ Quorum=quorum,
+ ActiveTUs=active_tus,
+ Submitter=request.user,
+ )
# Redirect to the new proposal.
endpoint = f"/tu/{voteinfo.ID}"
diff --git a/aurweb/rpc.py b/aurweb/rpc.py
index 3ea7e070..26677f80 100644
--- a/aurweb/rpc.py
+++ b/aurweb/rpc.py
@@ -1,5 +1,4 @@
import os
-
from collections import defaultdict
from typing import Any, Callable, NewType, Union
@@ -7,7 +6,6 @@ from fastapi.responses import HTMLResponse
from sqlalchemy import and_, literal, orm
import aurweb.config as config
-
from aurweb import db, defaults, models
from aurweb.exceptions import RPCError
from aurweb.filters import number_format
@@ -23,8 +21,7 @@ TYPE_MAPPING = {
"replaces": "Replaces",
}
-DataGenerator = NewType("DataGenerator",
- Callable[[models.Package], dict[str, Any]])
+DataGenerator = NewType("DataGenerator", Callable[[models.Package], dict[str, Any]])
def documentation():
@@ -40,7 +37,7 @@ def documentation():
class RPC:
- """ RPC API handler class.
+ """RPC API handler class.
There are various pieces to RPC's process, and encapsulating them
inside of a class means that external users do not abuse the
@@ -66,17 +63,25 @@ class RPC:
# A set of RPC types supported by this API.
EXPOSED_TYPES = {
- "info", "multiinfo",
- "search", "msearch",
- "suggest", "suggest-pkgbase"
+ "info",
+ "multiinfo",
+ "search",
+ "msearch",
+ "suggest",
+ "suggest-pkgbase",
}
# A mapping of type aliases.
TYPE_ALIASES = {"info": "multiinfo"}
EXPOSED_BYS = {
- "name-desc", "name", "maintainer",
- "depends", "makedepends", "optdepends", "checkdepends"
+ "name-desc",
+ "name",
+ "maintainer",
+ "depends",
+ "makedepends",
+ "optdepends",
+ "checkdepends",
}
# A mapping of by aliases.
@@ -92,7 +97,7 @@ class RPC:
"results": [],
"resultcount": 0,
"type": "error",
- "error": message
+ "error": message,
}
def _verify_inputs(self, by: str = [], args: list[str] = []) -> None:
@@ -116,7 +121,7 @@ class RPC:
raise RPCError("No request type/data specified.")
def _get_json_data(self, package: models.Package) -> dict[str, Any]:
- """ Produce dictionary data of one Package that can be JSON-serialized.
+ """Produce dictionary data of one Package that can be JSON-serialized.
:param package: Package instance
:returns: JSON-serializable dictionary
@@ -143,7 +148,7 @@ class RPC:
"Popularity": pop,
"OutOfDate": package.OutOfDateTS,
"FirstSubmitted": package.SubmittedTS,
- "LastModified": package.ModifiedTS
+ "LastModified": package.ModifiedTS,
}
def _get_info_json_data(self, package: models.Package) -> dict[str, Any]:
@@ -151,10 +156,7 @@ class RPC:
# All info results have _at least_ an empty list of
# License and Keywords.
- data.update({
- "License": [],
- "Keywords": []
- })
+ data.update({"License": [], "Keywords": []})
# If we actually got extra_info records, update data with
# them for this particular package.
@@ -163,9 +165,9 @@ class RPC:
return data
- def _assemble_json_data(self, packages: list[models.Package],
- data_generator: DataGenerator) \
- -> list[dict[str, Any]]:
+ def _assemble_json_data(
+ self, packages: list[models.Package], data_generator: DataGenerator
+ ) -> list[dict[str, Any]]:
"""
Assemble JSON data out of a list of packages.
@@ -175,7 +177,7 @@ class RPC:
return [data_generator(pkg) for pkg in packages]
def _entities(self, query: orm.Query) -> orm.Query:
- """ Select specific RPC columns on `query`. """
+ """Select specific RPC columns on `query`."""
return query.with_entities(
models.Package.ID,
models.Package.Name,
@@ -192,16 +194,22 @@ class RPC:
models.User.Username.label("Maintainer"),
).group_by(models.Package.ID)
- def _handle_multiinfo_type(self, args: list[str] = [], **kwargs) \
- -> list[dict[str, Any]]:
+ def _handle_multiinfo_type(
+ self, args: list[str] = [], **kwargs
+ ) -> list[dict[str, Any]]:
self._enforce_args(args)
args = set(args)
- packages = db.query(models.Package).join(models.PackageBase).join(
- models.User,
- models.User.ID == models.PackageBase.MaintainerUID,
- isouter=True
- ).filter(models.Package.Name.in_(args))
+ packages = (
+ db.query(models.Package)
+ .join(models.PackageBase)
+ .join(
+ models.User,
+ models.User.ID == models.PackageBase.MaintainerUID,
+ isouter=True,
+ )
+ .filter(models.Package.Name.in_(args))
+ )
max_results = config.getint("options", "max_rpc_results")
packages = self._entities(packages).limit(max_results + 1)
@@ -217,65 +225,75 @@ class RPC:
subqueries = [
# PackageDependency
- db.query(
- models.PackageDependency
- ).join(models.DependencyType).filter(
- models.PackageDependency.PackageID.in_(ids)
- ).with_entities(
+ db.query(models.PackageDependency)
+ .join(models.DependencyType)
+ .filter(models.PackageDependency.PackageID.in_(ids))
+ .with_entities(
models.PackageDependency.PackageID.label("ID"),
models.DependencyType.Name.label("Type"),
models.PackageDependency.DepName.label("Name"),
- models.PackageDependency.DepCondition.label("Cond")
- ).distinct().order_by("Name"),
-
+ models.PackageDependency.DepCondition.label("Cond"),
+ )
+ .distinct()
+ .order_by("Name"),
# PackageRelation
- db.query(
- models.PackageRelation
- ).join(models.RelationType).filter(
- models.PackageRelation.PackageID.in_(ids)
- ).with_entities(
+ db.query(models.PackageRelation)
+ .join(models.RelationType)
+ .filter(models.PackageRelation.PackageID.in_(ids))
+ .with_entities(
models.PackageRelation.PackageID.label("ID"),
models.RelationType.Name.label("Type"),
models.PackageRelation.RelName.label("Name"),
- models.PackageRelation.RelCondition.label("Cond")
- ).distinct().order_by("Name"),
-
+ models.PackageRelation.RelCondition.label("Cond"),
+ )
+ .distinct()
+ .order_by("Name"),
# Groups
- db.query(models.PackageGroup).join(
+ db.query(models.PackageGroup)
+ .join(
models.Group,
- and_(models.PackageGroup.GroupID == models.Group.ID,
- models.PackageGroup.PackageID.in_(ids))
- ).with_entities(
+ and_(
+ models.PackageGroup.GroupID == models.Group.ID,
+ models.PackageGroup.PackageID.in_(ids),
+ ),
+ )
+ .with_entities(
models.PackageGroup.PackageID.label("ID"),
literal("Groups").label("Type"),
models.Group.Name.label("Name"),
- literal(str()).label("Cond")
- ).distinct().order_by("Name"),
-
+ literal(str()).label("Cond"),
+ )
+ .distinct()
+ .order_by("Name"),
# Licenses
- db.query(models.PackageLicense).join(
- models.License,
- models.PackageLicense.LicenseID == models.License.ID
- ).filter(
- models.PackageLicense.PackageID.in_(ids)
- ).with_entities(
+ db.query(models.PackageLicense)
+ .join(models.License, models.PackageLicense.LicenseID == models.License.ID)
+ .filter(models.PackageLicense.PackageID.in_(ids))
+ .with_entities(
models.PackageLicense.PackageID.label("ID"),
literal("License").label("Type"),
models.License.Name.label("Name"),
- literal(str()).label("Cond")
- ).distinct().order_by("Name"),
-
+ literal(str()).label("Cond"),
+ )
+ .distinct()
+ .order_by("Name"),
# Keywords
- db.query(models.PackageKeyword).join(
+ db.query(models.PackageKeyword)
+ .join(
models.Package,
- and_(Package.PackageBaseID == PackageKeyword.PackageBaseID,
- Package.ID.in_(ids))
- ).with_entities(
+ and_(
+ Package.PackageBaseID == PackageKeyword.PackageBaseID,
+ Package.ID.in_(ids),
+ ),
+ )
+ .with_entities(
models.Package.ID.label("ID"),
literal("Keywords").label("Type"),
models.PackageKeyword.Keyword.label("Name"),
- literal(str()).label("Cond")
- ).distinct().order_by("Name")
+ literal(str()).label("Cond"),
+ )
+ .distinct()
+ .order_by("Name"),
]
# Union all subqueries together.
@@ -295,8 +313,9 @@ class RPC:
return self._assemble_json_data(packages, self._get_info_json_data)
- def _handle_search_type(self, by: str = defaults.RPC_SEARCH_BY,
- args: list[str] = []) -> list[dict[str, Any]]:
+ def _handle_search_type(
+ self, by: str = defaults.RPC_SEARCH_BY, args: list[str] = []
+ ) -> list[dict[str, Any]]:
# If `by` isn't maintainer and we don't have any args, raise an error.
# In maintainer's case, return all orphans if there are no args,
# so we need args to pass through to the handler without errors.
@@ -318,50 +337,64 @@ class RPC:
return self._assemble_json_data(results, self._get_json_data)
- def _handle_msearch_type(self, args: list[str] = [], **kwargs)\
- -> list[dict[str, Any]]:
+ def _handle_msearch_type(
+ self, args: list[str] = [], **kwargs
+ ) -> list[dict[str, Any]]:
return self._handle_search_type(by="m", args=args)
- def _handle_suggest_type(self, args: list[str] = [], **kwargs)\
- -> list[str]:
+ def _handle_suggest_type(self, args: list[str] = [], **kwargs) -> list[str]:
if not args:
return []
arg = args[0]
- packages = db.query(models.Package.Name).join(
- models.PackageBase
- ).filter(
- and_(models.PackageBase.PackagerUID.isnot(None),
- models.Package.Name.like(f"{arg}%"))
- ).order_by(models.Package.Name.asc()).limit(20)
+ packages = (
+ db.query(models.Package.Name)
+ .join(models.PackageBase)
+ .filter(
+ and_(
+ models.PackageBase.PackagerUID.isnot(None),
+ models.Package.Name.like(f"{arg}%"),
+ )
+ )
+ .order_by(models.Package.Name.asc())
+ .limit(20)
+ )
return [pkg.Name for pkg in packages]
- def _handle_suggest_pkgbase_type(self, args: list[str] = [], **kwargs)\
- -> list[str]:
+ def _handle_suggest_pkgbase_type(self, args: list[str] = [], **kwargs) -> list[str]:
if not args:
return []
arg = args[0]
- packages = db.query(models.PackageBase.Name).filter(
- and_(models.PackageBase.PackagerUID.isnot(None),
- models.PackageBase.Name.like(f"{arg}%"))
- ).order_by(models.PackageBase.Name.asc()).limit(20)
+ packages = (
+ db.query(models.PackageBase.Name)
+ .filter(
+ and_(
+ models.PackageBase.PackagerUID.isnot(None),
+ models.PackageBase.Name.like(f"{arg}%"),
+ )
+ )
+ .order_by(models.PackageBase.Name.asc())
+ .limit(20)
+ )
return [pkg.Name for pkg in packages]
def _is_suggestion(self) -> bool:
return self.type.startswith("suggest")
- def _handle_callback(self, by: str, args: list[str])\
- -> Union[list[dict[str, Any]], list[str]]:
+ def _handle_callback(
+ self, by: str, args: list[str]
+ ) -> Union[list[dict[str, Any]], list[str]]:
# Get a handle to our callback and trap an RPCError with
# an empty list of results based on callback's execution.
callback = getattr(self, f"_handle_{self.type.replace('-', '_')}_type")
results = callback(by=by, args=args)
return results
- def handle(self, by: str = defaults.RPC_SEARCH_BY, args: list[str] = [])\
- -> Union[list[dict[str, Any]], dict[str, Any]]:
- """ Request entrypoint. A router should pass v, type and args
+ def handle(
+ self, by: str = defaults.RPC_SEARCH_BY, args: list[str] = []
+ ) -> Union[list[dict[str, Any]], dict[str, Any]]:
+ """Request entrypoint. A router should pass v, type and args
to this function and expect an output dictionary to be returned.
:param v: RPC version argument
@@ -392,8 +425,5 @@ class RPC:
return results
# Return JSON output.
- data.update({
- "resultcount": len(results),
- "results": results
- })
+ data.update({"resultcount": len(results), "results": results})
return data
diff --git a/aurweb/schema.py b/aurweb/schema.py
index d2644541..b3b36195 100644
--- a/aurweb/schema.py
+++ b/aurweb/schema.py
@@ -6,7 +6,18 @@ usually be automatically generated. See `migrations/README` for details.
"""
-from sqlalchemy import CHAR, TIMESTAMP, Column, ForeignKey, Index, MetaData, String, Table, Text, text
+from sqlalchemy import (
+ CHAR,
+ TIMESTAMP,
+ Column,
+ ForeignKey,
+ Index,
+ MetaData,
+ String,
+ Table,
+ Text,
+ text,
+)
from sqlalchemy.dialects.mysql import BIGINT, DECIMAL, INTEGER, TINYINT
from sqlalchemy.ext.compiler import compiles
@@ -15,13 +26,13 @@ import aurweb.config
db_backend = aurweb.config.get("database", "backend")
-@compiles(TINYINT, 'sqlite')
+@compiles(TINYINT, "sqlite")
def compile_tinyint_sqlite(type_, compiler, **kw): # pragma: no cover
"""TINYINT is not supported on SQLite. Substitute it with INTEGER."""
- return 'INTEGER'
+ return "INTEGER"
-@compiles(BIGINT, 'sqlite')
+@compiles(BIGINT, "sqlite")
def compile_bigint_sqlite(type_, compiler, **kw): # pragma: no cover
"""
For SQLite's AUTOINCREMENT to work on BIGINT columns, we need to map BIGINT
@@ -29,429 +40,567 @@ def compile_bigint_sqlite(type_, compiler, **kw): # pragma: no cover
See https://docs.sqlalchemy.org/en/13/dialects/sqlite.html#allowing-autoincrement-behavior-sqlalchemy-types-other-than-integer-integer
""" # noqa: E501
- return 'INTEGER'
+ return "INTEGER"
metadata = MetaData()
# Define the Account Types for the AUR.
AccountTypes = Table(
- 'AccountTypes', metadata,
- Column('ID', TINYINT(unsigned=True), primary_key=True),
- Column('AccountType', String(32), nullable=False, server_default=text("''")),
- mysql_engine='InnoDB',
- mysql_charset='utf8mb4',
- mysql_collate='utf8mb4_general_ci'
+ "AccountTypes",
+ metadata,
+ Column("ID", TINYINT(unsigned=True), primary_key=True),
+ Column("AccountType", String(32), nullable=False, server_default=text("''")),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_general_ci",
)
# User information for each user regardless of type.
Users = Table(
- 'Users', metadata,
- Column('ID', INTEGER(unsigned=True), primary_key=True),
- Column('AccountTypeID', ForeignKey('AccountTypes.ID', ondelete="NO ACTION"), nullable=False, server_default=text("1")),
- Column('Suspended', TINYINT(unsigned=True), nullable=False, server_default=text("0")),
- Column('Username', String(32), nullable=False, unique=True),
- Column('Email', String(254), nullable=False, unique=True),
- Column('BackupEmail', String(254)),
- Column('HideEmail', TINYINT(unsigned=True), nullable=False, server_default=text("0")),
- Column('Passwd', String(255), nullable=False),
- Column('Salt', CHAR(32), nullable=False, server_default=text("''")),
- Column('ResetKey', CHAR(32), nullable=False, server_default=text("''")),
- Column('RealName', String(64), nullable=False, server_default=text("''")),
- Column('LangPreference', String(6), nullable=False, server_default=text("'en'")),
- Column('Timezone', String(32), nullable=False, server_default=text("'UTC'")),
- Column('Homepage', Text),
- Column('IRCNick', String(32), nullable=False, server_default=text("''")),
- Column('PGPKey', String(40)),
- Column('LastLogin', BIGINT(unsigned=True), nullable=False, server_default=text("0")),
- Column('LastLoginIPAddress', String(45)),
- Column('LastSSHLogin', BIGINT(unsigned=True), nullable=False, server_default=text("0")),
- Column('LastSSHLoginIPAddress', String(45)),
- Column('InactivityTS', BIGINT(unsigned=True), nullable=False, server_default=text("0")),
- Column('RegistrationTS', TIMESTAMP, nullable=False, server_default=text("CURRENT_TIMESTAMP")),
- Column('CommentNotify', TINYINT(1), nullable=False, server_default=text("1")),
- Column('UpdateNotify', TINYINT(1), nullable=False, server_default=text("0")),
- Column('OwnershipNotify', TINYINT(1), nullable=False, server_default=text("1")),
- Column('SSOAccountID', String(255), nullable=True, unique=True),
- Index('UsersAccountTypeID', 'AccountTypeID'),
- mysql_engine='InnoDB',
- mysql_charset='utf8mb4',
- mysql_collate='utf8mb4_general_ci',
+ "Users",
+ metadata,
+ Column("ID", INTEGER(unsigned=True), primary_key=True),
+ Column(
+ "AccountTypeID",
+ ForeignKey("AccountTypes.ID", ondelete="NO ACTION"),
+ nullable=False,
+ server_default=text("1"),
+ ),
+ Column(
+ "Suspended", TINYINT(unsigned=True), nullable=False, server_default=text("0")
+ ),
+ Column("Username", String(32), nullable=False, unique=True),
+ Column("Email", String(254), nullable=False, unique=True),
+ Column("BackupEmail", String(254)),
+ Column(
+ "HideEmail", TINYINT(unsigned=True), nullable=False, server_default=text("0")
+ ),
+ Column("Passwd", String(255), nullable=False),
+ Column("Salt", CHAR(32), nullable=False, server_default=text("''")),
+ Column("ResetKey", CHAR(32), nullable=False, server_default=text("''")),
+ Column("RealName", String(64), nullable=False, server_default=text("''")),
+ Column("LangPreference", String(6), nullable=False, server_default=text("'en'")),
+ Column("Timezone", String(32), nullable=False, server_default=text("'UTC'")),
+ Column("Homepage", Text),
+ Column("IRCNick", String(32), nullable=False, server_default=text("''")),
+ Column("PGPKey", String(40)),
+ Column(
+ "LastLogin", BIGINT(unsigned=True), nullable=False, server_default=text("0")
+ ),
+ Column("LastLoginIPAddress", String(45)),
+ Column(
+ "LastSSHLogin", BIGINT(unsigned=True), nullable=False, server_default=text("0")
+ ),
+ Column("LastSSHLoginIPAddress", String(45)),
+ Column(
+ "InactivityTS", BIGINT(unsigned=True), nullable=False, server_default=text("0")
+ ),
+ Column(
+ "RegistrationTS",
+ TIMESTAMP,
+ nullable=False,
+ server_default=text("CURRENT_TIMESTAMP"),
+ ),
+ Column("CommentNotify", TINYINT(1), nullable=False, server_default=text("1")),
+ Column("UpdateNotify", TINYINT(1), nullable=False, server_default=text("0")),
+ Column("OwnershipNotify", TINYINT(1), nullable=False, server_default=text("1")),
+ Column("SSOAccountID", String(255), nullable=True, unique=True),
+ Index("UsersAccountTypeID", "AccountTypeID"),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_general_ci",
)
# SSH public keys used for the aurweb SSH/Git interface.
SSHPubKeys = Table(
- 'SSHPubKeys', metadata,
- Column('UserID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False),
- Column('Fingerprint', String(44), primary_key=True),
- Column('PubKey', String(4096), nullable=False),
- mysql_engine='InnoDB', mysql_charset='utf8mb4', mysql_collate='utf8mb4_bin',
+ "SSHPubKeys",
+ metadata,
+ Column("UserID", ForeignKey("Users.ID", ondelete="CASCADE"), nullable=False),
+ Column("Fingerprint", String(44), primary_key=True),
+ Column("PubKey", String(4096), nullable=False),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_bin",
)
# Track Users logging in/out of AUR web site.
Sessions = Table(
- 'Sessions', metadata,
- Column('UsersID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False),
- Column('SessionID', CHAR(32), nullable=False, unique=True),
- Column('LastUpdateTS', BIGINT(unsigned=True), nullable=False),
- mysql_engine='InnoDB', mysql_charset='utf8mb4', mysql_collate='utf8mb4_bin',
+ "Sessions",
+ metadata,
+ Column("UsersID", ForeignKey("Users.ID", ondelete="CASCADE"), nullable=False),
+ Column("SessionID", CHAR(32), nullable=False, unique=True),
+ Column("LastUpdateTS", BIGINT(unsigned=True), nullable=False),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_bin",
)
# Information on package bases
PackageBases = Table(
- 'PackageBases', metadata,
- Column('ID', INTEGER(unsigned=True), primary_key=True),
- Column('Name', String(255), nullable=False, unique=True),
- Column('NumVotes', INTEGER(unsigned=True), nullable=False, server_default=text("0")),
- Column('Popularity',
- DECIMAL(10, 6, unsigned=True)
- if db_backend == "mysql" else String(17),
- nullable=False, server_default=text("0")),
- Column('OutOfDateTS', BIGINT(unsigned=True)),
- Column('FlaggerComment', Text, nullable=False),
- Column('SubmittedTS', BIGINT(unsigned=True), nullable=False),
- Column('ModifiedTS', BIGINT(unsigned=True), nullable=False),
- Column('FlaggerUID', ForeignKey('Users.ID', ondelete='SET NULL')), # who flagged the package out-of-date?
+ "PackageBases",
+ metadata,
+ Column("ID", INTEGER(unsigned=True), primary_key=True),
+ Column("Name", String(255), nullable=False, unique=True),
+ Column(
+ "NumVotes", INTEGER(unsigned=True), nullable=False, server_default=text("0")
+ ),
+ Column(
+ "Popularity",
+ DECIMAL(10, 6, unsigned=True) if db_backend == "mysql" else String(17),
+ nullable=False,
+ server_default=text("0"),
+ ),
+ Column("OutOfDateTS", BIGINT(unsigned=True)),
+ Column("FlaggerComment", Text, nullable=False),
+ Column("SubmittedTS", BIGINT(unsigned=True), nullable=False),
+ Column("ModifiedTS", BIGINT(unsigned=True), nullable=False),
+ Column(
+ "FlaggerUID", ForeignKey("Users.ID", ondelete="SET NULL")
+ ), # who flagged the package out-of-date?
# deleting a user will cause packages to be orphaned, not deleted
- Column('SubmitterUID', ForeignKey('Users.ID', ondelete='SET NULL')), # who submitted it?
- Column('MaintainerUID', ForeignKey('Users.ID', ondelete='SET NULL')), # User
- Column('PackagerUID', ForeignKey('Users.ID', ondelete='SET NULL')), # Last packager
- Index('BasesMaintainerUID', 'MaintainerUID'),
- Index('BasesNumVotes', 'NumVotes'),
- Index('BasesPackagerUID', 'PackagerUID'),
- Index('BasesSubmitterUID', 'SubmitterUID'),
- mysql_engine='InnoDB',
- mysql_charset='utf8mb4',
- mysql_collate='utf8mb4_general_ci',
+ Column(
+ "SubmitterUID", ForeignKey("Users.ID", ondelete="SET NULL")
+ ), # who submitted it?
+ Column("MaintainerUID", ForeignKey("Users.ID", ondelete="SET NULL")), # User
+ Column("PackagerUID", ForeignKey("Users.ID", ondelete="SET NULL")), # Last packager
+ Index("BasesMaintainerUID", "MaintainerUID"),
+ Index("BasesNumVotes", "NumVotes"),
+ Index("BasesPackagerUID", "PackagerUID"),
+ Index("BasesSubmitterUID", "SubmitterUID"),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_general_ci",
)
# Keywords of package bases
PackageKeywords = Table(
- 'PackageKeywords', metadata,
- Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), primary_key=True, nullable=True),
- Column('Keyword', String(255), primary_key=True, nullable=False, server_default=text("''")),
- mysql_engine='InnoDB',
- mysql_charset='utf8mb4',
- mysql_collate='utf8mb4_general_ci',
+ "PackageKeywords",
+ metadata,
+ Column(
+ "PackageBaseID",
+ ForeignKey("PackageBases.ID", ondelete="CASCADE"),
+ primary_key=True,
+ nullable=True,
+ ),
+ Column(
+ "Keyword",
+ String(255),
+ primary_key=True,
+ nullable=False,
+ server_default=text("''"),
+ ),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_general_ci",
)
# Information about the actual packages
Packages = Table(
- 'Packages', metadata,
- Column('ID', INTEGER(unsigned=True), primary_key=True),
- Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), nullable=False),
- Column('Name', String(255), nullable=False, unique=True),
- Column('Version', String(255), nullable=False, server_default=text("''")),
- Column('Description', String(255)),
- Column('URL', String(8000)),
- mysql_engine='InnoDB',
- mysql_charset='utf8mb4',
- mysql_collate='utf8mb4_general_ci',
+ "Packages",
+ metadata,
+ Column("ID", INTEGER(unsigned=True), primary_key=True),
+ Column(
+ "PackageBaseID",
+ ForeignKey("PackageBases.ID", ondelete="CASCADE"),
+ nullable=False,
+ ),
+ Column("Name", String(255), nullable=False, unique=True),
+ Column("Version", String(255), nullable=False, server_default=text("''")),
+ Column("Description", String(255)),
+ Column("URL", String(8000)),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_general_ci",
)
# Information about licenses
Licenses = Table(
- 'Licenses', metadata,
- Column('ID', INTEGER(unsigned=True), primary_key=True),
- Column('Name', String(255), nullable=False, unique=True),
- mysql_engine='InnoDB',
- mysql_charset='utf8mb4',
- mysql_collate='utf8mb4_general_ci',
+ "Licenses",
+ metadata,
+ Column("ID", INTEGER(unsigned=True), primary_key=True),
+ Column("Name", String(255), nullable=False, unique=True),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_general_ci",
)
# Information about package-license-relations
PackageLicenses = Table(
- 'PackageLicenses', metadata,
- Column('PackageID', ForeignKey('Packages.ID', ondelete='CASCADE'), primary_key=True, nullable=True),
- Column('LicenseID', ForeignKey('Licenses.ID', ondelete='CASCADE'), primary_key=True, nullable=True),
- mysql_engine='InnoDB',
+ "PackageLicenses",
+ metadata,
+ Column(
+ "PackageID",
+ ForeignKey("Packages.ID", ondelete="CASCADE"),
+ primary_key=True,
+ nullable=True,
+ ),
+ Column(
+ "LicenseID",
+ ForeignKey("Licenses.ID", ondelete="CASCADE"),
+ primary_key=True,
+ nullable=True,
+ ),
+ mysql_engine="InnoDB",
)
# Information about groups
Groups = Table(
- 'Groups', metadata,
- Column('ID', INTEGER(unsigned=True), primary_key=True),
- Column('Name', String(255), nullable=False, unique=True),
- mysql_engine='InnoDB',
- mysql_charset='utf8mb4',
- mysql_collate='utf8mb4_general_ci',
+ "Groups",
+ metadata,
+ Column("ID", INTEGER(unsigned=True), primary_key=True),
+ Column("Name", String(255), nullable=False, unique=True),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_general_ci",
)
# Information about package-group-relations
PackageGroups = Table(
- 'PackageGroups', metadata,
- Column('PackageID', ForeignKey('Packages.ID', ondelete='CASCADE'), primary_key=True, nullable=True),
- Column('GroupID', ForeignKey('Groups.ID', ondelete='CASCADE'), primary_key=True, nullable=True),
- mysql_engine='InnoDB',
+ "PackageGroups",
+ metadata,
+ Column(
+ "PackageID",
+ ForeignKey("Packages.ID", ondelete="CASCADE"),
+ primary_key=True,
+ nullable=True,
+ ),
+ Column(
+ "GroupID",
+ ForeignKey("Groups.ID", ondelete="CASCADE"),
+ primary_key=True,
+ nullable=True,
+ ),
+ mysql_engine="InnoDB",
)
# Define the package dependency types
DependencyTypes = Table(
- 'DependencyTypes', metadata,
- Column('ID', TINYINT(unsigned=True), primary_key=True),
- Column('Name', String(32), nullable=False, server_default=text("''")),
- mysql_engine='InnoDB',
- mysql_charset='utf8mb4',
- mysql_collate='utf8mb4_general_ci',
+ "DependencyTypes",
+ metadata,
+ Column("ID", TINYINT(unsigned=True), primary_key=True),
+ Column("Name", String(32), nullable=False, server_default=text("''")),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_general_ci",
)
# Track which dependencies a package has
PackageDepends = Table(
- 'PackageDepends', metadata,
- Column('PackageID', ForeignKey('Packages.ID', ondelete='CASCADE'), nullable=False),
- Column('DepTypeID', ForeignKey('DependencyTypes.ID', ondelete="NO ACTION"), nullable=False),
- Column('DepName', String(255), nullable=False),
- Column('DepDesc', String(255)),
- Column('DepCondition', String(255)),
- Column('DepArch', String(255)),
- Index('DependsDepName', 'DepName'),
- Index('DependsPackageID', 'PackageID'),
- mysql_engine='InnoDB',
- mysql_charset='utf8mb4',
- mysql_collate='utf8mb4_general_ci',
+ "PackageDepends",
+ metadata,
+ Column("PackageID", ForeignKey("Packages.ID", ondelete="CASCADE"), nullable=False),
+ Column(
+ "DepTypeID",
+ ForeignKey("DependencyTypes.ID", ondelete="NO ACTION"),
+ nullable=False,
+ ),
+ Column("DepName", String(255), nullable=False),
+ Column("DepDesc", String(255)),
+ Column("DepCondition", String(255)),
+ Column("DepArch", String(255)),
+ Index("DependsDepName", "DepName"),
+ Index("DependsPackageID", "PackageID"),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_general_ci",
)
# Define the package relation types
RelationTypes = Table(
- 'RelationTypes', metadata,
- Column('ID', TINYINT(unsigned=True), primary_key=True),
- Column('Name', String(32), nullable=False, server_default=text("''")),
- mysql_engine='InnoDB',
- mysql_charset='utf8mb4',
- mysql_collate='utf8mb4_general_ci',
+ "RelationTypes",
+ metadata,
+ Column("ID", TINYINT(unsigned=True), primary_key=True),
+ Column("Name", String(32), nullable=False, server_default=text("''")),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_general_ci",
)
# Track which conflicts, provides and replaces a package has
PackageRelations = Table(
- 'PackageRelations', metadata,
- Column('PackageID', ForeignKey('Packages.ID', ondelete='CASCADE'), nullable=False),
- Column('RelTypeID', ForeignKey('RelationTypes.ID', ondelete="NO ACTION"), nullable=False),
- Column('RelName', String(255), nullable=False),
- Column('RelCondition', String(255)),
- Column('RelArch', String(255)),
- Index('RelationsPackageID', 'PackageID'),
- Index('RelationsRelName', 'RelName'),
- mysql_engine='InnoDB',
- mysql_charset='utf8mb4',
- mysql_collate='utf8mb4_general_ci',
+ "PackageRelations",
+ metadata,
+ Column("PackageID", ForeignKey("Packages.ID", ondelete="CASCADE"), nullable=False),
+ Column(
+ "RelTypeID",
+ ForeignKey("RelationTypes.ID", ondelete="NO ACTION"),
+ nullable=False,
+ ),
+ Column("RelName", String(255), nullable=False),
+ Column("RelCondition", String(255)),
+ Column("RelArch", String(255)),
+ Index("RelationsPackageID", "PackageID"),
+ Index("RelationsRelName", "RelName"),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_general_ci",
)
# Track which sources a package has
PackageSources = Table(
- 'PackageSources', metadata,
- Column('PackageID', ForeignKey('Packages.ID', ondelete='CASCADE'), nullable=False),
- Column('Source', String(8000), nullable=False, server_default=text("'/dev/null'")),
- Column('SourceArch', String(255)),
- Index('SourcesPackageID', 'PackageID'),
- mysql_engine='InnoDB',
- mysql_charset='utf8mb4',
- mysql_collate='utf8mb4_general_ci',
+ "PackageSources",
+ metadata,
+ Column("PackageID", ForeignKey("Packages.ID", ondelete="CASCADE"), nullable=False),
+ Column("Source", String(8000), nullable=False, server_default=text("'/dev/null'")),
+ Column("SourceArch", String(255)),
+ Index("SourcesPackageID", "PackageID"),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_general_ci",
)
# Track votes for packages
PackageVotes = Table(
- 'PackageVotes', metadata,
- Column('UsersID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False),
- Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), nullable=False),
- Column('VoteTS', BIGINT(unsigned=True), nullable=False),
- Index('VoteUsersIDPackageID', 'UsersID', 'PackageBaseID', unique=True),
- Index('VotesPackageBaseID', 'PackageBaseID'),
- Index('VotesUsersID', 'UsersID'),
- mysql_engine='InnoDB',
+ "PackageVotes",
+ metadata,
+ Column("UsersID", ForeignKey("Users.ID", ondelete="CASCADE"), nullable=False),
+ Column(
+ "PackageBaseID",
+ ForeignKey("PackageBases.ID", ondelete="CASCADE"),
+ nullable=False,
+ ),
+ Column("VoteTS", BIGINT(unsigned=True), nullable=False),
+ Index("VoteUsersIDPackageID", "UsersID", "PackageBaseID", unique=True),
+ Index("VotesPackageBaseID", "PackageBaseID"),
+ Index("VotesUsersID", "UsersID"),
+ mysql_engine="InnoDB",
)
# Record comments for packages
PackageComments = Table(
- 'PackageComments', metadata,
- Column('ID', BIGINT(unsigned=True), primary_key=True),
- Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), nullable=False),
- Column('UsersID', ForeignKey('Users.ID', ondelete='SET NULL')),
- Column('Comments', Text, nullable=False),
- Column('RenderedComment', Text, nullable=False),
- Column('CommentTS', BIGINT(unsigned=True), nullable=False, server_default=text("0")),
- Column('EditedTS', BIGINT(unsigned=True)),
- Column('EditedUsersID', ForeignKey('Users.ID', ondelete='SET NULL')),
- Column('DelTS', BIGINT(unsigned=True)),
- Column('DelUsersID', ForeignKey('Users.ID', ondelete='CASCADE')),
- Column('PinnedTS', BIGINT(unsigned=True), nullable=False, server_default=text("0")),
- Index('CommentsPackageBaseID', 'PackageBaseID'),
- Index('CommentsUsersID', 'UsersID'),
- mysql_engine='InnoDB',
- mysql_charset='utf8mb4',
- mysql_collate='utf8mb4_general_ci',
+ "PackageComments",
+ metadata,
+ Column("ID", BIGINT(unsigned=True), primary_key=True),
+ Column(
+ "PackageBaseID",
+ ForeignKey("PackageBases.ID", ondelete="CASCADE"),
+ nullable=False,
+ ),
+ Column("UsersID", ForeignKey("Users.ID", ondelete="SET NULL")),
+ Column("Comments", Text, nullable=False),
+ Column("RenderedComment", Text, nullable=False),
+ Column(
+ "CommentTS", BIGINT(unsigned=True), nullable=False, server_default=text("0")
+ ),
+ Column("EditedTS", BIGINT(unsigned=True)),
+ Column("EditedUsersID", ForeignKey("Users.ID", ondelete="SET NULL")),
+ Column("DelTS", BIGINT(unsigned=True)),
+ Column("DelUsersID", ForeignKey("Users.ID", ondelete="CASCADE")),
+ Column("PinnedTS", BIGINT(unsigned=True), nullable=False, server_default=text("0")),
+ Index("CommentsPackageBaseID", "PackageBaseID"),
+ Index("CommentsUsersID", "UsersID"),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_general_ci",
)
# Package base co-maintainers
PackageComaintainers = Table(
- 'PackageComaintainers', metadata,
- Column('UsersID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False),
- Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), nullable=False),
- Column('Priority', INTEGER(unsigned=True), nullable=False),
- Index('ComaintainersPackageBaseID', 'PackageBaseID'),
- Index('ComaintainersUsersID', 'UsersID'),
- mysql_engine='InnoDB',
+ "PackageComaintainers",
+ metadata,
+ Column("UsersID", ForeignKey("Users.ID", ondelete="CASCADE"), nullable=False),
+ Column(
+ "PackageBaseID",
+ ForeignKey("PackageBases.ID", ondelete="CASCADE"),
+ nullable=False,
+ ),
+ Column("Priority", INTEGER(unsigned=True), nullable=False),
+ Index("ComaintainersPackageBaseID", "PackageBaseID"),
+ Index("ComaintainersUsersID", "UsersID"),
+ mysql_engine="InnoDB",
)
# Package base notifications
PackageNotifications = Table(
- 'PackageNotifications', metadata,
- Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), nullable=False),
- Column('UserID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False),
- Index('NotifyUserIDPkgID', 'UserID', 'PackageBaseID', unique=True),
- mysql_engine='InnoDB',
+ "PackageNotifications",
+ metadata,
+ Column(
+ "PackageBaseID",
+ ForeignKey("PackageBases.ID", ondelete="CASCADE"),
+ nullable=False,
+ ),
+ Column("UserID", ForeignKey("Users.ID", ondelete="CASCADE"), nullable=False),
+ Index("NotifyUserIDPkgID", "UserID", "PackageBaseID", unique=True),
+ mysql_engine="InnoDB",
)
# Package name blacklist
PackageBlacklist = Table(
- 'PackageBlacklist', metadata,
- Column('ID', INTEGER(unsigned=True), primary_key=True),
- Column('Name', String(64), nullable=False, unique=True),
- mysql_engine='InnoDB',
- mysql_charset='utf8mb4',
- mysql_collate='utf8mb4_general_ci',
+ "PackageBlacklist",
+ metadata,
+ Column("ID", INTEGER(unsigned=True), primary_key=True),
+ Column("Name", String(64), nullable=False, unique=True),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_general_ci",
)
# Providers in the official repositories
OfficialProviders = Table(
- 'OfficialProviders', metadata,
- Column('ID', INTEGER(unsigned=True), primary_key=True),
- Column('Name', String(64), nullable=False),
- Column('Repo', String(64), nullable=False),
- Column('Provides', String(64), nullable=False),
- Index('ProviderNameProvides', 'Name', 'Provides', unique=True),
- mysql_engine='InnoDB', mysql_charset='utf8mb4', mysql_collate='utf8mb4_bin',
+ "OfficialProviders",
+ metadata,
+ Column("ID", INTEGER(unsigned=True), primary_key=True),
+ Column("Name", String(64), nullable=False),
+ Column("Repo", String(64), nullable=False),
+ Column("Provides", String(64), nullable=False),
+ Index("ProviderNameProvides", "Name", "Provides", unique=True),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_bin",
)
# Define package request types
RequestTypes = Table(
- 'RequestTypes', metadata,
- Column('ID', TINYINT(unsigned=True), primary_key=True),
- Column('Name', String(32), nullable=False, server_default=text("''")),
- mysql_engine='InnoDB',
- mysql_charset='utf8mb4',
- mysql_collate='utf8mb4_general_ci',
+ "RequestTypes",
+ metadata,
+ Column("ID", TINYINT(unsigned=True), primary_key=True),
+ Column("Name", String(32), nullable=False, server_default=text("''")),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_general_ci",
)
# Package requests
PackageRequests = Table(
- 'PackageRequests', metadata,
- Column('ID', BIGINT(unsigned=True), primary_key=True),
- Column('ReqTypeID', ForeignKey('RequestTypes.ID', ondelete="NO ACTION"), nullable=False),
- Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='SET NULL')),
- Column('PackageBaseName', String(255), nullable=False),
- Column('MergeBaseName', String(255)),
- Column('UsersID', ForeignKey('Users.ID', ondelete='SET NULL')),
- Column('Comments', Text, nullable=False),
- Column('ClosureComment', Text, nullable=False),
- Column('RequestTS', BIGINT(unsigned=True), nullable=False, server_default=text("0")),
- Column('ClosedTS', BIGINT(unsigned=True)),
- Column('ClosedUID', ForeignKey('Users.ID', ondelete='SET NULL')),
- Column('Status', TINYINT(unsigned=True), nullable=False, server_default=text("0")),
- Index('RequestsPackageBaseID', 'PackageBaseID'),
- Index('RequestsUsersID', 'UsersID'),
- mysql_engine='InnoDB',
- mysql_charset='utf8mb4',
- mysql_collate='utf8mb4_general_ci',
+ "PackageRequests",
+ metadata,
+ Column("ID", BIGINT(unsigned=True), primary_key=True),
+ Column(
+ "ReqTypeID", ForeignKey("RequestTypes.ID", ondelete="NO ACTION"), nullable=False
+ ),
+ Column("PackageBaseID", ForeignKey("PackageBases.ID", ondelete="SET NULL")),
+ Column("PackageBaseName", String(255), nullable=False),
+ Column("MergeBaseName", String(255)),
+ Column("UsersID", ForeignKey("Users.ID", ondelete="SET NULL")),
+ Column("Comments", Text, nullable=False),
+ Column("ClosureComment", Text, nullable=False),
+ Column(
+ "RequestTS", BIGINT(unsigned=True), nullable=False, server_default=text("0")
+ ),
+ Column("ClosedTS", BIGINT(unsigned=True)),
+ Column("ClosedUID", ForeignKey("Users.ID", ondelete="SET NULL")),
+ Column("Status", TINYINT(unsigned=True), nullable=False, server_default=text("0")),
+ Index("RequestsPackageBaseID", "PackageBaseID"),
+ Index("RequestsUsersID", "UsersID"),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_general_ci",
)
# Vote information
TU_VoteInfo = Table(
- 'TU_VoteInfo', metadata,
- Column('ID', INTEGER(unsigned=True), primary_key=True),
- Column('Agenda', Text, nullable=False),
- Column('User', String(32), nullable=False),
- Column('Submitted', BIGINT(unsigned=True), nullable=False),
- Column('End', BIGINT(unsigned=True), nullable=False),
- Column('Quorum',
- DECIMAL(2, 2, unsigned=True)
- if db_backend == "mysql" else String(5),
- nullable=False),
- Column('SubmitterID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False),
- Column('Yes', INTEGER(unsigned=True), nullable=False, server_default=text("'0'")),
- Column('No', INTEGER(unsigned=True), nullable=False, server_default=text("'0'")),
- Column('Abstain', INTEGER(unsigned=True), nullable=False, server_default=text("'0'")),
- Column('ActiveTUs', INTEGER(unsigned=True), nullable=False, server_default=text("'0'")),
- mysql_engine='InnoDB',
- mysql_charset='utf8mb4',
- mysql_collate='utf8mb4_general_ci',
+ "TU_VoteInfo",
+ metadata,
+ Column("ID", INTEGER(unsigned=True), primary_key=True),
+ Column("Agenda", Text, nullable=False),
+ Column("User", String(32), nullable=False),
+ Column("Submitted", BIGINT(unsigned=True), nullable=False),
+ Column("End", BIGINT(unsigned=True), nullable=False),
+ Column(
+ "Quorum",
+ DECIMAL(2, 2, unsigned=True) if db_backend == "mysql" else String(5),
+ nullable=False,
+ ),
+ Column("SubmitterID", ForeignKey("Users.ID", ondelete="CASCADE"), nullable=False),
+ Column("Yes", INTEGER(unsigned=True), nullable=False, server_default=text("'0'")),
+ Column("No", INTEGER(unsigned=True), nullable=False, server_default=text("'0'")),
+ Column(
+ "Abstain", INTEGER(unsigned=True), nullable=False, server_default=text("'0'")
+ ),
+ Column(
+ "ActiveTUs", INTEGER(unsigned=True), nullable=False, server_default=text("'0'")
+ ),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_general_ci",
)
# Individual vote records
TU_Votes = Table(
- 'TU_Votes', metadata,
- Column('VoteID', ForeignKey('TU_VoteInfo.ID', ondelete='CASCADE'), nullable=False),
- Column('UserID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False),
- mysql_engine='InnoDB',
+ "TU_Votes",
+ metadata,
+ Column("VoteID", ForeignKey("TU_VoteInfo.ID", ondelete="CASCADE"), nullable=False),
+ Column("UserID", ForeignKey("Users.ID", ondelete="CASCADE"), nullable=False),
+ mysql_engine="InnoDB",
)
# Malicious user banning
Bans = Table(
- 'Bans', metadata,
- Column('IPAddress', String(45), primary_key=True),
- Column('BanTS', TIMESTAMP, nullable=False),
- mysql_engine='InnoDB',
- mysql_charset='utf8mb4',
- mysql_collate='utf8mb4_general_ci',
+ "Bans",
+ metadata,
+ Column("IPAddress", String(45), primary_key=True),
+ Column("BanTS", TIMESTAMP, nullable=False),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_general_ci",
)
# Terms and Conditions
Terms = Table(
- 'Terms', metadata,
- Column('ID', INTEGER(unsigned=True), primary_key=True),
- Column('Description', String(255), nullable=False),
- Column('URL', String(8000), nullable=False),
- Column('Revision', INTEGER(unsigned=True), nullable=False, server_default=text("1")),
- mysql_engine='InnoDB',
- mysql_charset='utf8mb4',
- mysql_collate='utf8mb4_general_ci',
+ "Terms",
+ metadata,
+ Column("ID", INTEGER(unsigned=True), primary_key=True),
+ Column("Description", String(255), nullable=False),
+ Column("URL", String(8000), nullable=False),
+ Column(
+ "Revision", INTEGER(unsigned=True), nullable=False, server_default=text("1")
+ ),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_general_ci",
)
# Terms and Conditions accepted by users
AcceptedTerms = Table(
- 'AcceptedTerms', metadata,
- Column('UsersID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False),
- Column('TermsID', ForeignKey('Terms.ID', ondelete='CASCADE'), nullable=False),
- Column('Revision', INTEGER(unsigned=True), nullable=False, server_default=text("0")),
- mysql_engine='InnoDB',
+ "AcceptedTerms",
+ metadata,
+ Column("UsersID", ForeignKey("Users.ID", ondelete="CASCADE"), nullable=False),
+ Column("TermsID", ForeignKey("Terms.ID", ondelete="CASCADE"), nullable=False),
+ Column(
+ "Revision", INTEGER(unsigned=True), nullable=False, server_default=text("0")
+ ),
+ mysql_engine="InnoDB",
)
# Rate limits for API
ApiRateLimit = Table(
- 'ApiRateLimit', metadata,
- Column('IP', String(45), primary_key=True, unique=True, default=str()),
- Column('Requests', INTEGER(11), nullable=False),
- Column('WindowStart', BIGINT(20), nullable=False),
- Index('ApiRateLimitWindowStart', 'WindowStart'),
- mysql_engine='InnoDB',
- mysql_charset='utf8mb4',
- mysql_collate='utf8mb4_general_ci',
+ "ApiRateLimit",
+ metadata,
+ Column("IP", String(45), primary_key=True, unique=True, default=str()),
+ Column("Requests", INTEGER(11), nullable=False),
+ Column("WindowStart", BIGINT(20), nullable=False),
+ Index("ApiRateLimitWindowStart", "WindowStart"),
+ mysql_engine="InnoDB",
+ mysql_charset="utf8mb4",
+ mysql_collate="utf8mb4_general_ci",
)
diff --git a/aurweb/scripts/adduser.py b/aurweb/scripts/adduser.py
index 4cc059d1..cf933c71 100644
--- a/aurweb/scripts/adduser.py
+++ b/aurweb/scripts/adduser.py
@@ -11,7 +11,6 @@ import sys
import traceback
import aurweb.models.account_type as at
-
from aurweb import db
from aurweb.models.account_type import AccountType
from aurweb.models.ssh_pub_key import SSHPubKey, get_fingerprint
@@ -30,8 +29,9 @@ def parse_args():
parser.add_argument("--ssh-pubkey", help="SSH PubKey")
choices = at.ACCOUNT_TYPE_NAME.values()
- parser.add_argument("-t", "--type", help="Account Type",
- choices=choices, default=at.USER)
+ parser.add_argument(
+ "-t", "--type", help="Account Type", choices=choices, default=at.USER
+ )
return parser.parse_args()
@@ -40,25 +40,29 @@ def main():
args = parse_args()
db.get_engine()
- type = db.query(AccountType,
- AccountType.AccountType == args.type).first()
+ type = db.query(AccountType, AccountType.AccountType == args.type).first()
with db.begin():
- user = db.create(User, Username=args.username,
- Email=args.email, Passwd=args.password,
- RealName=args.realname, IRCNick=args.ircnick,
- PGPKey=args.pgp_key, AccountType=type)
+ user = db.create(
+ User,
+ Username=args.username,
+ Email=args.email,
+ Passwd=args.password,
+ RealName=args.realname,
+ IRCNick=args.ircnick,
+ PGPKey=args.pgp_key,
+ AccountType=type,
+ )
if args.ssh_pubkey:
pubkey = args.ssh_pubkey.strip()
# Remove host from the pubkey if it's there.
- pubkey = ' '.join(pubkey.split(' ')[:2])
+ pubkey = " ".join(pubkey.split(" ")[:2])
with db.begin():
- db.create(SSHPubKey,
- User=user,
- PubKey=pubkey,
- Fingerprint=get_fingerprint(pubkey))
+ db.create(
+ SSHPubKey, User=user, PubKey=pubkey, Fingerprint=get_fingerprint(pubkey)
+ )
print(user.json())
return 0
diff --git a/aurweb/scripts/aurblup.py b/aurweb/scripts/aurblup.py
index 9c9059ec..340d1ccd 100755
--- a/aurweb/scripts/aurblup.py
+++ b/aurweb/scripts/aurblup.py
@@ -3,11 +3,9 @@
import re
import pyalpm
-
from sqlalchemy import and_
import aurweb.config
-
from aurweb import db, util
from aurweb.models import OfficialProvider
@@ -18,8 +16,8 @@ def _main(force: bool = False):
repomap = dict()
db_path = aurweb.config.get("aurblup", "db-path")
- sync_dbs = aurweb.config.get('aurblup', 'sync-dbs').split(' ')
- server = aurweb.config.get('aurblup', 'server')
+ sync_dbs = aurweb.config.get("aurblup", "sync-dbs").split(" ")
+ server = aurweb.config.get("aurblup", "server")
h = pyalpm.Handle("/", db_path)
for sync_db in sync_dbs:
@@ -35,28 +33,35 @@ def _main(force: bool = False):
providers.add((pkg.name, pkg.name))
repomap[(pkg.name, pkg.name)] = repo.name
for provision in pkg.provides:
- provisionname = re.sub(r'(<|=|>).*', '', provision)
+ provisionname = re.sub(r"(<|=|>).*", "", provision)
providers.add((pkg.name, provisionname))
repomap[(pkg.name, provisionname)] = repo.name
with db.begin():
old_providers = set(
- db.query(OfficialProvider).with_entities(
+ db.query(OfficialProvider)
+ .with_entities(
OfficialProvider.Name.label("Name"),
- OfficialProvider.Provides.label("Provides")
- ).distinct().order_by("Name").all()
+ OfficialProvider.Provides.label("Provides"),
+ )
+ .distinct()
+ .order_by("Name")
+ .all()
)
for name, provides in old_providers.difference(providers):
- db.delete_all(db.query(OfficialProvider).filter(
- and_(OfficialProvider.Name == name,
- OfficialProvider.Provides == provides)
- ))
+ db.delete_all(
+ db.query(OfficialProvider).filter(
+ and_(
+ OfficialProvider.Name == name,
+ OfficialProvider.Provides == provides,
+ )
+ )
+ )
for name, provides in providers.difference(old_providers):
repo = repomap.get((name, provides))
- db.create(OfficialProvider, Name=name,
- Repo=repo, Provides=provides)
+ db.create(OfficialProvider, Name=name, Repo=repo, Provides=provides)
def main(force: bool = False):
@@ -64,5 +69,5 @@ def main(force: bool = False):
_main(force)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/aurweb/scripts/config.py b/aurweb/scripts/config.py
index e7c91dd1..1d90f525 100644
--- a/aurweb/scripts/config.py
+++ b/aurweb/scripts/config.py
@@ -50,12 +50,12 @@ def parse_args():
actions = ["get", "set", "unset"]
parser = argparse.ArgumentParser(
description="aurweb configuration tool",
- formatter_class=lambda prog: fmt_cls(prog=prog, max_help_position=80))
+ formatter_class=lambda prog: fmt_cls(prog=prog, max_help_position=80),
+ )
parser.add_argument("action", choices=actions, help="script action")
parser.add_argument("section", help="config section")
parser.add_argument("option", help="config option")
- parser.add_argument("value", nargs="?", default=0,
- help="config option value")
+ parser.add_argument("value", nargs="?", default=0, help="config option value")
return parser.parse_args()
diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py
index 888e346c..7ca171ab 100755
--- a/aurweb/scripts/mkpkglists.py
+++ b/aurweb/scripts/mkpkglists.py
@@ -25,16 +25,13 @@ import os
import shutil
import sys
import tempfile
-
from collections import defaultdict
from typing import Any
import orjson
-
from sqlalchemy import literal, orm
import aurweb.config
-
from aurweb import db, filters, logging, models, util
from aurweb.benchmark import Benchmark
from aurweb.models import Package, PackageBase, User
@@ -90,65 +87,68 @@ def get_extended_dict(query: orm.Query):
def get_extended_fields():
subqueries = [
# PackageDependency
- db.query(
- models.PackageDependency
- ).join(models.DependencyType).with_entities(
+ db.query(models.PackageDependency)
+ .join(models.DependencyType)
+ .with_entities(
models.PackageDependency.PackageID.label("ID"),
models.DependencyType.Name.label("Type"),
models.PackageDependency.DepName.label("Name"),
- models.PackageDependency.DepCondition.label("Cond")
- ).distinct().order_by("Name"),
-
+ models.PackageDependency.DepCondition.label("Cond"),
+ )
+ .distinct()
+ .order_by("Name"),
# PackageRelation
- db.query(
- models.PackageRelation
- ).join(models.RelationType).with_entities(
+ db.query(models.PackageRelation)
+ .join(models.RelationType)
+ .with_entities(
models.PackageRelation.PackageID.label("ID"),
models.RelationType.Name.label("Type"),
models.PackageRelation.RelName.label("Name"),
- models.PackageRelation.RelCondition.label("Cond")
- ).distinct().order_by("Name"),
-
+ models.PackageRelation.RelCondition.label("Cond"),
+ )
+ .distinct()
+ .order_by("Name"),
# Groups
- db.query(models.PackageGroup).join(
- models.Group,
- models.PackageGroup.GroupID == models.Group.ID
- ).with_entities(
+ db.query(models.PackageGroup)
+ .join(models.Group, models.PackageGroup.GroupID == models.Group.ID)
+ .with_entities(
models.PackageGroup.PackageID.label("ID"),
literal("Groups").label("Type"),
models.Group.Name.label("Name"),
- literal(str()).label("Cond")
- ).distinct().order_by("Name"),
-
+ literal(str()).label("Cond"),
+ )
+ .distinct()
+ .order_by("Name"),
# Licenses
- db.query(models.PackageLicense).join(
- models.License,
- models.PackageLicense.LicenseID == models.License.ID
- ).with_entities(
+ db.query(models.PackageLicense)
+ .join(models.License, models.PackageLicense.LicenseID == models.License.ID)
+ .with_entities(
models.PackageLicense.PackageID.label("ID"),
literal("License").label("Type"),
models.License.Name.label("Name"),
- literal(str()).label("Cond")
- ).distinct().order_by("Name"),
-
+ literal(str()).label("Cond"),
+ )
+ .distinct()
+ .order_by("Name"),
# Keywords
- db.query(models.PackageKeyword).join(
- models.Package,
- Package.PackageBaseID == models.PackageKeyword.PackageBaseID
- ).with_entities(
+ db.query(models.PackageKeyword)
+ .join(
+ models.Package, Package.PackageBaseID == models.PackageKeyword.PackageBaseID
+ )
+ .with_entities(
models.Package.ID.label("ID"),
literal("Keywords").label("Type"),
models.PackageKeyword.Keyword.label("Name"),
- literal(str()).label("Cond")
- ).distinct().order_by("Name")
+ literal(str()).label("Cond"),
+ )
+ .distinct()
+ .order_by("Name"),
]
query = subqueries[0].union_all(*subqueries[1:])
return get_extended_dict(query)
-EXTENDED_FIELD_HANDLERS = {
- "--extended": get_extended_fields
-}
+EXTENDED_FIELD_HANDLERS = {"--extended": get_extended_fields}
def as_dict(package: Package) -> dict[str, Any]:
@@ -181,37 +181,38 @@ def _main():
archivedir = aurweb.config.get("mkpkglists", "archivedir")
os.makedirs(archivedir, exist_ok=True)
- PACKAGES = aurweb.config.get('mkpkglists', 'packagesfile')
- META = aurweb.config.get('mkpkglists', 'packagesmetafile')
- META_EXT = aurweb.config.get('mkpkglists', 'packagesmetaextfile')
- PKGBASE = aurweb.config.get('mkpkglists', 'pkgbasefile')
- USERS = aurweb.config.get('mkpkglists', 'userfile')
+ PACKAGES = aurweb.config.get("mkpkglists", "packagesfile")
+ META = aurweb.config.get("mkpkglists", "packagesmetafile")
+ META_EXT = aurweb.config.get("mkpkglists", "packagesmetaextfile")
+ PKGBASE = aurweb.config.get("mkpkglists", "pkgbasefile")
+ USERS = aurweb.config.get("mkpkglists", "userfile")
bench = Benchmark()
logger.info("Started re-creating archives, wait a while...")
- query = db.query(Package).join(
- PackageBase,
- PackageBase.ID == Package.PackageBaseID
- ).join(
- User,
- PackageBase.MaintainerUID == User.ID,
- isouter=True
- ).filter(PackageBase.PackagerUID.isnot(None)).with_entities(
- Package.ID,
- Package.Name,
- PackageBase.ID.label("PackageBaseID"),
- PackageBase.Name.label("PackageBase"),
- Package.Version,
- Package.Description,
- Package.URL,
- PackageBase.NumVotes,
- PackageBase.Popularity,
- PackageBase.OutOfDateTS.label("OutOfDate"),
- User.Username.label("Maintainer"),
- PackageBase.SubmittedTS.label("FirstSubmitted"),
- PackageBase.ModifiedTS.label("LastModified")
- ).distinct().order_by("Name")
+ query = (
+ db.query(Package)
+ .join(PackageBase, PackageBase.ID == Package.PackageBaseID)
+ .join(User, PackageBase.MaintainerUID == User.ID, isouter=True)
+ .filter(PackageBase.PackagerUID.isnot(None))
+ .with_entities(
+ Package.ID,
+ Package.Name,
+ PackageBase.ID.label("PackageBaseID"),
+ PackageBase.Name.label("PackageBase"),
+ Package.Version,
+ Package.Description,
+ Package.URL,
+ PackageBase.NumVotes,
+ PackageBase.Popularity,
+ PackageBase.OutOfDateTS.label("OutOfDate"),
+ User.Username.label("Maintainer"),
+ PackageBase.SubmittedTS.label("FirstSubmitted"),
+ PackageBase.ModifiedTS.label("LastModified"),
+ )
+ .distinct()
+ .order_by("Name")
+ )
# Produce packages-meta-v1.json.gz
output = list()
@@ -252,7 +253,7 @@ def _main():
# We stream out package json objects line per line, so
# we also need to include the ',' character at the end
# of package lines (excluding the last package).
- suffix = b",\n" if i < n else b'\n'
+ suffix = b",\n" if i < n else b"\n"
# Write out to packagesmetafile
output.append(item)
@@ -273,8 +274,7 @@ def _main():
util.apply_all(gzips.values(), lambda gz: gz.close())
# Produce pkgbase.gz
- query = db.query(PackageBase.Name).filter(
- PackageBase.PackagerUID.isnot(None)).all()
+ query = db.query(PackageBase.Name).filter(PackageBase.PackagerUID.isnot(None)).all()
tmp_pkgbase = os.path.join(tmpdir, os.path.basename(PKGBASE))
with gzip.open(tmp_pkgbase, "wt") as f:
f.writelines([f"{base.Name}\n" for i, base in enumerate(query)])
@@ -317,5 +317,5 @@ def main():
_main()
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py
index 6afa65ae..f19438bb 100755
--- a/aurweb/scripts/notify.py
+++ b/aurweb/scripts/notify.py
@@ -13,7 +13,6 @@ import aurweb.config
import aurweb.db
import aurweb.filters
import aurweb.l10n
-
from aurweb import db, logging
from aurweb.models import PackageBase, User
from aurweb.models.package_comaintainer import PackageComaintainer
@@ -25,15 +24,15 @@ from aurweb.models.tu_vote import TUVote
logger = logging.get_logger(__name__)
-aur_location = aurweb.config.get('options', 'aur_location')
+aur_location = aurweb.config.get("options", "aur_location")
def headers_msgid(thread_id):
- return {'Message-ID': thread_id}
+ return {"Message-ID": thread_id}
def headers_reply(thread_id):
- return {'In-Reply-To': thread_id, 'References': thread_id}
+ return {"In-Reply-To": thread_id, "References": thread_id}
class Notification:
@@ -47,67 +46,64 @@ class Notification:
return []
def get_body_fmt(self, lang):
- body = ''
+ body = ""
for line in self.get_body(lang).splitlines():
- if line == '--':
- body += '--\n'
+ if line == "--":
+ body += "--\n"
continue
- body += textwrap.fill(line, break_long_words=False) + '\n'
+ body += textwrap.fill(line, break_long_words=False) + "\n"
for i, ref in enumerate(self.get_refs()):
- body += '\n' + '[%d] %s' % (i + 1, ref)
+ body += "\n" + "[%d] %s" % (i + 1, ref)
return body.rstrip()
def _send(self) -> None:
- sendmail = aurweb.config.get('notifications', 'sendmail')
- sender = aurweb.config.get('notifications', 'sender')
- reply_to = aurweb.config.get('notifications', 'reply-to')
+ sendmail = aurweb.config.get("notifications", "sendmail")
+ sender = aurweb.config.get("notifications", "sender")
+ reply_to = aurweb.config.get("notifications", "reply-to")
reason = self.__class__.__name__
- if reason.endswith('Notification'):
- reason = reason[:-len('Notification')]
+ if reason.endswith("Notification"):
+ reason = reason[: -len("Notification")]
for recipient in self.get_recipients():
to, lang = recipient
- msg = email.mime.text.MIMEText(self.get_body_fmt(lang),
- 'plain', 'utf-8')
- msg['Subject'] = self.get_subject(lang)
- msg['From'] = sender
- msg['Reply-to'] = reply_to
- msg['To'] = to
+ msg = email.mime.text.MIMEText(self.get_body_fmt(lang), "plain", "utf-8")
+ msg["Subject"] = self.get_subject(lang)
+ msg["From"] = sender
+ msg["Reply-to"] = reply_to
+ msg["To"] = to
if self.get_cc():
- msg['Cc'] = str.join(', ', self.get_cc())
- msg['X-AUR-Reason'] = reason
- msg['Date'] = email.utils.formatdate(localtime=True)
+ msg["Cc"] = str.join(", ", self.get_cc())
+ msg["X-AUR-Reason"] = reason
+ msg["Date"] = email.utils.formatdate(localtime=True)
for key, value in self.get_headers().items():
msg[key] = value
- sendmail = aurweb.config.get('notifications', 'sendmail')
+ sendmail = aurweb.config.get("notifications", "sendmail")
if sendmail:
# send email using the sendmail binary specified in the
# configuration file
- p = subprocess.Popen([sendmail, '-t', '-oi'],
- stdin=subprocess.PIPE)
+ p = subprocess.Popen([sendmail, "-t", "-oi"], stdin=subprocess.PIPE)
p.communicate(msg.as_bytes())
else:
# send email using smtplib; no local MTA required
- server_addr = aurweb.config.get('notifications', 'smtp-server')
- server_port = aurweb.config.getint('notifications',
- 'smtp-port')
- use_ssl = aurweb.config.getboolean('notifications',
- 'smtp-use-ssl')
- use_starttls = aurweb.config.getboolean('notifications',
- 'smtp-use-starttls')
- user = aurweb.config.get('notifications', 'smtp-user')
- passwd = aurweb.config.get('notifications', 'smtp-password')
+ server_addr = aurweb.config.get("notifications", "smtp-server")
+ server_port = aurweb.config.getint("notifications", "smtp-port")
+ use_ssl = aurweb.config.getboolean("notifications", "smtp-use-ssl")
+ use_starttls = aurweb.config.getboolean(
+ "notifications", "smtp-use-starttls"
+ )
+ user = aurweb.config.get("notifications", "smtp-user")
+ passwd = aurweb.config.get("notifications", "smtp-password")
classes = {
False: smtplib.SMTP,
True: smtplib.SMTP_SSL,
}
- smtp_timeout = aurweb.config.getint("notifications",
- "smtp-timeout")
- server = classes[use_ssl](server_addr, server_port,
- timeout=smtp_timeout)
+ smtp_timeout = aurweb.config.getint("notifications", "smtp-timeout")
+ server = classes[use_ssl](
+ server_addr, server_port, timeout=smtp_timeout
+ )
if use_starttls:
server.ehlo()
@@ -126,23 +122,29 @@ class Notification:
try:
self._send()
except OSError as exc:
- logger.error("Unable to emit notification due to an "
- "OSError (precise exception following).")
+ logger.error(
+ "Unable to emit notification due to an "
+ "OSError (precise exception following)."
+ )
logger.error(str(exc))
class ResetKeyNotification(Notification):
def __init__(self, uid):
- user = db.query(User).filter(
- and_(User.ID == uid, User.Suspended == 0)
- ).with_entities(
- User.Username,
- User.Email,
- User.BackupEmail,
- User.LangPreference,
- User.ResetKey
- ).order_by(User.Username.asc()).first()
+ user = (
+ db.query(User)
+ .filter(and_(User.ID == uid, User.Suspended == 0))
+ .with_entities(
+ User.Username,
+ User.Email,
+ User.BackupEmail,
+ User.LangPreference,
+ User.ResetKey,
+ )
+ .order_by(User.Username.asc())
+ .first()
+ )
self._username = user.Username
self._to = user.Email
@@ -159,55 +161,66 @@ class ResetKeyNotification(Notification):
return [(self._to, self._lang)]
def get_subject(self, lang):
- return aurweb.l10n.translator.translate('AUR Password Reset', lang)
+ return aurweb.l10n.translator.translate("AUR Password Reset", lang)
def get_body(self, lang):
return aurweb.l10n.translator.translate(
- 'A password reset request was submitted for the account '
- '{user} associated with your email address. If you wish to '
- 'reset your password follow the link [1] below, otherwise '
- 'ignore this message and nothing will happen.',
- lang).format(user=self._username)
+ "A password reset request was submitted for the account "
+ "{user} associated with your email address. If you wish to "
+ "reset your password follow the link [1] below, otherwise "
+ "ignore this message and nothing will happen.",
+ lang,
+ ).format(user=self._username)
def get_refs(self):
- return (aur_location + '/passreset/?resetkey=' + self._resetkey,)
+ return (aur_location + "/passreset/?resetkey=" + self._resetkey,)
class WelcomeNotification(ResetKeyNotification):
def get_subject(self, lang):
return aurweb.l10n.translator.translate(
- 'Welcome to the Arch User Repository',
- lang)
+ "Welcome to the Arch User Repository", lang
+ )
def get_body(self, lang):
return aurweb.l10n.translator.translate(
- 'Welcome to the Arch User Repository! In order to set an '
- 'initial password for your new account, please click the '
- 'link [1] below. If the link does not work, try copying and '
- 'pasting it into your browser.', lang)
+ "Welcome to the Arch User Repository! In order to set an "
+ "initial password for your new account, please click the "
+ "link [1] below. If the link does not work, try copying and "
+ "pasting it into your browser.",
+ lang,
+ )
class CommentNotification(Notification):
def __init__(self, uid, pkgbase_id, comment_id):
- self._user = db.query(User.Username).filter(
- User.ID == uid).first().Username
- self._pkgbase = db.query(PackageBase.Name).filter(
- PackageBase.ID == pkgbase_id).first().Name
+ self._user = db.query(User.Username).filter(User.ID == uid).first().Username
+ self._pkgbase = (
+ db.query(PackageBase.Name).filter(PackageBase.ID == pkgbase_id).first().Name
+ )
- query = db.query(User).join(PackageNotification).filter(
- and_(User.CommentNotify == 1,
- PackageNotification.UserID != uid,
- PackageNotification.PackageBaseID == pkgbase_id,
- User.Suspended == 0)
- ).with_entities(
- User.Email,
- User.LangPreference
- ).distinct()
+ query = (
+ db.query(User)
+ .join(PackageNotification)
+ .filter(
+ and_(
+ User.CommentNotify == 1,
+ PackageNotification.UserID != uid,
+ PackageNotification.PackageBaseID == pkgbase_id,
+ User.Suspended == 0,
+ )
+ )
+ .with_entities(User.Email, User.LangPreference)
+ .distinct()
+ )
self._recipients = [(u.Email, u.LangPreference) for u in query]
- pkgcomment = db.query(PackageComment.Comments).filter(
- PackageComment.ID == comment_id).first()
+ pkgcomment = (
+ db.query(PackageComment.Comments)
+ .filter(PackageComment.ID == comment_id)
+ .first()
+ )
self._text = pkgcomment.Comments
super().__init__()
@@ -217,49 +230,56 @@ class CommentNotification(Notification):
def get_subject(self, lang):
return aurweb.l10n.translator.translate(
- 'AUR Comment for {pkgbase}',
- lang).format(pkgbase=self._pkgbase)
+ "AUR Comment for {pkgbase}", lang
+ ).format(pkgbase=self._pkgbase)
def get_body(self, lang):
body = aurweb.l10n.translator.translate(
- '{user} [1] added the following comment to {pkgbase} [2]:',
- lang).format(user=self._user, pkgbase=self._pkgbase)
- body += '\n\n' + self._text + '\n\n--\n'
- dnlabel = aurweb.l10n.translator.translate(
- 'Disable notifications', lang)
+ "{user} [1] added the following comment to {pkgbase} [2]:", lang
+ ).format(user=self._user, pkgbase=self._pkgbase)
+ body += "\n\n" + self._text + "\n\n--\n"
+ dnlabel = aurweb.l10n.translator.translate("Disable notifications", lang)
body += aurweb.l10n.translator.translate(
- 'If you no longer wish to receive notifications about this '
- 'package, please go to the package page [2] and select '
- '"{label}".', lang).format(label=dnlabel)
+ "If you no longer wish to receive notifications about this "
+ "package, please go to the package page [2] and select "
+ '"{label}".',
+ lang,
+ ).format(label=dnlabel)
return body
def get_refs(self):
- return (aur_location + '/account/' + self._user + '/',
- aur_location + '/pkgbase/' + self._pkgbase + '/')
+ return (
+ aur_location + "/account/" + self._user + "/",
+ aur_location + "/pkgbase/" + self._pkgbase + "/",
+ )
def get_headers(self):
- thread_id = ''
+ thread_id = ""
return headers_reply(thread_id)
class UpdateNotification(Notification):
def __init__(self, uid, pkgbase_id):
- self._user = db.query(User.Username).filter(
- User.ID == uid).first().Username
- self._pkgbase = db.query(PackageBase.Name).filter(
- PackageBase.ID == pkgbase_id).first().Name
+ self._user = db.query(User.Username).filter(User.ID == uid).first().Username
+ self._pkgbase = (
+ db.query(PackageBase.Name).filter(PackageBase.ID == pkgbase_id).first().Name
+ )
- query = db.query(User).join(PackageNotification).filter(
- and_(User.UpdateNotify == 1,
- PackageNotification.UserID != uid,
- PackageNotification.PackageBaseID == pkgbase_id,
- User.Suspended == 0)
- ).with_entities(
- User.Email,
- User.LangPreference
- ).distinct()
+ query = (
+ db.query(User)
+ .join(PackageNotification)
+ .filter(
+ and_(
+ User.UpdateNotify == 1,
+ PackageNotification.UserID != uid,
+ PackageNotification.PackageBaseID == pkgbase_id,
+ User.Suspended == 0,
+ )
+ )
+ .with_entities(User.Email, User.LangPreference)
+ .distinct()
+ )
self._recipients = [(u.Email, u.LangPreference) for u in query]
super().__init__()
@@ -269,55 +289,63 @@ class UpdateNotification(Notification):
def get_subject(self, lang):
return aurweb.l10n.translator.translate(
- 'AUR Package Update: {pkgbase}',
- lang).format(pkgbase=self._pkgbase)
+ "AUR Package Update: {pkgbase}", lang
+ ).format(pkgbase=self._pkgbase)
def get_body(self, lang):
body = aurweb.l10n.translator.translate(
- '{user} [1] pushed a new commit to {pkgbase} [2].',
- lang).format(user=self._user, pkgbase=self._pkgbase)
- body += '\n\n--\n'
- dnlabel = aurweb.l10n.translator.translate(
- 'Disable notifications', lang)
+ "{user} [1] pushed a new commit to {pkgbase} [2].", lang
+ ).format(user=self._user, pkgbase=self._pkgbase)
+ body += "\n\n--\n"
+ dnlabel = aurweb.l10n.translator.translate("Disable notifications", lang)
body += aurweb.l10n.translator.translate(
- 'If you no longer wish to receive notifications about this '
- 'package, please go to the package page [2] and select '
- '"{label}".', lang).format(label=dnlabel)
+ "If you no longer wish to receive notifications about this "
+ "package, please go to the package page [2] and select "
+ '"{label}".',
+ lang,
+ ).format(label=dnlabel)
return body
def get_refs(self):
- return (aur_location + '/account/' + self._user + '/',
- aur_location + '/pkgbase/' + self._pkgbase + '/')
+ return (
+ aur_location + "/account/" + self._user + "/",
+ aur_location + "/pkgbase/" + self._pkgbase + "/",
+ )
def get_headers(self):
- thread_id = ''
+ thread_id = ""
return headers_reply(thread_id)
class FlagNotification(Notification):
def __init__(self, uid, pkgbase_id):
- self._user = db.query(User.Username).filter(
- User.ID == uid).first().Username
- self._pkgbase = db.query(PackageBase.Name).filter(
- PackageBase.ID == pkgbase_id).first().Name
+ self._user = db.query(User.Username).filter(User.ID == uid).first().Username
+ self._pkgbase = (
+ db.query(PackageBase.Name).filter(PackageBase.ID == pkgbase_id).first().Name
+ )
- query = db.query(User).join(PackageComaintainer, isouter=True).join(
- PackageBase,
- or_(PackageBase.MaintainerUID == User.ID,
- PackageBase.ID == PackageComaintainer.PackageBaseID)
- ).filter(
- and_(PackageBase.ID == pkgbase_id,
- User.Suspended == 0)
- ).with_entities(
- User.Email,
- User.LangPreference
- ).distinct()
+ query = (
+ db.query(User)
+ .join(PackageComaintainer, isouter=True)
+ .join(
+ PackageBase,
+ or_(
+ PackageBase.MaintainerUID == User.ID,
+ PackageBase.ID == PackageComaintainer.PackageBaseID,
+ ),
+ )
+ .filter(and_(PackageBase.ID == pkgbase_id, User.Suspended == 0))
+ .with_entities(User.Email, User.LangPreference)
+ .distinct()
+ )
self._recipients = [(u.Email, u.LangPreference) for u in query]
- pkgbase = db.query(PackageBase.FlaggerComment).filter(
- PackageBase.ID == pkgbase_id).first()
+ pkgbase = (
+ db.query(PackageBase.FlaggerComment)
+ .filter(PackageBase.ID == pkgbase_id)
+ .first()
+ )
self._text = pkgbase.FlaggerComment
super().__init__()
@@ -327,43 +355,53 @@ class FlagNotification(Notification):
def get_subject(self, lang):
return aurweb.l10n.translator.translate(
- 'AUR Out-of-date Notification for {pkgbase}',
- lang).format(pkgbase=self._pkgbase)
+ "AUR Out-of-date Notification for {pkgbase}", lang
+ ).format(pkgbase=self._pkgbase)
def get_body(self, lang):
body = aurweb.l10n.translator.translate(
- 'Your package {pkgbase} [1] has been flagged out-of-date by '
- '{user} [2]:', lang).format(pkgbase=self._pkgbase,
- user=self._user)
- body += '\n\n' + self._text
+ "Your package {pkgbase} [1] has been flagged out-of-date by " "{user} [2]:",
+ lang,
+ ).format(pkgbase=self._pkgbase, user=self._user)
+ body += "\n\n" + self._text
return body
def get_refs(self):
- return (aur_location + '/pkgbase/' + self._pkgbase + '/',
- aur_location + '/account/' + self._user + '/')
+ return (
+ aur_location + "/pkgbase/" + self._pkgbase + "/",
+ aur_location + "/account/" + self._user + "/",
+ )
class OwnershipEventNotification(Notification):
def __init__(self, uid, pkgbase_id):
- self._user = db.query(User.Username).filter(
- User.ID == uid).first().Username
- self._pkgbase = db.query(PackageBase.Name).filter(
- PackageBase.ID == pkgbase_id).first().Name
+ self._user = db.query(User.Username).filter(User.ID == uid).first().Username
+ self._pkgbase = (
+ db.query(PackageBase.Name).filter(PackageBase.ID == pkgbase_id).first().Name
+ )
- query = db.query(User).join(PackageNotification).filter(
- and_(User.OwnershipNotify == 1,
- PackageNotification.UserID != uid,
- PackageNotification.PackageBaseID == pkgbase_id,
- User.Suspended == 0)
- ).with_entities(
- User.Email,
- User.LangPreference
- ).distinct()
+ query = (
+ db.query(User)
+ .join(PackageNotification)
+ .filter(
+ and_(
+ User.OwnershipNotify == 1,
+ PackageNotification.UserID != uid,
+ PackageNotification.PackageBaseID == pkgbase_id,
+ User.Suspended == 0,
+ )
+ )
+ .with_entities(User.Email, User.LangPreference)
+ .distinct()
+ )
self._recipients = [(u.Email, u.LangPreference) for u in query]
- pkgbase = db.query(PackageBase.FlaggerComment).filter(
- PackageBase.ID == pkgbase_id).first()
+ pkgbase = (
+ db.query(PackageBase.FlaggerComment)
+ .filter(PackageBase.ID == pkgbase_id)
+ .first()
+ )
self._text = pkgbase.FlaggerComment
super().__init__()
@@ -373,39 +411,43 @@ class OwnershipEventNotification(Notification):
def get_subject(self, lang):
return aurweb.l10n.translator.translate(
- 'AUR Ownership Notification for {pkgbase}',
- lang).format(pkgbase=self._pkgbase)
+ "AUR Ownership Notification for {pkgbase}", lang
+ ).format(pkgbase=self._pkgbase)
def get_refs(self):
- return (aur_location + '/pkgbase/' + self._pkgbase + '/',
- aur_location + '/account/' + self._user + '/')
+ return (
+ aur_location + "/pkgbase/" + self._pkgbase + "/",
+ aur_location + "/account/" + self._user + "/",
+ )
class AdoptNotification(OwnershipEventNotification):
def get_body(self, lang):
return aurweb.l10n.translator.translate(
- 'The package {pkgbase} [1] was adopted by {user} [2].',
- lang).format(pkgbase=self._pkgbase, user=self._user)
+ "The package {pkgbase} [1] was adopted by {user} [2].", lang
+ ).format(pkgbase=self._pkgbase, user=self._user)
class DisownNotification(OwnershipEventNotification):
def get_body(self, lang):
return aurweb.l10n.translator.translate(
- 'The package {pkgbase} [1] was disowned by {user} '
- '[2].', lang).format(pkgbase=self._pkgbase,
- user=self._user)
+ "The package {pkgbase} [1] was disowned by {user} " "[2].", lang
+ ).format(pkgbase=self._pkgbase, user=self._user)
class ComaintainershipEventNotification(Notification):
def __init__(self, uid, pkgbase_id):
- self._pkgbase = db.query(PackageBase.Name).filter(
- PackageBase.ID == pkgbase_id).first().Name
+ self._pkgbase = (
+ db.query(PackageBase.Name).filter(PackageBase.ID == pkgbase_id).first().Name
+ )
- user = db.query(User).filter(User.ID == uid).with_entities(
- User.Email,
- User.LangPreference
- ).first()
+ user = (
+ db.query(User)
+ .filter(User.ID == uid)
+ .with_entities(User.Email, User.LangPreference)
+ .first()
+ )
self._to = user.Email
self._lang = user.LangPreference
@@ -417,247 +459,59 @@ class ComaintainershipEventNotification(Notification):
def get_subject(self, lang):
return aurweb.l10n.translator.translate(
- 'AUR Co-Maintainer Notification for {pkgbase}',
- lang).format(pkgbase=self._pkgbase)
+ "AUR Co-Maintainer Notification for {pkgbase}", lang
+ ).format(pkgbase=self._pkgbase)
def get_refs(self):
- return (aur_location + '/pkgbase/' + self._pkgbase + '/',)
+ return (aur_location + "/pkgbase/" + self._pkgbase + "/",)
class ComaintainerAddNotification(ComaintainershipEventNotification):
def get_body(self, lang):
return aurweb.l10n.translator.translate(
- 'You were added to the co-maintainer list of {pkgbase} [1].',
- lang).format(pkgbase=self._pkgbase)
+ "You were added to the co-maintainer list of {pkgbase} [1].", lang
+ ).format(pkgbase=self._pkgbase)
class ComaintainerRemoveNotification(ComaintainershipEventNotification):
def get_body(self, lang):
return aurweb.l10n.translator.translate(
- 'You were removed from the co-maintainer list of {pkgbase} '
- '[1].', lang).format(pkgbase=self._pkgbase)
+ "You were removed from the co-maintainer list of {pkgbase} " "[1].", lang
+ ).format(pkgbase=self._pkgbase)
class DeleteNotification(Notification):
def __init__(self, uid, old_pkgbase_id, new_pkgbase_id=None):
- self._user = db.query(User.Username).filter(
- User.ID == uid).first().Username
- self._old_pkgbase = db.query(PackageBase.Name).filter(
- PackageBase.ID == old_pkgbase_id).first().Name
+ self._user = db.query(User.Username).filter(User.ID == uid).first().Username
+ self._old_pkgbase = (
+ db.query(PackageBase.Name)
+ .filter(PackageBase.ID == old_pkgbase_id)
+ .first()
+ .Name
+ )
self._new_pkgbase = None
if new_pkgbase_id:
- self._new_pkgbase = db.query(PackageBase.Name).filter(
- PackageBase.ID == new_pkgbase_id).first().Name
+ self._new_pkgbase = (
+ db.query(PackageBase.Name)
+ .filter(PackageBase.ID == new_pkgbase_id)
+ .first()
+ .Name
+ )
- query = db.query(User).join(PackageNotification).filter(
- and_(PackageNotification.UserID != uid,
- PackageNotification.PackageBaseID == old_pkgbase_id,
- User.Suspended == 0)
- ).with_entities(
- User.Email,
- User.LangPreference
- ).distinct()
- self._recipients = [(u.Email, u.LangPreference) for u in query]
-
- super().__init__()
-
- def get_recipients(self):
- return self._recipients
-
- def get_subject(self, lang):
- return aurweb.l10n.translator.translate(
- 'AUR Package deleted: {pkgbase}',
- lang).format(pkgbase=self._old_pkgbase)
-
- def get_body(self, lang):
- if self._new_pkgbase:
- dnlabel = aurweb.l10n.translator.translate(
- 'Disable notifications', lang)
- return aurweb.l10n.translator.translate(
- '{user} [1] merged {old} [2] into {new} [3].\n\n'
- '--\n'
- 'If you no longer wish receive notifications about the '
- 'new package, please go to [3] and click "{label}".',
- lang).format(user=self._user, old=self._old_pkgbase,
- new=self._new_pkgbase, label=dnlabel)
- else:
- return aurweb.l10n.translator.translate(
- '{user} [1] deleted {pkgbase} [2].\n\n'
- 'You will no longer receive notifications about this '
- 'package.', lang).format(user=self._user,
- pkgbase=self._old_pkgbase)
-
- def get_refs(self):
- refs = (aur_location + '/account/' + self._user + '/',
- aur_location + '/pkgbase/' + self._old_pkgbase + '/')
- if self._new_pkgbase:
- refs += (aur_location + '/pkgbase/' + self._new_pkgbase + '/',)
- return refs
-
-
-class RequestOpenNotification(Notification):
- def __init__(self, uid, reqid, reqtype, pkgbase_id, merge_into=None):
-
- self._user = db.query(User.Username).filter(
- User.ID == uid).first().Username
- self._pkgbase = db.query(PackageBase.Name).filter(
- PackageBase.ID == pkgbase_id).first().Name
-
- self._to = aurweb.config.get('options', 'aur_request_ml')
-
- query = db.query(PackageRequest).join(PackageBase).join(
- PackageComaintainer,
- PackageComaintainer.PackageBaseID == PackageRequest.PackageBaseID,
- isouter=True
- ).join(
- User,
- or_(User.ID == PackageRequest.UsersID,
- User.ID == PackageBase.MaintainerUID,
- User.ID == PackageComaintainer.UsersID)
- ).filter(
- and_(PackageRequest.ID == reqid,
- User.Suspended == 0)
- ).with_entities(
- User.Email
- ).distinct()
- self._cc = [u.Email for u in query]
-
- pkgreq = db.query(PackageRequest.Comments).filter(
- PackageRequest.ID == reqid).first()
-
- self._text = pkgreq.Comments
- self._reqid = int(reqid)
- self._reqtype = reqtype
- self._merge_into = merge_into
-
- def get_recipients(self):
- return [(self._to, 'en')]
-
- def get_cc(self):
- return self._cc
-
- def get_subject(self, lang):
- return '[PRQ#%d] %s Request for %s' % \
- (self._reqid, self._reqtype.title(), self._pkgbase)
-
- def get_body(self, lang):
- if self._merge_into:
- body = '%s [1] filed a request to merge %s [2] into %s [3]:' % \
- (self._user, self._pkgbase, self._merge_into)
- body += '\n\n' + self._text
- else:
- an = 'an' if self._reqtype[0] in 'aeiou' else 'a'
- body = '%s [1] filed %s %s request for %s [2]:' % \
- (self._user, an, self._reqtype, self._pkgbase)
- body += '\n\n' + self._text
- return body
-
- def get_refs(self):
- refs = (aur_location + '/account/' + self._user + '/',
- aur_location + '/pkgbase/' + self._pkgbase + '/')
- if self._merge_into:
- refs += (aur_location + '/pkgbase/' + self._merge_into + '/',)
- return refs
-
- def get_headers(self):
- thread_id = ''
- # Use a deterministic Message-ID for the first email referencing a
- # request.
- headers = headers_msgid(thread_id)
- return headers
-
-
-class RequestCloseNotification(Notification):
-
- def __init__(self, uid, reqid, reason):
- user = db.query(User.Username).filter(User.ID == uid).first()
- self._user = user.Username if user else None
-
- self._to = aurweb.config.get('options', 'aur_request_ml')
-
- query = db.query(PackageRequest).join(PackageBase).join(
- PackageComaintainer,
- PackageComaintainer.PackageBaseID == PackageRequest.PackageBaseID,
- isouter=True
- ).join(
- User,
- or_(User.ID == PackageRequest.UsersID,
- User.ID == PackageBase.MaintainerUID,
- User.ID == PackageComaintainer.UsersID)
- ).filter(
- and_(PackageRequest.ID == reqid,
- User.Suspended == 0)
- ).with_entities(
- User.Email
- ).distinct()
- self._cc = [u.Email for u in query]
-
- pkgreq = db.query(PackageRequest).join(RequestType).filter(
- PackageRequest.ID == reqid
- ).with_entities(
- PackageRequest.ClosureComment,
- RequestType.Name,
- PackageRequest.PackageBaseName
- ).first()
-
- self._text = pkgreq.ClosureComment
- self._reqtype = pkgreq.Name
- self._pkgbase = pkgreq.PackageBaseName
-
- self._reqid = int(reqid)
- self._reason = reason
-
- def get_recipients(self):
- return [(self._to, 'en')]
-
- def get_cc(self):
- return self._cc
-
- def get_subject(self, lang):
- return '[PRQ#%d] %s Request for %s %s' % (self._reqid,
- self._reqtype.title(),
- self._pkgbase,
- self._reason.title())
-
- def get_body(self, lang):
- if self._user:
- body = 'Request #%d has been %s by %s [1]' % \
- (self._reqid, self._reason, self._user)
- else:
- body = 'Request #%d has been %s automatically by the Arch User ' \
- 'Repository package request system' % \
- (self._reqid, self._reason)
- if self._text.strip() == '':
- body += '.'
- else:
- body += ':\n\n' + self._text
- return body
-
- def get_refs(self):
- if self._user:
- return (aur_location + '/account/' + self._user + '/',)
- else:
- return ()
-
- def get_headers(self):
- thread_id = ''
- headers = headers_reply(thread_id)
- return headers
-
-
-class TUVoteReminderNotification(Notification):
- def __init__(self, vote_id):
- self._vote_id = int(vote_id)
-
- subquery = db.query(TUVote.UserID).filter(TUVote.VoteID == vote_id)
- query = db.query(User).filter(
- and_(User.AccountTypeID.in_((2, 4)),
- ~User.ID.in_(subquery),
- User.Suspended == 0)
- ).with_entities(
- User.Email, User.LangPreference
+ query = (
+ db.query(User)
+ .join(PackageNotification)
+ .filter(
+ and_(
+ PackageNotification.UserID != uid,
+ PackageNotification.PackageBaseID == old_pkgbase_id,
+ User.Suspended == 0,
+ )
+ )
+ .with_entities(User.Email, User.LangPreference)
+ .distinct()
)
self._recipients = [(u.Email, u.LangPreference) for u in query]
@@ -668,36 +522,280 @@ class TUVoteReminderNotification(Notification):
def get_subject(self, lang):
return aurweb.l10n.translator.translate(
- 'TU Vote Reminder: Proposal {id}',
- lang).format(id=self._vote_id)
+ "AUR Package deleted: {pkgbase}", lang
+ ).format(pkgbase=self._old_pkgbase)
+
+ def get_body(self, lang):
+ if self._new_pkgbase:
+ dnlabel = aurweb.l10n.translator.translate("Disable notifications", lang)
+ return aurweb.l10n.translator.translate(
+ "{user} [1] merged {old} [2] into {new} [3].\n\n"
+ "--\n"
+ "If you no longer wish receive notifications about the "
+ 'new package, please go to [3] and click "{label}".',
+ lang,
+ ).format(
+ user=self._user,
+ old=self._old_pkgbase,
+ new=self._new_pkgbase,
+ label=dnlabel,
+ )
+ else:
+ return aurweb.l10n.translator.translate(
+ "{user} [1] deleted {pkgbase} [2].\n\n"
+ "You will no longer receive notifications about this "
+ "package.",
+ lang,
+ ).format(user=self._user, pkgbase=self._old_pkgbase)
+
+ def get_refs(self):
+ refs = (
+ aur_location + "/account/" + self._user + "/",
+ aur_location + "/pkgbase/" + self._old_pkgbase + "/",
+ )
+ if self._new_pkgbase:
+ refs += (aur_location + "/pkgbase/" + self._new_pkgbase + "/",)
+ return refs
+
+
+class RequestOpenNotification(Notification):
+ def __init__(self, uid, reqid, reqtype, pkgbase_id, merge_into=None):
+
+ self._user = db.query(User.Username).filter(User.ID == uid).first().Username
+ self._pkgbase = (
+ db.query(PackageBase.Name).filter(PackageBase.ID == pkgbase_id).first().Name
+ )
+
+ self._to = aurweb.config.get("options", "aur_request_ml")
+
+ query = (
+ db.query(PackageRequest)
+ .join(PackageBase)
+ .join(
+ PackageComaintainer,
+ PackageComaintainer.PackageBaseID == PackageRequest.PackageBaseID,
+ isouter=True,
+ )
+ .join(
+ User,
+ or_(
+ User.ID == PackageRequest.UsersID,
+ User.ID == PackageBase.MaintainerUID,
+ User.ID == PackageComaintainer.UsersID,
+ ),
+ )
+ .filter(and_(PackageRequest.ID == reqid, User.Suspended == 0))
+ .with_entities(User.Email)
+ .distinct()
+ )
+ self._cc = [u.Email for u in query]
+
+ pkgreq = (
+ db.query(PackageRequest.Comments).filter(PackageRequest.ID == reqid).first()
+ )
+
+ self._text = pkgreq.Comments
+ self._reqid = int(reqid)
+ self._reqtype = reqtype
+ self._merge_into = merge_into
+
+ def get_recipients(self):
+ return [(self._to, "en")]
+
+ def get_cc(self):
+ return self._cc
+
+ def get_subject(self, lang):
+ return "[PRQ#%d] %s Request for %s" % (
+ self._reqid,
+ self._reqtype.title(),
+ self._pkgbase,
+ )
+
+ def get_body(self, lang):
+ if self._merge_into:
+ body = "%s [1] filed a request to merge %s [2] into %s [3]:" % (
+ self._user,
+ self._pkgbase,
+ self._merge_into,
+ )
+ body += "\n\n" + self._text
+ else:
+ an = "an" if self._reqtype[0] in "aeiou" else "a"
+ body = "%s [1] filed %s %s request for %s [2]:" % (
+ self._user,
+ an,
+ self._reqtype,
+ self._pkgbase,
+ )
+ body += "\n\n" + self._text
+ return body
+
+ def get_refs(self):
+ refs = (
+ aur_location + "/account/" + self._user + "/",
+ aur_location + "/pkgbase/" + self._pkgbase + "/",
+ )
+ if self._merge_into:
+ refs += (aur_location + "/pkgbase/" + self._merge_into + "/",)
+ return refs
+
+ def get_headers(self):
+ thread_id = ""
+ # Use a deterministic Message-ID for the first email referencing a
+ # request.
+ headers = headers_msgid(thread_id)
+ return headers
+
+
+class RequestCloseNotification(Notification):
+ def __init__(self, uid, reqid, reason):
+ user = db.query(User.Username).filter(User.ID == uid).first()
+ self._user = user.Username if user else None
+
+ self._to = aurweb.config.get("options", "aur_request_ml")
+
+ query = (
+ db.query(PackageRequest)
+ .join(PackageBase)
+ .join(
+ PackageComaintainer,
+ PackageComaintainer.PackageBaseID == PackageRequest.PackageBaseID,
+ isouter=True,
+ )
+ .join(
+ User,
+ or_(
+ User.ID == PackageRequest.UsersID,
+ User.ID == PackageBase.MaintainerUID,
+ User.ID == PackageComaintainer.UsersID,
+ ),
+ )
+ .filter(and_(PackageRequest.ID == reqid, User.Suspended == 0))
+ .with_entities(User.Email)
+ .distinct()
+ )
+ self._cc = [u.Email for u in query]
+
+ pkgreq = (
+ db.query(PackageRequest)
+ .join(RequestType)
+ .filter(PackageRequest.ID == reqid)
+ .with_entities(
+ PackageRequest.ClosureComment,
+ RequestType.Name,
+ PackageRequest.PackageBaseName,
+ )
+ .first()
+ )
+
+ self._text = pkgreq.ClosureComment
+ self._reqtype = pkgreq.Name
+ self._pkgbase = pkgreq.PackageBaseName
+
+ self._reqid = int(reqid)
+ self._reason = reason
+
+ def get_recipients(self):
+ return [(self._to, "en")]
+
+ def get_cc(self):
+ return self._cc
+
+ def get_subject(self, lang):
+ return "[PRQ#%d] %s Request for %s %s" % (
+ self._reqid,
+ self._reqtype.title(),
+ self._pkgbase,
+ self._reason.title(),
+ )
+
+ def get_body(self, lang):
+ if self._user:
+ body = "Request #%d has been %s by %s [1]" % (
+ self._reqid,
+ self._reason,
+ self._user,
+ )
+ else:
+ body = (
+ "Request #%d has been %s automatically by the Arch User "
+ "Repository package request system" % (self._reqid, self._reason)
+ )
+ if self._text.strip() == "":
+ body += "."
+ else:
+ body += ":\n\n" + self._text
+ return body
+
+ def get_refs(self):
+ if self._user:
+ return (aur_location + "/account/" + self._user + "/",)
+ else:
+ return ()
+
+ def get_headers(self):
+ thread_id = ""
+ headers = headers_reply(thread_id)
+ return headers
+
+
+class TUVoteReminderNotification(Notification):
+ def __init__(self, vote_id):
+ self._vote_id = int(vote_id)
+
+ subquery = db.query(TUVote.UserID).filter(TUVote.VoteID == vote_id)
+ query = (
+ db.query(User)
+ .filter(
+ and_(
+ User.AccountTypeID.in_((2, 4)),
+ ~User.ID.in_(subquery),
+ User.Suspended == 0,
+ )
+ )
+ .with_entities(User.Email, User.LangPreference)
+ )
+ self._recipients = [(u.Email, u.LangPreference) for u in query]
+
+ super().__init__()
+
+ def get_recipients(self):
+ return self._recipients
+
+ def get_subject(self, lang):
+ return aurweb.l10n.translator.translate(
+ "TU Vote Reminder: Proposal {id}", lang
+ ).format(id=self._vote_id)
def get_body(self, lang):
return aurweb.l10n.translator.translate(
- 'Please remember to cast your vote on proposal {id} [1]. '
- 'The voting period ends in less than 48 hours.',
- lang).format(id=self._vote_id)
+ "Please remember to cast your vote on proposal {id} [1]. "
+ "The voting period ends in less than 48 hours.",
+ lang,
+ ).format(id=self._vote_id)
def get_refs(self):
- return (aur_location + '/tu/?id=' + str(self._vote_id),)
+ return (aur_location + "/tu/?id=" + str(self._vote_id),)
def main():
db.get_engine()
action = sys.argv[1]
action_map = {
- 'send-resetkey': ResetKeyNotification,
- 'welcome': WelcomeNotification,
- 'comment': CommentNotification,
- 'update': UpdateNotification,
- 'flag': FlagNotification,
- 'adopt': AdoptNotification,
- 'disown': DisownNotification,
- 'comaintainer-add': ComaintainerAddNotification,
- 'comaintainer-remove': ComaintainerRemoveNotification,
- 'delete': DeleteNotification,
- 'request-open': RequestOpenNotification,
- 'request-close': RequestCloseNotification,
- 'tu-vote-reminder': TUVoteReminderNotification,
+ "send-resetkey": ResetKeyNotification,
+ "welcome": WelcomeNotification,
+ "comment": CommentNotification,
+ "update": UpdateNotification,
+ "flag": FlagNotification,
+ "adopt": AdoptNotification,
+ "disown": DisownNotification,
+ "comaintainer-add": ComaintainerAddNotification,
+ "comaintainer-remove": ComaintainerRemoveNotification,
+ "delete": DeleteNotification,
+ "request-open": RequestOpenNotification,
+ "request-close": RequestCloseNotification,
+ "tu-vote-reminder": TUVoteReminderNotification,
}
with db.begin():
@@ -705,5 +803,5 @@ def main():
notification.send()
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/aurweb/scripts/pkgmaint.py b/aurweb/scripts/pkgmaint.py
index 2a2c638a..9d7cf53b 100755
--- a/aurweb/scripts/pkgmaint.py
+++ b/aurweb/scripts/pkgmaint.py
@@ -11,8 +11,8 @@ def _main():
limit_to = time.utcnow() - 86400
query = db.query(PackageBase).filter(
- and_(PackageBase.SubmittedTS < limit_to,
- PackageBase.PackagerUID.is_(None)))
+ and_(PackageBase.SubmittedTS < limit_to, PackageBase.PackagerUID.is_(None))
+ )
db.delete_all(query)
@@ -22,5 +22,5 @@ def main():
_main()
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/aurweb/scripts/popupdate.py b/aurweb/scripts/popupdate.py
index 637173eb..aa163be1 100755
--- a/aurweb/scripts/popupdate.py
+++ b/aurweb/scripts/popupdate.py
@@ -1,8 +1,7 @@
#!/usr/bin/env python3
from sqlalchemy import and_, func
-from sqlalchemy.sql.functions import coalesce
-from sqlalchemy.sql.functions import sum as _sum
+from sqlalchemy.sql.functions import coalesce, sum as _sum
from aurweb import db, time
from aurweb.models import PackageBase, PackageVote
@@ -20,18 +19,26 @@ def run_variable(pkgbases: list[PackageBase] = []) -> None:
now = time.utcnow()
# NumVotes subquery.
- votes_subq = db.get_session().query(
- func.count("*")
- ).select_from(PackageVote).filter(
- PackageVote.PackageBaseID == PackageBase.ID
+ votes_subq = (
+ db.get_session()
+ .query(func.count("*"))
+ .select_from(PackageVote)
+ .filter(PackageVote.PackageBaseID == PackageBase.ID)
)
# Popularity subquery.
- pop_subq = db.get_session().query(
- coalesce(_sum(func.pow(0.98, (now - PackageVote.VoteTS) / 86400)), 0.0),
- ).select_from(PackageVote).filter(
- and_(PackageVote.PackageBaseID == PackageBase.ID,
- PackageVote.VoteTS.isnot(None))
+ pop_subq = (
+ db.get_session()
+ .query(
+ coalesce(_sum(func.pow(0.98, (now - PackageVote.VoteTS) / 86400)), 0.0),
+ )
+ .select_from(PackageVote)
+ .filter(
+ and_(
+ PackageVote.PackageBaseID == PackageBase.ID,
+ PackageVote.VoteTS.isnot(None),
+ )
+ )
)
with db.begin():
@@ -42,14 +49,16 @@ def run_variable(pkgbases: list[PackageBase] = []) -> None:
ids = {pkgbase.ID for pkgbase in pkgbases}
query = query.filter(PackageBase.ID.in_(ids))
- query.update({
- "NumVotes": votes_subq.scalar_subquery(),
- "Popularity": pop_subq.scalar_subquery()
- })
+ query.update(
+ {
+ "NumVotes": votes_subq.scalar_subquery(),
+ "Popularity": pop_subq.scalar_subquery(),
+ }
+ )
def run_single(pkgbase: PackageBase) -> None:
- """ A single popupdate. The given pkgbase instance will be
+ """A single popupdate. The given pkgbase instance will be
refreshed after the database update is done.
NOTE: This function is compatible only with aurweb FastAPI.
@@ -65,5 +74,5 @@ def main():
run_variable()
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py
index 87f8b89f..ff6fe09c 100755
--- a/aurweb/scripts/rendercomment.py
+++ b/aurweb/scripts/rendercomment.py
@@ -1,7 +1,6 @@
#!/usr/bin/env python3
import sys
-
from urllib.parse import quote_plus
from xml.etree.ElementTree import Element
@@ -10,7 +9,6 @@ import markdown
import pygit2
import aurweb.config
-
from aurweb import db, logging, util
from aurweb.models import PackageComment
@@ -25,13 +23,15 @@ class LinkifyExtension(markdown.extensions.Extension):
# Captures http(s) and ftp URLs until the first non URL-ish character.
# Excludes trailing punctuation.
- _urlre = (r'(\b(?:https?|ftp):\/\/[\w\/\#~:.?+=&%@!\-;,]+?'
- r'(?=[.:?\-;,]*(?:[^\w\/\#~:.?+=&%@!\-;,]|$)))')
+ _urlre = (
+ r"(\b(?:https?|ftp):\/\/[\w\/\#~:.?+=&%@!\-;,]+?"
+ r"(?=[.:?\-;,]*(?:[^\w\/\#~:.?+=&%@!\-;,]|$)))"
+ )
def extendMarkdown(self, md):
processor = markdown.inlinepatterns.AutolinkInlineProcessor(self._urlre, md)
# Register it right after the default <>-link processor (priority 120).
- md.inlinePatterns.register(processor, 'linkify', 119)
+ md.inlinePatterns.register(processor, "linkify", 119)
class FlysprayLinksInlineProcessor(markdown.inlinepatterns.InlineProcessor):
@@ -43,16 +43,16 @@ class FlysprayLinksInlineProcessor(markdown.inlinepatterns.InlineProcessor):
"""
def handleMatch(self, m, data):
- el = Element('a')
- el.set('href', f'https://bugs.archlinux.org/task/{m.group(1)}')
+ el = Element("a")
+ el.set("href", f"https://bugs.archlinux.org/task/{m.group(1)}")
el.text = markdown.util.AtomicString(m.group(0))
return (el, m.start(0), m.end(0))
class FlysprayLinksExtension(markdown.extensions.Extension):
def extendMarkdown(self, md):
- processor = FlysprayLinksInlineProcessor(r'\bFS#(\d+)\b', md)
- md.inlinePatterns.register(processor, 'flyspray-links', 118)
+ processor = FlysprayLinksInlineProcessor(r"\bFS#(\d+)\b", md)
+ md.inlinePatterns.register(processor, "flyspray-links", 118)
class GitCommitsInlineProcessor(markdown.inlinepatterns.InlineProcessor):
@@ -65,10 +65,10 @@ class GitCommitsInlineProcessor(markdown.inlinepatterns.InlineProcessor):
"""
def __init__(self, md, head):
- repo_path = aurweb.config.get('serve', 'repo-path')
+ repo_path = aurweb.config.get("serve", "repo-path")
self._repo = pygit2.Repository(repo_path)
self._head = head
- super().__init__(r'\b([0-9a-f]{7,40})\b', md)
+ super().__init__(r"\b([0-9a-f]{7,40})\b", md)
def handleMatch(self, m, data):
oid = m.group(1)
@@ -76,13 +76,12 @@ class GitCommitsInlineProcessor(markdown.inlinepatterns.InlineProcessor):
# Unknown OID; preserve the orginal text.
return (None, None, None)
- el = Element('a')
+ el = Element("a")
commit_uri = aurweb.config.get("options", "commit_uri")
prefixlen = util.git_search(self._repo, oid)
- el.set('href', commit_uri % (
- quote_plus(self._head),
- quote_plus(oid[:prefixlen])
- ))
+ el.set(
+ "href", commit_uri % (quote_plus(self._head), quote_plus(oid[:prefixlen]))
+ )
el.text = markdown.util.AtomicString(oid[:prefixlen])
return (el, m.start(0), m.end(0))
@@ -97,7 +96,7 @@ class GitCommitsExtension(markdown.extensions.Extension):
def extendMarkdown(self, md):
try:
processor = GitCommitsInlineProcessor(md, self._head)
- md.inlinePatterns.register(processor, 'git-commits', 117)
+ md.inlinePatterns.register(processor, "git-commits", 117)
except pygit2.GitError:
logger.error(f"No git repository found for '{self._head}'.")
@@ -105,16 +104,16 @@ class GitCommitsExtension(markdown.extensions.Extension):
class HeadingTreeprocessor(markdown.treeprocessors.Treeprocessor):
def run(self, doc):
for elem in doc:
- if elem.tag == 'h1':
- elem.tag = 'h5'
- elif elem.tag in ['h2', 'h3', 'h4', 'h5']:
- elem.tag = 'h6'
+ if elem.tag == "h1":
+ elem.tag = "h5"
+ elif elem.tag in ["h2", "h3", "h4", "h5"]:
+ elem.tag = "h6"
class HeadingExtension(markdown.extensions.Extension):
def extendMarkdown(self, md):
# Priority doesn't matter since we don't conflict with other processors.
- md.treeprocessors.register(HeadingTreeprocessor(md), 'heading', 30)
+ md.treeprocessors.register(HeadingTreeprocessor(md), "heading", 30)
def save_rendered_comment(comment: PackageComment, html: str):
@@ -130,16 +129,26 @@ def update_comment_render(comment: PackageComment) -> None:
text = comment.Comments
pkgbasename = comment.PackageBase.Name
- html = markdown.markdown(text, extensions=[
- 'fenced_code',
- LinkifyExtension(),
- FlysprayLinksExtension(),
- GitCommitsExtension(pkgbasename),
- HeadingExtension()
- ])
+ html = markdown.markdown(
+ text,
+ extensions=[
+ "fenced_code",
+ LinkifyExtension(),
+ FlysprayLinksExtension(),
+ GitCommitsExtension(pkgbasename),
+ HeadingExtension(),
+ ],
+ )
- allowed_tags = (bleach.sanitizer.ALLOWED_TAGS
- + ['p', 'pre', 'h4', 'h5', 'h6', 'br', 'hr'])
+ allowed_tags = bleach.sanitizer.ALLOWED_TAGS + [
+ "p",
+ "pre",
+ "h4",
+ "h5",
+ "h6",
+ "br",
+ "hr",
+ ]
html = bleach.clean(html, tags=allowed_tags)
save_rendered_comment(comment, html)
db.refresh(comment)
@@ -148,11 +157,9 @@ def update_comment_render(comment: PackageComment) -> None:
def main():
db.get_engine()
comment_id = int(sys.argv[1])
- comment = db.query(PackageComment).filter(
- PackageComment.ID == comment_id
- ).first()
+ comment = db.query(PackageComment).filter(PackageComment.ID == comment_id).first()
update_comment_render(comment)
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/aurweb/scripts/tuvotereminder.py b/aurweb/scripts/tuvotereminder.py
index 742fa6d4..aa59d911 100755
--- a/aurweb/scripts/tuvotereminder.py
+++ b/aurweb/scripts/tuvotereminder.py
@@ -3,12 +3,11 @@
from sqlalchemy import and_
import aurweb.config
-
from aurweb import db, time
from aurweb.models import TUVoteInfo
from aurweb.scripts import notify
-notify_cmd = aurweb.config.get('notifications', 'notify-cmd')
+notify_cmd = aurweb.config.get("notifications", "notify-cmd")
def main():
@@ -23,13 +22,12 @@ def main():
filter_to = now + end
query = db.query(TUVoteInfo.ID).filter(
- and_(TUVoteInfo.End >= filter_from,
- TUVoteInfo.End <= filter_to)
+ and_(TUVoteInfo.End >= filter_from, TUVoteInfo.End <= filter_to)
)
for voteinfo in query:
notif = notify.TUVoteReminderNotification(voteinfo.ID)
notif.send()
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/aurweb/scripts/usermaint.py b/aurweb/scripts/usermaint.py
index 69f9db04..fb79aeaf 100755
--- a/aurweb/scripts/usermaint.py
+++ b/aurweb/scripts/usermaint.py
@@ -9,14 +9,16 @@ from aurweb.models import User
def _main():
limit_to = time.utcnow() - 86400 * 7
- update_ = update(User).where(
- User.LastLogin < limit_to
- ).values(LastLoginIPAddress=None)
+ update_ = (
+ update(User).where(User.LastLogin < limit_to).values(LastLoginIPAddress=None)
+ )
db.get_session().execute(update_)
- update_ = update(User).where(
- User.LastSSHLogin < limit_to
- ).values(LastSSHLoginIPAddress=None)
+ update_ = (
+ update(User)
+ .where(User.LastSSHLogin < limit_to)
+ .values(LastSSHLoginIPAddress=None)
+ )
db.get_session().execute(update_)
@@ -26,5 +28,5 @@ def main():
_main()
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/aurweb/spawn.py b/aurweb/spawn.py
index c7d54c4e..29162f33 100644
--- a/aurweb/spawn.py
+++ b/aurweb/spawn.py
@@ -16,18 +16,16 @@ import subprocess
import sys
import tempfile
import time
-
from typing import Iterable
import aurweb.config
import aurweb.schema
-
from aurweb.exceptions import AurwebException
children = []
temporary_dir = None
verbosity = 0
-asgi_backend = ''
+asgi_backend = ""
workers = 1
PHP_BINARY = os.environ.get("PHP_BINARY", "php")
@@ -60,22 +58,21 @@ def validate_php_config() -> None:
:return: None
"""
try:
- proc = subprocess.Popen([PHP_BINARY, "-m"],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
+ proc = subprocess.Popen(
+ [PHP_BINARY, "-m"], stdout=subprocess.PIPE, stderr=subprocess.PIPE
+ )
out, _ = proc.communicate()
except FileNotFoundError:
- raise AurwebException(f"Unable to locate the '{PHP_BINARY}' "
- "executable.")
+ raise AurwebException(f"Unable to locate the '{PHP_BINARY}' " "executable.")
- assert proc.returncode == 0, ("Received non-zero error code "
- f"{proc.returncode} from '{PHP_BINARY}'.")
+ assert proc.returncode == 0, (
+ "Received non-zero error code " f"{proc.returncode} from '{PHP_BINARY}'."
+ )
modules = out.decode().splitlines()
for module in PHP_MODULES:
if module not in modules:
- raise AurwebException(
- f"PHP does not have the '{module}' module enabled.")
+ raise AurwebException(f"PHP does not have the '{module}' module enabled.")
def generate_nginx_config():
@@ -91,7 +88,8 @@ def generate_nginx_config():
config_path = os.path.join(temporary_dir, "nginx.conf")
config = open(config_path, "w")
# We double nginx's braces because they conflict with Python's f-strings.
- config.write(f"""
+ config.write(
+ f"""
events {{}}
daemon off;
error_log /dev/stderr info;
@@ -124,7 +122,8 @@ def generate_nginx_config():
}}
}}
}}
- """)
+ """
+ )
return config_path
@@ -146,20 +145,23 @@ def start():
return
atexit.register(stop)
- if 'AUR_CONFIG' in os.environ:
- os.environ['AUR_CONFIG'] = os.path.realpath(os.environ['AUR_CONFIG'])
+ if "AUR_CONFIG" in os.environ:
+ os.environ["AUR_CONFIG"] = os.path.realpath(os.environ["AUR_CONFIG"])
try:
terminal_width = os.get_terminal_size().columns
except OSError:
terminal_width = 80
- print("{ruler}\n"
- "Spawing PHP and FastAPI, then nginx as a reverse proxy.\n"
- "Check out {aur_location}\n"
- "Hit ^C to terminate everything.\n"
- "{ruler}"
- .format(ruler=("-" * terminal_width),
- aur_location=aurweb.config.get('options', 'aur_location')))
+ print(
+ "{ruler}\n"
+ "Spawing PHP and FastAPI, then nginx as a reverse proxy.\n"
+ "Check out {aur_location}\n"
+ "Hit ^C to terminate everything.\n"
+ "{ruler}".format(
+ ruler=("-" * terminal_width),
+ aur_location=aurweb.config.get("options", "aur_location"),
+ )
+ )
# PHP
php_address = aurweb.config.get("php", "bind_address")
@@ -168,8 +170,9 @@ def start():
spawn_child(["php", "-S", php_address, "-t", htmldir])
# FastAPI
- fastapi_host, fastapi_port = aurweb.config.get(
- "fastapi", "bind_address").rsplit(":", 1)
+ fastapi_host, fastapi_port = aurweb.config.get("fastapi", "bind_address").rsplit(
+ ":", 1
+ )
# Logging config.
aurwebdir = aurweb.config.get("options", "aurwebdir")
@@ -178,20 +181,33 @@ def start():
backend_args = {
"hypercorn": ["-b", f"{fastapi_host}:{fastapi_port}"],
"uvicorn": ["--host", fastapi_host, "--port", fastapi_port],
- "gunicorn": ["--bind", f"{fastapi_host}:{fastapi_port}",
- "-k", "uvicorn.workers.UvicornWorker",
- "-w", str(workers)]
+ "gunicorn": [
+ "--bind",
+ f"{fastapi_host}:{fastapi_port}",
+ "-k",
+ "uvicorn.workers.UvicornWorker",
+ "-w",
+ str(workers),
+ ],
}
backend_args = backend_args.get(asgi_backend)
- spawn_child([
- "python", "-m", asgi_backend,
- "--log-config", fastapi_log_config,
- ] + backend_args + ["aurweb.asgi:app"])
+ spawn_child(
+ [
+ "python",
+ "-m",
+ asgi_backend,
+ "--log-config",
+ fastapi_log_config,
+ ]
+ + backend_args
+ + ["aurweb.asgi:app"]
+ )
# nginx
spawn_child(["nginx", "-p", temporary_dir, "-c", generate_nginx_config()])
- print(f"""
+ print(
+ f"""
> Started nginx.
>
> PHP backend: http://{php_address}
@@ -201,11 +217,13 @@ def start():
> FastAPI frontend: http://{fastapi_host}:{FASTAPI_NGINX_PORT}
>
> Frontends are hosted via nginx and should be preferred.
-""")
+"""
+ )
-def _kill_children(children: Iterable, exceptions: list[Exception] = []) \
- -> list[Exception]:
+def _kill_children(
+ children: Iterable, exceptions: list[Exception] = []
+) -> list[Exception]:
"""
Kill each process found in `children`.
@@ -223,8 +241,9 @@ def _kill_children(children: Iterable, exceptions: list[Exception] = []) \
return exceptions
-def _wait_for_children(children: Iterable, exceptions: list[Exception] = []) \
- -> list[Exception]:
+def _wait_for_children(
+ children: Iterable, exceptions: list[Exception] = []
+) -> list[Exception]:
"""
Wait for each process to end found in `children`.
@@ -261,21 +280,31 @@ def stop() -> None:
exceptions = _wait_for_children(children, exceptions)
children = []
if exceptions:
- raise ProcessExceptions("Errors terminating the child processes:",
- exceptions)
+ raise ProcessExceptions("Errors terminating the child processes:", exceptions)
-if __name__ == '__main__':
+if __name__ == "__main__":
parser = argparse.ArgumentParser(
- prog='python -m aurweb.spawn',
- description='Start aurweb\'s test server.')
- parser.add_argument('-v', '--verbose', action='count', default=0,
- help='increase verbosity')
- choices = ['hypercorn', 'gunicorn', 'uvicorn']
- parser.add_argument('-b', '--backend', choices=choices, default='uvicorn',
- help='asgi backend used to launch the python server')
- parser.add_argument("-w", "--workers", default=1, type=int,
- help="number of workers to use in gunicorn")
+ prog="python -m aurweb.spawn", description="Start aurweb's test server."
+ )
+ parser.add_argument(
+ "-v", "--verbose", action="count", default=0, help="increase verbosity"
+ )
+ choices = ["hypercorn", "gunicorn", "uvicorn"]
+ parser.add_argument(
+ "-b",
+ "--backend",
+ choices=choices,
+ default="uvicorn",
+ help="asgi backend used to launch the python server",
+ )
+ parser.add_argument(
+ "-w",
+ "--workers",
+ default=1,
+ type=int,
+ help="number of workers to use in gunicorn",
+ )
args = parser.parse_args()
try:
diff --git a/aurweb/templates.py b/aurweb/templates.py
index 6520bedf..781826ea 100644
--- a/aurweb/templates.py
+++ b/aurweb/templates.py
@@ -1,28 +1,27 @@
import copy
import functools
import os
-
from http import HTTPStatus
from typing import Callable
import jinja2
-
from fastapi import Request
from fastapi.responses import HTMLResponse
import aurweb.config
-
from aurweb import cookies, l10n, time
# Prepare jinja2 objects.
-_loader = jinja2.FileSystemLoader(os.path.join(
- aurweb.config.get("options", "aurwebdir"), "templates"))
-_env = jinja2.Environment(loader=_loader, autoescape=True,
- extensions=["jinja2.ext.i18n"])
+_loader = jinja2.FileSystemLoader(
+ os.path.join(aurweb.config.get("options", "aurwebdir"), "templates")
+)
+_env = jinja2.Environment(
+ loader=_loader, autoescape=True, extensions=["jinja2.ext.i18n"]
+)
def register_filter(name: str) -> Callable:
- """ A decorator that can be used to register a filter.
+ """A decorator that can be used to register a filter.
Example
@register_filter("some_filter")
@@ -35,31 +34,36 @@ def register_filter(name: str) -> Callable:
:param name: Filter name
:return: Callable used for filter
"""
+
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
+
_env.filters[name] = wrapper
return wrapper
+
return decorator
def register_function(name: str) -> Callable:
- """ A decorator that can be used to register a function.
- """
+ """A decorator that can be used to register a function."""
+
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
+
if name in _env.globals:
raise KeyError(f"Jinja already has a function named '{name}'")
_env.globals[name] = wrapper
return wrapper
+
return decorator
def make_context(request: Request, title: str, next: str = None):
- """ Create a context for a jinja2 TemplateResponse. """
+ """Create a context for a jinja2 TemplateResponse."""
import aurweb.auth.creds
commit_url = aurweb.config.get_with_fallback("devel", "commit_url", None)
@@ -85,17 +89,19 @@ def make_context(request: Request, title: str, next: str = None):
"config": aurweb.config,
"creds": aurweb.auth.creds,
"next": next if next else request.url.path,
- "version": os.environ.get("COMMIT_HASH", aurweb.config.AURWEB_VERSION)
+ "version": os.environ.get("COMMIT_HASH", aurweb.config.AURWEB_VERSION),
}
async def make_variable_context(request: Request, title: str, next: str = None):
- """ Make a context with variables provided by the user
- (query params via GET or form data via POST). """
+ """Make a context with variables provided by the user
+ (query params via GET or form data via POST)."""
context = make_context(request, title, next)
- to_copy = dict(request.query_params) \
- if request.method.lower() == "get" \
+ to_copy = (
+ dict(request.query_params)
+ if request.method.lower() == "get"
else dict(await request.form())
+ )
for k, v in to_copy.items():
context[k] = v
@@ -111,7 +117,7 @@ def base_template(path: str):
def render_raw_template(request: Request, path: str, context: dict):
- """ Render a Jinja2 multi-lingual template with some context. """
+ """Render a Jinja2 multi-lingual template with some context."""
# Create a deep copy of our jinja2 _environment. The _environment in
# total by itself is 48 bytes large (according to sys.getsizeof).
# This is done so we can install gettext translations on the template
@@ -126,11 +132,10 @@ def render_raw_template(request: Request, path: str, context: dict):
return template.render(context)
-def render_template(request: Request,
- path: str,
- context: dict,
- status_code: HTTPStatus = HTTPStatus.OK):
- """ Render a template as an HTMLResponse. """
+def render_template(
+ request: Request, path: str, context: dict, status_code: HTTPStatus = HTTPStatus.OK
+):
+ """Render a template as an HTMLResponse."""
rendered = render_raw_template(request, path, context)
response = HTMLResponse(rendered, status_code=int(status_code))
diff --git a/aurweb/testing/__init__.py b/aurweb/testing/__init__.py
index 8261051d..4451eb3a 100644
--- a/aurweb/testing/__init__.py
+++ b/aurweb/testing/__init__.py
@@ -1,10 +1,9 @@
import aurweb.db
-
from aurweb import models
def setup_test_db(*args):
- """ This function is to be used to setup a test database before
+ """This function is to be used to setup a test database before
using it. It takes a variable number of table strings, and for
each table in that set of table strings, it deletes all records.
diff --git a/aurweb/testing/alpm.py b/aurweb/testing/alpm.py
index ce30d042..ddafb710 100644
--- a/aurweb/testing/alpm.py
+++ b/aurweb/testing/alpm.py
@@ -17,6 +17,7 @@ class AlpmDatabase:
This class can be used to add or remove packages from a
test repository.
"""
+
repo = "test"
def __init__(self, database_root: str):
@@ -35,13 +36,14 @@ class AlpmDatabase:
os.makedirs(pkgdir)
return pkgdir
- def add(self, pkgname: str, pkgver: str, arch: str,
- provides: list[str] = []) -> None:
+ def add(
+ self, pkgname: str, pkgver: str, arch: str, provides: list[str] = []
+ ) -> None:
context = {
"pkgname": pkgname,
"pkgver": pkgver,
"arch": arch,
- "provides": provides
+ "provides": provides,
}
template = base_template("testing/alpm_package.j2")
pkgdir = self._get_pkgdir(pkgname, pkgver, self.repo)
@@ -76,8 +78,9 @@ class AlpmDatabase:
self.clean()
cmdline = ["bash", "-c", "bsdtar -czvf ../test.db *"]
proc = subprocess.run(cmdline, cwd=self.repopath)
- assert proc.returncode == 0, \
- f"Bad return code while creating alpm database: {proc.returncode}"
+ assert (
+ proc.returncode == 0
+ ), f"Bad return code while creating alpm database: {proc.returncode}"
# Print out the md5 hash value of the new test.db.
test_db = os.path.join(self.remote, "test.db")
diff --git a/aurweb/testing/email.py b/aurweb/testing/email.py
index b3e3990b..057ff792 100644
--- a/aurweb/testing/email.py
+++ b/aurweb/testing/email.py
@@ -5,7 +5,6 @@ import email
import os
import re
import sys
-
from typing import TextIO
@@ -28,6 +27,7 @@ class Email:
print(email.headers)
"""
+
TEST_DIR = "test-emails"
def __init__(self, serial: int = 1, autoparse: bool = True):
@@ -61,7 +61,7 @@ class Email:
value = os.environ.get("PYTEST_CURRENT_TEST", "email").split(" ")[0]
if suite:
value = value.split(":")[0]
- return re.sub(r'(\/|\.|,|:)', "_", value)
+ return re.sub(r"(\/|\.|,|:)", "_", value)
@staticmethod
def count() -> int:
@@ -159,6 +159,6 @@ class Email:
lines += [
f"== Email #{i + 1} ==",
email.glue(),
- f"== End of Email #{i + 1}"
+ f"== End of Email #{i + 1}",
]
print("\n".join(lines), file=file)
diff --git a/aurweb/testing/filelock.py b/aurweb/testing/filelock.py
index 3a18c153..33b42cb3 100644
--- a/aurweb/testing/filelock.py
+++ b/aurweb/testing/filelock.py
@@ -1,6 +1,5 @@
import hashlib
import os
-
from typing import Callable
from posix_ipc import O_CREAT, Semaphore
diff --git a/aurweb/testing/git.py b/aurweb/testing/git.py
index 019d870f..216515c8 100644
--- a/aurweb/testing/git.py
+++ b/aurweb/testing/git.py
@@ -1,6 +1,5 @@
import os
import shlex
-
from subprocess import PIPE, Popen
from typing import Tuple
diff --git a/aurweb/testing/html.py b/aurweb/testing/html.py
index 8c923438..16b7322b 100644
--- a/aurweb/testing/html.py
+++ b/aurweb/testing/html.py
@@ -6,7 +6,7 @@ parser = etree.HTMLParser()
def parse_root(html: str) -> etree.Element:
- """ Parse an lxml.etree.ElementTree root from html content.
+ """Parse an lxml.etree.ElementTree root from html content.
:param html: HTML markup
:return: etree.Element
diff --git a/aurweb/testing/requests.py b/aurweb/testing/requests.py
index c97d1532..98312e9e 100644
--- a/aurweb/testing/requests.py
+++ b/aurweb/testing/requests.py
@@ -2,7 +2,8 @@ import aurweb.config
class User:
- """ A fake User model. """
+ """A fake User model."""
+
# Fake columns.
LangPreference = aurweb.config.get("options", "default_lang")
Timezone = aurweb.config.get("options", "default_timezone")
@@ -15,7 +16,8 @@ class User:
class Client:
- """ A fake FastAPI Request.client object. """
+ """A fake FastAPI Request.client object."""
+
# A fake host.
host = "127.0.0.1"
@@ -25,16 +27,19 @@ class URL:
class Request:
- """ A fake Request object which mimics a FastAPI Request for tests. """
+ """A fake Request object which mimics a FastAPI Request for tests."""
+
client = Client()
url = URL()
- def __init__(self,
- user: User = User(),
- authenticated: bool = False,
- method: str = "GET",
- headers: dict[str, str] = dict(),
- cookies: dict[str, str] = dict()) -> "Request":
+ def __init__(
+ self,
+ user: User = User(),
+ authenticated: bool = False,
+ method: str = "GET",
+ headers: dict[str, str] = dict(),
+ cookies: dict[str, str] = dict(),
+ ) -> "Request":
self.user = user
self.user.authenticated = authenticated
diff --git a/aurweb/testing/smtp.py b/aurweb/testing/smtp.py
index e5d67991..7596fbe9 100644
--- a/aurweb/testing/smtp.py
+++ b/aurweb/testing/smtp.py
@@ -2,7 +2,7 @@
class FakeSMTP:
- """ A fake version of smtplib.SMTP used for testing. """
+ """A fake version of smtplib.SMTP used for testing."""
starttls_enabled = False
use_ssl = False
@@ -41,5 +41,6 @@ class FakeSMTP:
class FakeSMTP_SSL(FakeSMTP):
- """ A fake version of smtplib.SMTP_SSL used for testing. """
+ """A fake version of smtplib.SMTP_SSL used for testing."""
+
use_ssl = True
diff --git a/aurweb/time.py b/aurweb/time.py
index a97ca986..505f17f5 100644
--- a/aurweb/time.py
+++ b/aurweb/time.py
@@ -1,5 +1,4 @@
import zoneinfo
-
from collections import OrderedDict
from datetime import datetime
from urllib.parse import unquote
@@ -11,7 +10,7 @@ import aurweb.config
def tz_offset(name: str):
- """ Get a timezone offset in the form "+00:00" by its name.
+ """Get a timezone offset in the form "+00:00" by its name.
Example: tz_offset('America/Los_Angeles')
@@ -24,7 +23,7 @@ def tz_offset(name: str):
offset = dt.utcoffset().total_seconds() / 60 / 60
# Prefix the offset string with a - or +.
- offset_string = '-' if offset < 0 else '+'
+ offset_string = "-" if offset < 0 else "+"
# Remove any negativity from the offset. We want a good offset. :)
offset = abs(offset)
@@ -42,19 +41,25 @@ def tz_offset(name: str):
return offset_string
-SUPPORTED_TIMEZONES = OrderedDict({
- # Flatten out the list of tuples into an OrderedDict.
- timezone: offset for timezone, offset in sorted([
- # Comprehend a list of tuples (timezone, offset display string)
- # and sort them by (offset, timezone).
- (tz, "(UTC%s) %s" % (tz_offset(tz), tz))
- for tz in zoneinfo.available_timezones()
- ], key=lambda element: (tz_offset(element[0]), element[0]))
-})
+SUPPORTED_TIMEZONES = OrderedDict(
+ {
+ # Flatten out the list of tuples into an OrderedDict.
+ timezone: offset
+ for timezone, offset in sorted(
+ [
+ # Comprehend a list of tuples (timezone, offset display string)
+ # and sort them by (offset, timezone).
+ (tz, "(UTC%s) %s" % (tz_offset(tz), tz))
+ for tz in zoneinfo.available_timezones()
+ ],
+ key=lambda element: (tz_offset(element[0]), element[0]),
+ )
+ }
+)
def get_request_timezone(request: Request):
- """ Get a request's timezone by its AURTZ cookie. We use the
+ """Get a request's timezone by its AURTZ cookie. We use the
configuration's [options] default_timezone otherwise.
@param request FastAPI request
diff --git a/aurweb/users/update.py b/aurweb/users/update.py
index ffea1f2f..51f2d2e0 100644
--- a/aurweb/users/update.py
+++ b/aurweb/users/update.py
@@ -8,12 +8,23 @@ from aurweb.models.ssh_pub_key import get_fingerprint
from aurweb.util import strtobool
-def simple(U: str = str(), E: str = str(), H: bool = False,
- BE: str = str(), R: str = str(), HP: str = str(),
- I: str = str(), K: str = str(), J: bool = False,
- CN: bool = False, UN: bool = False, ON: bool = False,
- S: bool = False, user: models.User = None,
- **kwargs) -> None:
+def simple(
+ U: str = str(),
+ E: str = str(),
+ H: bool = False,
+ BE: str = str(),
+ R: str = str(),
+ HP: str = str(),
+ I: str = str(),
+ K: str = str(),
+ J: bool = False,
+ CN: bool = False,
+ UN: bool = False,
+ ON: bool = False,
+ S: bool = False,
+ user: models.User = None,
+ **kwargs,
+) -> None:
now = time.utcnow()
with db.begin():
user.Username = U or user.Username
@@ -31,22 +42,26 @@ def simple(U: str = str(), E: str = str(), H: bool = False,
user.OwnershipNotify = strtobool(ON)
-def language(L: str = str(),
- request: Request = None,
- user: models.User = None,
- context: dict[str, Any] = {},
- **kwargs) -> None:
+def language(
+ L: str = str(),
+ request: Request = None,
+ user: models.User = None,
+ context: dict[str, Any] = {},
+ **kwargs,
+) -> None:
if L and L != user.LangPreference:
with db.begin():
user.LangPreference = L
context["language"] = L
-def timezone(TZ: str = str(),
- request: Request = None,
- user: models.User = None,
- context: dict[str, Any] = {},
- **kwargs) -> None:
+def timezone(
+ TZ: str = str(),
+ request: Request = None,
+ user: models.User = None,
+ context: dict[str, Any] = {},
+ **kwargs,
+) -> None:
if TZ and TZ != user.Timezone:
with db.begin():
user.Timezone = TZ
@@ -67,8 +82,7 @@ def ssh_pubkey(PK: str = str(), user: models.User = None, **kwargs) -> None:
with db.begin():
# Delete any existing keys we can't find.
- to_remove = user.ssh_pub_keys.filter(
- ~SSHPubKey.Fingerprint.in_(fprints))
+ to_remove = user.ssh_pub_keys.filter(~SSHPubKey.Fingerprint.in_(fprints))
db.delete_all(to_remove)
# For each key, if it does not yet exist, create it.
@@ -79,24 +93,27 @@ def ssh_pubkey(PK: str = str(), user: models.User = None, **kwargs) -> None:
).exists()
if not db.query(exists).scalar():
# No public key exists, create one.
- db.create(models.SSHPubKey, UserID=user.ID,
- PubKey=" ".join([prefix, key]),
- Fingerprint=fprints[i])
+ db.create(
+ models.SSHPubKey,
+ UserID=user.ID,
+ PubKey=" ".join([prefix, key]),
+ Fingerprint=fprints[i],
+ )
-def account_type(T: int = None,
- user: models.User = None,
- **kwargs) -> None:
+def account_type(T: int = None, user: models.User = None, **kwargs) -> None:
if T is not None and (T := int(T)) != user.AccountTypeID:
with db.begin():
user.AccountTypeID = T
-def password(P: str = str(),
- request: Request = None,
- user: models.User = None,
- context: dict[str, Any] = {},
- **kwargs) -> None:
+def password(
+ P: str = str(),
+ request: Request = None,
+ user: models.User = None,
+ context: dict[str, Any] = {},
+ **kwargs,
+) -> None:
if P and not user.valid_password(P):
# Remove the fields we consumed for passwords.
context["P"] = context["C"] = str()
diff --git a/aurweb/users/validate.py b/aurweb/users/validate.py
index de51e3ff..6c27a0b7 100644
--- a/aurweb/users/validate.py
+++ b/aurweb/users/validate.py
@@ -25,42 +25,44 @@ def invalid_fields(E: str = str(), U: str = str(), **kwargs) -> None:
raise ValidationError(["Missing a required field."])
-def invalid_suspend_permission(request: Request = None,
- user: models.User = None,
- S: str = "False",
- **kwargs) -> None:
+def invalid_suspend_permission(
+ request: Request = None, user: models.User = None, S: str = "False", **kwargs
+) -> None:
if not request.user.is_elevated() and strtobool(S) != bool(user.Suspended):
- raise ValidationError([
- "You do not have permission to suspend accounts."])
+ raise ValidationError(["You do not have permission to suspend accounts."])
-def invalid_username(request: Request = None, U: str = str(),
- _: l10n.Translator = None,
- **kwargs) -> None:
+def invalid_username(
+ request: Request = None, U: str = str(), _: l10n.Translator = None, **kwargs
+) -> None:
if not util.valid_username(U):
username_min_len = config.getint("options", "username_min_len")
username_max_len = config.getint("options", "username_max_len")
- raise ValidationError([
- "The username is invalid.",
+ raise ValidationError(
[
- _("It must be between %s and %s characters long") % (
- username_min_len, username_max_len),
- "Start and end with a letter or number",
- "Can contain only one period, underscore or hyphen.",
+ "The username is invalid.",
+ [
+ _("It must be between %s and %s characters long")
+ % (username_min_len, username_max_len),
+ "Start and end with a letter or number",
+ "Can contain only one period, underscore or hyphen.",
+ ],
]
- ])
+ )
-def invalid_password(P: str = str(), C: str = str(),
- _: l10n.Translator = None, **kwargs) -> None:
+def invalid_password(
+ P: str = str(), C: str = str(), _: l10n.Translator = None, **kwargs
+) -> None:
if P:
if not util.valid_password(P):
- username_min_len = config.getint(
- "options", "username_min_len")
- raise ValidationError([
- _("Your password must be at least %s characters.") % (
- username_min_len)
- ])
+ username_min_len = config.getint("options", "username_min_len")
+ raise ValidationError(
+ [
+ _("Your password must be at least %s characters.")
+ % (username_min_len)
+ ]
+ )
elif not C:
raise ValidationError(["Please confirm your new password."])
elif P != C:
@@ -71,15 +73,18 @@ def is_banned(request: Request = None, **kwargs) -> None:
host = request.client.host
exists = db.query(models.Ban, models.Ban.IPAddress == host).exists()
if db.query(exists).scalar():
- raise ValidationError([
- "Account registration has been disabled for your "
- "IP address, probably due to sustained spam attacks. "
- "Sorry for the inconvenience."
- ])
+ raise ValidationError(
+ [
+ "Account registration has been disabled for your "
+ "IP address, probably due to sustained spam attacks. "
+ "Sorry for the inconvenience."
+ ]
+ )
-def invalid_user_password(request: Request = None, passwd: str = str(),
- **kwargs) -> None:
+def invalid_user_password(
+ request: Request = None, passwd: str = str(), **kwargs
+) -> None:
if request.user.is_authenticated():
if not request.user.valid_password(passwd):
raise ValidationError(["Invalid password."])
@@ -97,8 +102,9 @@ def invalid_backup_email(BE: str = str(), **kwargs) -> None:
def invalid_homepage(HP: str = str(), **kwargs) -> None:
if HP and not util.valid_homepage(HP):
- raise ValidationError([
- "The home page is invalid, please specify the full HTTP(s) URL."])
+ raise ValidationError(
+ ["The home page is invalid, please specify the full HTTP(s) URL."]
+ )
def invalid_pgp_key(K: str = str(), **kwargs) -> None:
@@ -106,8 +112,9 @@ def invalid_pgp_key(K: str = str(), **kwargs) -> None:
raise ValidationError(["The PGP key fingerprint is invalid."])
-def invalid_ssh_pubkey(PK: str = str(), user: models.User = None,
- _: l10n.Translator = None, **kwargs) -> None:
+def invalid_ssh_pubkey(
+ PK: str = str(), user: models.User = None, _: l10n.Translator = None, **kwargs
+) -> None:
if not PK:
return
@@ -119,15 +126,23 @@ def invalid_ssh_pubkey(PK: str = str(), user: models.User = None,
for prefix, key in keys:
fingerprint = get_fingerprint(f"{prefix} {key}")
- exists = db.query(models.SSHPubKey).filter(
- and_(models.SSHPubKey.UserID != user.ID,
- models.SSHPubKey.Fingerprint == fingerprint)
- ).exists()
+ exists = (
+ db.query(models.SSHPubKey)
+ .filter(
+ and_(
+ models.SSHPubKey.UserID != user.ID,
+ models.SSHPubKey.Fingerprint == fingerprint,
+ )
+ )
+ .exists()
+ )
if db.query(exists).scalar():
- raise ValidationError([
- _("The SSH public key, %s%s%s, is already in use.") % (
- "", fingerprint, "")
- ])
+ raise ValidationError(
+ [
+ _("The SSH public key, %s%s%s, is already in use.")
+ % ("", fingerprint, "")
+ ]
+ )
def invalid_language(L: str = str(), **kwargs) -> None:
@@ -140,60 +155,78 @@ def invalid_timezone(TZ: str = str(), **kwargs) -> None:
raise ValidationError(["Timezone is not currently supported."])
-def username_in_use(U: str = str(), user: models.User = None,
- _: l10n.Translator = None, **kwargs) -> None:
- exists = db.query(models.User).filter(
- and_(models.User.ID != user.ID,
- models.User.Username == U)
- ).exists()
+def username_in_use(
+ U: str = str(), user: models.User = None, _: l10n.Translator = None, **kwargs
+) -> None:
+ exists = (
+ db.query(models.User)
+ .filter(and_(models.User.ID != user.ID, models.User.Username == U))
+ .exists()
+ )
if db.query(exists).scalar():
# If the username already exists...
- raise ValidationError([
- _("The username, %s%s%s, is already in use.") % (
- "", U, "")
- ])
+ raise ValidationError(
+ [
+ _("The username, %s%s%s, is already in use.")
+ % ("", U, "")
+ ]
+ )
-def email_in_use(E: str = str(), user: models.User = None,
- _: l10n.Translator = None, **kwargs) -> None:
- exists = db.query(models.User).filter(
- and_(models.User.ID != user.ID,
- models.User.Email == E)
- ).exists()
+def email_in_use(
+ E: str = str(), user: models.User = None, _: l10n.Translator = None, **kwargs
+) -> None:
+ exists = (
+ db.query(models.User)
+ .filter(and_(models.User.ID != user.ID, models.User.Email == E))
+ .exists()
+ )
if db.query(exists).scalar():
# If the email already exists...
- raise ValidationError([
- _("The address, %s%s%s, is already in use.") % (
- "", E, "")
- ])
+ raise ValidationError(
+ [
+ _("The address, %s%s%s, is already in use.")
+ % ("", E, "")
+ ]
+ )
-def invalid_account_type(T: int = None, request: Request = None,
- user: models.User = None,
- _: l10n.Translator = None,
- **kwargs) -> None:
+def invalid_account_type(
+ T: int = None,
+ request: Request = None,
+ user: models.User = None,
+ _: l10n.Translator = None,
+ **kwargs,
+) -> None:
if T is not None and (T := int(T)) != user.AccountTypeID:
name = ACCOUNT_TYPE_NAME.get(T, None)
has_cred = request.user.has_credential(creds.ACCOUNT_CHANGE_TYPE)
if name is None:
raise ValidationError(["Invalid account type provided."])
elif not has_cred:
- raise ValidationError([
- "You do not have permission to change account types."])
+ raise ValidationError(
+ ["You do not have permission to change account types."]
+ )
elif T > request.user.AccountTypeID:
# If the chosen account type is higher than the editor's account
# type, the editor doesn't have permission to set the new type.
- error = _("You do not have permission to change "
- "this user's account type to %s.") % name
+ error = (
+ _(
+ "You do not have permission to change "
+ "this user's account type to %s."
+ )
+ % name
+ )
raise ValidationError([error])
- logger.debug(f"Trusted User '{request.user.Username}' has "
- f"modified '{user.Username}' account's type to"
- f" {name}.")
+ logger.debug(
+ f"Trusted User '{request.user.Username}' has "
+ f"modified '{user.Username}' account's type to"
+ f" {name}."
+ )
-def invalid_captcha(captcha_salt: str = None, captcha: str = None,
- **kwargs) -> None:
+def invalid_captcha(captcha_salt: str = None, captcha: str = None, **kwargs) -> None:
if captcha_salt and captcha_salt not in get_captcha_salts():
raise ValidationError(["This CAPTCHA has expired. Please try again."])
diff --git a/aurweb/util.py b/aurweb/util.py
index 8291b578..4f1bd64e 100644
--- a/aurweb/util.py
+++ b/aurweb/util.py
@@ -2,7 +2,6 @@ import math
import re
import secrets
import string
-
from datetime import datetime
from http import HTTPStatus
from subprocess import PIPE, Popen
@@ -11,12 +10,10 @@ from urllib.parse import urlparse
import fastapi
import pygit2
-
from email_validator import EmailSyntaxError, validate_email
from fastapi.responses import JSONResponse
import aurweb.config
-
from aurweb import defaults, logging
logger = logging.get_logger(__name__)
@@ -24,15 +21,15 @@ logger = logging.get_logger(__name__)
def make_random_string(length: int) -> str:
alphanumerics = string.ascii_lowercase + string.digits
- return ''.join([secrets.choice(alphanumerics) for i in range(length)])
+ return "".join([secrets.choice(alphanumerics) for i in range(length)])
def make_nonce(length: int = 8):
- """ Generate a single random nonce. Here, token_hex generates a hex
+ """Generate a single random nonce. Here, token_hex generates a hex
string of 2 hex characters per byte, where the length give is
nbytes. This means that to get our proper string length, we need to
cut it in half and truncate off any remaining (in the case that
- length was uneven). """
+ length was uneven)."""
return secrets.token_hex(math.ceil(length / 2))[:length]
@@ -45,7 +42,7 @@ def valid_username(username):
# Check that username contains: one or more alphanumeric
# characters, an optional separator of '.', '-' or '_', followed
# by alphanumeric characters.
- return re.match(r'^[a-zA-Z0-9]+[.\-_]?[a-zA-Z0-9]+$', username)
+ return re.match(r"^[a-zA-Z0-9]+[.\-_]?[a-zA-Z0-9]+$", username)
def valid_email(email):
@@ -82,7 +79,7 @@ def valid_pgp_fingerprint(fp):
def jsonify(obj):
- """ Perform a conversion on obj if it's needed. """
+ """Perform a conversion on obj if it's needed."""
if isinstance(obj, datetime):
obj = int(obj.timestamp())
return obj
@@ -151,8 +148,7 @@ def git_search(repo: pygit2.Repository, commit_hash: str) -> int:
return prefixlen
-async def error_or_result(next: Callable, *args, **kwargs) \
- -> fastapi.Response:
+async def error_or_result(next: Callable, *args, **kwargs) -> fastapi.Response:
"""
Try to return a response from `next`.
@@ -174,9 +170,9 @@ async def error_or_result(next: Callable, *args, **kwargs) \
def parse_ssh_key(string: str) -> Tuple[str, str]:
- """ Parse an SSH public key. """
+ """Parse an SSH public key."""
invalid_exc = ValueError("The SSH public key is invalid.")
- parts = re.sub(r'\s\s+', ' ', string.strip()).split()
+ parts = re.sub(r"\s\s+", " ", string.strip()).split()
if len(parts) < 2:
raise invalid_exc
@@ -185,8 +181,7 @@ def parse_ssh_key(string: str) -> Tuple[str, str]:
if prefix not in prefixes:
raise invalid_exc
- proc = Popen(["ssh-keygen", "-l", "-f", "-"], stdin=PIPE, stdout=PIPE,
- stderr=PIPE)
+ proc = Popen(["ssh-keygen", "-l", "-f", "-"], stdin=PIPE, stdout=PIPE, stderr=PIPE)
out, _ = proc.communicate(f"{prefix} {key}".encode())
if proc.returncode:
raise invalid_exc
@@ -195,5 +190,5 @@ def parse_ssh_key(string: str) -> Tuple[str, str]:
def parse_ssh_keys(string: str) -> list[Tuple[str, str]]:
- """ Parse a list of SSH public keys. """
+ """Parse a list of SSH public keys."""
return [parse_ssh_key(e) for e in string.splitlines()]
diff --git a/doc/web-auth.md b/doc/web-auth.md
index 17284889..dbb4403d 100644
--- a/doc/web-auth.md
+++ b/doc/web-auth.md
@@ -108,4 +108,3 @@ The following list of steps describes exactly how this verification works:
- `options.disable_http_login: 1`
- `options.login_timeout: `
- `options.persistent_cookie_timeout: `
-
diff --git a/docker-compose.yml b/docker-compose.yml
index 9edffeeb..a1c2bb42 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -43,7 +43,7 @@ services:
healthcheck:
test: "bash /docker/health/memcached.sh"
interval: 3s
-
+
redis:
image: aurweb:latest
init: true
diff --git a/docker/config/nginx.conf b/docker/config/nginx.conf
index 9fdf6015..99804d1d 100644
--- a/docker/config/nginx.conf
+++ b/docker/config/nginx.conf
@@ -147,4 +147,3 @@ http {
'' close;
}
}
-
diff --git a/migrations/env.py b/migrations/env.py
index 774ecdeb..dcc0329d 100644
--- a/migrations/env.py
+++ b/migrations/env.py
@@ -2,7 +2,6 @@ import logging
import logging.config
import sqlalchemy
-
from alembic import context
import aurweb.db
@@ -69,9 +68,7 @@ def run_migrations_online():
)
with connectable.connect() as connection:
- context.configure(
- connection=connection, target_metadata=target_metadata
- )
+ context.configure(connection=connection, target_metadata=target_metadata)
with context.begin_transaction():
context.run_migrations()
diff --git a/po/ar.po b/po/ar.po
index 676a5025..ea0e03cf 100644
--- a/po/ar.po
+++ b/po/ar.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# safa1996alfulaij , 2015
# صفا الفليج , 2015-2016
diff --git a/po/ast.po b/po/ast.po
index 16c363a6..2075edc1 100644
--- a/po/ast.po
+++ b/po/ast.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# enolp , 2014-2015,2017
# Ḷḷumex03 , 2014
diff --git a/po/az.po b/po/az.po
index 7e534b4c..1c7ca207 100644
--- a/po/az.po
+++ b/po/az.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
msgid ""
msgstr ""
diff --git a/po/az_AZ.po b/po/az_AZ.po
index e903027b..2f5ceabd 100644
--- a/po/az_AZ.po
+++ b/po/az_AZ.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
msgid ""
msgstr ""
diff --git a/po/bg.po b/po/bg.po
index 7864f5dc..c7c70021 100644
--- a/po/bg.po
+++ b/po/bg.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
msgid ""
msgstr ""
diff --git a/po/ca.po b/po/ca.po
index 391dd146..d43c84dc 100644
--- a/po/ca.po
+++ b/po/ca.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Adolfo Jayme-Barrientos, 2014
# Hector Mtz-Seara , 2011,2013
diff --git a/po/ca_ES.po b/po/ca_ES.po
index bad69bd1..aac7b03f 100644
--- a/po/ca_ES.po
+++ b/po/ca_ES.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
msgid ""
msgstr ""
diff --git a/po/cs.po b/po/cs.po
index b9bd739a..59a24007 100644
--- a/po/cs.po
+++ b/po/cs.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Daniel Milde , 2017
# Daniel Peukert , 2021
diff --git a/po/da.po b/po/da.po
index a6f290ea..822b5506 100644
--- a/po/da.po
+++ b/po/da.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Linuxbruger , 2018
# Louis Tim Larsen , 2015
diff --git a/po/de.po b/po/de.po
index ec0a0fbe..a0f8fb0f 100644
--- a/po/de.po
+++ b/po/de.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# 9d91e189c22376bb4ee81489bc27fc28, 2013
# 9d91e189c22376bb4ee81489bc27fc28, 2013-2014
diff --git a/po/el.po b/po/el.po
index f1fe704e..37db785c 100644
--- a/po/el.po
+++ b/po/el.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Achilleas Pipinellis, 2014
# Achilleas Pipinellis, 2013
diff --git a/po/es.po b/po/es.po
index ea7ac099..9cbe98a6 100644
--- a/po/es.po
+++ b/po/es.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Adolfo Jayme-Barrientos, 2015
# Angel Velasquez , 2011
diff --git a/po/es_419.po b/po/es_419.po
index 444eccb7..e2b96ae6 100644
--- a/po/es_419.po
+++ b/po/es_419.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Angel Velasquez , 2011
# juantascon , 2011
diff --git a/po/et.po b/po/et.po
index 9b6493b5..44f2b3a0 100644
--- a/po/et.po
+++ b/po/et.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
msgid ""
msgstr ""
diff --git a/po/fi.po b/po/fi.po
index 39cfe626..636681b7 100644
--- a/po/fi.po
+++ b/po/fi.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Elias Autio, 2016
# Jesse Jaara , 2011-2012,2015
diff --git a/po/fi_FI.po b/po/fi_FI.po
index f3253433..17a58b4a 100644
--- a/po/fi_FI.po
+++ b/po/fi_FI.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
msgid ""
msgstr ""
diff --git a/po/fr.po b/po/fr.po
index 99d01460..03192d48 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Alexandre Macabies , 2018
# Antoine Lubineau , 2012
diff --git a/po/he.po b/po/he.po
index cd4a0f87..936e93a1 100644
--- a/po/he.po
+++ b/po/he.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# GenghisKhan , 2016
# Lukas Fleischer , 2011
diff --git a/po/hi_IN.po b/po/hi_IN.po
index 37fd082e..114c9461 100644
--- a/po/hi_IN.po
+++ b/po/hi_IN.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Panwar108 , 2018,2020-2021
msgid ""
diff --git a/po/hr.po b/po/hr.po
index 4932bd7e..fe1857c1 100644
--- a/po/hr.po
+++ b/po/hr.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Lukas Fleischer , 2011
msgid ""
diff --git a/po/hu.po b/po/hu.po
index 51894457..e6ebd451 100644
--- a/po/hu.po
+++ b/po/hu.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Balló György , 2013
# Balló György , 2011,2013-2016
diff --git a/po/id.po b/po/id.po
index 75a6c98b..103c47e6 100644
--- a/po/id.po
+++ b/po/id.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# se7entime , 2013
# se7entime , 2016
diff --git a/po/id_ID.po b/po/id_ID.po
index d01294c8..c3acb167 100644
--- a/po/id_ID.po
+++ b/po/id_ID.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
msgid ""
msgstr ""
diff --git a/po/is.po b/po/is.po
index a7a88b04..aee80ce5 100644
--- a/po/is.po
+++ b/po/is.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
msgid ""
msgstr ""
diff --git a/po/it.po b/po/it.po
index 436b6459..f583cb2f 100644
--- a/po/it.po
+++ b/po/it.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Fanfurlio Farolfi , 2021-2022
# Giovanni Scafora , 2011-2015
diff --git a/po/ja.po b/po/ja.po
index 55d056bf..280edb46 100644
--- a/po/ja.po
+++ b/po/ja.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# kusakata, 2013
# kusakata, 2013
diff --git a/po/ko.po b/po/ko.po
index 808ffe27..6da57759 100644
--- a/po/ko.po
+++ b/po/ko.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
msgid ""
msgstr ""
diff --git a/po/lt.po b/po/lt.po
index d126f193..c9f55632 100644
--- a/po/lt.po
+++ b/po/lt.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
msgid ""
msgstr ""
diff --git a/po/nb.po b/po/nb.po
index 1cc090f1..307a80d6 100644
--- a/po/nb.po
+++ b/po/nb.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Alexander F. Rødseth , 2015,2017-2019
# Alexander F. Rødseth , 2011,2013-2014
diff --git a/po/nb_NO.po b/po/nb_NO.po
index 74af6936..5d958172 100644
--- a/po/nb_NO.po
+++ b/po/nb_NO.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Kim Nordmo , 2017,2019
# Lukas Fleischer , 2011
diff --git a/po/nl.po b/po/nl.po
index 282b5b40..54519d21 100644
--- a/po/nl.po
+++ b/po/nl.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Heimen Stoffels , 2021-2022
# Heimen Stoffels , 2015,2021
diff --git a/po/pl.po b/po/pl.po
index 4856f22b..94a6fb67 100644
--- a/po/pl.po
+++ b/po/pl.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Bartłomiej Piotrowski , 2011
# Bartłomiej Piotrowski , 2014
diff --git a/po/pt.po b/po/pt.po
index b2cf86b2..aed32031 100644
--- a/po/pt.po
+++ b/po/pt.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Lukas Fleischer , 2011
msgid ""
diff --git a/po/pt_BR.po b/po/pt_BR.po
index c9c15d72..d29a9448 100644
--- a/po/pt_BR.po
+++ b/po/pt_BR.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Albino Biasutti Neto Bino , 2011
# Fábio Nogueira , 2016
diff --git a/po/pt_PT.po b/po/pt_PT.po
index 3518cb7b..7f6ea67a 100644
--- a/po/pt_PT.po
+++ b/po/pt_PT.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Christophe Silva , 2018
# Gaspar Santos , 2011
diff --git a/po/ro.po b/po/ro.po
index fa159928..4409b698 100644
--- a/po/ro.po
+++ b/po/ro.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Arthur Țițeică , 2013-2015
# Lukas Fleischer , 2011
diff --git a/po/ru.po b/po/ru.po
index 75550c8c..44f000dd 100644
--- a/po/ru.po
+++ b/po/ru.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Alex , 2021
# Evgeniy Alekseev , 2014-2015
diff --git a/po/sk.po b/po/sk.po
index 76d3d1a8..853fc198 100644
--- a/po/sk.po
+++ b/po/sk.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# archetyp , 2013-2016
# Jose Riha , 2018
diff --git a/po/sr.po b/po/sr.po
index dae37bcd..426ce599 100644
--- a/po/sr.po
+++ b/po/sr.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Lukas Fleischer , 2011
# Slobodan Terzić , 2011-2012,2015-2017
diff --git a/po/sr_RS.po b/po/sr_RS.po
index 985ee007..b7560965 100644
--- a/po/sr_RS.po
+++ b/po/sr_RS.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Nikola Stojković , 2013
msgid ""
diff --git a/po/sv_SE.po b/po/sv_SE.po
index 6abb8452..4887fdde 100644
--- a/po/sv_SE.po
+++ b/po/sv_SE.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Johannes Löthberg , 2015-2016
# Kevin Morris , 2022
diff --git a/po/tr.po b/po/tr.po
index 83b1e4df..559a0008 100644
--- a/po/tr.po
+++ b/po/tr.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# tarakbumba , 2011,2013-2015
# tarakbumba , 2012,2014
diff --git a/po/uk.po b/po/uk.po
index a4410185..3bffe4f6 100644
--- a/po/uk.po
+++ b/po/uk.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Lukas Fleischer , 2011
# Rax Garfield , 2012
diff --git a/po/vi.po b/po/vi.po
index 3ea5bad3..87f7faac 100644
--- a/po/vi.po
+++ b/po/vi.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
msgid ""
msgstr ""
diff --git a/po/zh.po b/po/zh.po
index 04fe06f3..c932df9c 100644
--- a/po/zh.po
+++ b/po/zh.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
msgid ""
msgstr ""
diff --git a/po/zh_CN.po b/po/zh_CN.po
index 53d42bc8..675d15a3 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# Feng Chao , 2015-2016
# dongfengweixiao , 2015
diff --git a/po/zh_TW.po b/po/zh_TW.po
index e7399a19..1526b4a9 100644
--- a/po/zh_TW.po
+++ b/po/zh_TW.po
@@ -1,7 +1,7 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the AURWEB package.
-#
+#
# Translators:
# pan93412 , 2018
# 黃柏諺 , 2014-2017
diff --git a/schema/gendummydata.py b/schema/gendummydata.py
index aedfda7e..fa59855f 100755
--- a/schema/gendummydata.py
+++ b/schema/gendummydata.py
@@ -15,27 +15,26 @@ import os
import random
import sys
import time
-
from datetime import datetime
import bcrypt
LOG_LEVEL = logging.DEBUG # logging level. set to logging.INFO to reduce output
SEED_FILE = "/usr/share/dict/words"
-USER_ID = 5 # Users.ID of first bogus user
-PKG_ID = 1 # Packages.ID of first package
+USER_ID = 5 # Users.ID of first bogus user
+PKG_ID = 1 # Packages.ID of first package
# how many users to 'register'
MAX_USERS = int(os.environ.get("MAX_USERS", 38000))
-MAX_DEVS = .1 # what percentage of MAX_USERS are Developers
-MAX_TUS = .2 # what percentage of MAX_USERS are Trusted Users
+MAX_DEVS = 0.1 # what percentage of MAX_USERS are Developers
+MAX_TUS = 0.2 # what percentage of MAX_USERS are Trusted Users
# how many packages to load
MAX_PKGS = int(os.environ.get("MAX_PKGS", 32000))
-PKG_DEPS = (1, 15) # min/max depends a package has
-PKG_RELS = (1, 5) # min/max relations a package has
-PKG_SRC = (1, 3) # min/max sources a package has
-PKG_CMNTS = (1, 5) # min/max number of comments a package has
+PKG_DEPS = (1, 15) # min/max depends a package has
+PKG_RELS = (1, 5) # min/max relations a package has
+PKG_SRC = (1, 3) # min/max sources a package has
+PKG_CMNTS = (1, 5) # min/max number of comments a package has
CATEGORIES_COUNT = 17 # the number of categories from aur-schema
-VOTING = (0, .001) # percentage range for package voting
+VOTING = (0, 0.001) # percentage range for package voting
# number of open trusted user proposals
OPEN_PROPOSALS = int(os.environ.get("OPEN_PROPOSALS", 15))
# number of closed trusted user proposals
@@ -113,10 +112,10 @@ if not len(contents) - MAX_USERS > MAX_PKGS:
def normalize(unicode_data):
- """ We only accept ascii for usernames. Also use this to normalize
+ """We only accept ascii for usernames. Also use this to normalize
package names; our database utf8mb4 collations compare with Unicode
- Equivalence. """
- return unicode_data.encode('ascii', 'ignore').decode('ascii')
+ Equivalence."""
+ return unicode_data.encode("ascii", "ignore").decode("ascii")
# select random usernames
@@ -196,10 +195,12 @@ for u in user_keys:
# "{salt}{username}"
to_hash = f"{salt}{u}"
- h = hashlib.new('md5')
+ h = hashlib.new("md5")
h.update(to_hash.encode())
- s = ("INSERT INTO Users (ID, AccountTypeID, Username, Email, Passwd, Salt)"
- " VALUES (%d, %d, '%s', '%s@example.com', '%s', '%s');\n")
+ s = (
+ "INSERT INTO Users (ID, AccountTypeID, Username, Email, Passwd, Salt)"
+ " VALUES (%d, %d, '%s', '%s@example.com', '%s', '%s');\n"
+ )
s = s % (seen_users[u], account_type, u, u, h.hexdigest(), salt)
out.write(s)
@@ -230,13 +231,17 @@ for p in list(seen_pkgs.keys()):
uuid = genUID() # the submitter/user
- s = ("INSERT INTO PackageBases (ID, Name, FlaggerComment, SubmittedTS, ModifiedTS, "
- "SubmitterUID, MaintainerUID, PackagerUID) VALUES (%d, '%s', '', %d, %d, %d, %s, %s);\n")
+ s = (
+ "INSERT INTO PackageBases (ID, Name, FlaggerComment, SubmittedTS, ModifiedTS, "
+ "SubmitterUID, MaintainerUID, PackagerUID) VALUES (%d, '%s', '', %d, %d, %d, %s, %s);\n"
+ )
s = s % (seen_pkgs[p], p, NOW, NOW, uuid, muid, puid)
out.write(s)
- s = ("INSERT INTO Packages (ID, PackageBaseID, Name, Version) VALUES "
- "(%d, %d, '%s', '%s');\n")
+ s = (
+ "INSERT INTO Packages (ID, PackageBaseID, Name, Version) VALUES "
+ "(%d, %d, '%s', '%s');\n"
+ )
s = s % (seen_pkgs[p], seen_pkgs[p], p, genVersion())
out.write(s)
@@ -247,8 +252,10 @@ for p in list(seen_pkgs.keys()):
num_comments = random.randrange(PKG_CMNTS[0], PKG_CMNTS[1])
for i in range(0, num_comments):
now = NOW + random.randrange(400, 86400 * 3)
- s = ("INSERT INTO PackageComments (PackageBaseID, UsersID,"
- " Comments, RenderedComment, CommentTS) VALUES (%d, %d, '%s', '', %d);\n")
+ s = (
+ "INSERT INTO PackageComments (PackageBaseID, UsersID,"
+ " Comments, RenderedComment, CommentTS) VALUES (%d, %d, '%s', '', %d);\n"
+ )
s = s % (seen_pkgs[p], genUID(), genFortune(), now)
out.write(s)
@@ -258,14 +265,17 @@ utcnow = int(datetime.utcnow().timestamp())
track_votes = {}
log.debug("Casting votes for packages.")
for u in user_keys:
- num_votes = random.randrange(int(len(seen_pkgs) * VOTING[0]),
- int(len(seen_pkgs) * VOTING[1]))
+ num_votes = random.randrange(
+ int(len(seen_pkgs) * VOTING[0]), int(len(seen_pkgs) * VOTING[1])
+ )
pkgvote = {}
for v in range(num_votes):
pkg = random.randrange(1, len(seen_pkgs) + 1)
if pkg not in pkgvote:
- s = ("INSERT INTO PackageVotes (UsersID, PackageBaseID, VoteTS)"
- " VALUES (%d, %d, %d);\n")
+ s = (
+ "INSERT INTO PackageVotes (UsersID, PackageBaseID, VoteTS)"
+ " VALUES (%d, %d, %d);\n"
+ )
s = s % (seen_users[u], pkg, utcnow)
pkgvote[pkg] = 1
if pkg not in track_votes:
@@ -310,9 +320,12 @@ for p in seen_pkgs_keys:
src_file = user_keys[random.randrange(0, len(user_keys))]
src = "%s%s.%s/%s/%s-%s.tar.gz" % (
RANDOM_URL[random.randrange(0, len(RANDOM_URL))],
- p, RANDOM_TLDS[random.randrange(0, len(RANDOM_TLDS))],
+ p,
+ RANDOM_TLDS[random.randrange(0, len(RANDOM_TLDS))],
RANDOM_LOCS[random.randrange(0, len(RANDOM_LOCS))],
- src_file, genVersion())
+ src_file,
+ genVersion(),
+ )
s = "INSERT INTO PackageSources(PackageID, Source) VALUES (%d, '%s');\n"
s = s % (seen_pkgs[p], src)
out.write(s)
@@ -334,8 +347,10 @@ for t in range(0, OPEN_PROPOSALS + CLOSE_PROPOSALS):
else:
user = user_keys[random.randrange(0, len(user_keys))]
suid = trustedusers[random.randrange(0, len(trustedusers))]
- s = ("INSERT INTO TU_VoteInfo (Agenda, User, Submitted, End,"
- " Quorum, SubmitterID) VALUES ('%s', '%s', %d, %d, 0.0, %d);\n")
+ s = (
+ "INSERT INTO TU_VoteInfo (Agenda, User, Submitted, End,"
+ " Quorum, SubmitterID) VALUES ('%s', '%s', %d, %d, 0.0, %d);\n"
+ )
s = s % (genFortune(), user, start, end, suid)
out.write(s)
count += 1
diff --git a/templates/addvote.html b/templates/addvote.html
index 4d2b0292..8777cbf3 100644
--- a/templates/addvote.html
+++ b/templates/addvote.html
@@ -65,4 +65,3 @@
{% endblock %}
-
diff --git a/templates/home.html b/templates/home.html
index c1f172f4..6a5fca69 100644
--- a/templates/home.html
+++ b/templates/home.html
@@ -5,7 +5,7 @@
| tr
| format('', "",
'', "")
- | safe
+ | safe
}}
{{ "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s otherwise they will be deleted!"
| tr
@@ -61,7 +61,7 @@
{% trans %}The following SSH fingerprints are used for the AUR:{% endtrans %}
- {% for keytype in ssh_fingerprints %}
+ {% for keytype in ssh_fingerprints %}
{{ keytype }}
: {{ ssh_fingerprints[keytype] }}
{% endfor %}
@@ -85,7 +85,7 @@
| tr
| format('', "",
"", "")
- | safe
+ | safe
}}
diff --git a/templates/packages/index.html b/templates/packages/index.html
index 6034d2f6..58ce8648 100644
--- a/templates/packages/index.html
+++ b/templates/packages/index.html
@@ -12,7 +12,7 @@
{% elif not packages_count %}
- {% include "partials/packages/search.html" %}
+ {% include "partials/packages/search.html" %}
{{ "No packages matched your search criteria." | tr }}
diff --git a/templates/partials/account/results.html b/templates/partials/account/results.html
index 1c398ce1..ef8d927a 100644
--- a/templates/partials/account/results.html
+++ b/templates/partials/account/results.html
@@ -79,4 +79,3 @@
-
diff --git a/templates/tu/show.html b/templates/tu/show.html
index c36a3e8f..f4214018 100644
--- a/templates/tu/show.html
+++ b/templates/tu/show.html
@@ -4,7 +4,7 @@
{% include "partials/tu/proposal/details.html" %}
-
+
{% if utcnow >= voteinfo.End %}
{% include "partials/tu/proposal/voters.html" %}
diff --git a/test/conftest.py b/test/conftest.py
index 283c979a..aac221f7 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -39,12 +39,10 @@ ahead of each function takes too long when compared to this method.
"""
import os
import pathlib
-
from multiprocessing import Lock
import py
import pytest
-
from posix_ipc import O_CREAT, Semaphore
from sqlalchemy import create_engine
from sqlalchemy.engine import URL
@@ -54,7 +52,6 @@ from sqlalchemy.orm import scoped_session
import aurweb.config
import aurweb.db
-
from aurweb import initdb, logging, testing
from aurweb.testing.email import Email
from aurweb.testing.filelock import FileLock
@@ -78,13 +75,10 @@ def test_engine() -> Engine:
unix_socket = aurweb.config.get_with_fallback("database", "socket", None)
kwargs = {
"username": aurweb.config.get("database", "user"),
- "password": aurweb.config.get_with_fallback(
- "database", "password", None),
+ "password": aurweb.config.get_with_fallback("database", "password", None),
"host": aurweb.config.get("database", "host"),
"port": aurweb.config.get_with_fallback("database", "port", None),
- "query": {
- "unix_socket": unix_socket
- }
+ "query": {"unix_socket": unix_socket},
}
backend = aurweb.config.get("database", "backend")
@@ -99,6 +93,7 @@ class AlembicArgs:
This structure is needed to pass conftest-specific arguments
to initdb.run duration database creation.
"""
+
verbose = False
use_alembic = True
@@ -156,7 +151,7 @@ def setup_email():
@pytest.fixture(scope="module")
def setup_database(tmp_path_factory: pathlib.Path, worker_id: str) -> None:
- """ Create and drop a database for the suite this fixture is used in. """
+ """Create and drop a database for the suite this fixture is used in."""
engine = test_engine()
dbname = aurweb.db.name()
diff --git a/test/test_accepted_term.py b/test/test_accepted_term.py
index 2af7127b..9af19105 100644
--- a/test/test_accepted_term.py
+++ b/test/test_accepted_term.py
@@ -1,5 +1,4 @@
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db
@@ -17,17 +16,21 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- RealName="Test User", Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
@pytest.fixture
def term() -> Term:
with db.begin():
- term = db.create(Term, Description="Test term",
- URL="https://test.term")
+ term = db.create(Term, Description="Test term", URL="https://test.term")
yield term
diff --git a/test/test_account_type.py b/test/test_account_type.py
index 1d71f878..4b56b7ff 100644
--- a/test/test_account_type.py
+++ b/test/test_account_type.py
@@ -22,26 +22,30 @@ def account_type() -> AccountType:
def test_account_type(account_type):
- """ Test creating an AccountType, and reading its columns. """
+ """Test creating an AccountType, and reading its columns."""
# Make sure it got db.created and was given an ID.
assert bool(account_type.ID)
# Next, test our string functions.
assert str(account_type) == "TestUser"
- assert repr(account_type) == \
- "
" % (
- account_type.ID)
+ assert repr(account_type) == "" % (
+ account_type.ID
+ )
- record = db.query(AccountType,
- AccountType.AccountType == "TestUser").first()
+ record = db.query(AccountType, AccountType.AccountType == "TestUser").first()
assert account_type == record
def test_user_account_type_relationship(account_type):
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- RealName="Test User", Passwd="testPassword",
- AccountType=account_type)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User",
+ Passwd="testPassword",
+ AccountType=account_type,
+ )
assert user.AccountType == account_type
diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py
index 37b3d130..eab8fa4f 100644
--- a/test/test_accounts_routes.py
+++ b/test/test_accounts_routes.py
@@ -1,6 +1,5 @@
import re
import tempfile
-
from datetime import datetime
from http import HTTPStatus
from logging import DEBUG
@@ -8,17 +7,21 @@ from subprocess import Popen
import lxml.html
import pytest
-
from fastapi.testclient import TestClient
import aurweb.models.account_type as at
-
from aurweb import captcha, db, logging, time
from aurweb.asgi import app
from aurweb.db import create, query
from aurweb.models.accepted_term import AcceptedTerm
-from aurweb.models.account_type import (DEVELOPER_ID, TRUSTED_USER, TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID, USER_ID,
- AccountType)
+from aurweb.models.account_type import (
+ DEVELOPER_ID,
+ TRUSTED_USER,
+ TRUSTED_USER_AND_DEV_ID,
+ TRUSTED_USER_ID,
+ USER_ID,
+ AccountType,
+)
from aurweb.models.ban import Ban
from aurweb.models.session import Session
from aurweb.models.ssh_pub_key import SSHPubKey, get_fingerprint
@@ -39,8 +42,11 @@ def make_ssh_pubkey():
# dependency to passing this test).
with tempfile.TemporaryDirectory() as tmpdir:
with open("/dev/null", "w") as null:
- proc = Popen(["ssh-keygen", "-f", f"{tmpdir}/test.ssh", "-N", ""],
- stdout=null, stderr=null)
+ proc = Popen(
+ ["ssh-keygen", "-f", f"{tmpdir}/test.ssh", "-N", ""],
+ stdout=null,
+ stderr=null,
+ )
proc.wait()
assert proc.returncode == 0
@@ -60,9 +66,13 @@ def client() -> TestClient:
def create_user(username: str) -> User:
email = f"{username}@example.org"
- user = create(User, Username=username, Email=email,
- Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user = create(
+ User,
+ Username=username,
+ Email=email,
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
return user
@@ -85,8 +95,9 @@ def test_get_passreset_authed_redirects(client: TestClient, user: User):
assert sid is not None
with client as request:
- response = request.get("/passreset", cookies={"AURSID": sid},
- allow_redirects=False)
+ response = request.get(
+ "/passreset", cookies={"AURSID": sid}, allow_redirects=False
+ )
assert response.status_code == int(HTTPStatus.SEE_OTHER)
assert response.headers.get("location") == "/"
@@ -129,10 +140,12 @@ def test_post_passreset_authed_redirects(client: TestClient, user: User):
assert sid is not None
with client as request:
- response = request.post("/passreset",
- cookies={"AURSID": sid},
- data={"user": "blah"},
- allow_redirects=False)
+ response = request.post(
+ "/passreset",
+ cookies={"AURSID": sid},
+ data={"user": "blah"},
+ allow_redirects=False,
+ )
assert response.status_code == int(HTTPStatus.SEE_OTHER)
assert response.headers.get("location") == "/"
@@ -166,8 +179,9 @@ def test_post_passreset_user_suspended(client: TestClient, user: User):
def test_post_passreset_resetkey(client: TestClient, user: User):
with db.begin():
- user.session = Session(UsersID=user.ID, SessionID="blah",
- LastUpdateTS=time.utcnow())
+ user.session = Session(
+ UsersID=user.ID, SessionID="blah", LastUpdateTS=time.utcnow()
+ )
# Prepare a password reset.
with client as request:
@@ -182,7 +196,7 @@ def test_post_passreset_resetkey(client: TestClient, user: User):
"user": TEST_USERNAME,
"resetkey": resetkey,
"password": "abcd1234",
- "confirm": "abcd1234"
+ "confirm": "abcd1234",
}
with client as request:
@@ -200,10 +214,7 @@ def make_resetkey(client: TestClient, user: User):
def make_passreset_data(user: User, resetkey: str):
- return {
- "user": user.Username,
- "resetkey": resetkey
- }
+ return {"user": user.Username, "resetkey": resetkey}
def test_post_passreset_error_invalid_email(client: TestClient, user: User):
@@ -240,8 +251,7 @@ def test_post_passreset_error_missing_field(client: TestClient, user: User):
assert error in response.content.decode("utf-8")
-def test_post_passreset_error_password_mismatch(client: TestClient,
- user: User):
+def test_post_passreset_error_password_mismatch(client: TestClient, user: User):
resetkey = make_resetkey(client, user)
post_data = make_passreset_data(user, resetkey)
@@ -257,8 +267,7 @@ def test_post_passreset_error_password_mismatch(client: TestClient,
assert error in response.content.decode("utf-8")
-def test_post_passreset_error_password_requirements(client: TestClient,
- user: User):
+def test_post_passreset_error_password_requirements(client: TestClient, user: User):
resetkey = make_resetkey(client, user)
post_data = make_passreset_data(user, resetkey)
@@ -284,7 +293,7 @@ def test_get_register(client: TestClient):
def post_register(request, **kwargs):
- """ A simple helper that allows overrides to test defaults. """
+ """A simple helper that allows overrides to test defaults."""
salt = captcha.get_captcha_salts()[0]
token = captcha.get_captcha_token(salt)
answer = captcha.get_captcha_answer(token)
@@ -297,7 +306,7 @@ def post_register(request, **kwargs):
"L": "en",
"TZ": "UTC",
"captcha": answer,
- "captcha_salt": salt
+ "captcha_salt": salt,
}
# For any kwargs given, override their k:v pairs in data.
@@ -380,9 +389,11 @@ def test_post_register_error_ip_banned(client: TestClient):
assert response.status_code == int(HTTPStatus.BAD_REQUEST)
content = response.content.decode()
- assert ("Account registration has been disabled for your IP address, " +
- "probably due to sustained spam attacks. Sorry for the " +
- "inconvenience.") in content
+ assert (
+ "Account registration has been disabled for your IP address, "
+ + "probably due to sustained spam attacks. Sorry for the "
+ + "inconvenience."
+ ) in content
def test_post_register_error_missing_username(client: TestClient):
@@ -489,7 +500,7 @@ def test_post_register_error_invalid_pgp_fingerprints(client: TestClient):
expected = "The PGP key fingerprint is invalid."
assert expected in content
- pk = 'z' + ('a' * 39)
+ pk = "z" + ("a" * 39)
with client as request:
response = post_register(request, K=pk)
@@ -569,8 +580,11 @@ def test_post_register_error_ssh_pubkey_taken(client: TestClient, user: User):
# dependency to passing this test).
with tempfile.TemporaryDirectory() as tmpdir:
with open("/dev/null", "w") as null:
- proc = Popen(["ssh-keygen", "-f", f"{tmpdir}/test.ssh", "-N", ""],
- stdout=null, stderr=null)
+ proc = Popen(
+ ["ssh-keygen", "-f", f"{tmpdir}/test.ssh", "-N", ""],
+ stdout=null,
+ stderr=null,
+ )
proc.wait()
assert proc.returncode == 0
@@ -602,8 +616,11 @@ def test_post_register_with_ssh_pubkey(client: TestClient):
# dependency to passing this test).
with tempfile.TemporaryDirectory() as tmpdir:
with open("/dev/null", "w") as null:
- proc = Popen(["ssh-keygen", "-f", f"{tmpdir}/test.ssh", "-N", ""],
- stdout=null, stderr=null)
+ proc = Popen(
+ ["ssh-keygen", "-f", f"{tmpdir}/test.ssh", "-N", ""],
+ stdout=null,
+ stderr=null,
+ )
proc.wait()
assert proc.returncode == 0
@@ -617,7 +634,7 @@ def test_post_register_with_ssh_pubkey(client: TestClient):
def test_get_account_edit_tu_as_tu(client: TestClient, tu_user: User):
- """ Test edit get route of another TU as a TU. """
+ """Test edit get route of another TU as a TU."""
with db.begin():
user2 = create_user("test2")
user2.AccountTypeID = at.TRUSTED_USER_ID
@@ -643,7 +660,7 @@ def test_get_account_edit_tu_as_tu(client: TestClient, tu_user: User):
def test_get_account_edit_as_tu(client: TestClient, tu_user: User):
- """ Test edit get route of another user as a TU. """
+ """Test edit get route of another user as a TU."""
with db.begin():
user2 = create_user("test2")
@@ -669,7 +686,7 @@ def test_get_account_edit_as_tu(client: TestClient, tu_user: User):
def test_get_account_edit_type(client: TestClient, user: User):
- """ Test that users do not have an Account Type field. """
+ """Test that users do not have an Account Type field."""
cookies = {"AURSID": user.login(Request(), "testPassword")}
endpoint = f"/account/{user.Username}/edit"
@@ -700,14 +717,18 @@ def test_get_account_edit_unauthorized(client: TestClient, user: User):
sid = user.login(request, "testPassword")
with db.begin():
- user2 = create(User, Username="test2", Email="test2@example.org",
- Passwd="testPassword", AccountTypeID=USER_ID)
+ user2 = create(
+ User,
+ Username="test2",
+ Email="test2@example.org",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
endpoint = f"/account/{user2.Username}/edit"
with client as request:
# Try to edit `test2` while authenticated as `test`.
- response = request.get(endpoint, cookies={"AURSID": sid},
- allow_redirects=False)
+ response = request.get(endpoint, cookies={"AURSID": sid}, allow_redirects=False)
assert response.status_code == int(HTTPStatus.SEE_OTHER)
expected = f"/account/{user2.Username}"
@@ -718,16 +739,15 @@ def test_post_account_edit(client: TestClient, user: User):
request = Request()
sid = user.login(request, "testPassword")
- post_data = {
- "U": "test",
- "E": "test666@example.org",
- "passwd": "testPassword"
- }
+ post_data = {"U": "test", "E": "test666@example.org", "passwd": "testPassword"}
with client as request:
- response = request.post("/account/test/edit", cookies={
- "AURSID": sid
- }, data=post_data, allow_redirects=False)
+ response = request.post(
+ "/account/test/edit",
+ cookies={"AURSID": sid},
+ data=post_data,
+ allow_redirects=False,
+ )
assert response.status_code == int(HTTPStatus.OK)
@@ -772,8 +792,7 @@ def test_post_account_edit_type_as_dev(client: TestClient, tu_user: User):
assert user2.AccountTypeID == at.DEVELOPER_ID
-def test_post_account_edit_invalid_type_as_tu(client: TestClient,
- tu_user: User):
+def test_post_account_edit_invalid_type_as_tu(client: TestClient, tu_user: User):
with db.begin():
user2 = create_user("test_tu")
tu_user.AccountTypeID = at.TRUSTED_USER_ID
@@ -792,8 +811,10 @@ def test_post_account_edit_invalid_type_as_tu(client: TestClient,
assert user2.AccountTypeID == at.USER_ID
errors = get_errors(resp.text)
- expected = ("You do not have permission to change this user's "
- f"account type to {at.DEVELOPER}.")
+ expected = (
+ "You do not have permission to change this user's "
+ f"account type to {at.DEVELOPER}."
+ )
assert errors[0].text.strip() == expected
@@ -807,16 +828,13 @@ def test_post_account_edit_dev(client: TestClient, tu_user: User):
request = Request()
sid = tu_user.login(request, "testPassword")
- post_data = {
- "U": "test",
- "E": "test666@example.org",
- "passwd": "testPassword"
- }
+ post_data = {"U": "test", "E": "test666@example.org", "passwd": "testPassword"}
endpoint = f"/account/{tu_user.Username}/edit"
with client as request:
- response = request.post(endpoint, cookies={"AURSID": sid},
- data=post_data, allow_redirects=False)
+ response = request.post(
+ endpoint, cookies={"AURSID": sid}, data=post_data, allow_redirects=False
+ )
assert response.status_code == int(HTTPStatus.OK)
expected = "The account, test, "
@@ -832,13 +850,16 @@ def test_post_account_edit_language(client: TestClient, user: User):
"U": "test",
"E": "test@example.org",
"L": "de", # German
- "passwd": "testPassword"
+ "passwd": "testPassword",
}
with client as request:
- response = request.post("/account/test/edit", cookies={
- "AURSID": sid
- }, data=post_data, allow_redirects=False)
+ response = request.post(
+ "/account/test/edit",
+ cookies={"AURSID": sid},
+ data=post_data,
+ allow_redirects=False,
+ )
assert response.status_code == int(HTTPStatus.OK)
@@ -859,33 +880,33 @@ def test_post_account_edit_timezone(client: TestClient, user: User):
"U": "test",
"E": "test@example.org",
"TZ": "CET",
- "passwd": "testPassword"
+ "passwd": "testPassword",
}
with client as request:
- response = request.post("/account/test/edit", cookies={
- "AURSID": sid
- }, data=post_data, allow_redirects=False)
+ response = request.post(
+ "/account/test/edit",
+ cookies={"AURSID": sid},
+ data=post_data,
+ allow_redirects=False,
+ )
assert response.status_code == int(HTTPStatus.OK)
-def test_post_account_edit_error_missing_password(client: TestClient,
- user: User):
+def test_post_account_edit_error_missing_password(client: TestClient, user: User):
request = Request()
sid = user.login(request, "testPassword")
- post_data = {
- "U": "test",
- "E": "test@example.org",
- "TZ": "CET",
- "passwd": ""
- }
+ post_data = {"U": "test", "E": "test@example.org", "TZ": "CET", "passwd": ""}
with client as request:
- response = request.post("/account/test/edit", cookies={
- "AURSID": sid
- }, data=post_data, allow_redirects=False)
+ response = request.post(
+ "/account/test/edit",
+ cookies={"AURSID": sid},
+ data=post_data,
+ allow_redirects=False,
+ )
assert response.status_code == int(HTTPStatus.BAD_REQUEST)
@@ -893,22 +914,19 @@ def test_post_account_edit_error_missing_password(client: TestClient,
assert "Invalid password." in content
-def test_post_account_edit_error_invalid_password(client: TestClient,
- user: User):
+def test_post_account_edit_error_invalid_password(client: TestClient, user: User):
request = Request()
sid = user.login(request, "testPassword")
- post_data = {
- "U": "test",
- "E": "test@example.org",
- "TZ": "CET",
- "passwd": "invalid"
- }
+ post_data = {"U": "test", "E": "test@example.org", "TZ": "CET", "passwd": "invalid"}
with client as request:
- response = request.post("/account/test/edit", cookies={
- "AURSID": sid
- }, data=post_data, allow_redirects=False)
+ response = request.post(
+ "/account/test/edit",
+ cookies={"AURSID": sid},
+ data=post_data,
+ allow_redirects=False,
+ )
assert response.status_code == int(HTTPStatus.BAD_REQUEST)
@@ -916,18 +934,18 @@ def test_post_account_edit_error_invalid_password(client: TestClient,
assert "Invalid password." in content
-def test_post_account_edit_suspend_unauthorized(client: TestClient,
- user: User):
+def test_post_account_edit_suspend_unauthorized(client: TestClient, user: User):
cookies = {"AURSID": user.login(Request(), "testPassword")}
post_data = {
"U": "test",
"E": "test@example.org",
"S": True,
- "passwd": "testPassword"
+ "passwd": "testPassword",
}
with client as request:
- resp = request.post(f"/account/{user.Username}/edit", data=post_data,
- cookies=cookies)
+ resp = request.post(
+ f"/account/{user.Username}/edit", data=post_data, cookies=cookies
+ )
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
errors = get_errors(resp.text)
@@ -945,11 +963,12 @@ def test_post_account_edit_inactivity(client: TestClient, user: User):
"U": "test",
"E": "test@example.org",
"J": True,
- "passwd": "testPassword"
+ "passwd": "testPassword",
}
with client as request:
- resp = request.post(f"/account/{user.Username}/edit", data=post_data,
- cookies=cookies)
+ resp = request.post(
+ f"/account/{user.Username}/edit", data=post_data, cookies=cookies
+ )
assert resp.status_code == int(HTTPStatus.OK)
# Make sure the user record got updated correctly.
@@ -957,8 +976,9 @@ def test_post_account_edit_inactivity(client: TestClient, user: User):
post_data.update({"J": False})
with client as request:
- resp = request.post(f"/account/{user.Username}/edit", data=post_data,
- cookies=cookies)
+ resp = request.post(
+ f"/account/{user.Username}/edit", data=post_data, cookies=cookies
+ )
assert resp.status_code == int(HTTPStatus.OK)
assert user.InactivityTS == 0
@@ -974,7 +994,7 @@ def test_post_account_edit_suspended(client: TestClient, user: User):
"U": "test",
"E": "test@example.org",
"S": True,
- "passwd": "testPassword"
+ "passwd": "testPassword",
}
endpoint = f"/account/{user.Username}/edit"
with client as request:
@@ -997,21 +1017,27 @@ def test_post_account_edit_error_unauthorized(client: TestClient, user: User):
sid = user.login(request, "testPassword")
with db.begin():
- user2 = create(User, Username="test2", Email="test2@example.org",
- Passwd="testPassword", AccountTypeID=USER_ID)
+ user2 = create(
+ User,
+ Username="test2",
+ Email="test2@example.org",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
post_data = {
"U": "test",
"E": "test@example.org",
"TZ": "CET",
- "passwd": "testPassword"
+ "passwd": "testPassword",
}
endpoint = f"/account/{user2.Username}/edit"
with client as request:
# Attempt to edit 'test2' while logged in as 'test'.
- response = request.post(endpoint, cookies={"AURSID": sid},
- data=post_data, allow_redirects=False)
+ response = request.post(
+ endpoint, cookies={"AURSID": sid}, data=post_data, allow_redirects=False
+ )
assert response.status_code == int(HTTPStatus.SEE_OTHER)
expected = f"/account/{user2.Username}"
@@ -1026,13 +1052,16 @@ def test_post_account_edit_ssh_pub_key(client: TestClient, user: User):
"U": "test",
"E": "test@example.org",
"PK": make_ssh_pubkey(),
- "passwd": "testPassword"
+ "passwd": "testPassword",
}
with client as request:
- response = request.post("/account/test/edit", cookies={
- "AURSID": sid
- }, data=post_data, allow_redirects=False)
+ response = request.post(
+ "/account/test/edit",
+ cookies={"AURSID": sid},
+ data=post_data,
+ allow_redirects=False,
+ )
assert response.status_code == int(HTTPStatus.OK)
@@ -1040,9 +1069,12 @@ def test_post_account_edit_ssh_pub_key(client: TestClient, user: User):
post_data["PK"] = make_ssh_pubkey()
with client as request:
- response = request.post("/account/test/edit", cookies={
- "AURSID": sid
- }, data=post_data, allow_redirects=False)
+ response = request.post(
+ "/account/test/edit",
+ cookies={"AURSID": sid},
+ data=post_data,
+ allow_redirects=False,
+ )
assert response.status_code == int(HTTPStatus.OK)
@@ -1055,13 +1087,16 @@ def test_post_account_edit_missing_ssh_pubkey(client: TestClient, user: User):
"U": user.Username,
"E": user.Email,
"PK": make_ssh_pubkey(),
- "passwd": "testPassword"
+ "passwd": "testPassword",
}
with client as request:
- response = request.post("/account/test/edit", cookies={
- "AURSID": sid
- }, data=post_data, allow_redirects=False)
+ response = request.post(
+ "/account/test/edit",
+ cookies={"AURSID": sid},
+ data=post_data,
+ allow_redirects=False,
+ )
assert response.status_code == int(HTTPStatus.OK)
@@ -1069,13 +1104,16 @@ def test_post_account_edit_missing_ssh_pubkey(client: TestClient, user: User):
"U": user.Username,
"E": user.Email,
"PK": str(), # Pass an empty string now to walk the delete path.
- "passwd": "testPassword"
+ "passwd": "testPassword",
}
with client as request:
- response = request.post("/account/test/edit", cookies={
- "AURSID": sid
- }, data=post_data, allow_redirects=False)
+ response = request.post(
+ "/account/test/edit",
+ cookies={"AURSID": sid},
+ data=post_data,
+ allow_redirects=False,
+ )
assert response.status_code == int(HTTPStatus.OK)
@@ -1087,12 +1125,13 @@ def test_post_account_edit_invalid_ssh_pubkey(client: TestClient, user: User):
"U": "test",
"E": "test@example.org",
"PK": pubkey,
- "passwd": "testPassword"
+ "passwd": "testPassword",
}
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- response = request.post("/account/test/edit", data=data,
- cookies=cookies, allow_redirects=False)
+ response = request.post(
+ "/account/test/edit", data=data, cookies=cookies, allow_redirects=False
+ )
assert response.status_code == int(HTTPStatus.BAD_REQUEST)
@@ -1106,13 +1145,16 @@ def test_post_account_edit_password(client: TestClient, user: User):
"E": "test@example.org",
"P": "newPassword",
"C": "newPassword",
- "passwd": "testPassword"
+ "passwd": "testPassword",
}
with client as request:
- response = request.post("/account/test/edit", cookies={
- "AURSID": sid
- }, data=post_data, allow_redirects=False)
+ response = request.post(
+ "/account/test/edit",
+ cookies={"AURSID": sid},
+ data=post_data,
+ allow_redirects=False,
+ )
assert response.status_code == int(HTTPStatus.OK)
@@ -1132,7 +1174,7 @@ def test_post_account_edit_self_type_as_user(client: TestClient, user: User):
"U": user.Username,
"E": user.Email,
"T": TRUSTED_USER_ID,
- "passwd": "testPassword"
+ "passwd": "testPassword",
}
with client as request:
resp = request.post(endpoint, data=data, cookies=cookies)
@@ -1151,8 +1193,7 @@ def test_post_account_edit_other_user_as_user(client: TestClient, user: User):
endpoint = f"/account/{user2.Username}/edit"
with client as request:
- resp = request.get(endpoint, cookies=cookies,
- allow_redirects=False)
+ resp = request.get(endpoint, cookies=cookies, allow_redirects=False)
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
assert resp.headers.get("location") == f"/account/{user2.Username}"
@@ -1172,7 +1213,7 @@ def test_post_account_edit_self_type_as_tu(client: TestClient, tu_user: User):
"U": tu_user.Username,
"E": tu_user.Email,
"T": USER_ID,
- "passwd": "testPassword"
+ "passwd": "testPassword",
}
with client as request:
resp = request.post(endpoint, data=data, cookies=cookies)
@@ -1182,7 +1223,8 @@ def test_post_account_edit_self_type_as_tu(client: TestClient, tu_user: User):
def test_post_account_edit_other_user_type_as_tu(
- client: TestClient, tu_user: User, caplog: pytest.LogCaptureFixture):
+ client: TestClient, tu_user: User, caplog: pytest.LogCaptureFixture
+):
caplog.set_level(DEBUG)
with db.begin():
@@ -1202,7 +1244,7 @@ def test_post_account_edit_other_user_type_as_tu(
"U": user2.Username,
"E": user2.Email,
"T": TRUSTED_USER_ID,
- "passwd": "testPassword"
+ "passwd": "testPassword",
}
with client as request:
resp = request.post(endpoint, data=data, cookies=cookies)
@@ -1212,14 +1254,17 @@ def test_post_account_edit_other_user_type_as_tu(
assert user2.AccountTypeID == TRUSTED_USER_ID
# and also that this got logged out at DEBUG level.
- expected = (f"Trusted User '{tu_user.Username}' has "
- f"modified '{user2.Username}' account's type to"
- f" {TRUSTED_USER}.")
+ expected = (
+ f"Trusted User '{tu_user.Username}' has "
+ f"modified '{user2.Username}' account's type to"
+ f" {TRUSTED_USER}."
+ )
assert expected in caplog.text
def test_post_account_edit_other_user_type_as_tu_invalid_type(
- client: TestClient, tu_user: User, caplog: pytest.LogCaptureFixture):
+ client: TestClient, tu_user: User, caplog: pytest.LogCaptureFixture
+):
with db.begin():
user2 = create_user("test2")
@@ -1227,12 +1272,7 @@ def test_post_account_edit_other_user_type_as_tu_invalid_type(
endpoint = f"/account/{user2.Username}/edit"
# As a TU, we can modify other user's account types.
- data = {
- "U": user2.Username,
- "E": user2.Email,
- "T": 0,
- "passwd": "testPassword"
- }
+ data = {"U": user2.Username, "E": user2.Email, "T": 0, "passwd": "testPassword"}
with client as request:
resp = request.post(endpoint, data=data, cookies=cookies)
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
@@ -1247,8 +1287,9 @@ def test_get_account(client: TestClient, user: User):
sid = user.login(request, "testPassword")
with client as request:
- response = request.get("/account/test", cookies={"AURSID": sid},
- allow_redirects=False)
+ response = request.get(
+ "/account/test", cookies={"AURSID": sid}, allow_redirects=False
+ )
assert response.status_code == int(HTTPStatus.OK)
@@ -1258,8 +1299,9 @@ def test_get_account_not_found(client: TestClient, user: User):
sid = user.login(request, "testPassword")
with client as request:
- response = request.get("/account/not_found", cookies={"AURSID": sid},
- allow_redirects=False)
+ response = request.get(
+ "/account/not_found", cookies={"AURSID": sid}, allow_redirects=False
+ )
assert response.status_code == int(HTTPStatus.NOT_FOUND)
@@ -1274,8 +1316,8 @@ def test_get_account_unauthenticated(client: TestClient, user: User):
def test_get_accounts(client: TestClient, user: User, tu_user: User):
- """ Test that we can GET request /accounts and receive
- a form which can be used to POST /accounts. """
+ """Test that we can GET request /accounts and receive
+ a form which can be used to POST /accounts."""
sid = user.login(Request(), "testPassword")
cookies = {"AURSID": sid}
@@ -1296,8 +1338,8 @@ def test_get_accounts(client: TestClient, user: User, tu_user: User):
assert form.attrib.get("action") == "/accounts"
def field(element):
- """ Return the given element string as a valid
- selector in the form. """
+ """Return the given element string as a valid
+ selector in the form."""
return f"./fieldset/p/{element}"
username = form.xpath(field('input[@id="id_username"]'))
@@ -1360,8 +1402,7 @@ def test_post_accounts(client: TestClient, user: User, tu_user: User):
columns = rows[i].xpath("./td")
assert len(columns) == 7
- username, atype, suspended, real_name, \
- irc_nick, pgp_key, edit = columns
+ username, atype, suspended, real_name, irc_nick, pgp_key, edit = columns
username = next(iter(username.xpath("./a")))
assert username.text.strip() == _user.Username
@@ -1379,8 +1420,10 @@ def test_post_accounts(client: TestClient, user: User, tu_user: User):
else:
assert not edit
- logger.debug('Checked user row {"id": %s, "username": "%s"}.'
- % (_user.ID, _user.Username))
+ logger.debug(
+ 'Checked user row {"id": %s, "username": "%s"}.'
+ % (_user.ID, _user.Username)
+ )
def test_post_accounts_username(client: TestClient, user: User, tu_user: User):
@@ -1389,8 +1432,7 @@ def test_post_accounts_username(client: TestClient, user: User, tu_user: User):
cookies = {"AURSID": sid}
with client as request:
- response = request.post("/accounts", cookies=cookies,
- data={"U": user.Username})
+ response = request.post("/accounts", cookies=cookies, data={"U": user.Username})
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
@@ -1403,34 +1445,33 @@ def test_post_accounts_username(client: TestClient, user: User, tu_user: User):
assert username.text.strip() == user.Username
-def test_post_accounts_account_type(client: TestClient, user: User,
- tu_user: User):
+def test_post_accounts_account_type(client: TestClient, user: User, tu_user: User):
# Check the different account type options.
sid = user.login(Request(), "testPassword")
cookies = {"AURSID": sid}
# Make a user with the "User" role here so we can
# test the `u` parameter.
- account_type = query(AccountType,
- AccountType.AccountType == "User").first()
+ account_type = query(AccountType, AccountType.AccountType == "User").first()
with db.begin():
- create(User, Username="test_2",
- Email="test_2@example.org",
- RealName="Test User 2",
- Passwd="testPassword",
- AccountType=account_type)
+ create(
+ User,
+ Username="test_2",
+ Email="test_2@example.org",
+ RealName="Test User 2",
+ Passwd="testPassword",
+ AccountType=account_type,
+ )
# Expect no entries; we marked our only user as a User type.
with client as request:
- response = request.post("/accounts", cookies=cookies,
- data={"T": "t"})
+ response = request.post("/accounts", cookies=cookies, data={"T": "t"})
assert response.status_code == int(HTTPStatus.OK)
assert len(get_rows(response.text)) == 0
# So, let's also ensure that specifying "u" returns our user.
with client as request:
- response = request.post("/accounts", cookies=cookies,
- data={"T": "u"})
+ response = request.post("/accounts", cookies=cookies, data={"T": "u"})
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
@@ -1443,13 +1484,12 @@ def test_post_accounts_account_type(client: TestClient, user: User,
# Set our only user to a Trusted User.
with db.begin():
- user.AccountType = query(AccountType).filter(
- AccountType.ID == TRUSTED_USER_ID
- ).first()
+ user.AccountType = (
+ query(AccountType).filter(AccountType.ID == TRUSTED_USER_ID).first()
+ )
with client as request:
- response = request.post("/accounts", cookies=cookies,
- data={"T": "t"})
+ response = request.post("/accounts", cookies=cookies, data={"T": "t"})
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
@@ -1461,13 +1501,12 @@ def test_post_accounts_account_type(client: TestClient, user: User,
assert type.text.strip() == "Trusted User"
with db.begin():
- user.AccountType = query(AccountType).filter(
- AccountType.ID == DEVELOPER_ID
- ).first()
+ user.AccountType = (
+ query(AccountType).filter(AccountType.ID == DEVELOPER_ID).first()
+ )
with client as request:
- response = request.post("/accounts", cookies=cookies,
- data={"T": "d"})
+ response = request.post("/accounts", cookies=cookies, data={"T": "d"})
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
@@ -1479,13 +1518,12 @@ def test_post_accounts_account_type(client: TestClient, user: User,
assert type.text.strip() == "Developer"
with db.begin():
- user.AccountType = query(AccountType).filter(
- AccountType.ID == TRUSTED_USER_AND_DEV_ID
- ).first()
+ user.AccountType = (
+ query(AccountType).filter(AccountType.ID == TRUSTED_USER_AND_DEV_ID).first()
+ )
with client as request:
- response = request.post("/accounts", cookies=cookies,
- data={"T": "td"})
+ response = request.post("/accounts", cookies=cookies, data={"T": "td"})
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
@@ -1517,8 +1555,7 @@ def test_post_accounts_status(client: TestClient, user: User, tu_user: User):
user.Suspended = True
with client as request:
- response = request.post("/accounts", cookies=cookies,
- data={"S": True})
+ response = request.post("/accounts", cookies=cookies, data={"S": True})
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
@@ -1535,8 +1572,7 @@ def test_post_accounts_email(client: TestClient, user: User, tu_user: User):
# Search via email.
with client as request:
- response = request.post("/accounts", cookies=cookies,
- data={"E": user.Email})
+ response = request.post("/accounts", cookies=cookies, data={"E": user.Email})
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
@@ -1549,8 +1585,7 @@ def test_post_accounts_realname(client: TestClient, user: User, tu_user: User):
cookies = {"AURSID": sid}
with client as request:
- response = request.post("/accounts", cookies=cookies,
- data={"R": user.RealName})
+ response = request.post("/accounts", cookies=cookies, data={"R": user.RealName})
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
@@ -1563,8 +1598,7 @@ def test_post_accounts_irc(client: TestClient, user: User, tu_user: User):
cookies = {"AURSID": sid}
with client as request:
- response = request.post("/accounts", cookies=cookies,
- data={"I": user.IRCNick})
+ response = request.post("/accounts", cookies=cookies, data={"I": user.IRCNick})
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
@@ -1589,22 +1623,19 @@ def test_post_accounts_sortby(client: TestClient, user: User, tu_user: User):
first_rows = rows
with client as request:
- response = request.post("/accounts", cookies=cookies,
- data={"SB": "u"})
+ response = request.post("/accounts", cookies=cookies, data={"SB": "u"})
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
assert len(rows) == 2
def compare_text_values(column, lhs, rhs):
- return [row[column].text for row in lhs] \
- == [row[column].text for row in rhs]
+ return [row[column].text for row in lhs] == [row[column].text for row in rhs]
# Test the username rows are ordered the same.
assert compare_text_values(0, first_rows, rows) is True
with client as request:
- response = request.post("/accounts", cookies=cookies,
- data={"SB": "i"})
+ response = request.post("/accounts", cookies=cookies, data={"SB": "i"})
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
assert len(rows) == 2
@@ -1614,8 +1645,7 @@ def test_post_accounts_sortby(client: TestClient, user: User, tu_user: User):
# Sort by "i" -> RealName.
with client as request:
- response = request.post("/accounts", cookies=cookies,
- data={"SB": "r"})
+ response = request.post("/accounts", cookies=cookies, data={"SB": "r"})
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
assert len(rows) == 2
@@ -1624,9 +1654,9 @@ def test_post_accounts_sortby(client: TestClient, user: User, tu_user: User):
assert compare_text_values(4, first_rows, reversed(rows)) is True
with db.begin():
- user.AccountType = query(AccountType).filter(
- AccountType.ID == TRUSTED_USER_AND_DEV_ID
- ).first()
+ user.AccountType = (
+ query(AccountType).filter(AccountType.ID == TRUSTED_USER_AND_DEV_ID).first()
+ )
# Fetch first_rows again with our new AccountType ordering.
with client as request:
@@ -1638,8 +1668,7 @@ def test_post_accounts_sortby(client: TestClient, user: User, tu_user: User):
# Sort by "t" -> AccountType.
with client as request:
- response = request.post("/accounts", cookies=cookies,
- data={"SB": "t"})
+ response = request.post("/accounts", cookies=cookies, data={"SB": "t"})
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
assert len(rows) == 2
@@ -1657,8 +1686,7 @@ def test_post_accounts_pgp_key(client: TestClient, user: User, tu_user: User):
# Search via PGPKey.
with client as request:
- response = request.post("/accounts", cookies=cookies,
- data={"K": user.PGPKey})
+ response = request.post("/accounts", cookies=cookies, data={"K": user.PGPKey})
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
@@ -1668,15 +1696,17 @@ def test_post_accounts_pgp_key(client: TestClient, user: User, tu_user: User):
def test_post_accounts_paged(client: TestClient, user: User, tu_user: User):
# Create 150 users.
users = [user]
- account_type = query(AccountType,
- AccountType.AccountType == "User").first()
+ account_type = query(AccountType, AccountType.AccountType == "User").first()
with db.begin():
for i in range(150):
- _user = create(User, Username=f"test_#{i}",
- Email=f"test_#{i}@example.org",
- RealName=f"Test User #{i}",
- Passwd="testPassword",
- AccountType=account_type)
+ _user = create(
+ User,
+ Username=f"test_#{i}",
+ Email=f"test_#{i}@example.org",
+ RealName=f"Test User #{i}",
+ Passwd="testPassword",
+ AccountType=account_type,
+ )
users.append(_user)
sid = user.login(Request(), "testPassword")
@@ -1709,8 +1739,9 @@ def test_post_accounts_paged(client: TestClient, user: User, tu_user: User):
assert "disabled" not in page_next.attrib
with client as request:
- response = request.post("/accounts", cookies=cookies,
- data={"O": 50}) # +50 offset.
+ response = request.post(
+ "/accounts", cookies=cookies, data={"O": 50}
+ ) # +50 offset.
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
@@ -1724,8 +1755,9 @@ def test_post_accounts_paged(client: TestClient, user: User, tu_user: User):
assert username.text.strip() == _user.Username
with client as request:
- response = request.post("/accounts", cookies=cookies,
- data={"O": 101}) # Last page.
+ response = request.post(
+ "/accounts", cookies=cookies, data={"O": 101}
+ ) # Last page.
assert response.status_code == int(HTTPStatus.OK)
rows = get_rows(response.text)
@@ -1741,8 +1773,9 @@ def test_post_accounts_paged(client: TestClient, user: User, tu_user: User):
def test_get_terms_of_service(client: TestClient, user: User):
with db.begin():
- term = create(Term, Description="Test term.",
- URL="http://localhost", Revision=1)
+ term = create(
+ Term, Description="Test term.", URL="http://localhost", Revision=1
+ )
with client as request:
response = request.get("/tos", allow_redirects=False)
@@ -1764,8 +1797,9 @@ def test_get_terms_of_service(client: TestClient, user: User):
assert response.status_code == int(HTTPStatus.OK)
with db.begin():
- accepted_term = create(AcceptedTerm, User=user,
- Term=term, Revision=term.Revision)
+ accepted_term = create(
+ AcceptedTerm, User=user, Term=term, Revision=term.Revision
+ )
with client as request:
response = request.get("/tos", cookies=cookies, allow_redirects=False)
@@ -1800,8 +1834,9 @@ def test_post_terms_of_service(client: TestClient, user: User):
# Create a fresh Term.
with db.begin():
- term = create(Term, Description="Test term.",
- URL="http://localhost", Revision=1)
+ term = create(
+ Term, Description="Test term.", URL="http://localhost", Revision=1
+ )
# Test that the term we just created is listed.
with client as request:
@@ -1810,8 +1845,7 @@ def test_post_terms_of_service(client: TestClient, user: User):
# Make a POST request to /tos with the agree checkbox disabled (False).
with client as request:
- response = request.post("/tos", data={"accept": False},
- cookies=cookies)
+ response = request.post("/tos", data={"accept": False}, cookies=cookies)
assert response.status_code == int(HTTPStatus.OK)
# Make a POST request to /tos with the agree checkbox enabled (True).
@@ -1820,8 +1854,7 @@ def test_post_terms_of_service(client: TestClient, user: User):
assert response.status_code == int(HTTPStatus.SEE_OTHER)
# Query the db for the record created by the post request.
- accepted_term = query(AcceptedTerm,
- AcceptedTerm.TermsID == term.ID).first()
+ accepted_term = query(AcceptedTerm, AcceptedTerm.TermsID == term.ID).first()
assert accepted_term.User == user
assert accepted_term.Term == term
diff --git a/test/test_adduser.py b/test/test_adduser.py
index 65968d40..2cb71f3b 100644
--- a/test/test_adduser.py
+++ b/test/test_adduser.py
@@ -3,16 +3,17 @@ from unittest import mock
import pytest
import aurweb.models.account_type as at
-
from aurweb import db
from aurweb.models import User
from aurweb.scripts import adduser
from aurweb.testing.requests import Request
-TEST_SSH_PUBKEY = ("ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAI"
- "bmlzdHAyNTYAAABBBEURnkiY6JoLyqDE8Li1XuAW+LHmkmLDMW/GL5wY"
- "7k4/A+Ta7bjA3MOKrF9j4EuUTvCuNXULxvpfSqheTFWZc+g= "
- "kevr@volcano")
+TEST_SSH_PUBKEY = (
+ "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAI"
+ "bmlzdHAyNTYAAABBBEURnkiY6JoLyqDE8Li1XuAW+LHmkmLDMW/GL5wY"
+ "7k4/A+Ta7bjA3MOKrF9j4EuUTvCuNXULxvpfSqheTFWZc+g= "
+ "kevr@volcano"
+)
@pytest.fixture(autouse=True)
@@ -38,18 +39,36 @@ def test_adduser():
def test_adduser_tu():
- run_main([
- "-u", "test", "-e", "test@example.org", "-p", "abcd1234",
- "-t", at.TRUSTED_USER
- ])
+ run_main(
+ [
+ "-u",
+ "test",
+ "-e",
+ "test@example.org",
+ "-p",
+ "abcd1234",
+ "-t",
+ at.TRUSTED_USER,
+ ]
+ )
test = db.query(User).filter(User.Username == "test").first()
assert test is not None
assert test.AccountTypeID == at.TRUSTED_USER_ID
def test_adduser_ssh_pk():
- run_main(["-u", "test", "-e", "test@example.org", "-p", "abcd1234",
- "--ssh-pubkey", TEST_SSH_PUBKEY])
+ run_main(
+ [
+ "-u",
+ "test",
+ "-e",
+ "test@example.org",
+ "-p",
+ "abcd1234",
+ "--ssh-pubkey",
+ TEST_SSH_PUBKEY,
+ ]
+ )
test = db.query(User).filter(User.Username == "test").first()
assert test is not None
assert TEST_SSH_PUBKEY.startswith(test.ssh_pub_keys.first().PubKey)
diff --git a/test/test_api_rate_limit.py b/test/test_api_rate_limit.py
index 82805ecf..c67aa57d 100644
--- a/test/test_api_rate_limit.py
+++ b/test/test_api_rate_limit.py
@@ -1,5 +1,4 @@
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db
@@ -13,8 +12,7 @@ def setup(db_test):
def test_api_rate_key_creation():
with db.begin():
- rate = db.create(ApiRateLimit, IP="127.0.0.1", Requests=10,
- WindowStart=1)
+ rate = db.create(ApiRateLimit, IP="127.0.0.1", Requests=10, WindowStart=1)
assert rate.IP == "127.0.0.1"
assert rate.Requests == 10
assert rate.WindowStart == 1
diff --git a/test/test_asgi.py b/test/test_asgi.py
index c693a3a9..6ff80fa3 100644
--- a/test/test_asgi.py
+++ b/test/test_asgi.py
@@ -1,20 +1,17 @@
import http
import os
import re
-
from typing import Callable
from unittest import mock
import fastapi
import pytest
-
from fastapi import HTTPException
from fastapi.testclient import TestClient
import aurweb.asgi
import aurweb.config
import aurweb.redis
-
from aurweb.exceptions import handle_form_exceptions
from aurweb.testing.requests import Request
@@ -33,7 +30,9 @@ def mock_glab_request(monkeypatch):
if side_effect:
return side_effect # pragma: no cover
return return_value
+
monkeypatch.setattr("requests.post", what_to_return)
+
return wrapped
@@ -47,13 +46,14 @@ def mock_glab_config(project: str = "test/project", token: str = "test-token"):
elif key == "error-token":
return token
return config_get(section, key)
+
return wrapper
@pytest.mark.asyncio
async def test_asgi_startup_session_secret_exception(monkeypatch):
- """ Test that we get an IOError on app_startup when we cannot
- connect to options.redis_address. """
+ """Test that we get an IOError on app_startup when we cannot
+ connect to options.redis_address."""
redis_addr = aurweb.config.get("options", "redis_address")
@@ -110,8 +110,9 @@ async def test_asgi_app_disabled_metrics(caplog: pytest.LogCaptureFixture):
with mock.patch.dict(os.environ, env):
await aurweb.asgi.app_startup()
- expected = ("$PROMETHEUS_MULTIPROC_DIR is not set, the /metrics "
- "endpoint is disabled.")
+ expected = (
+ "$PROMETHEUS_MULTIPROC_DIR is not set, the /metrics " "endpoint is disabled."
+ )
assert expected in caplog.text
@@ -134,9 +135,12 @@ class FakeResponse:
self.text = text
-def test_internal_server_error_bad_glab(setup: None, use_traceback: None,
- mock_glab_request: Callable,
- caplog: pytest.LogCaptureFixture):
+def test_internal_server_error_bad_glab(
+ setup: None,
+ use_traceback: None,
+ mock_glab_request: Callable,
+ caplog: pytest.LogCaptureFixture,
+):
@aurweb.asgi.app.get("/internal_server_error")
async def internal_server_error(request: fastapi.Request):
raise ValueError("test exception")
@@ -154,9 +158,12 @@ def test_internal_server_error_bad_glab(setup: None, use_traceback: None,
assert re.search(expr, caplog.text)
-def test_internal_server_error_no_token(setup: None, use_traceback: None,
- mock_glab_request: Callable,
- caplog: pytest.LogCaptureFixture):
+def test_internal_server_error_no_token(
+ setup: None,
+ use_traceback: None,
+ mock_glab_request: Callable,
+ caplog: pytest.LogCaptureFixture,
+):
@aurweb.asgi.app.get("/internal_server_error")
async def internal_server_error(request: fastapi.Request):
raise ValueError("test exception")
@@ -175,9 +182,12 @@ def test_internal_server_error_no_token(setup: None, use_traceback: None,
assert re.search(expr, caplog.text)
-def test_internal_server_error(setup: None, use_traceback: None,
- mock_glab_request: Callable,
- caplog: pytest.LogCaptureFixture):
+def test_internal_server_error(
+ setup: None,
+ use_traceback: None,
+ mock_glab_request: Callable,
+ caplog: pytest.LogCaptureFixture,
+):
@aurweb.asgi.app.get("/internal_server_error")
async def internal_server_error(request: fastapi.Request):
raise ValueError("test exception")
@@ -203,9 +213,12 @@ def test_internal_server_error(setup: None, use_traceback: None,
assert "FATAL" not in caplog.text
-def test_internal_server_error_post(setup: None, use_traceback: None,
- mock_glab_request: Callable,
- caplog: pytest.LogCaptureFixture):
+def test_internal_server_error_post(
+ setup: None,
+ use_traceback: None,
+ mock_glab_request: Callable,
+ caplog: pytest.LogCaptureFixture,
+):
@aurweb.asgi.app.post("/internal_server_error")
@handle_form_exceptions
async def internal_server_error(request: fastapi.Request):
diff --git a/test/test_aurblup.py b/test/test_aurblup.py
index 0b499d57..93a832f9 100644
--- a/test/test_aurblup.py
+++ b/test/test_aurblup.py
@@ -1,5 +1,4 @@
import tempfile
-
from unittest import mock
import py
@@ -32,7 +31,7 @@ def setup(db_test, alpm_db: AlpmDatabase, tempdir: py.path.local) -> None:
if key == "db-path":
return alpm_db.local
elif key == "server":
- return f'file://{alpm_db.remote}'
+ return f"file://{alpm_db.remote}"
elif key == "sync-dbs":
return alpm_db.repo
return value
@@ -51,8 +50,7 @@ def test_aurblup(alpm_db: AlpmDatabase):
# Test that the package got added to the database.
for name in ("pkg", "pkg2"):
- pkg = db.query(OfficialProvider).filter(
- OfficialProvider.Name == name).first()
+ pkg = db.query(OfficialProvider).filter(OfficialProvider.Name == name).first()
assert pkg is not None
# Test that we can remove the package.
@@ -62,11 +60,9 @@ def test_aurblup(alpm_db: AlpmDatabase):
aurblup.main(True)
# Expect that the database got updated accordingly.
- pkg = db.query(OfficialProvider).filter(
- OfficialProvider.Name == "pkg").first()
+ pkg = db.query(OfficialProvider).filter(OfficialProvider.Name == "pkg").first()
assert pkg is None
- pkg2 = db.query(OfficialProvider).filter(
- OfficialProvider.Name == "pkg2").first()
+ pkg2 = db.query(OfficialProvider).filter(OfficialProvider.Name == "pkg2").first()
assert pkg2 is not None
@@ -78,14 +74,16 @@ def test_aurblup_cleanup(alpm_db: AlpmDatabase):
# Now, let's insert an OfficialPackage that doesn't exist,
# then exercise the old provider deletion path.
with db.begin():
- db.create(OfficialProvider, Name="fake package",
- Repo="test", Provides="package")
+ db.create(
+ OfficialProvider, Name="fake package", Repo="test", Provides="package"
+ )
# Run aurblup again.
aurblup.main()
# Expect that the fake package got deleted because it's
# not in alpm_db anymore.
- providers = db.query(OfficialProvider).filter(
- OfficialProvider.Name == "fake package").all()
+ providers = (
+ db.query(OfficialProvider).filter(OfficialProvider.Name == "fake package").all()
+ )
assert len(providers) == 0
diff --git a/test/test_auth.py b/test/test_auth.py
index b8221c19..4a4318e8 100644
--- a/test/test_auth.py
+++ b/test/test_auth.py
@@ -1,11 +1,15 @@
import fastapi
import pytest
-
from fastapi import HTTPException
from sqlalchemy.exc import IntegrityError
from aurweb import config, db, time
-from aurweb.auth import AnonymousUser, BasicAuthBackend, _auth_required, account_type_required
+from aurweb.auth import (
+ AnonymousUser,
+ BasicAuthBackend,
+ _auth_required,
+ account_type_required,
+)
from aurweb.models.account_type import USER, USER_ID
from aurweb.models.session import Session
from aurweb.models.user import User
@@ -20,9 +24,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.com",
- RealName="Test User", Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.com",
+ RealName="Test User",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
@@ -55,8 +64,7 @@ async def test_auth_backend_invalid_user_id():
# Create a new session with a fake user id.
now_ts = time.utcnow()
with pytest.raises(IntegrityError):
- Session(UsersID=666, SessionID="realSession",
- LastUpdateTS=now_ts + 5)
+ Session(UsersID=666, SessionID="realSession", LastUpdateTS=now_ts + 5)
@pytest.mark.asyncio
@@ -65,8 +73,9 @@ async def test_basic_auth_backend(user: User, backend: BasicAuthBackend):
# equal the real_user.
now_ts = time.utcnow()
with db.begin():
- db.create(Session, UsersID=user.ID, SessionID="realSession",
- LastUpdateTS=now_ts + 5)
+ db.create(
+ Session, UsersID=user.ID, SessionID="realSession", LastUpdateTS=now_ts + 5
+ )
request = Request()
request.cookies["AURSID"] = "realSession"
@@ -76,7 +85,7 @@ async def test_basic_auth_backend(user: User, backend: BasicAuthBackend):
@pytest.mark.asyncio
async def test_expired_session(backend: BasicAuthBackend, user: User):
- """ Login, expire the session manually, then authenticate. """
+ """Login, expire the session manually, then authenticate."""
# First, build a Request with a logged in user.
request = Request()
request.user = user
@@ -115,8 +124,8 @@ async def test_auth_required_redirection_bad_referrer():
def test_account_type_required():
- """ This test merely asserts that a few different paths
- do not raise exceptions. """
+ """This test merely asserts that a few different paths
+ do not raise exceptions."""
# This one shouldn't raise.
account_type_required({USER})
@@ -125,7 +134,7 @@ def test_account_type_required():
# But this one should! We have no "FAKE" key.
with pytest.raises(KeyError):
- account_type_required({'FAKE'})
+ account_type_required({"FAKE"})
def test_is_trusted_user():
diff --git a/test/test_auth_routes.py b/test/test_auth_routes.py
index 5942edcf..87ad86f6 100644
--- a/test/test_auth_routes.py
+++ b/test/test_auth_routes.py
@@ -1,14 +1,11 @@
import re
-
from http import HTTPStatus
from unittest import mock
import pytest
-
from fastapi.testclient import TestClient
import aurweb.config
-
from aurweb import db, time
from aurweb.asgi import app
from aurweb.models.account_type import USER_ID
@@ -42,39 +39,41 @@ def client() -> TestClient:
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username=TEST_USERNAME, Email=TEST_EMAIL,
- RealName="Test User", Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username=TEST_USERNAME,
+ Email=TEST_EMAIL,
+ RealName="Test User",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
def test_login_logout(client: TestClient, user: User):
- post_data = {
- "user": "test",
- "passwd": "testPassword",
- "next": "/"
- }
+ post_data = {"user": "test", "passwd": "testPassword", "next": "/"}
with client as request:
# First, let's test get /login.
response = request.get("/login")
assert response.status_code == int(HTTPStatus.OK)
- response = request.post("/login", data=post_data,
- allow_redirects=False)
+ response = request.post("/login", data=post_data, allow_redirects=False)
assert response.status_code == int(HTTPStatus.SEE_OTHER)
# Simulate following the redirect location from above's response.
response = request.get(response.headers.get("location"))
assert response.status_code == int(HTTPStatus.OK)
- response = request.post("/logout", data=post_data,
- allow_redirects=False)
+ response = request.post("/logout", data=post_data, allow_redirects=False)
assert response.status_code == int(HTTPStatus.SEE_OTHER)
- response = request.post("/logout", data=post_data, cookies={
- "AURSID": response.cookies.get("AURSID")
- }, allow_redirects=False)
+ response = request.post(
+ "/logout",
+ data=post_data,
+ cookies={"AURSID": response.cookies.get("AURSID")},
+ allow_redirects=False,
+ )
assert response.status_code == int(HTTPStatus.SEE_OTHER)
assert "AURSID" not in response.cookies
@@ -84,11 +83,7 @@ def test_login_suspended(client: TestClient, user: User):
with db.begin():
user.Suspended = 1
- data = {
- "user": user.Username,
- "passwd": "testPassword",
- "next": "/"
- }
+ data = {"user": user.Username, "passwd": "testPassword", "next": "/"}
with client as request:
resp = request.post("/login", data=data)
errors = get_errors(resp.text)
@@ -96,23 +91,17 @@ def test_login_suspended(client: TestClient, user: User):
def test_login_email(client: TestClient, user: user):
- post_data = {
- "user": user.Email,
- "passwd": "testPassword",
- "next": "/"
- }
+ post_data = {"user": user.Email, "passwd": "testPassword", "next": "/"}
with client as request:
- resp = request.post("/login", data=post_data,
- allow_redirects=False)
+ resp = request.post("/login", data=post_data, allow_redirects=False)
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
assert "AURSID" in resp.cookies
def mock_getboolean(**overrided_configs):
mocked_config = {
- tuple(config.split("__")): value
- for config, value in overrided_configs.items()
+ tuple(config.split("__")): value for config, value in overrided_configs.items()
}
def side_effect(*args):
@@ -123,19 +112,14 @@ def mock_getboolean(**overrided_configs):
@mock.patch(
"aurweb.config.getboolean",
- side_effect=mock_getboolean(options__disable_http_login=False)
+ side_effect=mock_getboolean(options__disable_http_login=False),
)
def test_insecure_login(getboolean: mock.Mock, client: TestClient, user: User):
- post_data = {
- "user": user.Username,
- "passwd": "testPassword",
- "next": "/"
- }
+ post_data = {"user": user.Username, "passwd": "testPassword", "next": "/"}
# Perform a login request with the data matching our user.
with client as request:
- response = request.post("/login", data=post_data,
- allow_redirects=False)
+ response = request.post("/login", data=post_data, allow_redirects=False)
# Make sure we got the expected status out of it.
assert response.status_code == int(HTTPStatus.SEE_OTHER)
@@ -152,17 +136,17 @@ def test_insecure_login(getboolean: mock.Mock, client: TestClient, user: User):
@mock.patch(
"aurweb.config.getboolean",
- side_effect=mock_getboolean(options__disable_http_login=True)
+ side_effect=mock_getboolean(options__disable_http_login=True),
)
def test_secure_login(getboolean: mock.Mock, client: TestClient, user: User):
- """ In this test, we check to verify the course of action taken
+ """In this test, we check to verify the course of action taken
by starlette when providing secure=True to a response cookie.
This is achieved by mocking aurweb.config.getboolean to return
True (or 1) when looking for `options.disable_http_login`.
When we receive a response with `disable_http_login` enabled,
we check the fields in cookies received for the secure and
httponly fields, in addition to the rest of the fields given
- on such a request. """
+ on such a request."""
# Create a local TestClient here since we mocked configuration.
# client = TestClient(app)
@@ -172,16 +156,11 @@ def test_secure_login(getboolean: mock.Mock, client: TestClient, user: User):
# client.headers.update(TEST_REFERER)
# Data used for our upcoming http post request.
- post_data = {
- "user": user.Username,
- "passwd": "testPassword",
- "next": "/"
- }
+ post_data = {"user": user.Username, "passwd": "testPassword", "next": "/"}
# Perform a login request with the data matching our user.
with client as request:
- response = request.post("/login", data=post_data,
- allow_redirects=False)
+ response = request.post("/login", data=post_data, allow_redirects=False)
# Make sure we got the expected status out of it.
assert response.status_code == int(HTTPStatus.SEE_OTHER)
@@ -203,16 +182,11 @@ def test_secure_login(getboolean: mock.Mock, client: TestClient, user: User):
def test_authenticated_login(client: TestClient, user: User):
- post_data = {
- "user": user.Username,
- "passwd": "testPassword",
- "next": "/"
- }
+ post_data = {"user": user.Username, "passwd": "testPassword", "next": "/"}
with client as request:
# Try to login.
- response = request.post("/login", data=post_data,
- allow_redirects=False)
+ response = request.post("/login", data=post_data, allow_redirects=False)
assert response.status_code == int(HTTPStatus.SEE_OTHER)
assert response.headers.get("location") == "/"
@@ -220,8 +194,9 @@ def test_authenticated_login(client: TestClient, user: User):
# when requesting GET /login as an authenticated user.
# Now, let's verify that we receive 403 Forbidden when we
# try to get /login as an authenticated user.
- response = request.get("/login", cookies=response.cookies,
- allow_redirects=False)
+ response = request.get(
+ "/login", cookies=response.cookies, allow_redirects=False
+ )
assert response.status_code == int(HTTPStatus.OK)
assert "Logged-in as: test" in response.text
@@ -236,10 +211,7 @@ def test_unauthenticated_logout_unauthorized(client: TestClient):
def test_login_missing_username(client: TestClient):
- post_data = {
- "passwd": "testPassword",
- "next": "/"
- }
+ post_data = {"passwd": "testPassword", "next": "/"}
with client as request:
response = request.post("/login", data=post_data)
@@ -256,17 +228,15 @@ def test_login_remember_me(client: TestClient, user: User):
"user": "test",
"passwd": "testPassword",
"next": "/",
- "remember_me": True
+ "remember_me": True,
}
with client as request:
- response = request.post("/login", data=post_data,
- allow_redirects=False)
+ response = request.post("/login", data=post_data, allow_redirects=False)
assert response.status_code == int(HTTPStatus.SEE_OTHER)
assert "AURSID" in response.cookies
- cookie_timeout = aurweb.config.getint(
- "options", "persistent_cookie_timeout")
+ cookie_timeout = aurweb.config.getint("options", "persistent_cookie_timeout")
now_ts = time.utcnow()
session = db.query(Session).filter(Session.UsersID == user.ID).first()
@@ -280,7 +250,7 @@ def test_login_incorrect_password_remember_me(client: TestClient, user: User):
"user": "test",
"passwd": "badPassword",
"next": "/",
- "remember_me": "on"
+ "remember_me": "on",
}
with client as request:
@@ -295,10 +265,7 @@ def test_login_incorrect_password_remember_me(client: TestClient, user: User):
def test_login_missing_password(client: TestClient):
- post_data = {
- "user": "test",
- "next": "/"
- }
+ post_data = {"user": "test", "next": "/"}
with client as request:
response = request.post("/login", data=post_data)
@@ -310,11 +277,7 @@ def test_login_missing_password(client: TestClient):
def test_login_incorrect_password(client: TestClient):
- post_data = {
- "user": "test",
- "passwd": "badPassword",
- "next": "/"
- }
+ post_data = {"user": "test", "passwd": "badPassword", "next": "/"}
with client as request:
response = request.post("/login", data=post_data)
@@ -350,8 +313,9 @@ def test_login_bad_referer(client: TestClient):
assert "AURSID" not in response.cookies
-def test_generate_unique_sid_exhausted(client: TestClient, user: User,
- caplog: pytest.LogCaptureFixture):
+def test_generate_unique_sid_exhausted(
+ client: TestClient, user: User, caplog: pytest.LogCaptureFixture
+):
"""
In this test, we mock up generate_unique_sid() to infinitely return
the same SessionID given to `user`. Within that mocking, we try
@@ -364,13 +328,17 @@ def test_generate_unique_sid_exhausted(client: TestClient, user: User,
now = time.utcnow()
with db.begin():
# Create a second user; we'll login with this one.
- user2 = db.create(User, Username="test2", Email="test2@example.org",
- ResetKey="testReset", Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user2 = db.create(
+ User,
+ Username="test2",
+ Email="test2@example.org",
+ ResetKey="testReset",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
# Create a session with ID == "testSession" for `user`.
- db.create(Session, User=user, SessionID="testSession",
- LastUpdateTS=now)
+ db.create(Session, User=user, SessionID="testSession", LastUpdateTS=now)
# Mock out generate_unique_sid; always return "testSession" which
# causes us to eventually error out and raise an internal error.
diff --git a/test/test_ban.py b/test/test_ban.py
index ff49f7e2..9db62296 100644
--- a/test/test_ban.py
+++ b/test/test_ban.py
@@ -1,9 +1,7 @@
import warnings
-
from datetime import datetime, timedelta
import pytest
-
from sqlalchemy import exc as sa_exc
from aurweb import db
diff --git a/test/test_cache.py b/test/test_cache.py
index b49ee386..83a9755a 100644
--- a/test/test_cache.py
+++ b/test/test_cache.py
@@ -11,7 +11,7 @@ def setup(db_test):
class StubRedis:
- """ A class which acts as a RedisConnection without using Redis. """
+ """A class which acts as a RedisConnection without using Redis."""
cache = dict()
expires = dict()
@@ -39,10 +39,13 @@ def redis():
@pytest.mark.asyncio
async def test_db_count_cache(redis):
- db.create(User, Username="user1",
- Email="user1@example.org",
- Passwd="testPassword",
- AccountTypeID=USER_ID)
+ db.create(
+ User,
+ Username="user1",
+ Email="user1@example.org",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
query = db.query(User)
@@ -57,10 +60,13 @@ async def test_db_count_cache(redis):
@pytest.mark.asyncio
async def test_db_count_cache_expires(redis):
- db.create(User, Username="user1",
- Email="user1@example.org",
- Passwd="testPassword",
- AccountTypeID=USER_ID)
+ db.create(
+ User,
+ Username="user1",
+ Email="user1@example.org",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
query = db.query(User)
diff --git a/test/test_captcha.py b/test/test_captcha.py
index e5f8c71a..fa6fcbcc 100644
--- a/test/test_captcha.py
+++ b/test/test_captcha.py
@@ -11,14 +11,14 @@ def setup(db_test):
def test_captcha_salts():
- """ Make sure we can get some captcha salts. """
+ """Make sure we can get some captcha salts."""
salts = captcha.get_captcha_salts()
assert len(salts) == 6
def test_captcha_token():
- """ Make sure getting a captcha salt's token matches up against
- the first three digits of the md5 hash of the salt. """
+ """Make sure getting a captcha salt's token matches up against
+ the first three digits of the md5 hash of the salt."""
salts = captcha.get_captcha_salts()
salt = salts[0]
@@ -29,9 +29,9 @@ def test_captcha_token():
def test_captcha_challenge_answer():
- """ Make sure that executing the captcha challenge via shell
+ """Make sure that executing the captcha challenge via shell
produces the correct result by comparing it against a straight
- up token conversion. """
+ up token conversion."""
salts = captcha.get_captcha_salts()
salt = salts[0]
@@ -44,7 +44,7 @@ def test_captcha_challenge_answer():
def test_captcha_salt_filter():
- """ Make sure captcha_salt_filter returns the first salt from
+ """Make sure captcha_salt_filter returns the first salt from
get_captcha_salts().
Example usage:
@@ -55,7 +55,7 @@ def test_captcha_salt_filter():
def test_captcha_cmdline_filter():
- """ Make sure that the captcha_cmdline filter gives us the
+ """Make sure that the captcha_cmdline filter gives us the
same challenge that get_captcha_challenge does.
Example usage:
diff --git a/test/test_config.py b/test/test_config.py
index f451d8b3..c7a3610e 100644
--- a/test/test_config.py
+++ b/test/test_config.py
@@ -2,7 +2,6 @@ import configparser
import io
import os
import re
-
from unittest import mock
import py
@@ -35,6 +34,7 @@ def mock_config_get():
if option == "salt_rounds":
return "666"
return config_get(section, option)
+
return _mock_config_get
@@ -59,7 +59,7 @@ def test_config_main_get_unknown_section(get: str):
main()
# With an invalid section, we should get a usage error.
- expected = r'^error: no section found$'
+ expected = r"^error: no section found$"
assert re.match(expected, stderr.getvalue().strip())
@@ -140,8 +140,7 @@ def test_config_main_set_immutable():
args = ["aurweb-config", "set", "options", "salt_rounds", "666"]
with mock.patch.dict(os.environ, {"AUR_CONFIG_IMMUTABLE": "1"}):
with mock.patch("sys.argv", args):
- with mock.patch("aurweb.config.set_option",
- side_effect=mock_set_option):
+ with mock.patch("aurweb.config.set_option", side_effect=mock_set_option):
main()
expected = None
@@ -170,8 +169,7 @@ def test_config_main_set_unknown_section(save: None):
args = ["aurweb-config", "set", "options", "salt_rounds", "666"]
with mock.patch("sys.argv", args):
with mock.patch("sys.stderr", stderr):
- with mock.patch("aurweb.config.set_option",
- side_effect=mock_set_option):
+ with mock.patch("aurweb.config.set_option", side_effect=mock_set_option):
main()
assert stderr.getvalue().strip() == "error: no section found"
diff --git a/test/test_db.py b/test/test_db.py
index f36fff2c..8ac5607d 100644
--- a/test/test_db.py
+++ b/test/test_db.py
@@ -2,26 +2,26 @@ import os
import re
import sqlite3
import tempfile
-
from unittest import mock
import pytest
import aurweb.config
import aurweb.initdb
-
from aurweb import db
from aurweb.models.account_type import AccountType
class Args:
- """ Stub arguments used for running aurweb.initdb. """
+ """Stub arguments used for running aurweb.initdb."""
+
use_alembic = True
verbose = True
class DBCursor:
- """ A fake database cursor object used in tests. """
+ """A fake database cursor object used in tests."""
+
items = []
def execute(self, *args, **kwargs):
@@ -33,7 +33,8 @@ class DBCursor:
class DBConnection:
- """ A fake database connection object used in tests. """
+ """A fake database connection object used in tests."""
+
@staticmethod
def cursor():
return DBCursor()
@@ -44,7 +45,7 @@ class DBConnection:
def make_temp_config(*replacements):
- """ Generate a temporary config file with a set of replacements.
+ """Generate a temporary config file with a set of replacements.
:param *replacements: A variable number of tuple regex replacement pairs
:return: A tuple containing (temp directory, temp config file)
@@ -85,13 +86,16 @@ def make_temp_config(*replacements):
def make_temp_sqlite_config():
- return make_temp_config((r"backend = .*", "backend = sqlite"),
- (r"name = .*", "name = /tmp/aurweb.sqlite3"))
+ return make_temp_config(
+ (r"backend = .*", "backend = sqlite"),
+ (r"name = .*", "name = /tmp/aurweb.sqlite3"),
+ )
def make_temp_mysql_config():
- return make_temp_config((r"backend = .*", "backend = mysql"),
- (r"name = .*", "name = aurweb_test"))
+ return make_temp_config(
+ (r"backend = .*", "backend = mysql"), (r"name = .*", "name = aurweb_test")
+ )
@pytest.fixture(autouse=True)
@@ -150,7 +154,7 @@ def test_sqlalchemy_unknown_backend():
def test_db_connects_without_fail():
- """ This only tests the actual config supplied to pytest. """
+ """This only tests the actual config supplied to pytest."""
db.connect()
diff --git a/test/test_dependency_type.py b/test/test_dependency_type.py
index c5afd38d..e172782b 100644
--- a/test/test_dependency_type.py
+++ b/test/test_dependency_type.py
@@ -12,8 +12,7 @@ def setup(db_test):
def test_dependency_types():
dep_types = ["depends", "makedepends", "checkdepends", "optdepends"]
for dep_type in dep_types:
- dependency_type = query(DependencyType,
- DependencyType.Name == dep_type).first()
+ dependency_type = query(DependencyType, DependencyType.Name == dep_type).first()
assert dependency_type is not None
diff --git a/test/test_email.py b/test/test_email.py
index 873feffe..81abd507 100644
--- a/test/test_email.py
+++ b/test/test_email.py
@@ -1,5 +1,4 @@
import io
-
from subprocess import PIPE, Popen
import pytest
@@ -23,7 +22,7 @@ def sendmail(from_: str, to_: str, content: str) -> Email:
def test_email_glue():
- """ Test that Email.glue() decodes both base64 and decoded content. """
+ """Test that Email.glue() decodes both base64 and decoded content."""
body = "Test email."
sendmail("test@example.org", "test@example.org", body)
assert Email.count() == 1
@@ -34,7 +33,7 @@ def test_email_glue():
def test_email_dump():
- """ Test that Email.dump() dumps a single email. """
+ """Test that Email.dump() dumps a single email."""
body = "Test email."
sendmail("test@example.org", "test@example.org", body)
assert Email.count() == 1
@@ -46,7 +45,7 @@ def test_email_dump():
def test_email_dump_multiple():
- """ Test that Email.dump() dumps multiple emails. """
+ """Test that Email.dump() dumps multiple emails."""
body = "Test email."
sendmail("test@example.org", "test@example.org", body)
sendmail("test2@example.org", "test2@example.org", body)
diff --git a/test/test_filelock.py b/test/test_filelock.py
index 70aa7580..c0580642 100644
--- a/test/test_filelock.py
+++ b/test/test_filelock.py
@@ -1,5 +1,4 @@
import py
-
from _pytest.logging import LogCaptureFixture
from aurweb.testing.filelock import FileLock
diff --git a/test/test_filters.py b/test/test_filters.py
index 558911f5..e74ddb87 100644
--- a/test/test_filters.py
+++ b/test/test_filters.py
@@ -22,7 +22,7 @@ def test_number_format():
def test_extend_query():
- """ Test extension of a query via extend_query. """
+ """Test extension of a query via extend_query."""
query = {"a": "b"}
extended = filters.extend_query(query, ("a", "c"), ("b", "d"))
assert extended.get("a") == "c"
@@ -30,7 +30,7 @@ def test_extend_query():
def test_to_qs():
- """ Test conversion from a query dictionary to a query string. """
+ """Test conversion from a query dictionary to a query string."""
query = {"a": "b", "c": [1, 2, 3]}
qs = filters.to_qs(query)
assert qs == "a=b&c=1&c=2&c=3"
diff --git a/test/test_group.py b/test/test_group.py
index 82b82464..a1c563b6 100644
--- a/test/test_group.py
+++ b/test/test_group.py
@@ -1,5 +1,4 @@
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db
diff --git a/test/test_homepage.py b/test/test_homepage.py
index 63b832e3..5490a244 100644
--- a/test/test_homepage.py
+++ b/test/test_homepage.py
@@ -1,10 +1,8 @@
import re
-
from http import HTTPStatus
from unittest.mock import patch
import pytest
-
from fastapi.testclient import TestClient
from aurweb import db, time
@@ -31,16 +29,26 @@ def setup(db_test):
@pytest.fixture
def user():
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- Passwd="testPassword", AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
@pytest.fixture
def user2():
with db.begin():
- user = db.create(User, Username="test2", Email="test2@example.org",
- Passwd="testPassword", AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test2",
+ Email="test2@example.org",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
@@ -50,10 +58,17 @@ def redis():
def delete_keys():
# Cleanup keys if they exist.
- for key in ("package_count", "orphan_count", "user_count",
- "trusted_user_count", "seven_days_old_added",
- "seven_days_old_updated", "year_old_updated",
- "never_updated", "package_updates"):
+ for key in (
+ "package_count",
+ "orphan_count",
+ "user_count",
+ "trusted_user_count",
+ "seven_days_old_added",
+ "seven_days_old_updated",
+ "year_old_updated",
+ "never_updated",
+ "package_updates",
+ ):
if redis.get(key) is not None:
redis.delete(key)
@@ -66,16 +81,21 @@ def redis():
def package(user: User) -> Package:
now = time.utcnow()
with db.begin():
- pkgbase = db.create(PackageBase, Name="test-pkg",
- Maintainer=user, Packager=user,
- SubmittedTS=now, ModifiedTS=now)
+ pkgbase = db.create(
+ PackageBase,
+ Name="test-pkg",
+ Maintainer=user,
+ Packager=user,
+ SubmittedTS=now,
+ ModifiedTS=now,
+ )
pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name)
yield pkg
@pytest.fixture
def packages(user):
- """ Yield a list of num_packages Package objects maintained by user. """
+ """Yield a list of num_packages Package objects maintained by user."""
num_packages = 50 # Tunable
# For i..num_packages, create a package named pkg_{i}.
@@ -83,9 +103,14 @@ def packages(user):
now = time.utcnow()
with db.begin():
for i in range(num_packages):
- pkgbase = db.create(PackageBase, Name=f"pkg_{i}",
- Maintainer=user, Packager=user,
- SubmittedTS=now, ModifiedTS=now)
+ pkgbase = db.create(
+ PackageBase,
+ Name=f"pkg_{i}",
+ Maintainer=user,
+ Packager=user,
+ SubmittedTS=now,
+ ModifiedTS=now,
+ )
pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name)
pkgs.append(pkg)
now += 1
@@ -99,9 +124,9 @@ def test_homepage():
assert response.status_code == int(HTTPStatus.OK)
-@patch('aurweb.util.get_ssh_fingerprints')
+@patch("aurweb.util.get_ssh_fingerprints")
def test_homepage_ssh_fingerprints(get_ssh_fingerprints_mock):
- fingerprints = {'Ed25519': "SHA256:RFzBCUItH9LZS0cKB5UE6ceAYhBD5C8GeOBip8Z11+4"}
+ fingerprints = {"Ed25519": "SHA256:RFzBCUItH9LZS0cKB5UE6ceAYhBD5C8GeOBip8Z11+4"}
get_ssh_fingerprints_mock.return_value = fingerprints
with client as request:
@@ -110,17 +135,23 @@ def test_homepage_ssh_fingerprints(get_ssh_fingerprints_mock):
for key, value in fingerprints.items():
assert key in response.content.decode()
assert value in response.content.decode()
- assert 'The following SSH fingerprints are used for the AUR' in response.content.decode()
+ assert (
+ "The following SSH fingerprints are used for the AUR"
+ in response.content.decode()
+ )
-@patch('aurweb.util.get_ssh_fingerprints')
+@patch("aurweb.util.get_ssh_fingerprints")
def test_homepage_no_ssh_fingerprints(get_ssh_fingerprints_mock):
get_ssh_fingerprints_mock.return_value = {}
with client as request:
response = request.get("/")
- assert 'The following SSH fingerprints are used for the AUR' not in response.content.decode()
+ assert (
+ "The following SSH fingerprints are used for the AUR"
+ not in response.content.decode()
+ )
def test_homepage_stats(redis, packages):
@@ -131,20 +162,20 @@ def test_homepage_stats(redis, packages):
root = parse_root(response.text)
expectations = [
- ("Packages", r'\d+'),
- ("Orphan Packages", r'\d+'),
- ("Packages added in the past 7 days", r'\d+'),
- ("Packages updated in the past 7 days", r'\d+'),
- ("Packages updated in the past year", r'\d+'),
- ("Packages never updated", r'\d+'),
- ("Registered Users", r'\d+'),
- ("Trusted Users", r'\d+')
+ ("Packages", r"\d+"),
+ ("Orphan Packages", r"\d+"),
+ ("Packages added in the past 7 days", r"\d+"),
+ ("Packages updated in the past 7 days", r"\d+"),
+ ("Packages updated in the past year", r"\d+"),
+ ("Packages never updated", r"\d+"),
+ ("Registered Users", r"\d+"),
+ ("Trusted Users", r"\d+"),
]
stats = root.xpath('//div[@id="pkg-stats"]//tr')
for i, expected in enumerate(expectations):
expected_key, expected_regex = expected
- key, value = stats[i].xpath('./td')
+ key, value = stats[i].xpath("./td")
assert key.text.strip() == expected_key
assert re.match(expected_regex, value.text.strip())
@@ -165,7 +196,7 @@ def test_homepage_updates(redis, packages):
expectations = [f"pkg_{i}" for i in range(50 - 1, 50 - 1 - 15, -1)]
updates = root.xpath('//div[@id="pkg-updates"]/table/tbody/tr')
for i, expected in enumerate(expectations):
- pkgname = updates[i].xpath('./td/a').pop(0)
+ pkgname = updates[i].xpath("./td/a").pop(0)
assert pkgname.text.strip() == expected
@@ -173,9 +204,9 @@ def test_homepage_dashboard(redis, packages, user):
# Create Comaintainer records for all of the packages.
with db.begin():
for pkg in packages:
- db.create(PackageComaintainer,
- PackageBase=pkg.PackageBase,
- User=user, Priority=1)
+ db.create(
+ PackageComaintainer, PackageBase=pkg.PackageBase, User=user, Priority=1
+ )
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
@@ -189,16 +220,18 @@ def test_homepage_dashboard(redis, packages, user):
expectations = [f"pkg_{i}" for i in range(50 - 1, 0, -1)]
my_packages = root.xpath('//table[@id="my-packages"]/tbody/tr')
for i, expected in enumerate(expectations):
- name, version, votes, pop, voted, notify, desc, maint \
- = my_packages[i].xpath('./td')
- assert name.xpath('./a').pop(0).text.strip() == expected
+ name, version, votes, pop, voted, notify, desc, maint = my_packages[i].xpath(
+ "./td"
+ )
+ assert name.xpath("./a").pop(0).text.strip() == expected
# Do the same for the Comaintained Packages table.
my_packages = root.xpath('//table[@id="comaintained-packages"]/tbody/tr')
for i, expected in enumerate(expectations):
- name, version, votes, pop, voted, notify, desc, maint \
- = my_packages[i].xpath('./td')
- assert name.xpath('./a').pop(0).text.strip() == expected
+ name, version, votes, pop, voted, notify, desc, maint = my_packages[i].xpath(
+ "./td"
+ )
+ assert name.xpath("./a").pop(0).text.strip() == expected
def test_homepage_dashboard_requests(redis, packages, user):
@@ -207,11 +240,16 @@ def test_homepage_dashboard_requests(redis, packages, user):
pkg = packages[0]
reqtype = db.query(RequestType, RequestType.ID == DELETION_ID).first()
with db.begin():
- pkgreq = db.create(PackageRequest, PackageBase=pkg.PackageBase,
- PackageBaseName=pkg.PackageBase.Name,
- User=user, Comments=str(),
- ClosureComment=str(), RequestTS=now,
- RequestType=reqtype)
+ pkgreq = db.create(
+ PackageRequest,
+ PackageBase=pkg.PackageBase,
+ PackageBaseName=pkg.PackageBase.Name,
+ User=user,
+ Comments=str(),
+ ClosureComment=str(),
+ RequestTS=now,
+ RequestType=reqtype,
+ )
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
@@ -220,7 +258,7 @@ def test_homepage_dashboard_requests(redis, packages, user):
root = parse_root(response.text)
request = root.xpath('//table[@id="pkgreq-results"]/tbody/tr').pop(0)
- pkgname = request.xpath('./td/a').pop(0)
+ pkgname = request.xpath("./td/a").pop(0)
assert pkgname.text.strip() == pkgreq.PackageBaseName
@@ -238,7 +276,7 @@ def test_homepage_dashboard_flagged_packages(redis, packages, user):
# Check to see that the package showed up in the Flagged Packages table.
root = parse_root(response.text)
flagged_pkg = root.xpath('//table[@id="flagged-packages"]/tbody/tr').pop(0)
- flagged_name = flagged_pkg.xpath('./td/a').pop(0)
+ flagged_name = flagged_pkg.xpath("./td/a").pop(0)
assert flagged_name.text.strip() == pkg.Name
@@ -247,8 +285,7 @@ def test_homepage_dashboard_flagged(user: User, user2: User, package: Package):
now = time.utcnow()
with db.begin():
- db.create(PackageComaintainer, User=user2,
- PackageBase=pkgbase, Priority=1)
+ db.create(PackageComaintainer, User=user2, PackageBase=pkgbase, Priority=1)
pkgbase.OutOfDateTS = now - 5
pkgbase.Flagger = user
diff --git a/test/test_html.py b/test/test_html.py
index ffe2a9f2..88c75a7c 100644
--- a/test/test_html.py
+++ b/test/test_html.py
@@ -2,13 +2,11 @@
import hashlib
import os
import tempfile
-
from http import HTTPStatus
from unittest import mock
import fastapi
import pytest
-
from fastapi import HTTPException
from fastapi.testclient import TestClient
@@ -33,8 +31,13 @@ def client() -> TestClient:
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- Passwd="testPassword", AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
@@ -53,12 +56,7 @@ def pkgbase(user: User) -> PackageBase:
def test_archdev_navbar(client: TestClient):
- expected = [
- "AUR Home",
- "Packages",
- "Register",
- "Login"
- ]
+ expected = ["AUR Home", "Packages", "Register", "Login"]
with client as request:
resp = request.get("/")
assert resp.status_code == int(HTTPStatus.OK)
@@ -70,13 +68,7 @@ def test_archdev_navbar(client: TestClient):
def test_archdev_navbar_authenticated(client: TestClient, user: User):
- expected = [
- "Dashboard",
- "Packages",
- "Requests",
- "My Account",
- "Logout"
- ]
+ expected = ["Dashboard", "Packages", "Requests", "My Account", "Logout"]
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
resp = request.get("/", cookies=cookies)
@@ -88,8 +80,7 @@ def test_archdev_navbar_authenticated(client: TestClient, user: User):
assert item.text.strip() == expected[i]
-def test_archdev_navbar_authenticated_tu(client: TestClient,
- trusted_user: User):
+def test_archdev_navbar_authenticated_tu(client: TestClient, trusted_user: User):
expected = [
"Dashboard",
"Packages",
@@ -97,7 +88,7 @@ def test_archdev_navbar_authenticated_tu(client: TestClient,
"Accounts",
"My Account",
"Trusted User",
- "Logout"
+ "Logout",
]
cookies = {"AURSID": trusted_user.login(Request(), "testPassword")}
with client as request:
@@ -131,7 +122,7 @@ def test_get_successes():
def test_archive_sig(client: TestClient):
- hash_value = hashlib.sha256(b'test').hexdigest()
+ hash_value = hashlib.sha256(b"test").hexdigest()
with tempfile.TemporaryDirectory() as tmpdir:
packages_sha256 = os.path.join(tmpdir, "packages.gz.sha256")
@@ -179,12 +170,7 @@ def test_disabled_metrics(client: TestClient):
def test_rtl(client: TestClient):
responses = {}
- expected = [
- [],
- [],
- ['rtl'],
- ['rtl']
- ]
+ expected = [[], [], ["rtl"], ["rtl"]]
with client as request:
responses["default"] = request.get("/")
responses["de"] = request.get("/", cookies={"AURLANG": "de"})
@@ -193,11 +179,11 @@ def test_rtl(client: TestClient):
for i, (lang, resp) in enumerate(responses.items()):
assert resp.status_code == int(HTTPStatus.OK)
t = parse_root(resp.text)
- assert t.xpath('//html/@dir') == expected[i]
+ assert t.xpath("//html/@dir") == expected[i]
def test_404_with_valid_pkgbase(client: TestClient, pkgbase: PackageBase):
- """ Test HTTPException with status_code == 404 and valid pkgbase. """
+ """Test HTTPException with status_code == 404 and valid pkgbase."""
endpoint = f"/{pkgbase.Name}"
with client as request:
response = request.get(endpoint)
@@ -209,7 +195,7 @@ def test_404_with_valid_pkgbase(client: TestClient, pkgbase: PackageBase):
def test_404(client: TestClient):
- """ Test HTTPException with status_code == 404 without a valid pkgbase. """
+ """Test HTTPException with status_code == 404 without a valid pkgbase."""
with client as request:
response = request.get("/nonexistentroute")
assert response.status_code == int(HTTPStatus.NOT_FOUND)
@@ -221,7 +207,8 @@ def test_404(client: TestClient):
def test_503(client: TestClient):
- """ Test HTTPException with status_code == 503 (Service Unavailable). """
+ """Test HTTPException with status_code == 503 (Service Unavailable)."""
+
@asgi.app.get("/raise-503")
async def raise_503(request: fastapi.Request):
raise HTTPException(status_code=HTTPStatus.SERVICE_UNAVAILABLE)
diff --git a/test/test_initdb.py b/test/test_initdb.py
index 44681d8e..db5edf74 100644
--- a/test/test_initdb.py
+++ b/test/test_initdb.py
@@ -3,7 +3,6 @@ import pytest
import aurweb.config
import aurweb.db
import aurweb.initdb
-
from aurweb.models.account_type import AccountType
@@ -19,11 +18,11 @@ class Args:
def test_run():
from aurweb.schema import metadata
+
aurweb.db.kill_engine()
metadata.drop_all(aurweb.db.get_engine())
aurweb.initdb.run(Args())
# Check that constant table rows got added via initdb.
- record = aurweb.db.query(AccountType,
- AccountType.AccountType == "User").first()
+ record = aurweb.db.query(AccountType, AccountType.AccountType == "User").first()
assert record is not None
diff --git a/test/test_l10n.py b/test/test_l10n.py
index c24c5f55..818d517f 100644
--- a/test/test_l10n.py
+++ b/test/test_l10n.py
@@ -4,13 +4,13 @@ from aurweb.testing.requests import Request
def test_translator():
- """ Test creating l10n translation tools. """
+ """Test creating l10n translation tools."""
de_home = l10n.translator.translate("Home", "de")
assert de_home == "Startseite"
def test_get_request_language():
- """ First, tests default_lang, then tests a modified AURLANG cookie. """
+ """First, tests default_lang, then tests a modified AURLANG cookie."""
request = Request()
assert l10n.get_request_language(request) == "en"
@@ -19,18 +19,17 @@ def test_get_request_language():
def test_get_raw_translator_for_request():
- """ Make sure that get_raw_translator_for_request is giving us
- the translator we expect. """
+ """Make sure that get_raw_translator_for_request is giving us
+ the translator we expect."""
request = Request()
request.cookies["AURLANG"] = "de"
translator = l10n.get_raw_translator_for_request(request)
- assert translator.gettext("Home") == \
- l10n.translator.translate("Home", "de")
+ assert translator.gettext("Home") == l10n.translator.translate("Home", "de")
def test_get_translator_for_request():
- """ Make sure that get_translator_for_request is giving us back
- our expected translation function. """
+ """Make sure that get_translator_for_request is giving us back
+ our expected translation function."""
request = Request()
request.cookies["AURLANG"] = "de"
@@ -43,10 +42,8 @@ def test_tn_filter():
request.cookies["AURLANG"] = "en"
context = {"language": "en", "request": request}
- translated = filters.tn(context, 1, "%d package found.",
- "%d packages found.")
+ translated = filters.tn(context, 1, "%d package found.", "%d packages found.")
assert translated == "%d package found."
- translated = filters.tn(context, 2, "%d package found.",
- "%d packages found.")
+ translated = filters.tn(context, 2, "%d package found.", "%d packages found.")
assert translated == "%d packages found."
diff --git a/test/test_license.py b/test/test_license.py
index b34bd260..cea76e7d 100644
--- a/test/test_license.py
+++ b/test/test_license.py
@@ -1,5 +1,4 @@
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db
diff --git a/test/test_mkpkglists.py b/test/test_mkpkglists.py
index 9bc1073b..3c105817 100644
--- a/test/test_mkpkglists.py
+++ b/test/test_mkpkglists.py
@@ -1,14 +1,20 @@
import gzip
import json
import os
-
from unittest import mock
import py
import pytest
from aurweb import config, db
-from aurweb.models import License, Package, PackageBase, PackageDependency, PackageLicense, User
+from aurweb.models import (
+ License,
+ Package,
+ PackageBase,
+ PackageDependency,
+ PackageLicense,
+ User,
+)
from aurweb.models.account_type import USER_ID
from aurweb.models.dependency_type import DEPENDS_ID
@@ -38,10 +44,13 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test",
- Email="test@example.org",
- Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
@@ -52,16 +61,18 @@ def packages(user: User) -> list[Package]:
lic = db.create(License, Name="GPL")
for i in range(5):
# Create the package.
- pkgbase = db.create(PackageBase, Name=f"pkgbase_{i}",
- Packager=user)
- pkg = db.create(Package, PackageBase=pkgbase,
- Name=f"pkg_{i}")
+ pkgbase = db.create(PackageBase, Name=f"pkgbase_{i}", Packager=user)
+ pkg = db.create(Package, PackageBase=pkgbase, Name=f"pkg_{i}")
# Create some related records.
db.create(PackageLicense, Package=pkg, License=lic)
- db.create(PackageDependency, DepTypeID=DEPENDS_ID,
- Package=pkg, DepName=f"dep_{i}",
- DepCondition=">=1.0")
+ db.create(
+ PackageDependency,
+ DepTypeID=DEPENDS_ID,
+ Package=pkg,
+ DepName=f"dep_{i}",
+ DepCondition=">=1.0",
+ )
# Add the package to our output list.
output.append(pkg)
@@ -88,8 +99,11 @@ def config_mock(tmpdir: py.path.local) -> None:
config.rehash()
-def test_mkpkglists(tmpdir: py.path.local, config_mock: None, user: User, packages: list[Package]):
+def test_mkpkglists(
+ tmpdir: py.path.local, config_mock: None, user: User, packages: list[Package]
+):
from aurweb.scripts import mkpkglists
+
mkpkglists.main()
PACKAGES = config.get("mkpkglists", "packagesfile")
@@ -106,10 +120,7 @@ def test_mkpkglists(tmpdir: py.path.local, config_mock: None, user: User, packag
PKGBASE,
"pkgbase_0\npkgbase_1\npkgbase_2\npkgbase_3\npkgbase_4\n",
),
- (
- USERS,
- "test\n"
- ),
+ (USERS, "test\n"),
]
for (file, expected_content) in expectations:
@@ -136,6 +147,7 @@ def test_mkpkglists(tmpdir: py.path.local, config_mock: None, user: User, packag
@mock.patch("sys.argv", ["mkpkglists", "--extended"])
def test_mkpkglists_extended_empty(config_mock: None):
from aurweb.scripts import mkpkglists
+
mkpkglists.main()
PACKAGES = config.get("mkpkglists", "packagesfile")
@@ -166,9 +178,9 @@ def test_mkpkglists_extended_empty(config_mock: None):
@mock.patch("sys.argv", ["mkpkglists", "--extended"])
-def test_mkpkglists_extended(config_mock: None, user: User,
- packages: list[Package]):
+def test_mkpkglists_extended(config_mock: None, user: User, packages: list[Package]):
from aurweb.scripts import mkpkglists
+
mkpkglists.main()
PACKAGES = config.get("mkpkglists", "packagesfile")
@@ -186,10 +198,7 @@ def test_mkpkglists_extended(config_mock: None, user: User,
PKGBASE,
"pkgbase_0\npkgbase_1\npkgbase_2\npkgbase_3\npkgbase_4\n",
),
- (
- USERS,
- "test\n"
- ),
+ (USERS, "test\n"),
]
for (file, expected_content) in expectations:
diff --git a/test/test_notify.py b/test/test_notify.py
index bbcc6b5a..9e61d9ee 100644
--- a/test/test_notify.py
+++ b/test/test_notify.py
@@ -23,24 +23,39 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- Passwd=str(), AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ Passwd=str(),
+ AccountTypeID=USER_ID,
+ )
yield user
@pytest.fixture
def user1() -> User:
with db.begin():
- user1 = db.create(User, Username="user1", Email="user1@example.org",
- Passwd=str(), AccountTypeID=USER_ID)
+ user1 = db.create(
+ User,
+ Username="user1",
+ Email="user1@example.org",
+ Passwd=str(),
+ AccountTypeID=USER_ID,
+ )
yield user1
@pytest.fixture
def user2() -> User:
with db.begin():
- user2 = db.create(User, Username="user2", Email="user2@example.org",
- Passwd=str(), AccountTypeID=USER_ID)
+ user2 = db.create(
+ User,
+ Username="user2",
+ Email="user2@example.org",
+ Passwd=str(),
+ AccountTypeID=USER_ID,
+ )
yield user2
@@ -52,11 +67,15 @@ def pkgbases(user: User) -> list[PackageBase]:
with db.begin():
for i in range(5):
output.append(
- db.create(PackageBase, Name=f"pkgbase_{i}",
- Maintainer=user, SubmittedTS=now,
- ModifiedTS=now))
- db.create(models.PackageNotification, PackageBase=output[-1],
- User=user)
+ db.create(
+ PackageBase,
+ Name=f"pkgbase_{i}",
+ Maintainer=user,
+ SubmittedTS=now,
+ ModifiedTS=now,
+ )
+ )
+ db.create(models.PackageNotification, PackageBase=output[-1], User=user)
yield output
@@ -64,11 +83,15 @@ def pkgbases(user: User) -> list[PackageBase]:
def pkgreq(user2: User, pkgbases: list[PackageBase]):
pkgbase = pkgbases[0]
with db.begin():
- pkgreq_ = db.create(PackageRequest, PackageBase=pkgbase,
- PackageBaseName=pkgbase.Name, User=user2,
- ReqTypeID=ORPHAN_ID,
- Comments="This is a request test comment.",
- ClosureComment=str())
+ pkgreq_ = db.create(
+ PackageRequest,
+ PackageBase=pkgbase,
+ PackageBaseName=pkgbase.Name,
+ User=user2,
+ ReqTypeID=ORPHAN_ID,
+ Comments="This is a request test comment.",
+ ClosureComment=str(),
+ )
yield pkgreq_
@@ -78,21 +101,24 @@ def packages(pkgbases: list[PackageBase]) -> list[Package]:
with db.begin():
for i, pkgbase in enumerate(pkgbases):
output.append(
- db.create(Package, PackageBase=pkgbase,
- Name=f"pkg_{i}", Version=f"{i}.0"))
+ db.create(
+ Package, PackageBase=pkgbase, Name=f"pkg_{i}", Version=f"{i}.0"
+ )
+ )
yield output
-def test_out_of_date(user: User, user1: User, user2: User,
- pkgbases: list[PackageBase]):
+def test_out_of_date(user: User, user1: User, user2: User, pkgbases: list[PackageBase]):
pkgbase = pkgbases[0]
# Create two comaintainers. We'll pass the maintainer uid to
# FlagNotification, so we should expect to get two emails.
with db.begin():
- db.create(models.PackageComaintainer,
- PackageBase=pkgbase, User=user1, Priority=1)
- db.create(models.PackageComaintainer,
- PackageBase=pkgbase, User=user2, Priority=2)
+ db.create(
+ models.PackageComaintainer, PackageBase=pkgbase, User=user1, Priority=1
+ )
+ db.create(
+ models.PackageComaintainer, PackageBase=pkgbase, User=user2, Priority=2
+ )
# Send the notification for pkgbases[0].
notif = notify.FlagNotification(user.ID, pkgbases[0].ID)
@@ -165,8 +191,12 @@ def test_comment(user: User, user2: User, pkgbases: list[PackageBase]):
pkgbase = pkgbases[0]
with db.begin():
- comment = db.create(models.PackageComment, PackageBase=pkgbase,
- User=user2, Comments="This is a test comment.")
+ comment = db.create(
+ models.PackageComment,
+ PackageBase=pkgbase,
+ User=user2,
+ Comments="This is a test comment.",
+ )
rendercomment.update_comment_render_fastapi(comment)
notif = notify.CommentNotification(user2.ID, pkgbase.ID, comment.ID)
@@ -366,15 +396,16 @@ def set_tu(users: list[User]) -> User:
user.AccountTypeID = TRUSTED_USER_ID
-def test_open_close_request(user: User, user2: User,
- pkgreq: PackageRequest,
- pkgbases: list[PackageBase]):
+def test_open_close_request(
+ user: User, user2: User, pkgreq: PackageRequest, pkgbases: list[PackageBase]
+):
set_tu([user])
pkgbase = pkgbases[0]
# Send an open request notification.
notif = notify.RequestOpenNotification(
- user2.ID, pkgreq.ID, pkgreq.RequestType.Name, pkgbase.ID)
+ user2.ID, pkgreq.ID, pkgreq.RequestType.Name, pkgbase.ID
+ )
notif.send()
assert Email.count() == 1
@@ -420,22 +451,24 @@ Request #{pkgreq.ID} has been rejected by {user2.Username} [1].
email = Email(3).parse()
assert email.headers.get("To") == aur_request_ml
assert email.headers.get("Cc") == ", ".join([user.Email, user2.Email])
- expected = (f"[PRQ#{pkgreq.ID}] Orphan Request for "
- f"{pkgbase.Name} Accepted")
+ expected = f"[PRQ#{pkgreq.ID}] Orphan Request for " f"{pkgbase.Name} Accepted"
assert email.headers.get("Subject") == expected
- expected = (f"Request #{pkgreq.ID} has been accepted automatically "
- "by the Arch User Repository\npackage request system.")
+ expected = (
+ f"Request #{pkgreq.ID} has been accepted automatically "
+ "by the Arch User Repository\npackage request system."
+ )
assert email.body == expected
-def test_close_request_comaintainer_cc(user: User, user2: User,
- pkgreq: PackageRequest,
- pkgbases: list[PackageBase]):
+def test_close_request_comaintainer_cc(
+ user: User, user2: User, pkgreq: PackageRequest, pkgbases: list[PackageBase]
+):
pkgbase = pkgbases[0]
with db.begin():
- db.create(models.PackageComaintainer, PackageBase=pkgbase,
- User=user2, Priority=1)
+ db.create(
+ models.PackageComaintainer, PackageBase=pkgbase, User=user2, Priority=1
+ )
notif = notify.RequestCloseNotification(0, pkgreq.ID, "accepted")
notif.send()
@@ -446,9 +479,9 @@ def test_close_request_comaintainer_cc(user: User, user2: User,
assert email.headers.get("Cc") == ", ".join([user.Email, user2.Email])
-def test_close_request_closure_comment(user: User, user2: User,
- pkgreq: PackageRequest,
- pkgbases: list[PackageBase]):
+def test_close_request_closure_comment(
+ user: User, user2: User, pkgreq: PackageRequest, pkgbases: list[PackageBase]
+):
pkgbase = pkgbases[0]
with db.begin():
pkgreq.ClosureComment = "This is a test closure comment."
@@ -496,7 +529,7 @@ ends in less than 48 hours.
def test_notify_main(user: User):
- """ Test TU vote reminder through aurweb.notify.main(). """
+ """Test TU vote reminder through aurweb.notify.main()."""
set_tu([user])
vote_id = 1
@@ -539,6 +572,7 @@ def mock_smtp_config(cls):
elif key == "smtp-password":
return cls()
return cls(config_get(section, key))
+
return _mock_smtp_config
@@ -574,6 +608,7 @@ def mock_smtp_starttls_config(cls):
elif key == "smtp-password":
return cls("password")
return cls(config_get(section, key))
+
return _mock_smtp_starttls_config
@@ -590,8 +625,7 @@ def test_smtp_starttls(user: User):
get = "aurweb.config.get"
getboolean = "aurweb.config.getboolean"
with mock.patch(get, side_effect=mock_smtp_starttls_config(str)):
- with mock.patch(
- getboolean, side_effect=mock_smtp_starttls_config(bool)):
+ with mock.patch(getboolean, side_effect=mock_smtp_starttls_config(bool)):
with mock.patch("smtplib.SMTP", side_effect=smtp):
notif = notify.WelcomeNotification(user.ID)
notif.send()
@@ -621,6 +655,7 @@ def mock_smtp_ssl_config(cls):
elif key == "smtp-password":
return cls("password")
return cls(config_get(section, key))
+
return _mock_smtp_ssl_config
@@ -651,7 +686,7 @@ def test_notification_defaults():
def test_notification_oserror(user: User, caplog: pytest.LogCaptureFixture):
- """ Try sending a notification with a bad SMTP configuration. """
+ """Try sending a notification with a bad SMTP configuration."""
caplog.set_level(ERROR)
config_get = config.get
config_getint = config.getint
diff --git a/test/test_official_provider.py b/test/test_official_provider.py
index 9287ea2d..b36fff5a 100644
--- a/test/test_official_provider.py
+++ b/test/test_official_provider.py
@@ -1,5 +1,4 @@
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db
@@ -13,10 +12,12 @@ def setup(db_test):
def test_official_provider_creation():
with db.begin():
- oprovider = db.create(OfficialProvider,
- Name="some-name",
- Repo="some-repo",
- Provides="some-provides")
+ oprovider = db.create(
+ OfficialProvider,
+ Name="some-name",
+ Repo="some-repo",
+ Provides="some-provides",
+ )
assert bool(oprovider.ID)
assert oprovider.Name == "some-name"
assert oprovider.Repo == "some-repo"
@@ -24,19 +25,23 @@ def test_official_provider_creation():
def test_official_provider_cs():
- """ Test case sensitivity of the database table. """
+ """Test case sensitivity of the database table."""
with db.begin():
- oprovider = db.create(OfficialProvider,
- Name="some-name",
- Repo="some-repo",
- Provides="some-provides")
+ oprovider = db.create(
+ OfficialProvider,
+ Name="some-name",
+ Repo="some-repo",
+ Provides="some-provides",
+ )
assert bool(oprovider.ID)
with db.begin():
- oprovider_cs = db.create(OfficialProvider,
- Name="SOME-NAME",
- Repo="SOME-REPO",
- Provides="SOME-PROVIDES")
+ oprovider_cs = db.create(
+ OfficialProvider,
+ Name="SOME-NAME",
+ Repo="SOME-REPO",
+ Provides="SOME-PROVIDES",
+ )
assert bool(oprovider_cs.ID)
assert oprovider.ID != oprovider_cs.ID
diff --git a/test/test_package.py b/test/test_package.py
index 1408a182..2a9df483 100644
--- a/test/test_package.py
+++ b/test/test_package.py
@@ -1,5 +1,4 @@
import pytest
-
from sqlalchemy import and_
from sqlalchemy.exc import IntegrityError
@@ -20,20 +19,28 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- RealName="Test User", Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
@pytest.fixture
def package(user: User) -> Package:
with db.begin():
- pkgbase = db.create(PackageBase, Name="beautiful-package",
- Maintainer=user)
- package = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name,
- Description="Test description.",
- URL="https://test.package")
+ pkgbase = db.create(PackageBase, Name="beautiful-package", Maintainer=user)
+ package = db.create(
+ Package,
+ PackageBase=pkgbase,
+ Name=pkgbase.Name,
+ Description="Test description.",
+ URL="https://test.package",
+ )
yield package
@@ -48,21 +55,28 @@ def test_package(package: Package):
package.Version = "1.2.3"
# Make sure it got updated in the database.
- record = db.query(Package).filter(
- and_(Package.ID == package.ID,
- Package.Version == "1.2.3")
- ).first()
+ record = (
+ db.query(Package)
+ .filter(and_(Package.ID == package.ID, Package.Version == "1.2.3"))
+ .first()
+ )
assert record is not None
def test_package_null_pkgbase_raises():
with pytest.raises(IntegrityError):
- Package(Name="some-package", Description="Some description.",
- URL="https://some.package")
+ Package(
+ Name="some-package",
+ Description="Some description.",
+ URL="https://some.package",
+ )
def test_package_null_name_raises(package: Package):
pkgbase = package.PackageBase
with pytest.raises(IntegrityError):
- Package(PackageBase=pkgbase, Description="Some description.",
- URL="https://some.package")
+ Package(
+ PackageBase=pkgbase,
+ Description="Some description.",
+ URL="https://some.package",
+ )
diff --git a/test/test_package_base.py b/test/test_package_base.py
index 5be7e40b..feea8183 100644
--- a/test/test_package_base.py
+++ b/test/test_package_base.py
@@ -1,5 +1,4 @@
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db
@@ -16,17 +15,21 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- RealName="Test User", Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
@pytest.fixture
def pkgbase(user: User) -> PackageBase:
with db.begin():
- pkgbase = db.create(PackageBase, Name="beautiful-package",
- Maintainer=user)
+ pkgbase = db.create(PackageBase, Name="beautiful-package", Maintainer=user)
yield pkgbase
@@ -44,7 +47,7 @@ def test_package_base(user: User, pkgbase: PackageBase):
def test_package_base_ci(user: User, pkgbase: PackageBase):
- """ Test case insensitivity of the database table. """
+ """Test case insensitivity of the database table."""
with pytest.raises(IntegrityError):
with db.begin():
db.create(PackageBase, Name=pkgbase.Name.upper(), Maintainer=user)
diff --git a/test/test_package_blacklist.py b/test/test_package_blacklist.py
index 427c3be4..44de1830 100644
--- a/test/test_package_blacklist.py
+++ b/test/test_package_blacklist.py
@@ -1,5 +1,4 @@
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db
diff --git a/test/test_package_comaintainer.py b/test/test_package_comaintainer.py
index e377edc0..52075887 100644
--- a/test/test_package_comaintainer.py
+++ b/test/test_package_comaintainer.py
@@ -1,5 +1,4 @@
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db
@@ -17,9 +16,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- RealName="Test User", Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
@@ -32,8 +36,9 @@ def pkgbase(user: User) -> PackageBase:
def test_package_comaintainer_creation(user: User, pkgbase: PackageBase):
with db.begin():
- package_comaintainer = db.create(PackageComaintainer, User=user,
- PackageBase=pkgbase, Priority=5)
+ package_comaintainer = db.create(
+ PackageComaintainer, User=user, PackageBase=pkgbase, Priority=5
+ )
assert bool(package_comaintainer)
assert package_comaintainer.User == user
assert package_comaintainer.PackageBase == pkgbase
@@ -50,7 +55,6 @@ def test_package_comaintainer_null_pkgbase_raises(user: User):
PackageComaintainer(User=user, Priority=1)
-def test_package_comaintainer_null_priority_raises(user: User,
- pkgbase: PackageBase):
+def test_package_comaintainer_null_priority_raises(user: User, pkgbase: PackageBase):
with pytest.raises(IntegrityError):
PackageComaintainer(User=user, PackageBase=pkgbase)
diff --git a/test/test_package_comment.py b/test/test_package_comment.py
index c89e23af..74f2895d 100644
--- a/test/test_package_comment.py
+++ b/test/test_package_comment.py
@@ -1,5 +1,4 @@
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db
@@ -17,9 +16,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- RealName="Test User", Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
@@ -32,35 +36,46 @@ def pkgbase(user: User) -> PackageBase:
def test_package_comment_creation(user: User, pkgbase: PackageBase):
with db.begin():
- package_comment = db.create(PackageComment, PackageBase=pkgbase,
- User=user, Comments="Test comment.",
- RenderedComment="Test rendered comment.")
+ package_comment = db.create(
+ PackageComment,
+ PackageBase=pkgbase,
+ User=user,
+ Comments="Test comment.",
+ RenderedComment="Test rendered comment.",
+ )
assert bool(package_comment.ID)
def test_package_comment_null_pkgbase_raises(user: User):
with pytest.raises(IntegrityError):
- PackageComment(User=user, Comments="Test comment.",
- RenderedComment="Test rendered comment.")
+ PackageComment(
+ User=user,
+ Comments="Test comment.",
+ RenderedComment="Test rendered comment.",
+ )
def test_package_comment_null_user_raises(pkgbase: PackageBase):
with pytest.raises(IntegrityError):
- PackageComment(PackageBase=pkgbase,
- Comments="Test comment.",
- RenderedComment="Test rendered comment.")
+ PackageComment(
+ PackageBase=pkgbase,
+ Comments="Test comment.",
+ RenderedComment="Test rendered comment.",
+ )
-def test_package_comment_null_comments_raises(user: User,
- pkgbase: PackageBase):
+def test_package_comment_null_comments_raises(user: User, pkgbase: PackageBase):
with pytest.raises(IntegrityError):
- PackageComment(PackageBase=pkgbase, User=user,
- RenderedComment="Test rendered comment.")
+ PackageComment(
+ PackageBase=pkgbase, User=user, RenderedComment="Test rendered comment."
+ )
-def test_package_comment_null_renderedcomment_defaults(user: User,
- pkgbase: PackageBase):
+def test_package_comment_null_renderedcomment_defaults(
+ user: User, pkgbase: PackageBase
+):
with db.begin():
- record = db.create(PackageComment, PackageBase=pkgbase,
- User=user, Comments="Test comment.")
+ record = db.create(
+ PackageComment, PackageBase=pkgbase, User=user, Comments="Test comment."
+ )
assert record.RenderedComment == str()
diff --git a/test/test_package_dependency.py b/test/test_package_dependency.py
index 2afbc1e3..9366bb55 100644
--- a/test/test_package_dependency.py
+++ b/test/test_package_dependency.py
@@ -1,5 +1,4 @@
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db
@@ -19,9 +18,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- RealName="Test User", Passwd=str(),
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User",
+ Passwd=str(),
+ AccountTypeID=USER_ID,
+ )
yield user
@@ -29,16 +33,21 @@ def user() -> User:
def package(user: User) -> Package:
with db.begin():
pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user)
- package = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name,
- Description="Test description.",
- URL="https://test.package")
+ package = db.create(
+ Package,
+ PackageBase=pkgbase,
+ Name=pkgbase.Name,
+ Description="Test description.",
+ URL="https://test.package",
+ )
yield package
def test_package_dependencies(user: User, package: Package):
with db.begin():
- pkgdep = db.create(PackageDependency, Package=package,
- DepTypeID=DEPENDS_ID, DepName="test-dep")
+ pkgdep = db.create(
+ PackageDependency, Package=package, DepTypeID=DEPENDS_ID, DepName="test-dep"
+ )
assert pkgdep.DepName == "test-dep"
assert pkgdep.Package == package
assert pkgdep in package.package_dependencies
diff --git a/test/test_package_group.py b/test/test_package_group.py
index 0cb83ee2..163f693d 100644
--- a/test/test_package_group.py
+++ b/test/test_package_group.py
@@ -1,5 +1,4 @@
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db
@@ -19,9 +18,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- RealName="Test User", Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
diff --git a/test/test_package_keyword.py b/test/test_package_keyword.py
index ff466efc..b52547f9 100644
--- a/test/test_package_keyword.py
+++ b/test/test_package_keyword.py
@@ -1,5 +1,4 @@
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db
@@ -17,24 +16,27 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- RealName="Test User", Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
@pytest.fixture
def pkgbase(user: User) -> PackageBase:
with db.begin():
- pkgbase = db.create(PackageBase, Name="beautiful-package",
- Maintainer=user)
+ pkgbase = db.create(PackageBase, Name="beautiful-package", Maintainer=user)
yield pkgbase
def test_package_keyword(pkgbase: PackageBase):
with db.begin():
- pkg_keyword = db.create(PackageKeyword, PackageBase=pkgbase,
- Keyword="test")
+ pkg_keyword = db.create(PackageKeyword, PackageBase=pkgbase, Keyword="test")
assert pkg_keyword in pkgbase.keywords
assert pkgbase == pkg_keyword.PackageBase
diff --git a/test/test_package_license.py b/test/test_package_license.py
index c43423b8..b9242647 100644
--- a/test/test_package_license.py
+++ b/test/test_package_license.py
@@ -1,5 +1,4 @@
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db
@@ -19,9 +18,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- RealName="Test User", Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
@@ -42,8 +46,7 @@ def package(user: User, license: License):
def test_package_license(license: License, package: Package):
with db.begin():
- package_license = db.create(PackageLicense, Package=package,
- License=license)
+ package_license = db.create(PackageLicense, Package=package, License=license)
assert package_license.License == license
assert package_license.Package == package
diff --git a/test/test_package_notification.py b/test/test_package_notification.py
index e7a72a43..27a03e84 100644
--- a/test/test_package_notification.py
+++ b/test/test_package_notification.py
@@ -1,5 +1,4 @@
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db
@@ -16,8 +15,13 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- RealName="Test User", Passwd="testPassword")
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User",
+ Passwd="testPassword",
+ )
yield user
@@ -31,7 +35,8 @@ def pkgbase(user: User) -> PackageBase:
def test_package_notification_creation(user: User, pkgbase: PackageBase):
with db.begin():
package_notification = db.create(
- PackageNotification, User=user, PackageBase=pkgbase)
+ PackageNotification, User=user, PackageBase=pkgbase
+ )
assert bool(package_notification)
assert package_notification.User == user
assert package_notification.PackageBase == pkgbase
diff --git a/test/test_package_relation.py b/test/test_package_relation.py
index 6e9a5545..c20b1394 100644
--- a/test/test_package_relation.py
+++ b/test/test_package_relation.py
@@ -1,5 +1,4 @@
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db
@@ -19,9 +18,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- RealName="Test User", Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
@@ -29,17 +33,24 @@ def user() -> User:
def package(user: User) -> Package:
with db.begin():
pkgbase = db.create(PackageBase, Name="test-package", Maintainer=user)
- package = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name,
- Description="Test description.",
- URL="https://test.package")
+ package = db.create(
+ Package,
+ PackageBase=pkgbase,
+ Name=pkgbase.Name,
+ Description="Test description.",
+ URL="https://test.package",
+ )
yield package
def test_package_relation(package: Package):
with db.begin():
- pkgrel = db.create(PackageRelation, Package=package,
- RelTypeID=CONFLICTS_ID,
- RelName="test-relation")
+ pkgrel = db.create(
+ PackageRelation,
+ Package=package,
+ RelTypeID=CONFLICTS_ID,
+ RelName="test-relation",
+ )
assert pkgrel.RelName == "test-relation"
assert pkgrel.Package == package
diff --git a/test/test_package_request.py b/test/test_package_request.py
index 3474c565..a69a0617 100644
--- a/test/test_package_request.py
+++ b/test/test_package_request.py
@@ -1,12 +1,20 @@
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db, time
from aurweb.models.account_type import USER_ID
from aurweb.models.package_base import PackageBase
-from aurweb.models.package_request import (ACCEPTED, ACCEPTED_ID, CLOSED, CLOSED_ID, PENDING, PENDING_ID, REJECTED,
- REJECTED_ID, PackageRequest)
+from aurweb.models.package_request import (
+ ACCEPTED,
+ ACCEPTED_ID,
+ CLOSED,
+ CLOSED_ID,
+ PENDING,
+ PENDING_ID,
+ REJECTED,
+ REJECTED_ID,
+ PackageRequest,
+)
from aurweb.models.request_type import MERGE_ID
from aurweb.models.user import User
@@ -19,9 +27,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- RealName="Test User", Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
@@ -34,10 +47,15 @@ def pkgbase(user: User) -> PackageBase:
def test_package_request_creation(user: User, pkgbase: PackageBase):
with db.begin():
- package_request = db.create(PackageRequest, ReqTypeID=MERGE_ID,
- User=user, PackageBase=pkgbase,
- PackageBaseName=pkgbase.Name,
- Comments=str(), ClosureComment=str())
+ package_request = db.create(
+ PackageRequest,
+ ReqTypeID=MERGE_ID,
+ User=user,
+ PackageBase=pkgbase,
+ PackageBaseName=pkgbase.Name,
+ Comments=str(),
+ ClosureComment=str(),
+ )
assert bool(package_request.ID)
assert package_request.User == user
@@ -54,11 +72,17 @@ def test_package_request_creation(user: User, pkgbase: PackageBase):
def test_package_request_closed(user: User, pkgbase: PackageBase):
ts = time.utcnow()
with db.begin():
- package_request = db.create(PackageRequest, ReqTypeID=MERGE_ID,
- User=user, PackageBase=pkgbase,
- PackageBaseName=pkgbase.Name,
- Closer=user, ClosedTS=ts,
- Comments=str(), ClosureComment=str())
+ package_request = db.create(
+ PackageRequest,
+ ReqTypeID=MERGE_ID,
+ User=user,
+ PackageBase=pkgbase,
+ PackageBaseName=pkgbase.Name,
+ Closer=user,
+ ClosedTS=ts,
+ Comments=str(),
+ ClosureComment=str(),
+ )
assert package_request.Closer == user
assert package_request.ClosedTS == ts
@@ -67,61 +91,87 @@ def test_package_request_closed(user: User, pkgbase: PackageBase):
assert package_request in user.closed_requests
-def test_package_request_null_request_type_raises(user: User,
- pkgbase: PackageBase):
+def test_package_request_null_request_type_raises(user: User, pkgbase: PackageBase):
with pytest.raises(IntegrityError):
- PackageRequest(User=user, PackageBase=pkgbase,
- PackageBaseName=pkgbase.Name,
- Comments=str(), ClosureComment=str())
+ PackageRequest(
+ User=user,
+ PackageBase=pkgbase,
+ PackageBaseName=pkgbase.Name,
+ Comments=str(),
+ ClosureComment=str(),
+ )
def test_package_request_null_user_raises(pkgbase: PackageBase):
with pytest.raises(IntegrityError):
- PackageRequest(ReqTypeID=MERGE_ID,
- PackageBase=pkgbase, PackageBaseName=pkgbase.Name,
- Comments=str(), ClosureComment=str())
+ PackageRequest(
+ ReqTypeID=MERGE_ID,
+ PackageBase=pkgbase,
+ PackageBaseName=pkgbase.Name,
+ Comments=str(),
+ ClosureComment=str(),
+ )
-def test_package_request_null_package_base_raises(user: User,
- pkgbase: PackageBase):
+def test_package_request_null_package_base_raises(user: User, pkgbase: PackageBase):
with pytest.raises(IntegrityError):
- PackageRequest(ReqTypeID=MERGE_ID,
- User=user, PackageBaseName=pkgbase.Name,
- Comments=str(), ClosureComment=str())
+ PackageRequest(
+ ReqTypeID=MERGE_ID,
+ User=user,
+ PackageBaseName=pkgbase.Name,
+ Comments=str(),
+ ClosureComment=str(),
+ )
-def test_package_request_null_package_base_name_raises(user: User,
- pkgbase: PackageBase):
+def test_package_request_null_package_base_name_raises(
+ user: User, pkgbase: PackageBase
+):
with pytest.raises(IntegrityError):
- PackageRequest(ReqTypeID=MERGE_ID,
- User=user, PackageBase=pkgbase,
- Comments=str(), ClosureComment=str())
+ PackageRequest(
+ ReqTypeID=MERGE_ID,
+ User=user,
+ PackageBase=pkgbase,
+ Comments=str(),
+ ClosureComment=str(),
+ )
-def test_package_request_null_comments_raises(user: User,
- pkgbase: PackageBase):
+def test_package_request_null_comments_raises(user: User, pkgbase: PackageBase):
with pytest.raises(IntegrityError):
- PackageRequest(ReqTypeID=MERGE_ID, User=user,
- PackageBase=pkgbase, PackageBaseName=pkgbase.Name,
- ClosureComment=str())
+ PackageRequest(
+ ReqTypeID=MERGE_ID,
+ User=user,
+ PackageBase=pkgbase,
+ PackageBaseName=pkgbase.Name,
+ ClosureComment=str(),
+ )
-def test_package_request_null_closure_comment_raises(user: User,
- pkgbase: PackageBase):
+def test_package_request_null_closure_comment_raises(user: User, pkgbase: PackageBase):
with pytest.raises(IntegrityError):
- PackageRequest(ReqTypeID=MERGE_ID, User=user,
- PackageBase=pkgbase, PackageBaseName=pkgbase.Name,
- Comments=str())
+ PackageRequest(
+ ReqTypeID=MERGE_ID,
+ User=user,
+ PackageBase=pkgbase,
+ PackageBaseName=pkgbase.Name,
+ Comments=str(),
+ )
def test_package_request_status_display(user: User, pkgbase: PackageBase):
- """ Test status_display() based on the Status column value. """
+ """Test status_display() based on the Status column value."""
with db.begin():
- pkgreq = db.create(PackageRequest, ReqTypeID=MERGE_ID,
- User=user, PackageBase=pkgbase,
- PackageBaseName=pkgbase.Name,
- Comments=str(), ClosureComment=str(),
- Status=PENDING_ID)
+ pkgreq = db.create(
+ PackageRequest,
+ ReqTypeID=MERGE_ID,
+ User=user,
+ PackageBase=pkgbase,
+ PackageBaseName=pkgbase.Name,
+ Comments=str(),
+ ClosureComment=str(),
+ Status=PENDING_ID,
+ )
assert pkgreq.status_display() == PENDING
with db.begin():
diff --git a/test/test_package_source.py b/test/test_package_source.py
index e5797f90..06230580 100644
--- a/test/test_package_source.py
+++ b/test/test_package_source.py
@@ -1,5 +1,4 @@
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db
@@ -18,9 +17,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- RealName="Test User", Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
diff --git a/test/test_package_vote.py b/test/test_package_vote.py
index 24d2fdd2..9a868262 100644
--- a/test/test_package_vote.py
+++ b/test/test_package_vote.py
@@ -1,5 +1,4 @@
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db, time
@@ -17,9 +16,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- RealName="Test User", Passwd=str(),
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User",
+ Passwd=str(),
+ AccountTypeID=USER_ID,
+ )
yield user
@@ -34,8 +38,7 @@ def test_package_vote_creation(user: User, pkgbase: PackageBase):
ts = time.utcnow()
with db.begin():
- package_vote = db.create(PackageVote, User=user,
- PackageBase=pkgbase, VoteTS=ts)
+ package_vote = db.create(PackageVote, User=user, PackageBase=pkgbase, VoteTS=ts)
assert bool(package_vote)
assert package_vote.User == user
assert package_vote.PackageBase == pkgbase
diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py
index 62f89e23..a707bbac 100644
--- a/test/test_packages_routes.py
+++ b/test/test_packages_routes.py
@@ -1,10 +1,8 @@
import re
-
from http import HTTPStatus
from unittest import mock
import pytest
-
from fastapi.testclient import TestClient
from aurweb import asgi, db, time
@@ -22,7 +20,12 @@ from aurweb.models.package_notification import PackageNotification
from aurweb.models.package_relation import PackageRelation
from aurweb.models.package_request import PackageRequest
from aurweb.models.package_vote import PackageVote
-from aurweb.models.relation_type import CONFLICTS_ID, PROVIDES_ID, REPLACES_ID, RelationType
+from aurweb.models.relation_type import (
+ CONFLICTS_ID,
+ PROVIDES_ID,
+ REPLACES_ID,
+ RelationType,
+)
from aurweb.models.request_type import DELETION_ID, RequestType
from aurweb.models.user import User
from aurweb.testing.html import get_errors, get_successes, parse_root
@@ -34,30 +37,24 @@ def package_endpoint(package: Package) -> str:
def create_package(pkgname: str, maintainer: User) -> Package:
- pkgbase = db.create(PackageBase,
- Name=pkgname,
- Maintainer=maintainer)
+ pkgbase = db.create(PackageBase, Name=pkgname, Maintainer=maintainer)
return db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase)
-def create_package_dep(package: Package, depname: str,
- dep_type_name: str = "depends") -> PackageDependency:
- dep_type = db.query(DependencyType,
- DependencyType.Name == dep_type_name).first()
- return db.create(PackageDependency,
- DependencyType=dep_type,
- Package=package,
- DepName=depname)
+def create_package_dep(
+ package: Package, depname: str, dep_type_name: str = "depends"
+) -> PackageDependency:
+ dep_type = db.query(DependencyType, DependencyType.Name == dep_type_name).first()
+ return db.create(
+ PackageDependency, DependencyType=dep_type, Package=package, DepName=depname
+ )
-def create_package_rel(package: Package,
- relname: str) -> PackageRelation:
- rel_type = db.query(RelationType,
- RelationType.ID == PROVIDES_ID).first()
- return db.create(PackageRelation,
- RelationType=rel_type,
- Package=package,
- RelName=relname)
+def create_package_rel(package: Package, relname: str) -> PackageRelation:
+ rel_type = db.query(RelationType, RelationType.ID == PROVIDES_ID).first()
+ return db.create(
+ PackageRelation, RelationType=rel_type, Package=package, RelName=relname
+ )
@pytest.fixture(autouse=True)
@@ -67,64 +64,73 @@ def setup(db_test):
@pytest.fixture
def client() -> TestClient:
- """ Yield a FastAPI TestClient. """
+ """Yield a FastAPI TestClient."""
yield TestClient(app=asgi.app)
def create_user(username: str) -> User:
with db.begin():
- user = db.create(User, Username=username,
- Email=f"{username}@example.org",
- Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username=username,
+ Email=f"{username}@example.org",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
return user
@pytest.fixture
def user() -> User:
- """ Yield a user. """
+ """Yield a user."""
user = create_user("test")
yield user
@pytest.fixture
def maintainer() -> User:
- """ Yield a specific User used to maintain packages. """
+ """Yield a specific User used to maintain packages."""
account_type = db.query(AccountType, AccountType.ID == USER_ID).first()
with db.begin():
- maintainer = db.create(User, Username="test_maintainer",
- Email="test_maintainer@example.org",
- Passwd="testPassword",
- AccountType=account_type)
+ maintainer = db.create(
+ User,
+ Username="test_maintainer",
+ Email="test_maintainer@example.org",
+ Passwd="testPassword",
+ AccountType=account_type,
+ )
yield maintainer
@pytest.fixture
def tu_user():
- tu_type = db.query(AccountType,
- AccountType.AccountType == "Trusted User").first()
+ tu_type = db.query(AccountType, AccountType.AccountType == "Trusted User").first()
with db.begin():
- tu_user = db.create(User, Username="test_tu",
- Email="test_tu@example.org",
- RealName="Test TU", Passwd="testPassword",
- AccountType=tu_type)
+ tu_user = db.create(
+ User,
+ Username="test_tu",
+ Email="test_tu@example.org",
+ RealName="Test TU",
+ Passwd="testPassword",
+ AccountType=tu_type,
+ )
yield tu_user
@pytest.fixture
def package(maintainer: User) -> Package:
- """ Yield a Package created by user. """
+ """Yield a Package created by user."""
now = time.utcnow()
with db.begin():
- pkgbase = db.create(PackageBase,
- Name="test-package",
- Maintainer=maintainer,
- Packager=maintainer,
- Submitter=maintainer,
- ModifiedTS=now)
- package = db.create(Package,
- PackageBase=pkgbase,
- Name=pkgbase.Name)
+ pkgbase = db.create(
+ PackageBase,
+ Name="test-package",
+ Maintainer=maintainer,
+ Packager=maintainer,
+ Submitter=maintainer,
+ ModifiedTS=now,
+ )
+ package = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name)
yield package
@@ -135,29 +141,34 @@ def pkgbase(package: Package) -> PackageBase:
@pytest.fixture
def target(maintainer: User) -> PackageBase:
- """ Merge target. """
+ """Merge target."""
now = time.utcnow()
with db.begin():
- pkgbase = db.create(PackageBase, Name="target-package",
- Maintainer=maintainer,
- Packager=maintainer,
- Submitter=maintainer,
- ModifiedTS=now)
+ pkgbase = db.create(
+ PackageBase,
+ Name="target-package",
+ Maintainer=maintainer,
+ Packager=maintainer,
+ Submitter=maintainer,
+ ModifiedTS=now,
+ )
db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name)
yield pkgbase
@pytest.fixture
def pkgreq(user: User, pkgbase: PackageBase) -> PackageRequest:
- """ Yield a PackageRequest related to `pkgbase`. """
+ """Yield a PackageRequest related to `pkgbase`."""
with db.begin():
- pkgreq = db.create(PackageRequest,
- ReqTypeID=DELETION_ID,
- User=user,
- PackageBase=pkgbase,
- PackageBaseName=pkgbase.Name,
- Comments=f"Deletion request for {pkgbase.Name}",
- ClosureComment=str())
+ pkgreq = db.create(
+ PackageRequest,
+ ReqTypeID=DELETION_ID,
+ User=user,
+ PackageBase=pkgbase,
+ PackageBaseName=pkgbase.Name,
+ Comments=f"Deletion request for {pkgbase.Name}",
+ ClosureComment=str(),
+ )
yield pkgreq
@@ -166,31 +177,33 @@ def comment(user: User, package: Package) -> PackageComment:
pkgbase = package.PackageBase
now = time.utcnow()
with db.begin():
- comment = db.create(PackageComment,
- User=user,
- PackageBase=pkgbase,
- Comments="Test comment.",
- RenderedComment=str(),
- CommentTS=now)
+ comment = db.create(
+ PackageComment,
+ User=user,
+ PackageBase=pkgbase,
+ Comments="Test comment.",
+ RenderedComment=str(),
+ CommentTS=now,
+ )
yield comment
@pytest.fixture
def packages(maintainer: User) -> list[Package]:
- """ Yield 55 packages named pkg_0 .. pkg_54. """
+ """Yield 55 packages named pkg_0 .. pkg_54."""
packages_ = []
now = time.utcnow()
with db.begin():
for i in range(55):
- pkgbase = db.create(PackageBase,
- Name=f"pkg_{i}",
- Maintainer=maintainer,
- Packager=maintainer,
- Submitter=maintainer,
- ModifiedTS=now)
- package = db.create(Package,
- PackageBase=pkgbase,
- Name=f"pkg_{i}")
+ pkgbase = db.create(
+ PackageBase,
+ Name=f"pkg_{i}",
+ Maintainer=maintainer,
+ Packager=maintainer,
+ Submitter=maintainer,
+ ModifiedTS=now,
+ )
+ package = db.create(Package, PackageBase=pkgbase, Name=f"pkg_{i}")
packages_.append(package)
yield packages_
@@ -203,40 +216,56 @@ def test_package_not_found(client: TestClient):
def test_package(client: TestClient, package: Package):
- """ Test a single / packages / {name} route. """
+ """Test a single / packages / {name} route."""
with db.begin():
- db.create(PackageRelation, PackageID=package.ID,
- RelTypeID=PROVIDES_ID,
- RelName="test_provider1")
- db.create(PackageRelation, PackageID=package.ID,
- RelTypeID=PROVIDES_ID,
- RelName="test_provider2")
+ db.create(
+ PackageRelation,
+ PackageID=package.ID,
+ RelTypeID=PROVIDES_ID,
+ RelName="test_provider1",
+ )
+ db.create(
+ PackageRelation,
+ PackageID=package.ID,
+ RelTypeID=PROVIDES_ID,
+ RelName="test_provider2",
+ )
- db.create(PackageRelation, PackageID=package.ID,
- RelTypeID=REPLACES_ID,
- RelName="test_replacer1")
- db.create(PackageRelation, PackageID=package.ID,
- RelTypeID=REPLACES_ID,
- RelName="test_replacer2")
+ db.create(
+ PackageRelation,
+ PackageID=package.ID,
+ RelTypeID=REPLACES_ID,
+ RelName="test_replacer1",
+ )
+ db.create(
+ PackageRelation,
+ PackageID=package.ID,
+ RelTypeID=REPLACES_ID,
+ RelName="test_replacer2",
+ )
- db.create(PackageRelation, PackageID=package.ID,
- RelTypeID=CONFLICTS_ID,
- RelName="test_conflict1")
- db.create(PackageRelation, PackageID=package.ID,
- RelTypeID=CONFLICTS_ID,
- RelName="test_conflict2")
+ db.create(
+ PackageRelation,
+ PackageID=package.ID,
+ RelTypeID=CONFLICTS_ID,
+ RelName="test_conflict1",
+ )
+ db.create(
+ PackageRelation,
+ PackageID=package.ID,
+ RelTypeID=CONFLICTS_ID,
+ RelName="test_conflict2",
+ )
# Create some licenses.
licenses = [
db.create(License, Name="test_license1"),
- db.create(License, Name="test_license2")
+ db.create(License, Name="test_license2"),
]
- db.create(PackageLicense, PackageID=package.ID,
- License=licenses[0])
- db.create(PackageLicense, PackageID=package.ID,
- License=licenses[1])
+ db.create(PackageLicense, PackageID=package.ID, License=licenses[0])
+ db.create(PackageLicense, PackageID=package.ID, License=licenses[1])
with client as request:
resp = request.get(package_endpoint(package))
@@ -311,7 +340,7 @@ def paged_depends_required(client: TestClient, package: Package):
params={
"all_deps": True,
"all_reqs": True,
- }
+ },
)
assert resp.status_code == int(HTTPStatus.OK)
@@ -321,10 +350,15 @@ def paged_depends_required(client: TestClient, package: Package):
def test_package_comments(client: TestClient, user: User, package: Package):
- now = (time.utcnow())
+ now = time.utcnow()
with db.begin():
- comment = db.create(PackageComment, PackageBase=package.PackageBase,
- User=user, Comments="Test comment", CommentTS=now)
+ comment = db.create(
+ PackageComment,
+ PackageBase=package.PackageBase,
+ User=user,
+ Comments="Test comment",
+ CommentTS=now,
+ )
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
@@ -332,17 +366,18 @@ def test_package_comments(client: TestClient, user: User, package: Package):
assert resp.status_code == int(HTTPStatus.OK)
root = parse_root(resp.text)
- expected = [
- comment.Comments
- ]
- comments = root.xpath('.//div[contains(@class, "package-comments")]'
- '/div[@class="article-content"]/div/text()')
+ expected = [comment.Comments]
+ comments = root.xpath(
+ './/div[contains(@class, "package-comments")]'
+ '/div[@class="article-content"]/div/text()'
+ )
for i, row in enumerate(expected):
assert comments[i].strip() == row
-def test_package_requests_display(client: TestClient, user: User,
- package: Package, pkgreq: PackageRequest):
+def test_package_requests_display(
+ client: TestClient, user: User, package: Package, pkgreq: PackageRequest
+):
# Test that a single request displays "1 pending request".
with client as request:
resp = request.get(package_endpoint(package))
@@ -355,11 +390,15 @@ def test_package_requests_display(client: TestClient, user: User,
type_ = db.query(RequestType, RequestType.ID == DELETION_ID).first()
with db.begin():
- db.create(PackageRequest, PackageBase=package.PackageBase,
- PackageBaseName=package.PackageBase.Name,
- User=user, RequestType=type_,
- Comments="Test comment2.",
- ClosureComment=str())
+ db.create(
+ PackageRequest,
+ PackageBase=package.PackageBase,
+ PackageBaseName=package.PackageBase.Name,
+ User=user,
+ RequestType=type_,
+ Comments="Test comment2.",
+ ClosureComment=str(),
+ )
# Test that a two requests display "2 pending requests".
with client as request:
@@ -372,11 +411,10 @@ def test_package_requests_display(client: TestClient, user: User,
assert target.text.strip() == "2 pending requests"
-def test_package_authenticated(client: TestClient, user: User,
- package: Package):
- """ We get the same here for either authenticated or not
+def test_package_authenticated(client: TestClient, user: User, package: Package):
+ """We get the same here for either authenticated or not
authenticated. Form inputs are presented to maintainers.
- This process also occurs when pkgbase.html is rendered. """
+ This process also occurs when pkgbase.html is rendered."""
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
resp = request.get(package_endpoint(package), cookies=cookies)
@@ -390,7 +428,7 @@ def test_package_authenticated(client: TestClient, user: User,
"Flag package out-of-date",
"Vote for this package",
"Enable notifications",
- "Submit Request"
+ "Submit Request",
]
for expected_text in expected:
assert expected_text in resp.text
@@ -402,9 +440,9 @@ def test_package_authenticated(client: TestClient, user: User,
assert len(target) == 0
-def test_package_authenticated_maintainer(client: TestClient,
- maintainer: User,
- package: Package):
+def test_package_authenticated_maintainer(
+ client: TestClient, maintainer: User, package: Package
+):
cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
with client as request:
resp = request.get(package_endpoint(package), cookies=cookies)
@@ -420,15 +458,13 @@ def test_package_authenticated_maintainer(client: TestClient,
"Enable notifications",
"Manage Co-Maintainers",
"Submit Request",
- "Disown Package"
+ "Disown Package",
]
for expected_text in expected:
assert expected_text in resp.text
-def test_package_authenticated_tu(client: TestClient,
- tu_user: User,
- package: Package):
+def test_package_authenticated_tu(client: TestClient, tu_user: User, package: Package):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
resp = request.get(package_endpoint(package), cookies=cookies)
@@ -446,14 +482,13 @@ def test_package_authenticated_tu(client: TestClient,
"Submit Request",
"Delete Package",
"Merge Package",
- "Disown Package"
+ "Disown Package",
]
for expected_text in expected:
assert expected_text in resp.text
-def test_package_dependencies(client: TestClient, maintainer: User,
- package: Package):
+def test_package_dependencies(client: TestClient, maintainer: User, package: Package):
# Create a normal dependency of type depends.
with db.begin():
dep_pkg = create_package("test-dep-1", maintainer)
@@ -461,32 +496,32 @@ def test_package_dependencies(client: TestClient, maintainer: User,
# Also, create a makedepends.
make_dep_pkg = create_package("test-dep-2", maintainer)
- make_dep = create_package_dep(package, make_dep_pkg.Name,
- dep_type_name="makedepends")
+ make_dep = create_package_dep(
+ package, make_dep_pkg.Name, dep_type_name="makedepends"
+ )
make_dep.DepArch = "x86_64"
# And... a checkdepends!
check_dep_pkg = create_package("test-dep-3", maintainer)
- create_package_dep(package, check_dep_pkg.Name,
- dep_type_name="checkdepends")
+ create_package_dep(package, check_dep_pkg.Name, dep_type_name="checkdepends")
# Geez. Just stop. This is optdepends.
opt_dep_pkg = create_package("test-dep-4", maintainer)
- create_package_dep(package, opt_dep_pkg.Name,
- dep_type_name="optdepends")
+ create_package_dep(package, opt_dep_pkg.Name, dep_type_name="optdepends")
# Heh. Another optdepends to test one with a description.
opt_desc_dep_pkg = create_package("test-dep-5", maintainer)
- opt_desc_dep = create_package_dep(package, opt_desc_dep_pkg.Name,
- dep_type_name="optdepends")
+ opt_desc_dep = create_package_dep(
+ package, opt_desc_dep_pkg.Name, dep_type_name="optdepends"
+ )
opt_desc_dep.DepDesc = "Test description."
- broken_dep = create_package_dep(package, "test-dep-6",
- dep_type_name="depends")
+ broken_dep = create_package_dep(package, "test-dep-6", dep_type_name="depends")
# Create an official provider record.
- db.create(OfficialProvider, Name="test-dep-99",
- Repo="core", Provides="test-dep-99")
+ db.create(
+ OfficialProvider, Name="test-dep-99", Repo="core", Provides="test-dep-99"
+ )
create_package_dep(package, "test-dep-99")
# Also, create a provider who provides our test-dep-99.
@@ -498,13 +533,14 @@ def test_package_dependencies(client: TestClient, maintainer: User,
assert resp.status_code == int(HTTPStatus.OK)
# Let's make sure all the non-broken deps are ordered as we expect.
- expected = list(filter(
- lambda e: e.is_package(),
- package.package_dependencies.order_by(
- PackageDependency.DepTypeID.asc(),
- PackageDependency.DepName.asc()
- ).all()
- ))
+ expected = list(
+ filter(
+ lambda e: e.is_package(),
+ package.package_dependencies.order_by(
+ PackageDependency.DepTypeID.asc(), PackageDependency.DepName.asc()
+ ).all(),
+ )
+ )
root = parse_root(resp.text)
pkgdeps = root.findall('.//ul[@id="pkgdepslist"]/li/a')
for i, expectation in enumerate(expected):
@@ -512,7 +548,7 @@ def test_package_dependencies(client: TestClient, maintainer: User,
# Let's make sure the DepArch was displayed for our target make dep.
arch = root.findall('.//ul[@id="pkgdepslist"]/li')[3]
- arch = arch.xpath('./em')[0]
+ arch = arch.xpath("./em")[0]
assert arch.text.strip() == "(make, x86_64)"
# And let's make sure that the broken package was displayed.
@@ -522,16 +558,19 @@ def test_package_dependencies(client: TestClient, maintainer: User,
def test_packages(client: TestClient, packages: list[Package]):
with client as request:
- response = request.get("/packages", params={
- "SeB": "X", # "X" isn't valid, defaults to "nd"
- "PP": "1 or 1",
- "O": "0 or 0"
- })
+ response = request.get(
+ "/packages",
+ params={
+ "SeB": "X", # "X" isn't valid, defaults to "nd"
+ "PP": "1 or 1",
+ "O": "0 or 0",
+ },
+ )
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
stats = root.xpath('//div[@class="pkglist-stats"]/p')[0]
- pager_text = re.sub(r'\s+', " ", stats.text.replace("\n", "").strip())
+ pager_text = re.sub(r"\s+", " ", stats.text.replace("\n", "").strip())
assert pager_text == "55 packages found. Page 1 of 2."
rows = root.xpath('//table[@class="results"]/tbody/tr')
@@ -551,10 +590,7 @@ def test_packages_empty(client: TestClient):
def test_packages_search_by_name(client: TestClient, packages: list[Package]):
with client as request:
- response = request.get("/packages", params={
- "SeB": "n",
- "K": "pkg_"
- })
+ response = request.get("/packages", params={"SeB": "n", "K": "pkg_"})
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
@@ -563,13 +599,9 @@ def test_packages_search_by_name(client: TestClient, packages: list[Package]):
assert len(rows) == 50 # Default per-page
-def test_packages_search_by_exact_name(client: TestClient,
- packages: list[Package]):
+def test_packages_search_by_exact_name(client: TestClient, packages: list[Package]):
with client as request:
- response = request.get("/packages", params={
- "SeB": "N",
- "K": "pkg_"
- })
+ response = request.get("/packages", params={"SeB": "N", "K": "pkg_"})
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
@@ -579,10 +611,7 @@ def test_packages_search_by_exact_name(client: TestClient,
assert len(rows) == 0
with client as request:
- response = request.get("/packages", params={
- "SeB": "N",
- "K": "pkg_1"
- })
+ response = request.get("/packages", params={"SeB": "N", "K": "pkg_1"})
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
@@ -592,13 +621,9 @@ def test_packages_search_by_exact_name(client: TestClient,
assert len(rows) == 1
-def test_packages_search_by_pkgbase(client: TestClient,
- packages: list[Package]):
+def test_packages_search_by_pkgbase(client: TestClient, packages: list[Package]):
with client as request:
- response = request.get("/packages", params={
- "SeB": "b",
- "K": "pkg_"
- })
+ response = request.get("/packages", params={"SeB": "b", "K": "pkg_"})
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
@@ -607,13 +632,9 @@ def test_packages_search_by_pkgbase(client: TestClient,
assert len(rows) == 50
-def test_packages_search_by_exact_pkgbase(client: TestClient,
- packages: list[Package]):
+def test_packages_search_by_exact_pkgbase(client: TestClient, packages: list[Package]):
with client as request:
- response = request.get("/packages", params={
- "SeB": "B",
- "K": "pkg_"
- })
+ response = request.get("/packages", params={"SeB": "B", "K": "pkg_"})
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
@@ -621,10 +642,7 @@ def test_packages_search_by_exact_pkgbase(client: TestClient,
assert len(rows) == 0
with client as request:
- response = request.get("/packages", params={
- "SeB": "B",
- "K": "pkg_1"
- })
+ response = request.get("/packages", params={"SeB": "B", "K": "pkg_1"})
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
@@ -632,14 +650,10 @@ def test_packages_search_by_exact_pkgbase(client: TestClient,
assert len(rows) == 1
-def test_packages_search_by_keywords(client: TestClient,
- packages: list[Package]):
+def test_packages_search_by_keywords(client: TestClient, packages: list[Package]):
# None of our packages have keywords, so this query should return nothing.
with client as request:
- response = request.get("/packages", params={
- "SeB": "k",
- "K": "testKeyword"
- })
+ response = request.get("/packages", params={"SeB": "k", "K": "testKeyword"})
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
@@ -649,16 +663,13 @@ def test_packages_search_by_keywords(client: TestClient,
# But now, let's create the keyword for the first package.
package = packages[0]
with db.begin():
- db.create(PackageKeyword,
- PackageBase=package.PackageBase,
- Keyword="testKeyword")
+ db.create(
+ PackageKeyword, PackageBase=package.PackageBase, Keyword="testKeyword"
+ )
# And request packages with that keyword, we should get 1 result.
with client as request:
- response = request.get("/packages", params={
- "SeB": "k",
- "K": "testKeyword"
- })
+ response = request.get("/packages", params={"SeB": "k", "K": "testKeyword"})
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
@@ -666,16 +677,15 @@ def test_packages_search_by_keywords(client: TestClient,
assert len(rows) == 1
-def test_packages_search_by_maintainer(client: TestClient,
- maintainer: User,
- package: Package):
+def test_packages_search_by_maintainer(
+ client: TestClient, maintainer: User, package: Package
+):
# We should expect that searching by `package`'s maintainer
# returns `package` in the results.
with client as request:
- response = request.get("/packages", params={
- "SeB": "m",
- "K": maintainer.Username
- })
+ response = request.get(
+ "/packages", params={"SeB": "m", "K": maintainer.Username}
+ )
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
rows = root.xpath('//table[@class="results"]/tbody/tr')
@@ -704,15 +714,14 @@ def test_packages_search_by_maintainer(client: TestClient,
assert len(rows) == 1
-def test_packages_search_by_comaintainer(client: TestClient,
- maintainer: User,
- package: Package):
+def test_packages_search_by_comaintainer(
+ client: TestClient, maintainer: User, package: Package
+):
# Nobody's a comaintainer yet.
with client as request:
- response = request.get("/packages", params={
- "SeB": "c",
- "K": maintainer.Username
- })
+ response = request.get(
+ "/packages", params={"SeB": "c", "K": maintainer.Username}
+ )
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
@@ -721,17 +730,18 @@ def test_packages_search_by_comaintainer(client: TestClient,
# Now, we create a comaintainer.
with db.begin():
- db.create(PackageComaintainer,
- PackageBase=package.PackageBase,
- User=maintainer,
- Priority=1)
+ db.create(
+ PackageComaintainer,
+ PackageBase=package.PackageBase,
+ User=maintainer,
+ Priority=1,
+ )
# Then test that it's returned by our search.
with client as request:
- response = request.get("/packages", params={
- "SeB": "c",
- "K": maintainer.Username
- })
+ response = request.get(
+ "/packages", params={"SeB": "c", "K": maintainer.Username}
+ )
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
@@ -739,15 +749,18 @@ def test_packages_search_by_comaintainer(client: TestClient,
assert len(rows) == 1
-def test_packages_search_by_co_or_maintainer(client: TestClient,
- maintainer: User,
- package: Package):
+def test_packages_search_by_co_or_maintainer(
+ client: TestClient, maintainer: User, package: Package
+):
with client as request:
- response = request.get("/packages", params={
- "SeB": "M",
- "SB": "BLAH", # Invalid SB; gets reset to default "n".
- "K": maintainer.Username
- })
+ response = request.get(
+ "/packages",
+ params={
+ "SeB": "M",
+ "SB": "BLAH", # Invalid SB; gets reset to default "n".
+ "K": maintainer.Username,
+ },
+ )
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
@@ -755,19 +768,18 @@ def test_packages_search_by_co_or_maintainer(client: TestClient,
assert len(rows) == 1
with db.begin():
- user = db.create(User, Username="comaintainer",
- Email="comaintainer@example.org",
- Passwd="testPassword")
- db.create(PackageComaintainer,
- PackageBase=package.PackageBase,
- User=user,
- Priority=1)
+ user = db.create(
+ User,
+ Username="comaintainer",
+ Email="comaintainer@example.org",
+ Passwd="testPassword",
+ )
+ db.create(
+ PackageComaintainer, PackageBase=package.PackageBase, User=user, Priority=1
+ )
with client as request:
- response = request.get("/packages", params={
- "SeB": "M",
- "K": user.Username
- })
+ response = request.get("/packages", params={"SeB": "M", "K": user.Username})
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
@@ -775,14 +787,13 @@ def test_packages_search_by_co_or_maintainer(client: TestClient,
assert len(rows) == 1
-def test_packages_search_by_submitter(client: TestClient,
- maintainer: User,
- package: Package):
+def test_packages_search_by_submitter(
+ client: TestClient, maintainer: User, package: Package
+):
with client as request:
- response = request.get("/packages", params={
- "SeB": "s",
- "K": maintainer.Username
- })
+ response = request.get(
+ "/packages", params={"SeB": "s", "K": maintainer.Username}
+ )
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
@@ -792,184 +803,184 @@ def test_packages_search_by_submitter(client: TestClient,
def test_packages_sort_by_name(client: TestClient, packages: list[Package]):
with client as request:
- response = request.get("/packages", params={
- "SB": "n", # Name
- "SO": "a", # Ascending
- "PP": "150"
- })
+ response = request.get(
+ "/packages", params={"SB": "n", "SO": "a", "PP": "150"} # Name # Ascending
+ )
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
rows = root.xpath('//table[@class="results"]/tbody/tr')
- rows = [row.xpath('./td/a')[0].text.strip() for row in rows]
+ rows = [row.xpath("./td/a")[0].text.strip() for row in rows]
with client as request:
- response2 = request.get("/packages", params={
- "SB": "n", # Name
- "SO": "d", # Ascending
- "PP": "150"
- })
+ response2 = request.get(
+ "/packages", params={"SB": "n", "SO": "d", "PP": "150"} # Name # Ascending
+ )
assert response2.status_code == int(HTTPStatus.OK)
root = parse_root(response2.text)
rows2 = root.xpath('//table[@class="results"]/tbody/tr')
- rows2 = [row.xpath('./td/a')[0].text.strip() for row in rows2]
+ rows2 = [row.xpath("./td/a")[0].text.strip() for row in rows2]
assert rows == list(reversed(rows2))
-def test_packages_sort_by_votes(client: TestClient,
- maintainer: User,
- packages: list[Package]):
+def test_packages_sort_by_votes(
+ client: TestClient, maintainer: User, packages: list[Package]
+):
# Set the first package's NumVotes to 1.
with db.begin():
packages[0].PackageBase.NumVotes = 1
# Test that, by default, the first result is what we just set above.
with client as request:
- response = request.get("/packages", params={
- "SB": "v" # Votes.
- })
+ response = request.get("/packages", params={"SB": "v"}) # Votes.
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
rows = root.xpath('//table[@class="results"]/tbody/tr')
- votes = rows[0].xpath('./td')[2] # The third column of the first row.
+ votes = rows[0].xpath("./td")[2] # The third column of the first row.
assert votes.text.strip() == "1"
# Now, test that with an ascending order, the last result is
# the one we set, since the default (above) is descending.
with client as request:
- response = request.get("/packages", params={
- "SB": "v", # Votes.
- "SO": "a", # Ascending.
- "O": "50" # Second page.
- })
+ response = request.get(
+ "/packages",
+ params={
+ "SB": "v", # Votes.
+ "SO": "a", # Ascending.
+ "O": "50", # Second page.
+ },
+ )
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
rows = root.xpath('//table[@class="results"]/tbody/tr')
- votes = rows[-1].xpath('./td')[2] # The third column of the last row.
+ votes = rows[-1].xpath("./td")[2] # The third column of the last row.
assert votes.text.strip() == "1"
-def test_packages_sort_by_popularity(client: TestClient,
- maintainer: User,
- packages: list[Package]):
+def test_packages_sort_by_popularity(
+ client: TestClient, maintainer: User, packages: list[Package]
+):
# Set the first package's Popularity to 0.50.
with db.begin():
packages[0].PackageBase.Popularity = "0.50"
# Test that, by default, the first result is what we just set above.
with client as request:
- response = request.get("/packages", params={
- "SB": "p" # Popularity
- })
+ response = request.get("/packages", params={"SB": "p"}) # Popularity
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
rows = root.xpath('//table[@class="results"]/tbody/tr')
- pop = rows[0].xpath('./td')[3] # The fourth column of the first row.
+ pop = rows[0].xpath("./td")[3] # The fourth column of the first row.
assert pop.text.strip() == "0.50"
-def test_packages_sort_by_voted(client: TestClient,
- maintainer: User,
- packages: list[Package]):
+def test_packages_sort_by_voted(
+ client: TestClient, maintainer: User, packages: list[Package]
+):
now = time.utcnow()
with db.begin():
- db.create(PackageVote, PackageBase=packages[0].PackageBase,
- User=maintainer, VoteTS=now)
+ db.create(
+ PackageVote,
+ PackageBase=packages[0].PackageBase,
+ User=maintainer,
+ VoteTS=now,
+ )
# Test that, by default, the first result is what we just set above.
cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
with client as request:
- response = request.get("/packages", params={
- "SB": "w", # Voted
- "SO": "d" # Descending, Voted first.
- }, cookies=cookies)
+ response = request.get(
+ "/packages",
+ params={"SB": "w", "SO": "d"}, # Voted # Descending, Voted first.
+ cookies=cookies,
+ )
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
rows = root.xpath('//table[@class="results"]/tbody/tr')
- voted = rows[0].xpath('./td')[5] # The sixth column of the first row.
+ voted = rows[0].xpath("./td")[5] # The sixth column of the first row.
assert voted.text.strip() == "Yes"
# Conversely, everything else was not voted on.
- voted = rows[1].xpath('./td')[5] # The sixth column of the second row.
+ voted = rows[1].xpath("./td")[5] # The sixth column of the second row.
assert voted.text.strip() == str() # Empty.
-def test_packages_sort_by_notify(client: TestClient,
- maintainer: User,
- packages: list[Package]):
- db.create(PackageNotification,
- PackageBase=packages[0].PackageBase,
- User=maintainer)
+def test_packages_sort_by_notify(
+ client: TestClient, maintainer: User, packages: list[Package]
+):
+ db.create(PackageNotification, PackageBase=packages[0].PackageBase, User=maintainer)
# Test that, by default, the first result is what we just set above.
cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
with client as request:
- response = request.get("/packages", params={
- "SB": "o", # Voted
- "SO": "d" # Descending, Voted first.
- }, cookies=cookies)
+ response = request.get(
+ "/packages",
+ params={"SB": "o", "SO": "d"}, # Voted # Descending, Voted first.
+ cookies=cookies,
+ )
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
rows = root.xpath('//table[@class="results"]/tbody/tr')
- notify = rows[0].xpath('./td')[6] # The sixth column of the first row.
+ notify = rows[0].xpath("./td")[6] # The sixth column of the first row.
assert notify.text.strip() == "Yes"
# Conversely, everything else was not voted on.
- notify = rows[1].xpath('./td')[6] # The sixth column of the second row.
+ notify = rows[1].xpath("./td")[6] # The sixth column of the second row.
assert notify.text.strip() == str() # Empty.
-def test_packages_sort_by_maintainer(client: TestClient,
- maintainer: User,
- package: Package):
- """ Sort a package search by the maintainer column. """
+def test_packages_sort_by_maintainer(
+ client: TestClient, maintainer: User, package: Package
+):
+ """Sort a package search by the maintainer column."""
# Create a second package, so the two can be ordered and checked.
with db.begin():
- maintainer2 = db.create(User, Username="maintainer2",
- Email="maintainer2@example.org",
- Passwd="testPassword")
- base2 = db.create(PackageBase, Name="pkg_2", Maintainer=maintainer2,
- Submitter=maintainer2, Packager=maintainer2)
+ maintainer2 = db.create(
+ User,
+ Username="maintainer2",
+ Email="maintainer2@example.org",
+ Passwd="testPassword",
+ )
+ base2 = db.create(
+ PackageBase,
+ Name="pkg_2",
+ Maintainer=maintainer2,
+ Submitter=maintainer2,
+ Packager=maintainer2,
+ )
db.create(Package, Name="pkg_2", PackageBase=base2)
# Check the descending order route.
with client as request:
- response = request.get("/packages", params={
- "SB": "m",
- "SO": "d"
- })
+ response = request.get("/packages", params={"SB": "m", "SO": "d"})
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
rows = root.xpath('//table[@class="results"]/tbody/tr')
- col = rows[0].xpath('./td')[5].xpath('./a')[0] # Last column.
+ col = rows[0].xpath("./td")[5].xpath("./a")[0] # Last column.
assert col.text.strip() == maintainer.Username
# On the other hand, with ascending, we should get reverse ordering.
with client as request:
- response = request.get("/packages", params={
- "SB": "m",
- "SO": "a"
- })
+ response = request.get("/packages", params={"SB": "m", "SO": "a"})
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
rows = root.xpath('//table[@class="results"]/tbody/tr')
- col = rows[0].xpath('./td')[5].xpath('./a')[0] # Last column.
+ col = rows[0].xpath("./td")[5].xpath("./a")[0] # Last column.
assert col.text.strip() == maintainer2.Username
-def test_packages_sort_by_last_modified(client: TestClient,
- packages: list[Package]):
+def test_packages_sort_by_last_modified(client: TestClient, packages: list[Package]):
now = time.utcnow()
# Set the first package's ModifiedTS to be 1000 seconds before now.
package = packages[0]
@@ -977,10 +988,10 @@ def test_packages_sort_by_last_modified(client: TestClient,
package.PackageBase.ModifiedTS = now - 1000
with client as request:
- response = request.get("/packages", params={
- "SB": "l",
- "SO": "a" # Ascending; oldest modification first.
- })
+ response = request.get(
+ "/packages",
+ params={"SB": "l", "SO": "a"}, # Ascending; oldest modification first.
+ )
assert response.status_code == int(HTTPStatus.OK)
# We should have 50 (default per page) results.
@@ -990,12 +1001,13 @@ def test_packages_sort_by_last_modified(client: TestClient,
# Let's assert that the first item returned was the one we modified above.
row = rows[0]
- col = row.xpath('./td')[0].xpath('./a')[0]
+ col = row.xpath("./td")[0].xpath("./a")[0]
assert col.text.strip() == package.Name
-def test_packages_flagged(client: TestClient, maintainer: User,
- packages: list[Package]):
+def test_packages_flagged(
+ client: TestClient, maintainer: User, packages: list[Package]
+):
package = packages[0]
now = time.utcnow()
@@ -1005,9 +1017,7 @@ def test_packages_flagged(client: TestClient, maintainer: User,
package.PackageBase.Flagger = maintainer
with client as request:
- response = request.get("/packages", params={
- "outdated": "on"
- })
+ response = request.get("/packages", params={"outdated": "on"})
assert response.status_code == int(HTTPStatus.OK)
# We should only get one result from this query; the package we flagged.
@@ -1016,9 +1026,7 @@ def test_packages_flagged(client: TestClient, maintainer: User,
assert len(rows) == 1
with client as request:
- response = request.get("/packages", params={
- "outdated": "off"
- })
+ response = request.get("/packages", params={"outdated": "off"})
assert response.status_code == int(HTTPStatus.OK)
# In this case, we should get 54 results, which means that the first
@@ -1044,14 +1052,17 @@ def test_packages_orphans(client: TestClient, packages: list[Package]):
def test_packages_per_page(client: TestClient, maintainer: User):
- """ Test the ability for /packages to deal with the PP query
- argument specifications (50, 100, 250; default: 50). """
+ """Test the ability for /packages to deal with the PP query
+ argument specifications (50, 100, 250; default: 50)."""
with db.begin():
for i in range(255):
- base = db.create(PackageBase, Name=f"pkg_{i}",
- Maintainer=maintainer,
- Submitter=maintainer,
- Packager=maintainer)
+ base = db.create(
+ PackageBase,
+ Name=f"pkg_{i}",
+ Maintainer=maintainer,
+ Submitter=maintainer,
+ Packager=maintainer,
+ )
db.create(Package, PackageBase=base, Name=base.Name)
# Test default case, PP of 50.
@@ -1079,18 +1090,20 @@ def test_packages_per_page(client: TestClient, maintainer: User):
assert len(rows) == 250
-def test_packages_post_unknown_action(client: TestClient, user: User,
- package: Package):
+def test_packages_post_unknown_action(client: TestClient, user: User, package: Package):
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- resp = request.post("/packages", data={"action": "unknown"},
- cookies=cookies, allow_redirects=False)
+ resp = request.post(
+ "/packages",
+ data={"action": "unknown"},
+ cookies=cookies,
+ allow_redirects=False,
+ )
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
def test_packages_post_error(client: TestClient, user: User, package: Package):
-
async def stub_action(request: Request, **kwargs):
return (False, ["Some error."])
@@ -1098,8 +1111,12 @@ def test_packages_post_error(client: TestClient, user: User, package: Package):
with mock.patch.dict("aurweb.routers.packages.PACKAGE_ACTIONS", actions):
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- resp = request.post("/packages", data={"action": "stub"},
- cookies=cookies, allow_redirects=False)
+ resp = request.post(
+ "/packages",
+ data={"action": "stub"},
+ cookies=cookies,
+ allow_redirects=False,
+ )
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
errors = get_errors(resp.text)
@@ -1108,7 +1125,6 @@ def test_packages_post_error(client: TestClient, user: User, package: Package):
def test_packages_post(client: TestClient, user: User, package: Package):
-
async def stub_action(request: Request, **kwargs):
return (True, ["Some success."])
@@ -1116,8 +1132,12 @@ def test_packages_post(client: TestClient, user: User, package: Package):
with mock.patch.dict("aurweb.routers.packages.PACKAGE_ACTIONS", actions):
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- resp = request.post("/packages", data={"action": "stub"},
- cookies=cookies, allow_redirects=False)
+ resp = request.post(
+ "/packages",
+ data={"action": "stub"},
+ cookies=cookies,
+ allow_redirects=False,
+ )
assert resp.status_code == int(HTTPStatus.OK)
errors = get_successes(resp.text)
@@ -1125,8 +1145,9 @@ def test_packages_post(client: TestClient, user: User, package: Package):
assert errors[0].text.strip() == expected
-def test_packages_post_unflag(client: TestClient, user: User,
- maintainer: User, package: Package):
+def test_packages_post_unflag(
+ client: TestClient, user: User, maintainer: User, package: Package
+):
# Flag `package` as `user`.
now = time.utcnow()
with db.begin():
@@ -1181,8 +1202,7 @@ def test_packages_post_notify(client: TestClient, user: User, package: Package):
# an error to be rendered.
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- resp = request.post("/packages", data={"action": "notify"},
- cookies=cookies)
+ resp = request.post("/packages", data={"action": "notify"}, cookies=cookies)
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
errors = get_errors(resp.text)
expected = "You did not select any packages to be notified about."
@@ -1190,10 +1210,9 @@ def test_packages_post_notify(client: TestClient, user: User, package: Package):
# Now let's actually enable notifications on `package`.
with client as request:
- resp = request.post("/packages", data={
- "action": "notify",
- "IDs": [package.ID]
- }, cookies=cookies)
+ resp = request.post(
+ "/packages", data={"action": "notify", "IDs": [package.ID]}, cookies=cookies
+ )
assert resp.status_code == int(HTTPStatus.OK)
expected = "The selected packages' notifications have been enabled."
successes = get_successes(resp.text)
@@ -1202,31 +1221,27 @@ def test_packages_post_notify(client: TestClient, user: User, package: Package):
# Try to enable notifications when they're already enabled,
# causing an error to be rendered.
with client as request:
- resp = request.post("/packages", data={
- "action": "notify",
- "IDs": [package.ID]
- }, cookies=cookies)
+ resp = request.post(
+ "/packages", data={"action": "notify", "IDs": [package.ID]}, cookies=cookies
+ )
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
errors = get_errors(resp.text)
expected = "You did not select any packages to be notified about."
assert errors[0].text.strip() == expected
-def test_packages_post_unnotify(client: TestClient, user: User,
- package: Package):
+def test_packages_post_unnotify(client: TestClient, user: User, package: Package):
# Create a notification record.
with db.begin():
- notif = db.create(PackageNotification,
- PackageBase=package.PackageBase,
- User=user)
+ notif = db.create(
+ PackageNotification, PackageBase=package.PackageBase, User=user
+ )
assert notif is not None
# Request removal of the notification without any IDs.
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- resp = request.post("/packages", data={
- "action": "unnotify"
- }, cookies=cookies)
+ resp = request.post("/packages", data={"action": "unnotify"}, cookies=cookies)
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
errors = get_errors(resp.text)
expected = "You did not select any packages for notification removal."
@@ -1234,10 +1249,11 @@ def test_packages_post_unnotify(client: TestClient, user: User,
# Request removal of the notification; really.
with client as request:
- resp = request.post("/packages", data={
- "action": "unnotify",
- "IDs": [package.ID]
- }, cookies=cookies)
+ resp = request.post(
+ "/packages",
+ data={"action": "unnotify", "IDs": [package.ID]},
+ cookies=cookies,
+ )
assert resp.status_code == int(HTTPStatus.OK)
successes = get_successes(resp.text)
expected = "The selected packages' notifications have been removed."
@@ -1251,25 +1267,23 @@ def test_packages_post_unnotify(client: TestClient, user: User,
# Try it again. The notif no longer exists.
with client as request:
- resp = request.post("/packages", data={
- "action": "unnotify",
- "IDs": [package.ID]
- }, cookies=cookies)
+ resp = request.post(
+ "/packages",
+ data={"action": "unnotify", "IDs": [package.ID]},
+ cookies=cookies,
+ )
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
errors = get_errors(resp.text)
expected = "A package you selected does not have notifications enabled."
assert errors[0].text.strip() == expected
-def test_packages_post_adopt(client: TestClient, user: User,
- package: Package):
+def test_packages_post_adopt(client: TestClient, user: User, package: Package):
# Try to adopt an empty list of packages.
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- resp = request.post("/packages", data={
- "action": "adopt"
- }, cookies=cookies)
+ resp = request.post("/packages", data={"action": "adopt"}, cookies=cookies)
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
errors = get_errors(resp.text)
expected = "You did not select any packages to adopt."
@@ -1277,11 +1291,11 @@ def test_packages_post_adopt(client: TestClient, user: User,
# Now, let's try to adopt a package that's already maintained.
with client as request:
- resp = request.post("/packages", data={
- "action": "adopt",
- "IDs": [package.ID],
- "confirm": True
- }, cookies=cookies)
+ resp = request.post(
+ "/packages",
+ data={"action": "adopt", "IDs": [package.ID], "confirm": True},
+ cookies=cookies,
+ )
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
errors = get_errors(resp.text)
expected = "You are not allowed to adopt one of the packages you selected."
@@ -1294,33 +1308,34 @@ def test_packages_post_adopt(client: TestClient, user: User,
# Now, let's try to adopt without confirming.
with client as request:
- resp = request.post("/packages", data={
- "action": "adopt",
- "IDs": [package.ID]
- }, cookies=cookies)
+ resp = request.post(
+ "/packages", data={"action": "adopt", "IDs": [package.ID]}, cookies=cookies
+ )
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
errors = get_errors(resp.text)
- expected = ("The selected packages have not been adopted, "
- "check the confirmation checkbox.")
+ expected = (
+ "The selected packages have not been adopted, "
+ "check the confirmation checkbox."
+ )
assert errors[0].text.strip() == expected
# Let's do it again now that there is no maintainer.
with client as request:
- resp = request.post("/packages", data={
- "action": "adopt",
- "IDs": [package.ID],
- "confirm": True
- }, cookies=cookies)
+ resp = request.post(
+ "/packages",
+ data={"action": "adopt", "IDs": [package.ID], "confirm": True},
+ cookies=cookies,
+ )
assert resp.status_code == int(HTTPStatus.OK)
successes = get_successes(resp.text)
expected = "The selected packages have been adopted."
assert successes[0].text.strip() == expected
-def test_packages_post_disown_as_maintainer(client: TestClient, user: User,
- maintainer: User,
- package: Package):
- """ Disown packages as a maintainer. """
+def test_packages_post_disown_as_maintainer(
+ client: TestClient, user: User, maintainer: User, package: Package
+):
+ """Disown packages as a maintainer."""
# Initially prove that we have a maintainer.
assert package.PackageBase.Maintainer is not None
assert package.PackageBase.Maintainer == maintainer
@@ -1328,9 +1343,7 @@ def test_packages_post_disown_as_maintainer(client: TestClient, user: User,
# Try to run the disown action with no IDs; get an error.
cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
with client as request:
- resp = request.post("/packages", data={
- "action": "disown"
- }, cookies=cookies)
+ resp = request.post("/packages", data={"action": "disown"}, cookies=cookies)
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
errors = get_errors(resp.text)
expected = "You did not select any packages to disown."
@@ -1339,25 +1352,26 @@ def test_packages_post_disown_as_maintainer(client: TestClient, user: User,
# Try to disown `package` without giving the confirm argument.
with client as request:
- resp = request.post("/packages", data={
- "action": "disown",
- "IDs": [package.ID]
- }, cookies=cookies)
+ resp = request.post(
+ "/packages", data={"action": "disown", "IDs": [package.ID]}, cookies=cookies
+ )
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
assert package.PackageBase.Maintainer is not None
errors = get_errors(resp.text)
- expected = ("The selected packages have not been disowned, "
- "check the confirmation checkbox.")
+ expected = (
+ "The selected packages have not been disowned, "
+ "check the confirmation checkbox."
+ )
assert errors[0].text.strip() == expected
# Now, try to disown `package` without credentials (as `user`).
user_cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- resp = request.post("/packages", data={
- "action": "disown",
- "IDs": [package.ID],
- "confirm": True
- }, cookies=user_cookies)
+ resp = request.post(
+ "/packages",
+ data={"action": "disown", "IDs": [package.ID], "confirm": True},
+ cookies=user_cookies,
+ )
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
assert package.PackageBase.Maintainer is not None
errors = get_errors(resp.text)
@@ -1366,11 +1380,11 @@ def test_packages_post_disown_as_maintainer(client: TestClient, user: User,
# Now, let's really disown `package` as `maintainer`.
with client as request:
- resp = request.post("/packages", data={
- "action": "disown",
- "IDs": [package.ID],
- "confirm": True
- }, cookies=cookies)
+ resp = request.post(
+ "/packages",
+ data={"action": "disown", "IDs": [package.ID], "confirm": True},
+ cookies=cookies,
+ )
assert package.PackageBase.Maintainer is None
successes = get_successes(resp.text)
@@ -1378,30 +1392,36 @@ def test_packages_post_disown_as_maintainer(client: TestClient, user: User,
assert successes[0].text.strip() == expected
-def test_packages_post_disown(client: TestClient, tu_user: User,
- maintainer: User, package: Package):
- """ Disown packages as a Trusted User, which cannot bypass idle time. """
+def test_packages_post_disown(
+ client: TestClient, tu_user: User, maintainer: User, package: Package
+):
+ """Disown packages as a Trusted User, which cannot bypass idle time."""
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
- resp = request.post("/packages", data={
- "action": "disown",
- "IDs": [package.ID],
- "confirm": True
- }, cookies=cookies)
+ resp = request.post(
+ "/packages",
+ data={"action": "disown", "IDs": [package.ID], "confirm": True},
+ cookies=cookies,
+ )
errors = get_errors(resp.text)
expected = r"^No due existing orphan requests to accept for .+\.$"
assert re.match(expected, errors[0].text.strip())
-def test_packages_post_delete(caplog: pytest.fixture, client: TestClient,
- user: User, tu_user: User, package: Package):
+def test_packages_post_delete(
+ caplog: pytest.fixture,
+ client: TestClient,
+ user: User,
+ tu_user: User,
+ package: Package,
+):
# First, let's try to use the delete action with no packages IDs.
user_cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- resp = request.post("/packages", data={
- "action": "delete"
- }, cookies=user_cookies)
+ resp = request.post(
+ "/packages", data={"action": "delete"}, cookies=user_cookies
+ )
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
errors = get_errors(resp.text)
expected = "You did not select any packages to delete."
@@ -1409,23 +1429,26 @@ def test_packages_post_delete(caplog: pytest.fixture, client: TestClient,
# Now, let's try to delete real packages without supplying "confirm".
with client as request:
- resp = request.post("/packages", data={
- "action": "delete",
- "IDs": [package.ID]
- }, cookies=user_cookies)
+ resp = request.post(
+ "/packages",
+ data={"action": "delete", "IDs": [package.ID]},
+ cookies=user_cookies,
+ )
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
errors = get_errors(resp.text)
- expected = ("The selected packages have not been deleted, "
- "check the confirmation checkbox.")
+ expected = (
+ "The selected packages have not been deleted, "
+ "check the confirmation checkbox."
+ )
assert errors[0].text.strip() == expected
# And again, with everything, but `user` doesn't have permissions.
with client as request:
- resp = request.post("/packages", data={
- "action": "delete",
- "IDs": [package.ID],
- "confirm": True
- }, cookies=user_cookies)
+ resp = request.post(
+ "/packages",
+ data={"action": "delete", "IDs": [package.ID], "confirm": True},
+ cookies=user_cookies,
+ )
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
errors = get_errors(resp.text)
expected = "You do not have permission to delete packages."
@@ -1436,11 +1459,11 @@ def test_packages_post_delete(caplog: pytest.fixture, client: TestClient,
# an invalid package ID.
tu_cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
- resp = request.post("/packages", data={
- "action": "delete",
- "IDs": [0],
- "confirm": True
- }, cookies=tu_cookies)
+ resp = request.post(
+ "/packages",
+ data={"action": "delete", "IDs": [0], "confirm": True},
+ cookies=tu_cookies,
+ )
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
errors = get_errors(resp.text)
expected = "One of the packages you selected does not exist."
@@ -1449,11 +1472,11 @@ def test_packages_post_delete(caplog: pytest.fixture, client: TestClient,
# Whoo. Now, let's finally make a valid request as `tu_user`
# to delete `package`.
with client as request:
- resp = request.post("/packages", data={
- "action": "delete",
- "IDs": [package.ID],
- "confirm": True
- }, cookies=tu_cookies)
+ resp = request.post(
+ "/packages",
+ data={"action": "delete", "IDs": [package.ID], "confirm": True},
+ cookies=tu_cookies,
+ )
assert resp.status_code == int(HTTPStatus.OK)
successes = get_successes(resp.text)
expected = "The selected packages have been deleted."
@@ -1461,15 +1484,17 @@ def test_packages_post_delete(caplog: pytest.fixture, client: TestClient,
# Expect that the package deletion was logged.
pkgbases = [package.PackageBase.Name]
- expected = (f"Privileged user '{tu_user.Username}' deleted the "
- f"following package bases: {str(pkgbases)}.")
+ expected = (
+ f"Privileged user '{tu_user.Username}' deleted the "
+ f"following package bases: {str(pkgbases)}."
+ )
assert expected in caplog.text
def test_account_comments_unauthorized(client: TestClient, user: User):
- """ This test may seem out of place, but it requires packages,
+ """This test may seem out of place, but it requires packages,
so its being included in the packages routes test suite to
- leverage existing fixtures. """
+ leverage existing fixtures."""
endpoint = f"/account/{user.Username}/comments"
with client as request:
resp = request.get(endpoint, allow_redirects=False)
@@ -1478,22 +1503,28 @@ def test_account_comments_unauthorized(client: TestClient, user: User):
def test_account_comments(client: TestClient, user: User, package: Package):
- """ This test may seem out of place, but it requires packages,
+ """This test may seem out of place, but it requires packages,
so its being included in the packages routes test suite to
- leverage existing fixtures. """
+ leverage existing fixtures."""
now = time.utcnow()
with db.begin():
# This comment's CommentTS is `now + 1`, so it is found in rendered
# HTML before the rendered_comment, which has a CommentTS of `now`.
- comment = db.create(PackageComment,
- PackageBase=package.PackageBase,
- User=user, Comments="Test comment",
- CommentTS=now + 1)
- rendered_comment = db.create(PackageComment,
- PackageBase=package.PackageBase,
- User=user, Comments="Test comment",
- RenderedComment="Test comment
",
- CommentTS=now)
+ comment = db.create(
+ PackageComment,
+ PackageBase=package.PackageBase,
+ User=user,
+ Comments="Test comment",
+ CommentTS=now + 1,
+ )
+ rendered_comment = db.create(
+ PackageComment,
+ PackageBase=package.PackageBase,
+ User=user,
+ Comments="Test comment",
+ RenderedComment="Test comment
",
+ CommentTS=now,
+ )
cookies = {"AURSID": user.login(Request(), "testPassword")}
endpoint = f"/account/{user.Username}/comments"
@@ -1508,7 +1539,6 @@ def test_account_comments(client: TestClient, user: User, package: Package):
assert comments[0].text.strip() == comment.Comments
# And from the second, we have rendered content.
- rendered = comments[1].xpath('./p')
- expected = rendered_comment.RenderedComment.replace(
- "", "").replace("
", "")
+ rendered = comments[1].xpath("./p")
+ expected = rendered_comment.RenderedComment.replace("", "").replace("
", "")
assert rendered[0].text.strip() == expected
diff --git a/test/test_packages_util.py b/test/test_packages_util.py
index 02f84601..0042cd71 100644
--- a/test/test_packages_util.py
+++ b/test/test_packages_util.py
@@ -1,5 +1,4 @@
import pytest
-
from fastapi.testclient import TestClient
from aurweb import asgi, config, db, time
@@ -23,18 +22,22 @@ def setup(db_test):
@pytest.fixture
def maintainer() -> User:
with db.begin():
- maintainer = db.create(User, Username="test_maintainer",
- Email="test_maintainer@examepl.org",
- Passwd="testPassword",
- AccountTypeID=USER_ID)
+ maintainer = db.create(
+ User,
+ Username="test_maintainer",
+ Email="test_maintainer@examepl.org",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield maintainer
@pytest.fixture
def package(maintainer: User) -> Package:
with db.begin():
- pkgbase = db.create(PackageBase, Name="test-pkg",
- Packager=maintainer, Maintainer=maintainer)
+ pkgbase = db.create(
+ PackageBase, Name="test-pkg", Packager=maintainer, Maintainer=maintainer
+ )
package = db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase)
yield package
@@ -51,10 +54,9 @@ def test_package_link(client: TestClient, package: Package):
def test_official_package_link(client: TestClient, package: Package):
with db.begin():
- provider = db.create(OfficialProvider,
- Name=package.Name,
- Repo="core",
- Provides=package.Name)
+ provider = db.create(
+ OfficialProvider, Name=package.Name, Repo="core", Provides=package.Name
+ )
expected = f"{OFFICIAL_BASE}/packages/?q={package.Name}"
assert util.package_link(provider) == expected
@@ -63,9 +65,7 @@ def test_updated_packages(maintainer: User, package: Package):
expected = {
"Name": package.Name,
"Version": package.Version,
- "PackageBase": {
- "ModifiedTS": package.PackageBase.ModifiedTS
- }
+ "PackageBase": {"ModifiedTS": package.PackageBase.ModifiedTS},
}
kill_redis() # Kill it here to ensure we're on a fake instance.
@@ -77,8 +77,9 @@ def test_updated_packages(maintainer: User, package: Package):
def test_query_voted(maintainer: User, package: Package):
now = time.utcnow()
with db.begin():
- db.create(PackageVote, User=maintainer, VoteTS=now,
- PackageBase=package.PackageBase)
+ db.create(
+ PackageVote, User=maintainer, VoteTS=now, PackageBase=package.PackageBase
+ )
query = db.query(Package).filter(Package.ID == package.ID).all()
query_voted = util.query_voted(query, maintainer)
@@ -87,8 +88,7 @@ def test_query_voted(maintainer: User, package: Package):
def test_query_notified(maintainer: User, package: Package):
with db.begin():
- db.create(PackageNotification, User=maintainer,
- PackageBase=package.PackageBase)
+ db.create(PackageNotification, User=maintainer, PackageBase=package.PackageBase)
query = db.query(Package).filter(Package.ID == package.ID).all()
query_notified = util.query_notified(query, maintainer)
@@ -99,8 +99,9 @@ def test_source_uri_file(package: Package):
FILE = "test_file"
with db.begin():
- pkgsrc = db.create(PackageSource, Source=FILE,
- Package=package, SourceArch="x86_64")
+ pkgsrc = db.create(
+ PackageSource, Source=FILE, Package=package, SourceArch="x86_64"
+ )
source_file_uri = config.get("options", "source_file_uri")
file, uri = util.source_uri(pkgsrc)
expected = source_file_uri % (pkgsrc.Source, package.PackageBase.Name)
@@ -112,8 +113,9 @@ def test_source_uri_named_uri(package: Package):
URL = "https://test.xyz"
with db.begin():
- pkgsrc = db.create(PackageSource, Source=f"{FILE}::{URL}",
- Package=package, SourceArch="x86_64")
+ pkgsrc = db.create(
+ PackageSource, Source=f"{FILE}::{URL}", Package=package, SourceArch="x86_64"
+ )
file, uri = util.source_uri(pkgsrc)
assert (file, uri) == (FILE, URL)
@@ -122,7 +124,8 @@ def test_source_uri_unnamed_uri(package: Package):
URL = "https://test.xyz"
with db.begin():
- pkgsrc = db.create(PackageSource, Source=f"{URL}",
- Package=package, SourceArch="x86_64")
+ pkgsrc = db.create(
+ PackageSource, Source=f"{URL}", Package=package, SourceArch="x86_64"
+ )
file, uri = util.source_uri(pkgsrc)
assert (file, uri) == (URL, URL)
diff --git a/test/test_pkgbase_routes.py b/test/test_pkgbase_routes.py
index 52241b9e..bfdb0c37 100644
--- a/test/test_pkgbase_routes.py
+++ b/test/test_pkgbase_routes.py
@@ -1,10 +1,8 @@
import re
-
from http import HTTPStatus
from unittest import mock
import pytest
-
from fastapi.testclient import TestClient
from sqlalchemy import and_
@@ -33,30 +31,24 @@ def package_endpoint(package: Package) -> str:
def create_package(pkgname: str, maintainer: User) -> Package:
- pkgbase = db.create(PackageBase,
- Name=pkgname,
- Maintainer=maintainer)
+ pkgbase = db.create(PackageBase, Name=pkgname, Maintainer=maintainer)
return db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase)
-def create_package_dep(package: Package, depname: str,
- dep_type_name: str = "depends") -> PackageDependency:
- dep_type = db.query(DependencyType,
- DependencyType.Name == dep_type_name).first()
- return db.create(PackageDependency,
- DependencyType=dep_type,
- Package=package,
- DepName=depname)
+def create_package_dep(
+ package: Package, depname: str, dep_type_name: str = "depends"
+) -> PackageDependency:
+ dep_type = db.query(DependencyType, DependencyType.Name == dep_type_name).first()
+ return db.create(
+ PackageDependency, DependencyType=dep_type, Package=package, DepName=depname
+ )
-def create_package_rel(package: Package,
- relname: str) -> PackageRelation:
- rel_type = db.query(RelationType,
- RelationType.ID == PROVIDES_ID).first()
- return db.create(PackageRelation,
- RelationType=rel_type,
- Package=package,
- RelName=relname)
+def create_package_rel(package: Package, relname: str) -> PackageRelation:
+ rel_type = db.query(RelationType, RelationType.ID == PROVIDES_ID).first()
+ return db.create(
+ PackageRelation, RelationType=rel_type, Package=package, RelName=relname
+ )
@pytest.fixture(autouse=True)
@@ -66,76 +58,88 @@ def setup(db_test):
@pytest.fixture
def client() -> TestClient:
- """ Yield a FastAPI TestClient. """
+ """Yield a FastAPI TestClient."""
yield TestClient(app=asgi.app)
def create_user(username: str) -> User:
with db.begin():
- user = db.create(User, Username=username,
- Email=f"{username}@example.org",
- Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username=username,
+ Email=f"{username}@example.org",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
return user
@pytest.fixture
def user() -> User:
- """ Yield a user. """
+ """Yield a user."""
user = create_user("test")
yield user
@pytest.fixture
def maintainer() -> User:
- """ Yield a specific User used to maintain packages. """
+ """Yield a specific User used to maintain packages."""
account_type = db.query(AccountType, AccountType.ID == USER_ID).first()
with db.begin():
- maintainer = db.create(User, Username="test_maintainer",
- Email="test_maintainer@example.org",
- Passwd="testPassword",
- AccountType=account_type)
+ maintainer = db.create(
+ User,
+ Username="test_maintainer",
+ Email="test_maintainer@example.org",
+ Passwd="testPassword",
+ AccountType=account_type,
+ )
yield maintainer
@pytest.fixture
def comaintainer() -> User:
- """ Yield a specific User used to maintain packages. """
+ """Yield a specific User used to maintain packages."""
account_type = db.query(AccountType, AccountType.ID == USER_ID).first()
with db.begin():
- comaintainer = db.create(User, Username="test_comaintainer",
- Email="test_comaintainer@example.org",
- Passwd="testPassword",
- AccountType=account_type)
+ comaintainer = db.create(
+ User,
+ Username="test_comaintainer",
+ Email="test_comaintainer@example.org",
+ Passwd="testPassword",
+ AccountType=account_type,
+ )
yield comaintainer
@pytest.fixture
def tu_user():
- tu_type = db.query(AccountType,
- AccountType.AccountType == "Trusted User").first()
+ tu_type = db.query(AccountType, AccountType.AccountType == "Trusted User").first()
with db.begin():
- tu_user = db.create(User, Username="test_tu",
- Email="test_tu@example.org",
- RealName="Test TU", Passwd="testPassword",
- AccountType=tu_type)
+ tu_user = db.create(
+ User,
+ Username="test_tu",
+ Email="test_tu@example.org",
+ RealName="Test TU",
+ Passwd="testPassword",
+ AccountType=tu_type,
+ )
yield tu_user
@pytest.fixture
def package(maintainer: User) -> Package:
- """ Yield a Package created by user. """
+ """Yield a Package created by user."""
now = time.utcnow()
with db.begin():
- pkgbase = db.create(PackageBase,
- Name="test-package",
- Maintainer=maintainer,
- Packager=maintainer,
- Submitter=maintainer,
- ModifiedTS=now)
- package = db.create(Package,
- PackageBase=pkgbase,
- Name=pkgbase.Name)
+ pkgbase = db.create(
+ PackageBase,
+ Name="test-package",
+ Maintainer=maintainer,
+ Packager=maintainer,
+ Submitter=maintainer,
+ ModifiedTS=now,
+ )
+ package = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name)
yield package
@@ -146,29 +150,34 @@ def pkgbase(package: Package) -> PackageBase:
@pytest.fixture
def target(maintainer: User) -> PackageBase:
- """ Merge target. """
+ """Merge target."""
now = time.utcnow()
with db.begin():
- pkgbase = db.create(PackageBase, Name="target-package",
- Maintainer=maintainer,
- Packager=maintainer,
- Submitter=maintainer,
- ModifiedTS=now)
+ pkgbase = db.create(
+ PackageBase,
+ Name="target-package",
+ Maintainer=maintainer,
+ Packager=maintainer,
+ Submitter=maintainer,
+ ModifiedTS=now,
+ )
db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name)
yield pkgbase
@pytest.fixture
def pkgreq(user: User, pkgbase: PackageBase) -> PackageRequest:
- """ Yield a PackageRequest related to `pkgbase`. """
+ """Yield a PackageRequest related to `pkgbase`."""
with db.begin():
- pkgreq = db.create(PackageRequest,
- ReqTypeID=DELETION_ID,
- User=user,
- PackageBase=pkgbase,
- PackageBaseName=pkgbase.Name,
- Comments=f"Deletion request for {pkgbase.Name}",
- ClosureComment=str())
+ pkgreq = db.create(
+ PackageRequest,
+ ReqTypeID=DELETION_ID,
+ User=user,
+ PackageBase=pkgbase,
+ PackageBaseName=pkgbase.Name,
+ Comments=f"Deletion request for {pkgbase.Name}",
+ ClosureComment=str(),
+ )
yield pkgreq
@@ -177,31 +186,33 @@ def comment(user: User, package: Package) -> PackageComment:
pkgbase = package.PackageBase
now = time.utcnow()
with db.begin():
- comment = db.create(PackageComment,
- User=user,
- PackageBase=pkgbase,
- Comments="Test comment.",
- RenderedComment=str(),
- CommentTS=now)
+ comment = db.create(
+ PackageComment,
+ User=user,
+ PackageBase=pkgbase,
+ Comments="Test comment.",
+ RenderedComment=str(),
+ CommentTS=now,
+ )
yield comment
@pytest.fixture
def packages(maintainer: User) -> list[Package]:
- """ Yield 55 packages named pkg_0 .. pkg_54. """
+ """Yield 55 packages named pkg_0 .. pkg_54."""
packages_ = []
now = time.utcnow()
with db.begin():
for i in range(55):
- pkgbase = db.create(PackageBase,
- Name=f"pkg_{i}",
- Maintainer=maintainer,
- Packager=maintainer,
- Submitter=maintainer,
- ModifiedTS=now)
- package = db.create(Package,
- PackageBase=pkgbase,
- Name=f"pkg_{i}")
+ pkgbase = db.create(
+ PackageBase,
+ Name=f"pkg_{i}",
+ Maintainer=maintainer,
+ Packager=maintainer,
+ Submitter=maintainer,
+ ModifiedTS=now,
+ )
+ package = db.create(Package, PackageBase=pkgbase, Name=f"pkg_{i}")
packages_.append(package)
yield packages_
@@ -210,18 +221,18 @@ def packages(maintainer: User) -> list[Package]:
@pytest.fixture
def requests(user: User, packages: list[Package]) -> list[PackageRequest]:
pkgreqs = []
- deletion_type = db.query(RequestType).filter(
- RequestType.ID == DELETION_ID
- ).first()
+ deletion_type = db.query(RequestType).filter(RequestType.ID == DELETION_ID).first()
with db.begin():
for i in range(55):
- pkgreq = db.create(PackageRequest,
- RequestType=deletion_type,
- User=user,
- PackageBase=packages[i].PackageBase,
- PackageBaseName=packages[i].Name,
- Comments=f"Deletion request for pkg_{i}",
- ClosureComment=str())
+ pkgreq = db.create(
+ PackageRequest,
+ RequestType=deletion_type,
+ User=user,
+ PackageBase=packages[i].PackageBase,
+ PackageBaseName=packages[i].Name,
+ Comments=f"Deletion request for pkg_{i}",
+ ClosureComment=str(),
+ )
pkgreqs.append(pkgreq)
yield pkgreqs
@@ -234,21 +245,18 @@ def test_pkgbase_not_found(client: TestClient):
def test_pkgbase_redirect(client: TestClient, package: Package):
with client as request:
- resp = request.get(f"/pkgbase/{package.Name}",
- allow_redirects=False)
+ resp = request.get(f"/pkgbase/{package.Name}", allow_redirects=False)
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
assert resp.headers.get("location") == f"/packages/{package.Name}"
def test_pkgbase(client: TestClient, package: Package):
with db.begin():
- second = db.create(Package, Name="second-pkg",
- PackageBase=package.PackageBase)
+ second = db.create(Package, Name="second-pkg", PackageBase=package.PackageBase)
expected = [package.Name, second.Name]
with client as request:
- resp = request.get(f"/pkgbase/{package.Name}",
- allow_redirects=False)
+ resp = request.get(f"/pkgbase/{package.Name}", allow_redirects=False)
assert resp.status_code == int(HTTPStatus.OK)
root = parse_root(resp.text)
@@ -264,8 +272,9 @@ def test_pkgbase(client: TestClient, package: Package):
assert pkgs[i].text.strip() == name
-def test_pkgbase_maintainer(client: TestClient, user: User, maintainer: User,
- package: Package):
+def test_pkgbase_maintainer(
+ client: TestClient, user: User, maintainer: User, package: Package
+):
"""
Test that the Maintainer field is beind displayed correctly.
@@ -273,9 +282,9 @@ def test_pkgbase_maintainer(client: TestClient, user: User, maintainer: User,
the maintainer.
"""
with db.begin():
- db.create(PackageComaintainer, User=user,
- PackageBase=package.PackageBase,
- Priority=1)
+ db.create(
+ PackageComaintainer, User=user, PackageBase=package.PackageBase, Priority=1
+ )
with client as request:
resp = request.get(f"/pkgbase/{package.Name}")
@@ -286,7 +295,7 @@ def test_pkgbase_maintainer(client: TestClient, user: User, maintainer: User,
maint = root.xpath('//table[@id="pkginfo"]/tr[@class="pkgmaint"]/td')[0]
maint, comaint = maint.text.strip().split()
assert maint == maintainer.Username
- assert comaint == f'({user.Username})'
+ assert comaint == f"({user.Username})"
def test_pkgbase_voters(client: TestClient, tu_user: User, package: Package):
@@ -309,8 +318,7 @@ def test_pkgbase_voters(client: TestClient, tu_user: User, package: Package):
assert rows[0].text.strip() == tu_user.Username
-def test_pkgbase_voters_unauthorized(client: TestClient, user: User,
- package: Package):
+def test_pkgbase_voters_unauthorized(client: TestClient, user: User, package: Package):
pkgbase = package.PackageBase
endpoint = f"/pkgbase/{pkgbase.Name}/voters"
@@ -324,25 +332,30 @@ def test_pkgbase_voters_unauthorized(client: TestClient, user: User,
assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}"
-def test_pkgbase_comment_not_found(client: TestClient, maintainer: User,
- package: Package):
+def test_pkgbase_comment_not_found(
+ client: TestClient, maintainer: User, package: Package
+):
cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
comment_id = 12345 # A non-existing comment.
endpoint = f"/pkgbase/{package.PackageBase.Name}/comments/{comment_id}"
with client as request:
- resp = request.post(endpoint, data={
- "comment": "Failure"
- }, cookies=cookies)
+ resp = request.post(endpoint, data={"comment": "Failure"}, cookies=cookies)
assert resp.status_code == int(HTTPStatus.NOT_FOUND)
-def test_pkgbase_comment_form_unauthorized(client: TestClient, user: User,
- maintainer: User, package: Package):
+def test_pkgbase_comment_form_unauthorized(
+ client: TestClient, user: User, maintainer: User, package: Package
+):
now = time.utcnow()
with db.begin():
- comment = db.create(PackageComment, PackageBase=package.PackageBase,
- User=maintainer, Comments="Test",
- RenderedComment=str(), CommentTS=now)
+ comment = db.create(
+ PackageComment,
+ PackageBase=package.PackageBase,
+ User=maintainer,
+ Comments="Test",
+ RenderedComment=str(),
+ CommentTS=now,
+ )
cookies = {"AURSID": user.login(Request(), "testPassword")}
pkgbasename = package.PackageBase.Name
@@ -352,8 +365,9 @@ def test_pkgbase_comment_form_unauthorized(client: TestClient, user: User,
assert resp.status_code == int(HTTPStatus.UNAUTHORIZED)
-def test_pkgbase_comment_form_not_found(client: TestClient, maintainer: User,
- package: Package):
+def test_pkgbase_comment_form_not_found(
+ client: TestClient, maintainer: User, package: Package
+):
cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
comment_id = 12345 # A non-existing comment.
pkgbasename = package.PackageBase.Name
@@ -363,8 +377,9 @@ def test_pkgbase_comment_form_not_found(client: TestClient, maintainer: User,
assert resp.status_code == int(HTTPStatus.NOT_FOUND)
-def test_pkgbase_comments_missing_comment(client: TestClient, maintainer: User,
- package: Package):
+def test_pkgbase_comments_missing_comment(
+ client: TestClient, maintainer: User, package: Package
+):
cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
endpoint = f"/pkgbase/{package.PackageBase.Name}/comments"
with client as request:
@@ -372,9 +387,10 @@ def test_pkgbase_comments_missing_comment(client: TestClient, maintainer: User,
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
-def test_pkgbase_comments(client: TestClient, maintainer: User, user: User,
- package: Package):
- """ This test includes tests against the following routes:
+def test_pkgbase_comments(
+ client: TestClient, maintainer: User, user: User, package: Package
+):
+ """This test includes tests against the following routes:
- POST /pkgbase/{name}/comments
- GET /pkgbase/{name} (to check comments)
- Tested against a comment created with the POST route
@@ -383,18 +399,17 @@ def test_pkgbase_comments(client: TestClient, maintainer: User, user: User,
"""
with db.begin():
user.CommentNotify = 1
- db.create(PackageNotification,
- PackageBase=package.PackageBase,
- User=user)
+ db.create(PackageNotification, PackageBase=package.PackageBase, User=user)
cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
pkgbasename = package.PackageBase.Name
endpoint = f"/pkgbase/{pkgbasename}/comments"
with client as request:
- resp = request.post(endpoint, data={
- "comment": "Test comment.",
- "enable_notifications": True
- }, cookies=cookies)
+ resp = request.post(
+ endpoint,
+ data={"comment": "Test comment.", "enable_notifications": True},
+ cookies=cookies,
+ )
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
# user should've gotten a CommentNotification email.
@@ -438,10 +453,11 @@ def test_pkgbase_comments(client: TestClient, maintainer: User, user: User,
comment_id = int(headers[0].attrib["id"].split("-")[-1])
endpoint = f"/pkgbase/{pkgbasename}/comments/{comment_id}"
with client as request:
- resp = request.post(endpoint, data={
- "comment": "Edited comment.",
- "enable_notifications": True
- }, cookies=cookies)
+ resp = request.post(
+ endpoint,
+ data={"comment": "Edited comment.", "enable_notifications": True},
+ cookies=cookies,
+ )
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
with client as request:
@@ -479,27 +495,33 @@ def test_pkgbase_comments(client: TestClient, maintainer: User, user: User,
assert "form" in data
-def test_pkgbase_comment_edit_unauthorized(client: TestClient,
- user: User,
- maintainer: User,
- package: Package,
- comment: PackageComment):
+def test_pkgbase_comment_edit_unauthorized(
+ client: TestClient,
+ user: User,
+ maintainer: User,
+ package: Package,
+ comment: PackageComment,
+):
pkgbase = package.PackageBase
cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
with client as request:
endp = f"/pkgbase/{pkgbase.Name}/comments/{comment.ID}"
- response = request.post(endp, data={
- "comment": "abcd im trying to change this comment."
- }, cookies=cookies)
+ response = request.post(
+ endp,
+ data={"comment": "abcd im trying to change this comment."},
+ cookies=cookies,
+ )
assert response.status_code == HTTPStatus.UNAUTHORIZED
-def test_pkgbase_comment_delete(client: TestClient,
- maintainer: User,
- user: User,
- package: Package,
- comment: PackageComment):
+def test_pkgbase_comment_delete(
+ client: TestClient,
+ maintainer: User,
+ user: User,
+ package: Package,
+ comment: PackageComment,
+):
# Test the unauthorized case of comment deletion.
cookies = {"AURSID": user.login(Request(), "testPassword")}
pkgbasename = package.PackageBase.Name
@@ -524,10 +546,9 @@ def test_pkgbase_comment_delete(client: TestClient,
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
-def test_pkgbase_comment_delete_unauthorized(client: TestClient,
- maintainer: User,
- package: Package,
- comment: PackageComment):
+def test_pkgbase_comment_delete_unauthorized(
+ client: TestClient, maintainer: User, package: Package, comment: PackageComment
+):
# Test the unauthorized case of comment deletion.
cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
pkgbasename = package.PackageBase.Name
@@ -537,9 +558,9 @@ def test_pkgbase_comment_delete_unauthorized(client: TestClient,
assert resp.status_code == int(HTTPStatus.UNAUTHORIZED)
-def test_pkgbase_comment_delete_not_found(client: TestClient,
- maintainer: User,
- package: Package):
+def test_pkgbase_comment_delete_not_found(
+ client: TestClient, maintainer: User, package: Package
+):
cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
comment_id = 12345 # Non-existing comment.
pkgbasename = package.PackageBase.Name
@@ -549,9 +570,9 @@ def test_pkgbase_comment_delete_not_found(client: TestClient,
assert resp.status_code == int(HTTPStatus.NOT_FOUND)
-def test_pkgbase_comment_undelete_not_found(client: TestClient,
- maintainer: User,
- package: Package):
+def test_pkgbase_comment_undelete_not_found(
+ client: TestClient, maintainer: User, package: Package
+):
cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
comment_id = 12345 # Non-existing comment.
pkgbasename = package.PackageBase.Name
@@ -561,13 +582,18 @@ def test_pkgbase_comment_undelete_not_found(client: TestClient,
assert resp.status_code == int(HTTPStatus.NOT_FOUND)
-def test_pkgbase_comment_pin_as_co(client: TestClient, package: Package,
- comment: PackageComment):
+def test_pkgbase_comment_pin_as_co(
+ client: TestClient, package: Package, comment: PackageComment
+):
comaint = create_user("comaint1")
with db.begin():
- db.create(PackageComaintainer, PackageBase=package.PackageBase,
- User=comaint, Priority=1)
+ db.create(
+ PackageComaintainer,
+ PackageBase=package.PackageBase,
+ User=comaint,
+ Priority=1,
+ )
# Pin the comment.
pkgbasename = package.PackageBase.Name
@@ -590,10 +616,9 @@ def test_pkgbase_comment_pin_as_co(client: TestClient, package: Package,
assert comment.PinnedTS == 0
-def test_pkgbase_comment_pin(client: TestClient,
- maintainer: User,
- package: Package,
- comment: PackageComment):
+def test_pkgbase_comment_pin(
+ client: TestClient, maintainer: User, package: Package, comment: PackageComment
+):
cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
comment_id = comment.ID
pkgbasename = package.PackageBase.Name
@@ -617,10 +642,9 @@ def test_pkgbase_comment_pin(client: TestClient,
assert comment.PinnedTS == 0
-def test_pkgbase_comment_pin_unauthorized(client: TestClient,
- user: User,
- package: Package,
- comment: PackageComment):
+def test_pkgbase_comment_pin_unauthorized(
+ client: TestClient, user: User, package: Package, comment: PackageComment
+):
cookies = {"AURSID": user.login(Request(), "testPassword")}
comment_id = comment.ID
pkgbasename = package.PackageBase.Name
@@ -630,10 +654,9 @@ def test_pkgbase_comment_pin_unauthorized(client: TestClient,
assert resp.status_code == int(HTTPStatus.UNAUTHORIZED)
-def test_pkgbase_comment_unpin_unauthorized(client: TestClient,
- user: User,
- package: Package,
- comment: PackageComment):
+def test_pkgbase_comment_unpin_unauthorized(
+ client: TestClient, user: User, package: Package, comment: PackageComment
+):
cookies = {"AURSID": user.login(Request(), "testPassword")}
comment_id = comment.ID
pkgbasename = package.PackageBase.Name
@@ -651,8 +674,7 @@ def test_pkgbase_comaintainers_not_found(client: TestClient, maintainer: User):
assert resp.status_code == int(HTTPStatus.NOT_FOUND)
-def test_pkgbase_comaintainers_post_not_found(client: TestClient,
- maintainer: User):
+def test_pkgbase_comaintainers_post_not_found(client: TestClient, maintainer: User):
cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
endpoint = "/pkgbase/fake/comaintainers"
with client as request:
@@ -660,8 +682,9 @@ def test_pkgbase_comaintainers_post_not_found(client: TestClient,
assert resp.status_code == int(HTTPStatus.NOT_FOUND)
-def test_pkgbase_comaintainers_unauthorized(client: TestClient, user: User,
- package: Package):
+def test_pkgbase_comaintainers_unauthorized(
+ client: TestClient, user: User, package: Package
+):
pkgbase = package.PackageBase
endpoint = f"/pkgbase/{pkgbase.Name}/comaintainers"
cookies = {"AURSID": user.login(Request(), "testPassword")}
@@ -671,9 +694,9 @@ def test_pkgbase_comaintainers_unauthorized(client: TestClient, user: User,
assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}"
-def test_pkgbase_comaintainers_post_unauthorized(client: TestClient,
- user: User,
- package: Package):
+def test_pkgbase_comaintainers_post_unauthorized(
+ client: TestClient, user: User, package: Package
+):
pkgbase = package.PackageBase
endpoint = f"/pkgbase/{pkgbase.Name}/comaintainers"
cookies = {"AURSID": user.login(Request(), "testPassword")}
@@ -683,16 +706,16 @@ def test_pkgbase_comaintainers_post_unauthorized(client: TestClient,
assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}"
-def test_pkgbase_comaintainers_post_invalid_user(client: TestClient,
- maintainer: User,
- package: Package):
+def test_pkgbase_comaintainers_post_invalid_user(
+ client: TestClient, maintainer: User, package: Package
+):
pkgbase = package.PackageBase
endpoint = f"/pkgbase/{pkgbase.Name}/comaintainers"
cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
with client as request:
- resp = request.post(endpoint, data={
- "users": "\nfake\n"
- }, cookies=cookies, allow_redirects=False)
+ resp = request.post(
+ endpoint, data={"users": "\nfake\n"}, cookies=cookies, allow_redirects=False
+ )
assert resp.status_code == int(HTTPStatus.OK)
root = parse_root(resp.text)
@@ -700,8 +723,9 @@ def test_pkgbase_comaintainers_post_invalid_user(client: TestClient,
assert error.text.strip() == "Invalid user name: fake"
-def test_pkgbase_comaintainers(client: TestClient, user: User,
- maintainer: User, package: Package):
+def test_pkgbase_comaintainers(
+ client: TestClient, user: User, maintainer: User, package: Package
+):
pkgbase = package.PackageBase
endpoint = f"/pkgbase/{pkgbase.Name}/comaintainers"
cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
@@ -709,17 +733,23 @@ def test_pkgbase_comaintainers(client: TestClient, user: User,
# Start off by adding user as a comaintainer to package.
# The maintainer username given should be ignored.
with client as request:
- resp = request.post(endpoint, data={
- "users": f"\n{user.Username}\n{maintainer.Username}\n"
- }, cookies=cookies, allow_redirects=False)
+ resp = request.post(
+ endpoint,
+ data={"users": f"\n{user.Username}\n{maintainer.Username}\n"},
+ cookies=cookies,
+ allow_redirects=False,
+ )
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}"
# Do it again to exercise the last_priority bump path.
with client as request:
- resp = request.post(endpoint, data={
- "users": f"\n{user.Username}\n{maintainer.Username}\n"
- }, cookies=cookies, allow_redirects=False)
+ resp = request.post(
+ endpoint,
+ data={"users": f"\n{user.Username}\n{maintainer.Username}\n"},
+ cookies=cookies,
+ allow_redirects=False,
+ )
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}"
@@ -736,9 +766,9 @@ def test_pkgbase_comaintainers(client: TestClient, user: User,
# Finish off by removing all the comaintainers.
with client as request:
- resp = request.post(endpoint, data={
- "users": str()
- }, cookies=cookies, allow_redirects=False)
+ resp = request.post(
+ endpoint, data={"users": str()}, cookies=cookies, allow_redirects=False
+ )
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}"
@@ -774,15 +804,15 @@ def test_pkgbase_request(client: TestClient, user: User, package: Package):
def test_pkgbase_request_post_not_found(client: TestClient, user: User):
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- resp = request.post("/pkgbase/fake/request", data={
- "type": "fake"
- }, cookies=cookies)
+ resp = request.post(
+ "/pkgbase/fake/request", data={"type": "fake"}, cookies=cookies
+ )
assert resp.status_code == int(HTTPStatus.NOT_FOUND)
-def test_pkgbase_request_post_invalid_type(client: TestClient,
- user: User,
- package: Package):
+def test_pkgbase_request_post_invalid_type(
+ client: TestClient, user: User, package: Package
+):
endpoint = f"/pkgbase/{package.PackageBase.Name}/request"
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
@@ -790,16 +820,20 @@ def test_pkgbase_request_post_invalid_type(client: TestClient,
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
-def test_pkgbase_request_post_no_comment_error(client: TestClient,
- user: User,
- package: Package):
+def test_pkgbase_request_post_no_comment_error(
+ client: TestClient, user: User, package: Package
+):
endpoint = f"/pkgbase/{package.PackageBase.Name}/request"
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- resp = request.post(endpoint, data={
- "type": "deletion",
- "comments": "" # An empty comment field causes an error.
- }, cookies=cookies)
+ resp = request.post(
+ endpoint,
+ data={
+ "type": "deletion",
+ "comments": "", # An empty comment field causes an error.
+ },
+ cookies=cookies,
+ )
assert resp.status_code == int(HTTPStatus.OK)
root = parse_root(resp.text)
@@ -808,17 +842,22 @@ def test_pkgbase_request_post_no_comment_error(client: TestClient,
assert error.text.strip() == expected
-def test_pkgbase_request_post_merge_not_found_error(client: TestClient,
- user: User,
- package: Package):
+def test_pkgbase_request_post_merge_not_found_error(
+ client: TestClient, user: User, package: Package
+):
endpoint = f"/pkgbase/{package.PackageBase.Name}/request"
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- resp = request.post(endpoint, data={
- "type": "merge",
- "merge_into": "fake", # There is no PackageBase.Name "fake"
- "comments": "We want to merge this."
- }, cookies=cookies, allow_redirects=False)
+ resp = request.post(
+ endpoint,
+ data={
+ "type": "merge",
+ "merge_into": "fake", # There is no PackageBase.Name "fake"
+ "comments": "We want to merge this.",
+ },
+ cookies=cookies,
+ allow_redirects=False,
+ )
assert resp.status_code == int(HTTPStatus.OK)
root = parse_root(resp.text)
@@ -827,17 +866,22 @@ def test_pkgbase_request_post_merge_not_found_error(client: TestClient,
assert error.text.strip() == expected
-def test_pkgbase_request_post_merge_no_merge_into_error(client: TestClient,
- user: User,
- package: Package):
+def test_pkgbase_request_post_merge_no_merge_into_error(
+ client: TestClient, user: User, package: Package
+):
endpoint = f"/pkgbase/{package.PackageBase.Name}/request"
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- resp = request.post(endpoint, data={
- "type": "merge",
- "merge_into": "", # There is no PackageBase.Name "fake"
- "comments": "We want to merge this."
- }, cookies=cookies, allow_redirects=False)
+ resp = request.post(
+ endpoint,
+ data={
+ "type": "merge",
+ "merge_into": "", # There is no PackageBase.Name "fake"
+ "comments": "We want to merge this.",
+ },
+ cookies=cookies,
+ allow_redirects=False,
+ )
assert resp.status_code == int(HTTPStatus.OK)
root = parse_root(resp.text)
@@ -846,16 +890,22 @@ def test_pkgbase_request_post_merge_no_merge_into_error(client: TestClient,
assert error.text.strip() == expected
-def test_pkgbase_request_post_merge_self_error(client: TestClient, user: User,
- package: Package):
+def test_pkgbase_request_post_merge_self_error(
+ client: TestClient, user: User, package: Package
+):
endpoint = f"/pkgbase/{package.PackageBase.Name}/request"
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- resp = request.post(endpoint, data={
- "type": "merge",
- "merge_into": package.PackageBase.Name,
- "comments": "We want to merge this."
- }, cookies=cookies, allow_redirects=False)
+ resp = request.post(
+ endpoint,
+ data={
+ "type": "merge",
+ "merge_into": package.PackageBase.Name,
+ "comments": "We want to merge this.",
+ },
+ cookies=cookies,
+ allow_redirects=False,
+ )
assert resp.status_code == int(HTTPStatus.OK)
root = parse_root(resp.text)
@@ -864,8 +914,9 @@ def test_pkgbase_request_post_merge_self_error(client: TestClient, user: User,
assert error.text.strip() == expected
-def test_pkgbase_flag(client: TestClient, user: User, maintainer: User,
- package: Package):
+def test_pkgbase_flag(
+ client: TestClient, user: User, maintainer: User, package: Package
+):
pkgbase = package.PackageBase
# We shouldn't have flagged the package yet; assert so.
@@ -882,8 +933,9 @@ def test_pkgbase_flag(client: TestClient, user: User, maintainer: User,
# Now, let's check the /pkgbase/{name}/flag-comment route.
flag_comment_endpoint = f"/pkgbase/{pkgbase.Name}/flag-comment"
with client as request:
- resp = request.get(flag_comment_endpoint, cookies=cookies,
- allow_redirects=False)
+ resp = request.get(
+ flag_comment_endpoint, cookies=cookies, allow_redirects=False
+ )
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}"
@@ -894,9 +946,7 @@ def test_pkgbase_flag(client: TestClient, user: User, maintainer: User,
# Flag it with a valid comment.
with client as request:
- resp = request.post(endpoint, data={
- "comments": "Test"
- }, cookies=cookies)
+ resp = request.post(endpoint, data={"comments": "Test"}, cookies=cookies)
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
assert pkgbase.Flagger == user
assert pkgbase.FlaggerComment == "Test"
@@ -907,8 +957,9 @@ def test_pkgbase_flag(client: TestClient, user: User, maintainer: User,
# Now, let's check the /pkgbase/{name}/flag-comment route.
flag_comment_endpoint = f"/pkgbase/{pkgbase.Name}/flag-comment"
with client as request:
- resp = request.get(flag_comment_endpoint, cookies=cookies,
- allow_redirects=False)
+ resp = request.get(
+ flag_comment_endpoint, cookies=cookies, allow_redirects=False
+ )
assert resp.status_code == int(HTTPStatus.OK)
# Now try to perform a get; we should be redirected because
@@ -918,10 +969,13 @@ def test_pkgbase_flag(client: TestClient, user: User, maintainer: User,
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
with db.begin():
- user2 = db.create(User, Username="test2",
- Email="test2@example.org",
- Passwd="testPassword",
- AccountType=user.AccountType)
+ user2 = db.create(
+ User,
+ Username="test2",
+ Email="test2@example.org",
+ Passwd="testPassword",
+ AccountType=user.AccountType,
+ )
# Now, test that the 'user2' user can't unflag it, because they
# didn't flag it to begin with.
@@ -941,9 +995,9 @@ def test_pkgbase_flag(client: TestClient, user: User, maintainer: User,
# Flag it again.
with client as request:
- resp = request.post(f"/pkgbase/{pkgbase.Name}/flag", data={
- "comments": "Test"
- }, cookies=cookies)
+ resp = request.post(
+ f"/pkgbase/{pkgbase.Name}/flag", data={"comments": "Test"}, cookies=cookies
+ )
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
# Now, unflag it for real.
@@ -961,16 +1015,17 @@ def test_pkgbase_flag_vcs(client: TestClient, user: User, package: Package):
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- resp = request.get(f"/pkgbase/{package.PackageBase.Name}/flag",
- cookies=cookies)
+ resp = request.get(f"/pkgbase/{package.PackageBase.Name}/flag", cookies=cookies)
assert resp.status_code == int(HTTPStatus.OK)
- expected = ("This seems to be a VCS package. Please do "
- "not flag it out-of-date if the package "
- "version in the AUR does not match the most recent commit. "
- "Flagging this package should only be done if the sources "
- "moved or changes in the PKGBUILD are required because of "
- "recent upstream changes.")
+ expected = (
+ "This seems to be a VCS package. Please do "
+ "not flag it out-of-date if the package "
+ "version in the AUR does not match the most recent commit. "
+ "Flagging this package should only be done if the sources "
+ "moved or changes in the PKGBUILD are required because of "
+ "recent upstream changes."
+ )
assert expected in resp.text
@@ -978,9 +1033,7 @@ def test_pkgbase_notify(client: TestClient, user: User, package: Package):
pkgbase = package.PackageBase
# We have no notif record yet; assert that.
- notif = pkgbase.notifications.filter(
- PackageNotification.UserID == user.ID
- ).first()
+ notif = pkgbase.notifications.filter(PackageNotification.UserID == user.ID).first()
assert notif is None
# Enable notifications.
@@ -990,9 +1043,7 @@ def test_pkgbase_notify(client: TestClient, user: User, package: Package):
resp = request.post(endpoint, cookies=cookies)
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
- notif = pkgbase.notifications.filter(
- PackageNotification.UserID == user.ID
- ).first()
+ notif = pkgbase.notifications.filter(PackageNotification.UserID == user.ID).first()
assert notif is not None
# Disable notifications.
@@ -1001,9 +1052,7 @@ def test_pkgbase_notify(client: TestClient, user: User, package: Package):
resp = request.post(endpoint, cookies=cookies)
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
- notif = pkgbase.notifications.filter(
- PackageNotification.UserID == user.ID
- ).first()
+ notif = pkgbase.notifications.filter(PackageNotification.UserID == user.ID).first()
assert notif is None
@@ -1036,9 +1085,9 @@ def test_pkgbase_vote(client: TestClient, user: User, package: Package):
assert pkgbase.NumVotes == 0
-def test_pkgbase_disown_as_sole_maintainer(client: TestClient,
- maintainer: User,
- package: Package):
+def test_pkgbase_disown_as_sole_maintainer(
+ client: TestClient, maintainer: User, package: Package
+):
cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
pkgbase = package.PackageBase
endpoint = f"/pkgbase/{pkgbase.Name}/disown"
@@ -1049,26 +1098,23 @@ def test_pkgbase_disown_as_sole_maintainer(client: TestClient,
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
-def test_pkgbase_disown_as_maint_with_comaint(client: TestClient,
- user: User,
- maintainer: User,
- package: Package):
- """ When disowning as a maintainer, the lowest priority comaintainer
- is promoted to maintainer. """
+def test_pkgbase_disown_as_maint_with_comaint(
+ client: TestClient, user: User, maintainer: User, package: Package
+):
+ """When disowning as a maintainer, the lowest priority comaintainer
+ is promoted to maintainer."""
pkgbase = package.PackageBase
endp = f"/pkgbase/{pkgbase.Name}/disown"
post_data = {"confirm": True}
with db.begin():
- db.create(PackageComaintainer,
- PackageBase=pkgbase,
- User=user,
- Priority=1)
+ db.create(PackageComaintainer, PackageBase=pkgbase, User=user, Priority=1)
maint_cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
with client as request:
- resp = request.post(endp, data=post_data, cookies=maint_cookies,
- allow_redirects=True)
+ resp = request.post(
+ endp, data=post_data, cookies=maint_cookies, allow_redirects=True
+ )
assert resp.status_code == int(HTTPStatus.OK)
package = db.refresh(package)
@@ -1078,8 +1124,13 @@ def test_pkgbase_disown_as_maint_with_comaint(client: TestClient,
assert pkgbase.comaintainers.count() == 0
-def test_pkgbase_disown(client: TestClient, user: User, maintainer: User,
- comaintainer: User, package: Package):
+def test_pkgbase_disown(
+ client: TestClient,
+ user: User,
+ maintainer: User,
+ comaintainer: User,
+ package: Package,
+):
maint_cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
comaint_cookies = {"AURSID": comaintainer.login(Request(), "testPassword")}
user_cookies = {"AURSID": user.login(Request(), "testPassword")}
@@ -1088,21 +1139,18 @@ def test_pkgbase_disown(client: TestClient, user: User, maintainer: User,
endpoint = f"{pkgbase_endp}/disown"
with db.begin():
- db.create(PackageComaintainer,
- User=comaintainer,
- PackageBase=pkgbase,
- Priority=1)
+ db.create(
+ PackageComaintainer, User=comaintainer, PackageBase=pkgbase, Priority=1
+ )
# GET as a normal user, which is rejected for lack of credentials.
with client as request:
- resp = request.get(endpoint, cookies=user_cookies,
- allow_redirects=False)
+ resp = request.get(endpoint, cookies=user_cookies, allow_redirects=False)
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
# GET as a comaintainer.
with client as request:
- resp = request.get(endpoint, cookies=comaint_cookies,
- allow_redirects=False)
+ resp = request.get(endpoint, cookies=comaint_cookies, allow_redirects=False)
assert resp.status_code == int(HTTPStatus.OK)
# Ensure that the comaintainer can see "Disown Package" link
@@ -1146,8 +1194,9 @@ def test_pkgbase_disown(client: TestClient, user: User, maintainer: User,
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
-def test_pkgbase_adopt(client: TestClient, user: User, tu_user: User,
- maintainer: User, package: Package):
+def test_pkgbase_adopt(
+ client: TestClient, user: User, tu_user: User, maintainer: User, package: Package
+):
# Unset the maintainer as if package is orphaned.
with db.begin():
package.PackageBase.Maintainer = None
@@ -1165,22 +1214,19 @@ def test_pkgbase_adopt(client: TestClient, user: User, tu_user: User,
# Try to adopt it when it already has a maintainer; nothing changes.
user_cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- resp = request.post(endpoint, cookies=user_cookies,
- allow_redirects=False)
+ resp = request.post(endpoint, cookies=user_cookies, allow_redirects=False)
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
assert package.PackageBase.Maintainer == maintainer
# Steal the package as a TU.
tu_cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
- resp = request.post(endpoint, cookies=tu_cookies,
- allow_redirects=False)
+ resp = request.post(endpoint, cookies=tu_cookies, allow_redirects=False)
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
assert package.PackageBase.Maintainer == tu_user
-def test_pkgbase_delete_unauthorized(client: TestClient, user: User,
- package: Package):
+def test_pkgbase_delete_unauthorized(client: TestClient, user: User, package: Package):
pkgbase = package.PackageBase
cookies = {"AURSID": user.login(Request(), "testPassword")}
endpoint = f"/pkgbase/{pkgbase.Name}/delete"
@@ -1219,9 +1265,7 @@ def test_pkgbase_delete(client: TestClient, tu_user: User, package: Package):
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
# Let's assert that the package base record got removed.
- record = db.query(PackageBase).filter(
- PackageBase.Name == pkgbase.Name
- ).first()
+ record = db.query(PackageBase).filter(PackageBase.Name == pkgbase.Name).first()
assert record is None
# Two emails should've been sent out; an autogenerated
@@ -1234,9 +1278,9 @@ def test_pkgbase_delete(client: TestClient, tu_user: User, package: Package):
assert re.match(expr, subject)
-def test_pkgbase_delete_with_request(client: TestClient, tu_user: User,
- pkgbase: PackageBase,
- pkgreq: PackageRequest):
+def test_pkgbase_delete_with_request(
+ client: TestClient, tu_user: User, pkgbase: PackageBase, pkgreq: PackageRequest
+):
# TODO: Test that a previously existing request gets Accepted when
# a TU deleted the package.
@@ -1257,12 +1301,15 @@ def test_pkgbase_delete_with_request(client: TestClient, tu_user: User,
assert re.match(expr, email.headers.get("Subject"))
-def test_packages_post_unknown_action(client: TestClient, user: User,
- package: Package):
+def test_packages_post_unknown_action(client: TestClient, user: User, package: Package):
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- resp = request.post("/packages", data={"action": "unknown"},
- cookies=cookies, allow_redirects=False)
+ resp = request.post(
+ "/packages",
+ data={"action": "unknown"},
+ cookies=cookies,
+ allow_redirects=False,
+ )
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
@@ -1274,8 +1321,12 @@ def test_packages_post_error(client: TestClient, user: User, package: Package):
with mock.patch.dict("aurweb.routers.packages.PACKAGE_ACTIONS", actions):
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- resp = request.post("/packages", data={"action": "stub"},
- cookies=cookies, allow_redirects=False)
+ resp = request.post(
+ "/packages",
+ data={"action": "stub"},
+ cookies=cookies,
+ allow_redirects=False,
+ )
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
errors = get_errors(resp.text)
@@ -1291,8 +1342,12 @@ def test_packages_post(client: TestClient, user: User, package: Package):
with mock.patch.dict("aurweb.routers.packages.PACKAGE_ACTIONS", actions):
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- resp = request.post("/packages", data={"action": "stub"},
- cookies=cookies, allow_redirects=False)
+ resp = request.post(
+ "/packages",
+ data={"action": "stub"},
+ cookies=cookies,
+ allow_redirects=False,
+ )
assert resp.status_code == int(HTTPStatus.OK)
errors = get_successes(resp.text)
@@ -1300,8 +1355,7 @@ def test_packages_post(client: TestClient, user: User, package: Package):
assert errors[0].text.strip() == expected
-def test_pkgbase_merge_unauthorized(client: TestClient, user: User,
- package: Package):
+def test_pkgbase_merge_unauthorized(client: TestClient, user: User, package: Package):
cookies = {"AURSID": user.login(Request(), "testPassword")}
endpoint = f"/pkgbase/{package.PackageBase.Name}/merge"
with client as request:
@@ -1318,8 +1372,9 @@ def test_pkgbase_merge(client: TestClient, tu_user: User, package: Package):
assert not get_errors(resp.text)
-def test_pkgbase_merge_post_unauthorized(client: TestClient, user: User,
- package: Package):
+def test_pkgbase_merge_post_unauthorized(
+ client: TestClient, user: User, package: Package
+):
cookies = {"AURSID": user.login(Request(), "testPassword")}
endpoint = f"/pkgbase/{package.PackageBase.Name}/merge"
with client as request:
@@ -1327,54 +1382,62 @@ def test_pkgbase_merge_post_unauthorized(client: TestClient, user: User,
assert resp.status_code == int(HTTPStatus.UNAUTHORIZED)
-def test_pkgbase_merge_post_unconfirmed(client: TestClient, tu_user: User,
- package: Package):
+def test_pkgbase_merge_post_unconfirmed(
+ client: TestClient, tu_user: User, package: Package
+):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
endpoint = f"/pkgbase/{package.PackageBase.Name}/merge"
with client as request:
resp = request.post(endpoint, cookies=cookies)
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
errors = get_errors(resp.text)
- expected = ("The selected packages have not been deleted, "
- "check the confirmation checkbox.")
+ expected = (
+ "The selected packages have not been deleted, "
+ "check the confirmation checkbox."
+ )
assert errors[0].text.strip() == expected
-def test_pkgbase_merge_post_invalid_into(client: TestClient, tu_user: User,
- package: Package):
+def test_pkgbase_merge_post_invalid_into(
+ client: TestClient, tu_user: User, package: Package
+):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
endpoint = f"/pkgbase/{package.PackageBase.Name}/merge"
with client as request:
- resp = request.post(endpoint, data={
- "into": "not_real",
- "confirm": True
- }, cookies=cookies)
+ resp = request.post(
+ endpoint, data={"into": "not_real", "confirm": True}, cookies=cookies
+ )
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
errors = get_errors(resp.text)
expected = "Cannot find package to merge votes and comments into."
assert errors[0].text.strip() == expected
-def test_pkgbase_merge_post_self_invalid(client: TestClient, tu_user: User,
- package: Package):
+def test_pkgbase_merge_post_self_invalid(
+ client: TestClient, tu_user: User, package: Package
+):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
endpoint = f"/pkgbase/{package.PackageBase.Name}/merge"
with client as request:
- resp = request.post(endpoint, data={
- "into": package.PackageBase.Name,
- "confirm": True
- }, cookies=cookies)
+ resp = request.post(
+ endpoint,
+ data={"into": package.PackageBase.Name, "confirm": True},
+ cookies=cookies,
+ )
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
errors = get_errors(resp.text)
expected = "Cannot merge a package base with itself."
assert errors[0].text.strip() == expected
-def test_pkgbase_merge_post(client: TestClient, tu_user: User,
- package: Package,
- pkgbase: PackageBase,
- target: PackageBase,
- pkgreq: PackageRequest):
+def test_pkgbase_merge_post(
+ client: TestClient,
+ tu_user: User,
+ package: Package,
+ pkgbase: PackageBase,
+ target: PackageBase,
+ pkgreq: PackageRequest,
+):
pkgname = package.Name
pkgbasename = pkgbase.Name
@@ -1401,9 +1464,9 @@ def test_pkgbase_merge_post(client: TestClient, tu_user: User,
# Comment on the package.
endpoint = f"/pkgbase/{package.PackageBase.Name}/comments"
with client as request:
- resp = request.post(endpoint, data={
- "comment": "Test comment."
- }, cookies=cookies)
+ resp = request.post(
+ endpoint, data={"comment": "Test comment."}, cookies=cookies
+ )
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
# Save these relationships for later comparison.
@@ -1414,10 +1477,9 @@ def test_pkgbase_merge_post(client: TestClient, tu_user: User,
# Merge the package into target.
endpoint = f"/pkgbase/{package.PackageBase.Name}/merge"
with client as request:
- resp = request.post(endpoint, data={
- "into": target.Name,
- "confirm": True
- }, cookies=cookies)
+ resp = request.post(
+ endpoint, data={"into": target.Name, "confirm": True}, cookies=cookies
+ )
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
loc = resp.headers.get("location")
assert loc == f"/pkgbase/{target.Name}"
@@ -1442,11 +1504,17 @@ def test_pkgbase_merge_post(client: TestClient, tu_user: User,
assert pkgreq.Closer is not None
# A PackageRequest is always created when merging this way.
- pkgreq = db.query(PackageRequest).filter(
- and_(PackageRequest.ReqTypeID == MERGE_ID,
- PackageRequest.PackageBaseName == pkgbasename,
- PackageRequest.MergeBaseName == target.Name)
- ).first()
+ pkgreq = (
+ db.query(PackageRequest)
+ .filter(
+ and_(
+ PackageRequest.ReqTypeID == MERGE_ID,
+ PackageRequest.PackageBaseName == pkgbasename,
+ PackageRequest.MergeBaseName == target.Name,
+ )
+ )
+ .first()
+ )
assert pkgreq is not None
@@ -1464,9 +1532,9 @@ def test_pkgbase_keywords(client: TestClient, user: User, package: Package):
cookies = {"AURSID": maint.login(Request(), "testPassword")}
post_endpoint = f"{endpoint}/keywords"
with client as request:
- resp = request.post(post_endpoint, data={
- "keywords": "abc test"
- }, cookies=cookies)
+ resp = request.post(
+ post_endpoint, data={"keywords": "abc test"}, cookies=cookies
+ )
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
with client as request:
@@ -1495,9 +1563,11 @@ def test_pkgbase_empty_keywords(client: TestClient, user: User, package: Package
cookies = {"AURSID": maint.login(Request(), "testPassword")}
post_endpoint = f"{endpoint}/keywords"
with client as request:
- resp = request.post(post_endpoint, data={
- "keywords": "abc test foo bar "
- }, cookies=cookies)
+ resp = request.post(
+ post_endpoint,
+ data={"keywords": "abc test foo bar "},
+ cookies=cookies,
+ )
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
with client as request:
@@ -1514,8 +1584,9 @@ def test_pkgbase_empty_keywords(client: TestClient, user: User, package: Package
def test_unauthorized_pkgbase_keywords(client: TestClient, package: Package):
with db.begin():
- user = db.create(User, Username="random_user", Email="random_user",
- Passwd="testPassword")
+ user = db.create(
+ User, Username="random_user", Email="random_user", Passwd="testPassword"
+ )
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
@@ -1525,20 +1596,25 @@ def test_unauthorized_pkgbase_keywords(client: TestClient, package: Package):
assert response.status_code == HTTPStatus.UNAUTHORIZED
-def test_independent_user_unflag(client: TestClient, user: User,
- package: Package):
+def test_independent_user_unflag(client: TestClient, user: User, package: Package):
with db.begin():
- flagger = db.create(User, Username="test_flagger",
- Email="test_flagger@example.com",
- Passwd="testPassword")
+ flagger = db.create(
+ User,
+ Username="test_flagger",
+ Email="test_flagger@example.com",
+ Passwd="testPassword",
+ )
pkgbase = package.PackageBase
cookies = {"AURSID": flagger.login(Request(), "testPassword")}
with client as request:
endp = f"/pkgbase/{pkgbase.Name}/flag"
- response = request.post(endp, data={
- "comments": "This thing needs a flag!"
- }, cookies=cookies, allow_redirects=True)
+ response = request.post(
+ endp,
+ data={"comments": "This thing needs a flag!"},
+ cookies=cookies,
+ allow_redirects=True,
+ )
assert response.status_code == HTTPStatus.OK
# At this point, we've flagged it as `flagger`.
diff --git a/test/test_pkgmaint.py b/test/test_pkgmaint.py
index da758c22..a0fece78 100644
--- a/test/test_pkgmaint.py
+++ b/test/test_pkgmaint.py
@@ -14,8 +14,13 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- Passwd="testPassword", AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
@@ -26,11 +31,12 @@ def packages(user: User) -> list[Package]:
now = time.utcnow()
with db.begin():
for i in range(5):
- pkgbase = db.create(PackageBase, Name=f"pkg_{i}",
- SubmittedTS=now,
- ModifiedTS=now)
- pkg = db.create(Package, PackageBase=pkgbase,
- Name=f"pkg_{i}", Version=f"{i}.0")
+ pkgbase = db.create(
+ PackageBase, Name=f"pkg_{i}", SubmittedTS=now, ModifiedTS=now
+ )
+ pkg = db.create(
+ Package, PackageBase=pkgbase, Name=f"pkg_{i}", Version=f"{i}.0"
+ )
output.append(pkg)
yield output
@@ -48,7 +54,7 @@ def test_pkgmaint(packages: list[Package]):
# Modify the first package so it's out of date and gets deleted.
with db.begin():
# Reduce SubmittedTS by a day + 10 seconds.
- packages[0].PackageBase.SubmittedTS -= (86400 + 10)
+ packages[0].PackageBase.SubmittedTS -= 86400 + 10
# Run pkgmaint.
pkgmaint.main()
diff --git a/test/test_ratelimit.py b/test/test_ratelimit.py
index 859adea9..20528847 100644
--- a/test/test_ratelimit.py
+++ b/test/test_ratelimit.py
@@ -1,7 +1,6 @@
from unittest import mock
import pytest
-
from redis.client import Pipeline
from aurweb import config, db, logging
@@ -49,6 +48,7 @@ def mock_config_getboolean(return_value: int = 0):
if section == "ratelimit" and key == "cache":
return return_value
return config_getboolean(section, key)
+
return fn
@@ -60,17 +60,22 @@ def mock_config_get(return_value: str = "none"):
if section == "options" and key == "cache":
return return_value
return config_get(section, key)
+
return fn
@mock.patch("aurweb.config.getint", side_effect=mock_config_getint)
@mock.patch("aurweb.config.getboolean", side_effect=mock_config_getboolean(1))
@mock.patch("aurweb.config.get", side_effect=mock_config_get("none"))
-def test_ratelimit_redis(get: mock.MagicMock, getboolean: mock.MagicMock,
- getint: mock.MagicMock, pipeline: Pipeline):
- """ This test will only cover aurweb.ratelimit's Redis
+def test_ratelimit_redis(
+ get: mock.MagicMock,
+ getboolean: mock.MagicMock,
+ getint: mock.MagicMock,
+ pipeline: Pipeline,
+):
+ """This test will only cover aurweb.ratelimit's Redis
path if a real Redis server is configured. Otherwise,
- it'll use the database. """
+ it'll use the database."""
# We'll need a Request for everything here.
request = Request()
@@ -96,8 +101,12 @@ def test_ratelimit_redis(get: mock.MagicMock, getboolean: mock.MagicMock,
@mock.patch("aurweb.config.getint", side_effect=mock_config_getint)
@mock.patch("aurweb.config.getboolean", side_effect=mock_config_getboolean(0))
@mock.patch("aurweb.config.get", side_effect=mock_config_get("none"))
-def test_ratelimit_db(get: mock.MagicMock, getboolean: mock.MagicMock,
- getint: mock.MagicMock, pipeline: Pipeline):
+def test_ratelimit_db(
+ get: mock.MagicMock,
+ getboolean: mock.MagicMock,
+ getint: mock.MagicMock,
+ pipeline: Pipeline,
+):
# We'll need a Request for everything here.
request = Request()
diff --git a/test/test_redis.py b/test/test_redis.py
index 82aebb57..a66cd204 100644
--- a/test/test_redis.py
+++ b/test/test_redis.py
@@ -3,13 +3,13 @@ from unittest import mock
import pytest
import aurweb.config
-
from aurweb.redis import redis_connection
@pytest.fixture
def rediss():
- """ Create a RedisStub. """
+ """Create a RedisStub."""
+
def mock_get(section, key):
return "none"
diff --git a/test/test_rendercomment.py b/test/test_rendercomment.py
index bf4009fd..5b7ff5ac 100644
--- a/test/test_rendercomment.py
+++ b/test/test_rendercomment.py
@@ -31,8 +31,13 @@ def setup(db_test, git: GitRepository):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- Passwd=str(), AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ Passwd=str(),
+ AccountTypeID=USER_ID,
+ )
yield user
@@ -40,24 +45,32 @@ def user() -> User:
def pkgbase(user: User) -> PackageBase:
now = time.utcnow()
with db.begin():
- pkgbase = db.create(PackageBase, Packager=user, Name="pkgbase_0",
- SubmittedTS=now, ModifiedTS=now)
+ pkgbase = db.create(
+ PackageBase,
+ Packager=user,
+ Name="pkgbase_0",
+ SubmittedTS=now,
+ ModifiedTS=now,
+ )
yield pkgbase
@pytest.fixture
def package(pkgbase: PackageBase) -> Package:
with db.begin():
- package = db.create(Package, PackageBase=pkgbase,
- Name=pkgbase.Name, Version="1.0")
+ package = db.create(
+ Package, PackageBase=pkgbase, Name=pkgbase.Name, Version="1.0"
+ )
yield package
-def create_comment(user: User, pkgbase: PackageBase, comments: str,
- render: bool = True):
+def create_comment(
+ user: User, pkgbase: PackageBase, comments: str, render: bool = True
+):
with db.begin():
- comment = db.create(PackageComment, User=user,
- PackageBase=pkgbase, Comments=comments)
+ comment = db.create(
+ PackageComment, User=user, PackageBase=pkgbase, Comments=comments
+ )
if render:
update_comment_render(comment)
return comment
@@ -86,8 +99,7 @@ def test_rendercomment_main(user: User, pkgbase: PackageBase):
def test_markdown_conversion(user: User, pkgbase: PackageBase):
text = "*Hello* [world](https://aur.archlinux.org)!"
comment = create_comment(user, pkgbase, text)
- expected = ('Hello '
- 'world!
')
+ expected = "Hello " 'world!
'
assert comment.RenderedComment == expected
@@ -109,7 +121,7 @@ Visit [Arch Linux][arch].
[arch]: https://www.archlinux.org/\
"""
comment = create_comment(user, pkgbase, text)
- expected = '''\
+ expected = """\
Visit \
https://www.archlinux.org/#_test_.
Visit https://www.archlinux.org/.
@@ -117,7 +129,7 @@ Visit https://www.archlinux.org/.
Visit https://www.archlinux.org/
.
Visit Arch Linux.
Visit Arch Linux.
\
-'''
+"""
assert comment.RenderedComment == expected
diff --git a/test/test_requests.py b/test/test_requests.py
index b7ab3835..fd831674 100644
--- a/test/test_requests.py
+++ b/test/test_requests.py
@@ -1,10 +1,8 @@
import re
-
from http import HTTPStatus
from logging import DEBUG
import pytest
-
from fastapi import HTTPException
from fastapi.testclient import TestClient
@@ -24,13 +22,13 @@ from aurweb.testing.requests import Request
@pytest.fixture(autouse=True)
def setup(db_test) -> None:
- """ Setup the database. """
+ """Setup the database."""
return
@pytest.fixture
def client() -> TestClient:
- """ Yield a TestClient. """
+ """Yield a TestClient."""
yield TestClient(app=asgi.app)
@@ -43,21 +41,26 @@ def create_user(username: str, email: str) -> User:
:return: User instance
"""
with db.begin():
- user = db.create(User, Username=username, Email=email,
- Passwd="testPassword", AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username=username,
+ Email=email,
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
return user
@pytest.fixture
def user() -> User:
- """ Yield a User instance. """
+ """Yield a User instance."""
user = create_user("test", "test@example.org")
yield user
@pytest.fixture
def auser(user: User) -> User:
- """ Yield an authenticated User instance. """
+ """Yield an authenticated User instance."""
cookies = {"AURSID": user.login(Request(), "testPassword")}
user.cookies = cookies
yield user
@@ -65,14 +68,14 @@ def auser(user: User) -> User:
@pytest.fixture
def user2() -> User:
- """ Yield a secondary non-maintainer User instance. """
+ """Yield a secondary non-maintainer User instance."""
user = create_user("test2", "test2@example.org")
yield user
@pytest.fixture
def auser2(user2: User) -> User:
- """ Yield an authenticated secondary non-maintainer User instance. """
+ """Yield an authenticated secondary non-maintainer User instance."""
cookies = {"AURSID": user2.login(Request(), "testPassword")}
user2.cookies = cookies
yield user2
@@ -80,31 +83,34 @@ def auser2(user2: User) -> User:
@pytest.fixture
def maintainer() -> User:
- """ Yield a specific User used to maintain packages. """
+ """Yield a specific User used to maintain packages."""
with db.begin():
- maintainer = db.create(User, Username="test_maintainer",
- Email="test_maintainer@example.org",
- Passwd="testPassword",
- AccountTypeID=USER_ID)
+ maintainer = db.create(
+ User,
+ Username="test_maintainer",
+ Email="test_maintainer@example.org",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield maintainer
@pytest.fixture
def packages(maintainer: User) -> list[Package]:
- """ Yield 55 packages named pkg_0 .. pkg_54. """
+ """Yield 55 packages named pkg_0 .. pkg_54."""
packages_ = []
now = time.utcnow()
with db.begin():
for i in range(55):
- pkgbase = db.create(PackageBase,
- Name=f"pkg_{i}",
- Maintainer=maintainer,
- Packager=maintainer,
- Submitter=maintainer,
- ModifiedTS=now)
- package = db.create(Package,
- PackageBase=pkgbase,
- Name=f"pkg_{i}")
+ pkgbase = db.create(
+ PackageBase,
+ Name=f"pkg_{i}",
+ Maintainer=maintainer,
+ Packager=maintainer,
+ Submitter=maintainer,
+ ModifiedTS=now,
+ )
+ package = db.create(Package, PackageBase=pkgbase, Name=f"pkg_{i}")
packages_.append(package)
yield packages_
@@ -115,20 +121,22 @@ def requests(user: User, packages: list[Package]) -> list[PackageRequest]:
pkgreqs = []
with db.begin():
for i in range(55):
- pkgreq = db.create(PackageRequest,
- ReqTypeID=DELETION_ID,
- User=user,
- PackageBase=packages[i].PackageBase,
- PackageBaseName=packages[i].Name,
- Comments=f"Deletion request for pkg_{i}",
- ClosureComment=str())
+ pkgreq = db.create(
+ PackageRequest,
+ ReqTypeID=DELETION_ID,
+ User=user,
+ PackageBase=packages[i].PackageBase,
+ PackageBaseName=packages[i].Name,
+ Comments=f"Deletion request for pkg_{i}",
+ ClosureComment=str(),
+ )
pkgreqs.append(pkgreq)
yield pkgreqs
@pytest.fixture
def tu_user() -> User:
- """ Yield an authenticated Trusted User instance. """
+ """Yield an authenticated Trusted User instance."""
user = create_user("test_tu", "test_tu@example.org")
with db.begin():
user.AccountTypeID = TRUSTED_USER_ID
@@ -149,31 +157,38 @@ def create_pkgbase(user: User, name: str) -> PackageBase:
"""
now = time.utcnow()
with db.begin():
- pkgbase = db.create(PackageBase, Name=name,
- Maintainer=user, Packager=user,
- SubmittedTS=now, ModifiedTS=now)
+ pkgbase = db.create(
+ PackageBase,
+ Name=name,
+ Maintainer=user,
+ Packager=user,
+ SubmittedTS=now,
+ ModifiedTS=now,
+ )
db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase)
return pkgbase
@pytest.fixture
def pkgbase(user: User) -> PackageBase:
- """ Yield a package base. """
+ """Yield a package base."""
pkgbase = create_pkgbase(user, "test-package")
yield pkgbase
@pytest.fixture
def target(user: User) -> PackageBase:
- """ Yield a merge target (package base). """
+ """Yield a merge target (package base)."""
with db.begin():
- target = db.create(PackageBase, Name="target-package",
- Maintainer=user, Packager=user)
+ target = db.create(
+ PackageBase, Name="target-package", Maintainer=user, Packager=user
+ )
yield target
-def create_request(reqtype_id: int, user: User, pkgbase: PackageBase,
- comments: str) -> PackageRequest:
+def create_request(
+ reqtype_id: int, user: User, pkgbase: PackageBase, comments: str
+) -> PackageRequest:
"""
Create a package request based on `reqtype_id`, `user`,
`pkgbase` and `comments`.
@@ -186,40 +201,43 @@ def create_request(reqtype_id: int, user: User, pkgbase: PackageBase,
"""
now = time.utcnow()
with db.begin():
- pkgreq = db.create(PackageRequest, ReqTypeID=reqtype_id,
- User=user, PackageBase=pkgbase,
- PackageBaseName=pkgbase.Name,
- RequestTS=now,
- Comments=comments,
- ClosureComment=str())
+ pkgreq = db.create(
+ PackageRequest,
+ ReqTypeID=reqtype_id,
+ User=user,
+ PackageBase=pkgbase,
+ PackageBaseName=pkgbase.Name,
+ RequestTS=now,
+ Comments=comments,
+ ClosureComment=str(),
+ )
return pkgreq
@pytest.fixture
def pkgreq(user: User, pkgbase: PackageBase):
- """ Yield a package request. """
+ """Yield a package request."""
pkgreq = create_request(DELETION_ID, user, pkgbase, "Test request.")
yield pkgreq
def create_notification(user: User, pkgbase: PackageBase):
- """ Create a notification for a `user` on `pkgbase`. """
+ """Create a notification for a `user` on `pkgbase`."""
with db.begin():
notif = db.create(PackageNotification, User=user, PackageBase=pkgbase)
return notif
def test_request(client: TestClient, auser: User, pkgbase: PackageBase):
- """ Test the standard pkgbase request route GET method. """
+ """Test the standard pkgbase request route GET method."""
endpoint = f"/pkgbase/{pkgbase.Name}/request"
with client as request:
resp = request.get(endpoint, cookies=auser.cookies)
assert resp.status_code == int(HTTPStatus.OK)
-def test_request_post_deletion(client: TestClient, auser2: User,
- pkgbase: PackageBase):
- """ Test the POST route for creating a deletion request works. """
+def test_request_post_deletion(client: TestClient, auser2: User, pkgbase: PackageBase):
+ """Test the POST route for creating a deletion request works."""
endpoint = f"/pkgbase/{pkgbase.Name}/request"
data = {"comments": "Test request.", "type": "deletion"}
with client as request:
@@ -238,9 +256,10 @@ def test_request_post_deletion(client: TestClient, auser2: User,
assert re.match(expr, email.headers.get("Subject"))
-def test_request_post_deletion_as_maintainer(client: TestClient, auser: User,
- pkgbase: PackageBase):
- """ Test the POST route for creating a deletion request as maint works. """
+def test_request_post_deletion_as_maintainer(
+ client: TestClient, auser: User, pkgbase: PackageBase
+):
+ """Test the POST route for creating a deletion request as maint works."""
endpoint = f"/pkgbase/{pkgbase.Name}/request"
data = {"comments": "Test request.", "type": "deletion"}
with client as request:
@@ -267,10 +286,13 @@ def test_request_post_deletion_as_maintainer(client: TestClient, auser: User,
assert re.match(expr, email.headers.get("Subject"))
-def test_request_post_deletion_autoaccept(client: TestClient, auser: User,
- pkgbase: PackageBase,
- caplog: pytest.LogCaptureFixture):
- """ Test the request route for deletion as maintainer. """
+def test_request_post_deletion_autoaccept(
+ client: TestClient,
+ auser: User,
+ pkgbase: PackageBase,
+ caplog: pytest.LogCaptureFixture,
+):
+ """Test the request route for deletion as maintainer."""
caplog.set_level(DEBUG)
now = time.utcnow()
@@ -284,9 +306,11 @@ def test_request_post_deletion_autoaccept(client: TestClient, auser: User,
resp = request.post(endpoint, data=data, cookies=auser.cookies)
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
- pkgreq = db.query(PackageRequest).filter(
- PackageRequest.PackageBaseName == pkgbase.Name
- ).first()
+ pkgreq = (
+ db.query(PackageRequest)
+ .filter(PackageRequest.PackageBaseName == pkgbase.Name)
+ .first()
+ )
assert pkgreq is not None
assert pkgreq.ReqTypeID == DELETION_ID
assert pkgreq.Status == ACCEPTED_ID
@@ -310,9 +334,10 @@ def test_request_post_deletion_autoaccept(client: TestClient, auser: User,
assert re.search(expr, caplog.text)
-def test_request_post_merge(client: TestClient, auser: User,
- pkgbase: PackageBase, target: PackageBase):
- """ Test the request route for merge as maintainer. """
+def test_request_post_merge(
+ client: TestClient, auser: User, pkgbase: PackageBase, target: PackageBase
+):
+ """Test the request route for merge as maintainer."""
endpoint = f"/pkgbase/{pkgbase.Name}/request"
data = {
"type": "merge",
@@ -336,9 +361,8 @@ def test_request_post_merge(client: TestClient, auser: User,
assert re.match(expr, email.headers.get("Subject"))
-def test_request_post_orphan(client: TestClient, auser: User,
- pkgbase: PackageBase):
- """ Test the POST route for creating an orphan request works. """
+def test_request_post_orphan(client: TestClient, auser: User, pkgbase: PackageBase):
+ """Test the POST route for creating an orphan request works."""
endpoint = f"/pkgbase/{pkgbase.Name}/request"
data = {
"type": "orphan",
@@ -361,9 +385,14 @@ def test_request_post_orphan(client: TestClient, auser: User,
assert re.match(expr, email.headers.get("Subject"))
-def test_deletion_request(client: TestClient, user: User, tu_user: User,
- pkgbase: PackageBase, pkgreq: PackageRequest):
- """ Test deleting a package with a preexisting request. """
+def test_deletion_request(
+ client: TestClient,
+ user: User,
+ tu_user: User,
+ pkgbase: PackageBase,
+ pkgreq: PackageRequest,
+):
+ """Test deleting a package with a preexisting request."""
# `pkgreq`.ReqTypeID is already DELETION_ID.
create_request(DELETION_ID, user, pkgbase, "Other request.")
@@ -402,9 +431,8 @@ def test_deletion_request(client: TestClient, user: User, tu_user: User,
assert body in email.body
-def test_deletion_autorequest(client: TestClient, tu_user: User,
- pkgbase: PackageBase):
- """ Test deleting a package without a request. """
+def test_deletion_autorequest(client: TestClient, tu_user: User, pkgbase: PackageBase):
+ """Test deleting a package without a request."""
# `pkgreq`.ReqTypeID is already DELETION_ID.
endpoint = f"/pkgbase/{pkgbase.Name}/delete"
data = {"confirm": True}
@@ -421,10 +449,15 @@ def test_deletion_autorequest(client: TestClient, tu_user: User,
assert "[Autogenerated]" in email.body
-def test_merge_request(client: TestClient, user: User, tu_user: User,
- pkgbase: PackageBase, target: PackageBase,
- pkgreq: PackageRequest):
- """ Test merging a package with a pre - existing request. """
+def test_merge_request(
+ client: TestClient,
+ user: User,
+ tu_user: User,
+ pkgbase: PackageBase,
+ target: PackageBase,
+ pkgreq: PackageRequest,
+):
+ """Test merging a package with a pre - existing request."""
with db.begin():
pkgreq.ReqTypeID = MERGE_ID
pkgreq.MergeBaseName = target.Name
@@ -473,9 +506,14 @@ def test_merge_request(client: TestClient, user: User, tu_user: User,
assert "[Autogenerated]" in rejected.body
-def test_merge_autorequest(client: TestClient, user: User, tu_user: User,
- pkgbase: PackageBase, target: PackageBase):
- """ Test merging a package without a request. """
+def test_merge_autorequest(
+ client: TestClient,
+ user: User,
+ tu_user: User,
+ pkgbase: PackageBase,
+ target: PackageBase,
+):
+ """Test merging a package without a request."""
with db.begin():
pkgreq.ReqTypeID = MERGE_ID
pkgreq.MergeBaseName = target.Name
@@ -498,13 +536,17 @@ def test_merge_autorequest(client: TestClient, user: User, tu_user: User,
assert "[Autogenerated]" in email.body
-def test_orphan_request(client: TestClient, user: User, tu_user: User,
- pkgbase: PackageBase, pkgreq: PackageRequest):
- """ Test the standard orphan request route. """
+def test_orphan_request(
+ client: TestClient,
+ user: User,
+ tu_user: User,
+ pkgbase: PackageBase,
+ pkgreq: PackageRequest,
+):
+ """Test the standard orphan request route."""
user2 = create_user("user2", "user2@example.org")
with db.begin():
- db.create(PackageComaintainer, User=user2,
- PackageBase=pkgbase, Priority=1)
+ db.create(PackageComaintainer, User=user2, PackageBase=pkgbase, Priority=1)
idle_time = config.getint("options", "request_idle_time")
now = time.utcnow()
@@ -537,10 +579,9 @@ def test_orphan_request(client: TestClient, user: User, tu_user: User,
assert re.match(subj, email.headers.get("Subject"))
-def test_request_post_orphan_autogenerated_closure(client: TestClient,
- tu_user: User,
- pkgbase: PackageBase,
- pkgreq: PackageRequest):
+def test_request_post_orphan_autogenerated_closure(
+ client: TestClient, tu_user: User, pkgbase: PackageBase, pkgreq: PackageRequest
+):
idle_time = config.getint("options", "request_idle_time")
now = time.utcnow()
with db.begin():
@@ -564,10 +605,13 @@ def test_request_post_orphan_autogenerated_closure(client: TestClient,
assert re.search(expr, email.body)
-def test_request_post_orphan_autoaccept(client: TestClient, auser: User,
- pkgbase: PackageBase,
- caplog: pytest.LogCaptureFixture):
- """ Test the standard pkgbase request route GET method. """
+def test_request_post_orphan_autoaccept(
+ client: TestClient,
+ auser: User,
+ pkgbase: PackageBase,
+ caplog: pytest.LogCaptureFixture,
+):
+ """Test the standard pkgbase request route GET method."""
caplog.set_level(DEBUG)
now = time.utcnow()
auto_orphan_age = config.getint("options", "auto_orphan_age")
@@ -605,8 +649,7 @@ def test_request_post_orphan_autoaccept(client: TestClient, auser: User,
assert re.search(expr, caplog.text)
-def test_orphan_as_maintainer(client: TestClient, auser: User,
- pkgbase: PackageBase):
+def test_orphan_as_maintainer(client: TestClient, auser: User, pkgbase: PackageBase):
endpoint = f"/pkgbase/{pkgbase.Name}/disown"
data = {"confirm": True}
with client as request:
@@ -620,9 +663,10 @@ def test_orphan_as_maintainer(client: TestClient, auser: User,
assert pkgbase.Maintainer is None
-def test_orphan_without_requests(client: TestClient, tu_user: User,
- pkgbase: PackageBase):
- """ Test orphans are automatically accepted past a certain date. """
+def test_orphan_without_requests(
+ client: TestClient, tu_user: User, pkgbase: PackageBase
+):
+ """Test orphans are automatically accepted past a certain date."""
endpoint = f"/pkgbase/{pkgbase.Name}/disown"
data = {"confirm": True}
with client as request:
@@ -637,7 +681,7 @@ def test_orphan_without_requests(client: TestClient, tu_user: User,
def test_closure_factory_invalid_reqtype_id():
- """ Test providing an invalid reqtype_id raises NotImplementedError. """
+ """Test providing an invalid reqtype_id raises NotImplementedError."""
automated = ClosureFactory()
match = r"^Unsupported '.+' value\.$"
with pytest.raises(NotImplementedError, match=match):
@@ -657,19 +701,25 @@ def test_requests_unauthorized(client: TestClient):
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
-def test_requests(client: TestClient,
- tu_user: User,
- packages: list[Package],
- requests: list[PackageRequest]):
+def test_requests(
+ client: TestClient,
+ tu_user: User,
+ packages: list[Package],
+ requests: list[PackageRequest],
+):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
- resp = request.get("/requests", params={
- # Pass in url query parameters O, SeB and SB to exercise
- # their paths inside of the pager_nav used in this request.
- "O": 0, # Page 1
- "SeB": "nd",
- "SB": "n"
- }, cookies=cookies)
+ resp = request.get(
+ "/requests",
+ params={
+ # Pass in url query parameters O, SeB and SB to exercise
+ # their paths inside of the pager_nav used in this request.
+ "O": 0, # Page 1
+ "SeB": "nd",
+ "SB": "n",
+ },
+ cookies=cookies,
+ )
assert resp.status_code == int(HTTPStatus.OK)
assert "Next ›" in resp.text
@@ -682,9 +732,7 @@ def test_requests(client: TestClient,
# Request page 2 of the requests page.
with client as request:
- resp = request.get("/requests", params={
- "O": 50 # Page 2
- }, cookies=cookies)
+ resp = request.get("/requests", params={"O": 50}, cookies=cookies) # Page 2
assert resp.status_code == int(HTTPStatus.OK)
assert "‹ Previous" in resp.text
@@ -695,8 +743,9 @@ def test_requests(client: TestClient,
assert len(rows) == 5 # There are five records left on the second page.
-def test_requests_selfmade(client: TestClient, user: User,
- requests: list[PackageRequest]):
+def test_requests_selfmade(
+ client: TestClient, user: User, requests: list[PackageRequest]
+):
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
resp = request.get("/requests", cookies=cookies)
@@ -710,46 +759,52 @@ def test_requests_selfmade(client: TestClient, user: User,
# Our first and only link in the last row should be "Close".
for row in rows:
- last_row = row.xpath('./td')[-1].xpath('./a')[0]
+ last_row = row.xpath("./td")[-1].xpath("./a")[0]
assert last_row.text.strip() == "Close"
-def test_requests_close(client: TestClient, user: User,
- pkgreq: PackageRequest):
+def test_requests_close(client: TestClient, user: User, pkgreq: PackageRequest):
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- resp = request.get(f"/requests/{pkgreq.ID}/close", cookies=cookies,
- allow_redirects=False)
+ resp = request.get(
+ f"/requests/{pkgreq.ID}/close", cookies=cookies, allow_redirects=False
+ )
assert resp.status_code == int(HTTPStatus.OK)
-def test_requests_close_unauthorized(client: TestClient, maintainer: User,
- pkgreq: PackageRequest):
+def test_requests_close_unauthorized(
+ client: TestClient, maintainer: User, pkgreq: PackageRequest
+):
cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
with client as request:
- resp = request.get(f"/requests/{pkgreq.ID}/close", cookies=cookies,
- allow_redirects=False)
+ resp = request.get(
+ f"/requests/{pkgreq.ID}/close", cookies=cookies, allow_redirects=False
+ )
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
assert resp.headers.get("location") == "/"
-def test_requests_close_post_unauthorized(client: TestClient, maintainer: User,
- pkgreq: PackageRequest):
+def test_requests_close_post_unauthorized(
+ client: TestClient, maintainer: User, pkgreq: PackageRequest
+):
cookies = {"AURSID": maintainer.login(Request(), "testPassword")}
with client as request:
- resp = request.post(f"/requests/{pkgreq.ID}/close", data={
- "reason": ACCEPTED_ID
- }, cookies=cookies, allow_redirects=False)
+ resp = request.post(
+ f"/requests/{pkgreq.ID}/close",
+ data={"reason": ACCEPTED_ID},
+ cookies=cookies,
+ allow_redirects=False,
+ )
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
assert resp.headers.get("location") == "/"
-def test_requests_close_post(client: TestClient, user: User,
- pkgreq: PackageRequest):
+def test_requests_close_post(client: TestClient, user: User, pkgreq: PackageRequest):
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- resp = request.post(f"/requests/{pkgreq.ID}/close",
- cookies=cookies, allow_redirects=False)
+ resp = request.post(
+ f"/requests/{pkgreq.ID}/close", cookies=cookies, allow_redirects=False
+ )
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
assert pkgreq.Status == REJECTED_ID
@@ -757,12 +812,14 @@ def test_requests_close_post(client: TestClient, user: User,
assert pkgreq.ClosureComment == str()
-def test_requests_close_post_rejected(client: TestClient, user: User,
- pkgreq: PackageRequest):
+def test_requests_close_post_rejected(
+ client: TestClient, user: User, pkgreq: PackageRequest
+):
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- resp = request.post(f"/requests/{pkgreq.ID}/close",
- cookies=cookies, allow_redirects=False)
+ resp = request.post(
+ f"/requests/{pkgreq.ID}/close", cookies=cookies, allow_redirects=False
+ )
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
assert pkgreq.Status == REJECTED_ID
diff --git a/test/test_routes.py b/test/test_routes.py
index 85d30c02..78b0a65b 100644
--- a/test/test_routes.py
+++ b/test/test_routes.py
@@ -1,11 +1,9 @@
import re
import urllib.parse
-
from http import HTTPStatus
import lxml.etree
import pytest
-
from fastapi.testclient import TestClient
from aurweb import db
@@ -28,21 +26,26 @@ def client() -> TestClient:
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- RealName="Test User", Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
def test_index(client: TestClient):
- """ Test the index route at '/'. """
+ """Test the index route at '/'."""
with client as req:
response = req.get("/")
assert response.status_code == int(HTTPStatus.OK)
def test_index_security_headers(client: TestClient):
- """ Check for the existence of CSP, XCTO, XFO and RP security headers.
+ """Check for the existence of CSP, XCTO, XFO and RP security headers.
CSP: Content-Security-Policy
XCTO: X-Content-Type-Options
@@ -60,7 +63,7 @@ def test_index_security_headers(client: TestClient):
def test_favicon(client: TestClient):
- """ Test the favicon route at '/favicon.ico'. """
+ """Test the favicon route at '/favicon.ico'."""
with client as request:
response1 = request.get("/static/images/favicon.ico")
response2 = request.get("/favicon.ico")
@@ -69,52 +72,38 @@ def test_favicon(client: TestClient):
def test_language(client: TestClient):
- """ Test the language post route as a guest user. """
- post_data = {
- "set_lang": "de",
- "next": "/"
- }
+ """Test the language post route as a guest user."""
+ post_data = {"set_lang": "de", "next": "/"}
with client as req:
response = req.post("/language", data=post_data)
assert response.status_code == int(HTTPStatus.SEE_OTHER)
def test_language_invalid_next(client: TestClient):
- """ Test an invalid next route at '/language'. """
- post_data = {
- "set_lang": "de",
- "next": "https://evil.net"
- }
+ """Test an invalid next route at '/language'."""
+ post_data = {"set_lang": "de", "next": "https://evil.net"}
with client as req:
response = req.post("/language", data=post_data)
assert response.status_code == int(HTTPStatus.BAD_REQUEST)
def test_user_language(client: TestClient, user: User):
- """ Test the language post route as an authenticated user. """
- post_data = {
- "set_lang": "de",
- "next": "/"
- }
+ """Test the language post route as an authenticated user."""
+ post_data = {"set_lang": "de", "next": "/"}
sid = user.login(Request(), "testPassword")
assert sid is not None
with client as req:
- response = req.post("/language", data=post_data,
- cookies={"AURSID": sid})
+ response = req.post("/language", data=post_data, cookies={"AURSID": sid})
assert response.status_code == int(HTTPStatus.SEE_OTHER)
assert user.LangPreference == "de"
def test_language_query_params(client: TestClient):
- """ Test the language post route with query params. """
+ """Test the language post route with query params."""
next = urllib.parse.quote_plus("/")
- post_data = {
- "set_lang": "de",
- "next": "/",
- "q": f"next={next}"
- }
+ post_data = {"set_lang": "de", "next": "/", "q": f"next={next}"}
q = post_data.get("q")
with client as req:
response = req.post("/language", data=post_data)
@@ -154,9 +143,13 @@ def test_nonce_csp(client: TestClient):
def test_id_redirect(client: TestClient):
with client as request:
- response = request.get("/", params={
- "id": "test", # This param will be rewritten into Location.
- "key": "value", # Test that this param persists.
- "key2": "value2" # And this one.
- }, allow_redirects=False)
+ response = request.get(
+ "/",
+ params={
+ "id": "test", # This param will be rewritten into Location.
+ "key": "value", # Test that this param persists.
+ "key2": "value2", # And this one.
+ },
+ allow_redirects=False,
+ )
assert response.headers.get("location") == "/test?key=value&key2=value2"
diff --git a/test/test_rpc.py b/test/test_rpc.py
index c0861d3d..ed7e8894 100644
--- a/test/test_rpc.py
+++ b/test/test_rpc.py
@@ -1,17 +1,14 @@
import re
-
from http import HTTPStatus
from unittest import mock
import orjson
import pytest
-
from fastapi.testclient import TestClient
from redis.client import Pipeline
import aurweb.models.dependency_type as dt
import aurweb.models.relation_type as rt
-
from aurweb import asgi, config, db, rpc, scripts, time
from aurweb.models.account_type import USER_ID
from aurweb.models.dependency_type import DEPENDS_ID
@@ -36,27 +33,42 @@ def client() -> TestClient:
@pytest.fixture
def user(db_test) -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- RealName="Test User 1", Passwd=str(),
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User 1",
+ Passwd=str(),
+ AccountTypeID=USER_ID,
+ )
yield user
@pytest.fixture
def user2() -> User:
with db.begin():
- user = db.create(User, Username="user2", Email="user2@example.org",
- RealName="Test User 2", Passwd=str(),
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="user2",
+ Email="user2@example.org",
+ RealName="Test User 2",
+ Passwd=str(),
+ AccountTypeID=USER_ID,
+ )
yield user
@pytest.fixture
def user3() -> User:
with db.begin():
- user = db.create(User, Username="user3", Email="user3@example.org",
- RealName="Test User 3", Passwd=str(),
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="user3",
+ Email="user3@example.org",
+ RealName="Test User 3",
+ Passwd=str(),
+ AccountTypeID=USER_ID,
+ )
yield user
@@ -66,39 +78,64 @@ def packages(user: User, user2: User, user3: User) -> list[Package]:
# Create package records used in our tests.
with db.begin():
- pkgbase = db.create(PackageBase, Name="big-chungus",
- Maintainer=user, Packager=user)
- pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name,
- Description="Bunny bunny around bunny",
- URL="https://example.com/")
+ pkgbase = db.create(
+ PackageBase, Name="big-chungus", Maintainer=user, Packager=user
+ )
+ pkg = db.create(
+ Package,
+ PackageBase=pkgbase,
+ Name=pkgbase.Name,
+ Description="Bunny bunny around bunny",
+ URL="https://example.com/",
+ )
output.append(pkg)
- pkgbase = db.create(PackageBase, Name="chungy-chungus",
- Maintainer=user, Packager=user)
- pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name,
- Description="Wubby wubby on wobba wuubu",
- URL="https://example.com/")
+ pkgbase = db.create(
+ PackageBase, Name="chungy-chungus", Maintainer=user, Packager=user
+ )
+ pkg = db.create(
+ Package,
+ PackageBase=pkgbase,
+ Name=pkgbase.Name,
+ Description="Wubby wubby on wobba wuubu",
+ URL="https://example.com/",
+ )
output.append(pkg)
- pkgbase = db.create(PackageBase, Name="gluggly-chungus",
- Maintainer=user, Packager=user)
- pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name,
- Description="glurrba glurrba gur globba",
- URL="https://example.com/")
+ pkgbase = db.create(
+ PackageBase, Name="gluggly-chungus", Maintainer=user, Packager=user
+ )
+ pkg = db.create(
+ Package,
+ PackageBase=pkgbase,
+ Name=pkgbase.Name,
+ Description="glurrba glurrba gur globba",
+ URL="https://example.com/",
+ )
output.append(pkg)
- pkgbase = db.create(PackageBase, Name="fugly-chungus",
- Maintainer=user, Packager=user)
+ pkgbase = db.create(
+ PackageBase, Name="fugly-chungus", Maintainer=user, Packager=user
+ )
desc = "A Package belonging to a PackageBase with another name."
- pkg = db.create(Package, PackageBase=pkgbase, Name="other-pkg",
- Description=desc, URL="https://example.com")
+ pkg = db.create(
+ Package,
+ PackageBase=pkgbase,
+ Name="other-pkg",
+ Description=desc,
+ URL="https://example.com",
+ )
output.append(pkg)
pkgbase = db.create(PackageBase, Name="woogly-chungus")
- pkg = db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name,
- Description="wuggla woblabeloop shemashmoop",
- URL="https://example.com/")
+ pkg = db.create(
+ Package,
+ PackageBase=pkgbase,
+ Name=pkgbase.Name,
+ Description="wuggla woblabeloop shemashmoop",
+ URL="https://example.com/",
+ )
output.append(pkg)
# Setup a few more related records on the first package:
@@ -108,14 +145,15 @@ def packages(user: User, user2: User, user3: User) -> list[Package]:
db.create(PackageLicense, Package=output[0], License=lic)
for keyword in ["big-chungus", "smol-chungus", "sizeable-chungus"]:
- db.create(PackageKeyword,
- PackageBase=output[0].PackageBase,
- Keyword=keyword)
+ db.create(
+ PackageKeyword, PackageBase=output[0].PackageBase, Keyword=keyword
+ )
now = time.utcnow()
for user_ in [user, user2, user3]:
- db.create(PackageVote, User=user_,
- PackageBase=output[0].PackageBase, VoteTS=now)
+ db.create(
+ PackageVote, User=user_, PackageBase=output[0].PackageBase, VoteTS=now
+ )
scripts.popupdate.run_single(output[0].PackageBase)
yield output
@@ -126,35 +164,45 @@ def depends(packages: list[Package]) -> list[PackageDependency]:
output = []
with db.begin():
- dep = db.create(PackageDependency,
- Package=packages[0],
- DepTypeID=dt.DEPENDS_ID,
- DepName="chungus-depends")
+ dep = db.create(
+ PackageDependency,
+ Package=packages[0],
+ DepTypeID=dt.DEPENDS_ID,
+ DepName="chungus-depends",
+ )
output.append(dep)
- dep = db.create(PackageDependency,
- Package=packages[1],
- DepTypeID=dt.DEPENDS_ID,
- DepName="chungy-depends")
+ dep = db.create(
+ PackageDependency,
+ Package=packages[1],
+ DepTypeID=dt.DEPENDS_ID,
+ DepName="chungy-depends",
+ )
output.append(dep)
- dep = db.create(PackageDependency,
- Package=packages[0],
- DepTypeID=dt.OPTDEPENDS_ID,
- DepName="chungus-optdepends",
- DepCondition="=50")
+ dep = db.create(
+ PackageDependency,
+ Package=packages[0],
+ DepTypeID=dt.OPTDEPENDS_ID,
+ DepName="chungus-optdepends",
+ DepCondition="=50",
+ )
output.append(dep)
- dep = db.create(PackageDependency,
- Package=packages[0],
- DepTypeID=dt.MAKEDEPENDS_ID,
- DepName="chungus-makedepends")
+ dep = db.create(
+ PackageDependency,
+ Package=packages[0],
+ DepTypeID=dt.MAKEDEPENDS_ID,
+ DepName="chungus-makedepends",
+ )
output.append(dep)
- dep = db.create(PackageDependency,
- Package=packages[0],
- DepTypeID=dt.CHECKDEPENDS_ID,
- DepName="chungus-checkdepends")
+ dep = db.create(
+ PackageDependency,
+ Package=packages[0],
+ DepTypeID=dt.CHECKDEPENDS_ID,
+ DepName="chungus-checkdepends",
+ )
output.append(dep)
yield output
@@ -165,30 +213,38 @@ def relations(user: User, packages: list[Package]) -> list[PackageRelation]:
output = []
with db.begin():
- rel = db.create(PackageRelation,
- Package=packages[0],
- RelTypeID=rt.CONFLICTS_ID,
- RelName="chungus-conflicts")
+ rel = db.create(
+ PackageRelation,
+ Package=packages[0],
+ RelTypeID=rt.CONFLICTS_ID,
+ RelName="chungus-conflicts",
+ )
output.append(rel)
- rel = db.create(PackageRelation,
- Package=packages[1],
- RelTypeID=rt.CONFLICTS_ID,
- RelName="chungy-conflicts")
+ rel = db.create(
+ PackageRelation,
+ Package=packages[1],
+ RelTypeID=rt.CONFLICTS_ID,
+ RelName="chungy-conflicts",
+ )
output.append(rel)
- rel = db.create(PackageRelation,
- Package=packages[0],
- RelTypeID=rt.PROVIDES_ID,
- RelName="chungus-provides",
- RelCondition="<=200")
+ rel = db.create(
+ PackageRelation,
+ Package=packages[0],
+ RelTypeID=rt.PROVIDES_ID,
+ RelName="chungus-provides",
+ RelCondition="<=200",
+ )
output.append(rel)
- rel = db.create(PackageRelation,
- Package=packages[0],
- RelTypeID=rt.REPLACES_ID,
- RelName="chungus-replaces",
- RelCondition="<=200")
+ rel = db.create(
+ PackageRelation,
+ Package=packages[0],
+ RelTypeID=rt.REPLACES_ID,
+ RelName="chungus-replaces",
+ RelCondition="<=200",
+ )
output.append(rel)
# Finally, yield the packages.
@@ -238,51 +294,54 @@ def test_rpc_documentation_missing():
config.rehash()
-def test_rpc_singular_info(client: TestClient,
- user: User,
- packages: list[Package],
- depends: list[PackageDependency],
- relations: list[PackageRelation]):
+def test_rpc_singular_info(
+ client: TestClient,
+ user: User,
+ packages: list[Package],
+ depends: list[PackageDependency],
+ relations: list[PackageRelation],
+):
# Define expected response.
pkg = packages[0]
expected_data = {
"version": 5,
- "results": [{
- "Name": pkg.Name,
- "Version": pkg.Version,
- "Description": pkg.Description,
- "URL": pkg.URL,
- "PackageBase": pkg.PackageBase.Name,
- "NumVotes": pkg.PackageBase.NumVotes,
- "Popularity": float(pkg.PackageBase.Popularity),
- "OutOfDate": None,
- "Maintainer": user.Username,
- "URLPath": f"/cgit/aur.git/snapshot/{pkg.Name}.tar.gz",
- "Depends": ["chungus-depends"],
- "OptDepends": ["chungus-optdepends=50"],
- "MakeDepends": ["chungus-makedepends"],
- "CheckDepends": ["chungus-checkdepends"],
- "Conflicts": ["chungus-conflicts"],
- "Provides": ["chungus-provides<=200"],
- "Replaces": ["chungus-replaces<=200"],
- "License": [pkg.package_licenses.first().License.Name],
- "Keywords": [
- "big-chungus",
- "sizeable-chungus",
- "smol-chungus"
- ]
- }],
+ "results": [
+ {
+ "Name": pkg.Name,
+ "Version": pkg.Version,
+ "Description": pkg.Description,
+ "URL": pkg.URL,
+ "PackageBase": pkg.PackageBase.Name,
+ "NumVotes": pkg.PackageBase.NumVotes,
+ "Popularity": float(pkg.PackageBase.Popularity),
+ "OutOfDate": None,
+ "Maintainer": user.Username,
+ "URLPath": f"/cgit/aur.git/snapshot/{pkg.Name}.tar.gz",
+ "Depends": ["chungus-depends"],
+ "OptDepends": ["chungus-optdepends=50"],
+ "MakeDepends": ["chungus-makedepends"],
+ "CheckDepends": ["chungus-checkdepends"],
+ "Conflicts": ["chungus-conflicts"],
+ "Provides": ["chungus-provides<=200"],
+ "Replaces": ["chungus-replaces<=200"],
+ "License": [pkg.package_licenses.first().License.Name],
+ "Keywords": ["big-chungus", "sizeable-chungus", "smol-chungus"],
+ }
+ ],
"resultcount": 1,
- "type": "multiinfo"
+ "type": "multiinfo",
}
# Make dummy request.
with client as request:
- resp = request.get("/rpc", params={
- "v": 5,
- "type": "info",
- "arg": ["chungy-chungus", "big-chungus"],
- })
+ resp = request.get(
+ "/rpc",
+ params={
+ "v": 5,
+ "type": "info",
+ "arg": ["chungy-chungus", "big-chungus"],
+ },
+ )
# Load request response into Python dictionary.
response_data = orjson.loads(resp.text)
@@ -299,19 +358,21 @@ def test_rpc_singular_info(client: TestClient,
def test_rpc_split_package_urlpath(client: TestClient, user: User):
with db.begin():
- pkgbase = db.create(PackageBase, Name="pkg",
- Maintainer=user, Packager=user)
+ pkgbase = db.create(PackageBase, Name="pkg", Maintainer=user, Packager=user)
pkgs = [
db.create(Package, PackageBase=pkgbase, Name="pkg_1"),
db.create(Package, PackageBase=pkgbase, Name="pkg_2"),
]
with client as request:
- response = request.get("/rpc", params={
- "v": 5,
- "type": "info",
- "arg": [pkgs[0].Name],
- })
+ response = request.get(
+ "/rpc",
+ params={
+ "v": 5,
+ "type": "info",
+ "arg": [pkgs[0].Name],
+ },
+ )
data = orjson.loads(response.text)
snapshot_uri = config.get("options", "snapshot_uri")
@@ -335,9 +396,9 @@ def test_rpc_multiinfo(client: TestClient, packages: list[Package]):
# Make dummy request.
request_packages = ["big-chungus", "chungy-chungus"]
with client as request:
- response = request.get("/rpc", params={
- "v": 5, "type": "info", "arg[]": request_packages
- })
+ response = request.get(
+ "/rpc", params={"v": 5, "type": "info", "arg[]": request_packages}
+ )
# Load request response into Python dictionary.
response_data = orjson.loads(response.content.decode())
@@ -357,13 +418,15 @@ def test_rpc_mixedargs(client: TestClient, packages: list[Package]):
with client as request:
# Supply all of the args in the url to enforce ordering.
response1 = request.get(
- "/rpc?v=5&arg[]=big-chungus&arg=gluggly-chungus&type=info")
+ "/rpc?v=5&arg[]=big-chungus&arg=gluggly-chungus&type=info"
+ )
assert response1.status_code == int(HTTPStatus.OK)
with client as request:
response2 = request.get(
"/rpc?v=5&arg=big-chungus&arg[]=gluggly-chungus"
- "&type=info&arg[]=chungy-chungus")
+ "&type=info&arg[]=chungy-chungus"
+ )
assert response1.status_code == int(HTTPStatus.OK)
# Load request response into Python dictionary.
@@ -381,42 +444,47 @@ def test_rpc_mixedargs(client: TestClient, packages: list[Package]):
assert i == []
-def test_rpc_no_dependencies_omits_key(client: TestClient, user: User,
- packages: list[Package],
- depends: list[PackageDependency],
- relations: list[PackageRelation]):
+def test_rpc_no_dependencies_omits_key(
+ client: TestClient,
+ user: User,
+ packages: list[Package],
+ depends: list[PackageDependency],
+ relations: list[PackageRelation],
+):
"""
This makes sure things like 'MakeDepends' get removed from JSON strings
when they don't have set values.
"""
pkg = packages[1]
expected_response = {
- 'version': 5,
- 'results': [{
- 'Name': pkg.Name,
- 'Version': pkg.Version,
- 'Description': pkg.Description,
- 'URL': pkg.URL,
- 'PackageBase': pkg.PackageBase.Name,
- 'NumVotes': pkg.PackageBase.NumVotes,
- 'Popularity': int(pkg.PackageBase.Popularity),
- 'OutOfDate': None,
- 'Maintainer': user.Username,
- 'URLPath': '/cgit/aur.git/snapshot/chungy-chungus.tar.gz',
- 'Depends': ['chungy-depends'],
- 'Conflicts': ['chungy-conflicts'],
- 'License': [],
- 'Keywords': []
- }],
- 'resultcount': 1,
- 'type': 'multiinfo'
+ "version": 5,
+ "results": [
+ {
+ "Name": pkg.Name,
+ "Version": pkg.Version,
+ "Description": pkg.Description,
+ "URL": pkg.URL,
+ "PackageBase": pkg.PackageBase.Name,
+ "NumVotes": pkg.PackageBase.NumVotes,
+ "Popularity": int(pkg.PackageBase.Popularity),
+ "OutOfDate": None,
+ "Maintainer": user.Username,
+ "URLPath": "/cgit/aur.git/snapshot/chungy-chungus.tar.gz",
+ "Depends": ["chungy-depends"],
+ "Conflicts": ["chungy-conflicts"],
+ "License": [],
+ "Keywords": [],
+ }
+ ],
+ "resultcount": 1,
+ "type": "multiinfo",
}
# Make dummy request.
with client as request:
- response = request.get("/rpc", params={
- "v": 5, "type": "info", "arg": "chungy-chungus"
- })
+ response = request.get(
+ "/rpc", params={"v": 5, "type": "info", "arg": "chungy-chungus"}
+ )
response_data = orjson.loads(response.content.decode())
# Remove inconsistent keys.
@@ -429,18 +497,18 @@ def test_rpc_no_dependencies_omits_key(client: TestClient, user: User,
def test_rpc_bad_type(client: TestClient):
# Define expected response.
expected_data = {
- 'version': 5,
- 'results': [],
- 'resultcount': 0,
- 'type': 'error',
- 'error': 'Incorrect request type specified.'
+ "version": 5,
+ "results": [],
+ "resultcount": 0,
+ "type": "error",
+ "error": "Incorrect request type specified.",
}
# Make dummy request.
with client as request:
- response = request.get("/rpc", params={
- "v": 5, "type": "invalid-type", "arg": "big-chungus"
- })
+ response = request.get(
+ "/rpc", params={"v": 5, "type": "invalid-type", "arg": "big-chungus"}
+ )
# Load request response into Python dictionary.
response_data = orjson.loads(response.content.decode())
@@ -452,18 +520,18 @@ def test_rpc_bad_type(client: TestClient):
def test_rpc_bad_version(client: TestClient):
# Define expected response.
expected_data = {
- 'version': 0,
- 'resultcount': 0,
- 'results': [],
- 'type': 'error',
- 'error': 'Invalid version specified.'
+ "version": 0,
+ "resultcount": 0,
+ "results": [],
+ "type": "error",
+ "error": "Invalid version specified.",
}
# Make dummy request.
with client as request:
- response = request.get("/rpc", params={
- "v": 0, "type": "info", "arg": "big-chungus"
- })
+ response = request.get(
+ "/rpc", params={"v": 0, "type": "info", "arg": "big-chungus"}
+ )
# Load request response into Python dictionary.
response_data = orjson.loads(response.content.decode())
@@ -475,19 +543,16 @@ def test_rpc_bad_version(client: TestClient):
def test_rpc_no_version(client: TestClient):
# Define expected response.
expected_data = {
- 'version': None,
- 'resultcount': 0,
- 'results': [],
- 'type': 'error',
- 'error': 'Please specify an API version.'
+ "version": None,
+ "resultcount": 0,
+ "results": [],
+ "type": "error",
+ "error": "Please specify an API version.",
}
# Make dummy request.
with client as request:
- response = request.get("/rpc", params={
- "type": "info",
- "arg": "big-chungus"
- })
+ response = request.get("/rpc", params={"type": "info", "arg": "big-chungus"})
# Load request response into Python dictionary.
response_data = orjson.loads(response.content.decode())
@@ -499,11 +564,11 @@ def test_rpc_no_version(client: TestClient):
def test_rpc_no_type(client: TestClient):
# Define expected response.
expected_data = {
- 'version': 5,
- 'results': [],
- 'resultcount': 0,
- 'type': 'error',
- 'error': 'No request type/data specified.'
+ "version": 5,
+ "results": [],
+ "resultcount": 0,
+ "type": "error",
+ "error": "No request type/data specified.",
}
# Make dummy request.
@@ -520,11 +585,11 @@ def test_rpc_no_type(client: TestClient):
def test_rpc_no_args(client: TestClient):
# Define expected response.
expected_data = {
- 'version': 5,
- 'results': [],
- 'resultcount': 0,
- 'type': 'error',
- 'error': 'No request type/data specified.'
+ "version": 5,
+ "results": [],
+ "resultcount": 0,
+ "type": "error",
+ "error": "No request type/data specified.",
}
# Make dummy request.
@@ -541,9 +606,9 @@ def test_rpc_no_args(client: TestClient):
def test_rpc_no_maintainer(client: TestClient, packages: list[Package]):
# Make dummy request.
with client as request:
- response = request.get("/rpc", params={
- "v": 5, "type": "info", "arg": "woogly-chungus"
- })
+ response = request.get(
+ "/rpc", params={"v": 5, "type": "info", "arg": "woogly-chungus"}
+ )
# Load request response into Python dictionary.
response_data = orjson.loads(response.content.decode())
@@ -620,8 +685,12 @@ def mock_config_getint(section: str, key: str):
@mock.patch("aurweb.config.getint", side_effect=mock_config_getint)
-def test_rpc_ratelimit(getint: mock.MagicMock, client: TestClient,
- pipeline: Pipeline, packages: list[Package]):
+def test_rpc_ratelimit(
+ getint: mock.MagicMock,
+ client: TestClient,
+ pipeline: Pipeline,
+ packages: list[Package],
+):
params = {"v": 5, "type": "suggest-pkgbase", "arg": "big"}
for i in range(4):
@@ -685,7 +754,7 @@ def test_rpc_search(client: TestClient, packages: list[Package]):
headers = {"If-None-Match": etag}
response = request.get("/rpc", params=params, headers=headers)
assert response.status_code == int(HTTPStatus.NOT_MODIFIED)
- assert response.content == b''
+ assert response.content == b""
# No args on non-m by types return an error.
del params["arg"]
@@ -703,12 +772,7 @@ def test_rpc_msearch(client: TestClient, user: User, packages: list[Package]):
# user1 maintains 4 packages; assert that we got them all.
assert data.get("resultcount") == 4
names = list(sorted(r.get("Name") for r in data.get("results")))
- expected_results = [
- "big-chungus",
- "chungy-chungus",
- "gluggly-chungus",
- "other-pkg"
- ]
+ expected_results = ["big-chungus", "chungy-chungus", "gluggly-chungus", "other-pkg"]
assert names == expected_results
# Search for a non-existent maintainer, giving us zero packages.
@@ -730,11 +794,10 @@ def test_rpc_msearch(client: TestClient, user: User, packages: list[Package]):
assert result.get("Name") == "big-chungus"
-def test_rpc_search_depends(client: TestClient, packages: list[Package],
- depends: list[PackageDependency]):
- params = {
- "v": 5, "type": "search", "by": "depends", "arg": "chungus-depends"
- }
+def test_rpc_search_depends(
+ client: TestClient, packages: list[Package], depends: list[PackageDependency]
+):
+ params = {"v": 5, "type": "search", "by": "depends", "arg": "chungus-depends"}
with client as request:
response = request.get("/rpc", params=params)
data = response.json()
@@ -743,13 +806,14 @@ def test_rpc_search_depends(client: TestClient, packages: list[Package],
assert result.get("Name") == packages[0].Name
-def test_rpc_search_makedepends(client: TestClient, packages: list[Package],
- depends: list[PackageDependency]):
+def test_rpc_search_makedepends(
+ client: TestClient, packages: list[Package], depends: list[PackageDependency]
+):
params = {
"v": 5,
"type": "search",
"by": "makedepends",
- "arg": "chungus-makedepends"
+ "arg": "chungus-makedepends",
}
with client as request:
response = request.get("/rpc", params=params)
@@ -759,14 +823,10 @@ def test_rpc_search_makedepends(client: TestClient, packages: list[Package],
assert result.get("Name") == packages[0].Name
-def test_rpc_search_optdepends(client: TestClient, packages: list[Package],
- depends: list[PackageDependency]):
- params = {
- "v": 5,
- "type": "search",
- "by": "optdepends",
- "arg": "chungus-optdepends"
- }
+def test_rpc_search_optdepends(
+ client: TestClient, packages: list[Package], depends: list[PackageDependency]
+):
+ params = {"v": 5, "type": "search", "by": "optdepends", "arg": "chungus-optdepends"}
with client as request:
response = request.get("/rpc", params=params)
data = response.json()
@@ -775,13 +835,14 @@ def test_rpc_search_optdepends(client: TestClient, packages: list[Package],
assert result.get("Name") == packages[0].Name
-def test_rpc_search_checkdepends(client: TestClient, packages: list[Package],
- depends: list[PackageDependency]):
+def test_rpc_search_checkdepends(
+ client: TestClient, packages: list[Package], depends: list[PackageDependency]
+):
params = {
"v": 5,
"type": "search",
"by": "checkdepends",
- "arg": "chungus-checkdepends"
+ "arg": "chungus-checkdepends",
}
with client as request:
response = request.get("/rpc", params=params)
@@ -799,21 +860,16 @@ def test_rpc_incorrect_by(client: TestClient):
def test_rpc_jsonp_callback(client: TestClient):
- """ Test the callback parameter.
+ """Test the callback parameter.
For end-to-end verification, the `examples/jsonp.html` file can be
used to submit jsonp callback requests to the RPC.
"""
- params = {
- "v": 5,
- "type": "search",
- "arg": "big",
- "callback": "jsonCallback"
- }
+ params = {"v": 5, "type": "search", "arg": "big", "callback": "jsonCallback"}
with client as request:
response = request.get("/rpc", params=params)
assert response.headers.get("content-type") == "text/javascript"
- assert re.search(r'^/\*\*/jsonCallback\(.*\)$', response.text) is not None
+ assert re.search(r"^/\*\*/jsonCallback\(.*\)$", response.text) is not None
# Test an invalid callback name; we get an application/json error.
params["callback"] = "jsonCallback!"
@@ -824,20 +880,14 @@ def test_rpc_jsonp_callback(client: TestClient):
def test_rpc_post(client: TestClient, packages: list[Package]):
- data = {
- "v": 5,
- "type": "info",
- "arg": "big-chungus",
- "arg[]": ["chungy-chungus"]
- }
+ data = {"v": 5, "type": "info", "arg": "big-chungus", "arg[]": ["chungy-chungus"]}
with client as request:
resp = request.post("/rpc", data=data)
assert resp.status_code == int(HTTPStatus.OK)
assert resp.json().get("resultcount") == 2
-def test_rpc_too_many_search_results(client: TestClient,
- packages: list[Package]):
+def test_rpc_too_many_search_results(client: TestClient, packages: list[Package]):
config_getint = config.getint
def mock_config(section: str, key: str):
@@ -858,10 +908,18 @@ def test_rpc_too_many_info_results(client: TestClient, packages: list[Package]):
# regardless of the number of related records.
with db.begin():
for i in range(len(packages) - 1):
- db.create(PackageDependency, DepTypeID=DEPENDS_ID,
- Package=packages[i], DepName=packages[i + 1].Name)
- db.create(PackageRelation, RelTypeID=PROVIDES_ID,
- Package=packages[i], RelName=packages[i + 1].Name)
+ db.create(
+ PackageDependency,
+ DepTypeID=DEPENDS_ID,
+ Package=packages[i],
+ DepName=packages[i + 1].Name,
+ )
+ db.create(
+ PackageRelation,
+ RelTypeID=PROVIDES_ID,
+ Package=packages[i],
+ RelName=packages[i + 1].Name,
+ )
config_getint = config.getint
diff --git a/test/test_rss.py b/test/test_rss.py
index cef6a46f..8526caa1 100644
--- a/test/test_rss.py
+++ b/test/test_rss.py
@@ -2,7 +2,6 @@ from http import HTTPStatus
import lxml.etree
import pytest
-
from fastapi.testclient import TestClient
from aurweb import db, logging, time
@@ -27,13 +26,15 @@ def client():
@pytest.fixture
def user():
- account_type = db.query(AccountType,
- AccountType.AccountType == "User").first()
- yield db.create(User, Username="test",
- Email="test@example.org",
- RealName="Test User",
- Passwd="testPassword",
- AccountType=account_type)
+ account_type = db.query(AccountType, AccountType.AccountType == "User").first()
+ yield db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User",
+ Passwd="testPassword",
+ AccountType=account_type,
+ )
@pytest.fixture
@@ -45,8 +46,12 @@ def packages(user):
with db.begin():
for i in range(101):
pkgbase = db.create(
- PackageBase, Maintainer=user, Name=f"test-package-{i}",
- SubmittedTS=(now + i), ModifiedTS=(now + i))
+ PackageBase,
+ Maintainer=user,
+ Name=f"test-package-{i}",
+ SubmittedTS=(now + i),
+ ModifiedTS=(now + i),
+ )
pkg = db.create(Package, Name=pkgbase.Name, PackageBase=pkgbase)
pkgs.append(pkg)
yield pkgs
@@ -64,6 +69,7 @@ def test_rss(client, user, packages):
# Test that the RSS we got is sorted by descending SubmittedTS.
def key_(pkg):
return pkg.PackageBase.SubmittedTS
+
packages = list(reversed(sorted(packages, key=key_)))
# Just take the first 100.
@@ -74,7 +80,7 @@ def test_rss(client, user, packages):
assert len(items) == 100
for i, item in enumerate(items):
- title = next(iter(item.xpath('./title')))
+ title = next(iter(item.xpath("./title")))
logger.debug(f"title: '{title.text}' vs name: '{packages[i].Name}'")
assert title.text == packages[i].Name
@@ -87,6 +93,7 @@ def test_rss_modified(client, user, packages):
# Test that the RSS we got is sorted by descending SubmittedTS.
def key_(pkg):
return pkg.PackageBase.ModifiedTS
+
packages = list(reversed(sorted(packages, key=key_)))
# Just take the first 100.
@@ -97,6 +104,6 @@ def test_rss_modified(client, user, packages):
assert len(items) == 100
for i, item in enumerate(items):
- title = next(iter(item.xpath('./title')))
+ title = next(iter(item.xpath("./title")))
logger.debug(f"title: '{title.text}' vs name: '{packages[i].Name}'")
assert title.text == packages[i].Name
diff --git a/test/test_session.py b/test/test_session.py
index edae57f9..db792b33 100644
--- a/test/test_session.py
+++ b/test/test_session.py
@@ -2,7 +2,6 @@
from unittest import mock
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db, time
@@ -19,17 +18,23 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- ResetKey="testReset", Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ ResetKey="testReset",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
@pytest.fixture
def session(user: User) -> Session:
with db.begin():
- session = db.create(Session, User=user, SessionID="testSession",
- LastUpdateTS=time.utcnow())
+ session = db.create(
+ Session, User=user, SessionID="testSession", LastUpdateTS=time.utcnow()
+ )
yield session
@@ -39,15 +44,21 @@ def test_session(user: User, session: Session):
def test_session_cs():
- """ Test case sensitivity of the database table. """
+ """Test case sensitivity of the database table."""
with db.begin():
- user2 = db.create(User, Username="test2", Email="test2@example.org",
- ResetKey="testReset2", Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user2 = db.create(
+ User,
+ Username="test2",
+ Email="test2@example.org",
+ ResetKey="testReset2",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
with db.begin():
- session_cs = db.create(Session, User=user2, SessionID="TESTSESSION",
- LastUpdateTS=time.utcnow())
+ session_cs = db.create(
+ Session, User=user2, SessionID="TESTSESSION", LastUpdateTS=time.utcnow()
+ )
assert session_cs.SessionID == "TESTSESSION"
assert session_cs.SessionID != "testSession"
diff --git a/test/test_spawn.py b/test/test_spawn.py
index 195eb897..be1c5e7c 100644
--- a/test/test_spawn.py
+++ b/test/test_spawn.py
@@ -1,6 +1,5 @@
import os
import tempfile
-
from typing import Tuple
from unittest import mock
@@ -8,26 +7,21 @@ import pytest
import aurweb.config
import aurweb.spawn
-
from aurweb.exceptions import AurwebException
# Some os.environ overrides we use in this suite.
-TEST_ENVIRONMENT = {
- "PHP_NGINX_PORT": "8001",
- "FASTAPI_NGINX_PORT": "8002"
-}
+TEST_ENVIRONMENT = {"PHP_NGINX_PORT": "8001", "FASTAPI_NGINX_PORT": "8002"}
class FakeProcess:
- """ Fake a subprocess.Popen return object. """
+ """Fake a subprocess.Popen return object."""
returncode = 0
- stdout = b''
- stderr = b''
+ stdout = b""
+ stderr = b""
def __init__(self, *args, **kwargs):
- """ We need this constructor to remain compatible with Popen. """
- pass
+ """We need this constructor to remain compatible with Popen."""
def communicate(self) -> Tuple[bytes, bytes]:
return (self.stdout, self.stderr)
@@ -40,10 +34,9 @@ class FakeProcess:
class MockFakeProcess:
- """ FakeProcess construction helper to be used in mocks. """
+ """FakeProcess construction helper to be used in mocks."""
- def __init__(self, return_code: int = 0, stdout: bytes = b'',
- stderr: bytes = b''):
+ def __init__(self, return_code: int = 0, stdout: bytes = b"", stderr: bytes = b""):
self.returncode = return_code
self.stdout = stdout
self.stderr = stderr
@@ -101,7 +94,7 @@ def test_spawn_generate_nginx_config():
f'listen {php_host}:{TEST_ENVIRONMENT.get("PHP_NGINX_PORT")}',
f"proxy_pass http://{php_address}",
f'listen {fastapi_host}:{TEST_ENVIRONMENT.get("FASTAPI_NGINX_PORT")}',
- f"proxy_pass http://{fastapi_address}"
+ f"proxy_pass http://{fastapi_address}",
]
for expected in expected_content:
assert expected in nginx_config
diff --git a/test/test_ssh_pub_key.py b/test/test_ssh_pub_key.py
index 93298a11..1a586800 100644
--- a/test/test_ssh_pub_key.py
+++ b/test/test_ssh_pub_key.py
@@ -27,18 +27,23 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- RealName="Test User", Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
@pytest.fixture
def pubkey(user: User) -> SSHPubKey:
with db.begin():
- pubkey = db.create(SSHPubKey, User=user,
- Fingerprint="testFingerprint",
- PubKey="testPubKey")
+ pubkey = db.create(
+ SSHPubKey, User=user, Fingerprint="testFingerprint", PubKey="testPubKey"
+ )
yield pubkey
@@ -50,11 +55,11 @@ def test_pubkey(user: User, pubkey: SSHPubKey):
def test_pubkey_cs(user: User):
- """ Test case sensitivity of the database table. """
+ """Test case sensitivity of the database table."""
with db.begin():
- pubkey_cs = db.create(SSHPubKey, User=user,
- Fingerprint="TESTFINGERPRINT",
- PubKey="TESTPUBKEY")
+ pubkey_cs = db.create(
+ SSHPubKey, User=user, Fingerprint="TESTFINGERPRINT", PubKey="TESTPUBKEY"
+ )
assert pubkey_cs.Fingerprint == "TESTFINGERPRINT"
assert pubkey_cs.Fingerprint != "testFingerprint"
diff --git a/test/test_templates.py b/test/test_templates.py
index 4b138567..383f45d1 100644
--- a/test/test_templates.py
+++ b/test/test_templates.py
@@ -1,21 +1,23 @@
import re
-
from typing import Any
import pytest
import aurweb.filters # noqa: F401
-
from aurweb import config, db, templates, time
-from aurweb.filters import as_timezone, number_format
-from aurweb.filters import timestamp_to_datetime as to_dt
+from aurweb.filters import as_timezone, number_format, timestamp_to_datetime as to_dt
from aurweb.models import Package, PackageBase, User
from aurweb.models.account_type import USER_ID
from aurweb.models.license import License
from aurweb.models.package_license import PackageLicense
from aurweb.models.package_relation import PackageRelation
from aurweb.models.relation_type import PROVIDES_ID, REPLACES_ID
-from aurweb.templates import base_template, make_context, register_filter, register_function
+from aurweb.templates import (
+ base_template,
+ make_context,
+ register_filter,
+ register_function,
+)
from aurweb.testing.html import parse_root
from aurweb.testing.requests import Request
@@ -35,19 +37,20 @@ def function():
def create_user(username: str) -> User:
with db.begin():
- user = db.create(User, Username=username,
- Email=f"{username}@example.org",
- Passwd="testPassword",
- AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username=username,
+ Email=f"{username}@example.org",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
return user
-def create_pkgrel(package: Package, reltype_id: int, relname: str) \
- -> PackageRelation:
- return db.create(PackageRelation,
- Package=package,
- RelTypeID=reltype_id,
- RelName=relname)
+def create_pkgrel(package: Package, reltype_id: int, relname: str) -> PackageRelation:
+ return db.create(
+ PackageRelation, Package=package, RelTypeID=reltype_id, RelName=relname
+ )
@pytest.fixture
@@ -60,8 +63,13 @@ def user(db_test) -> User:
def pkgbase(user: User) -> PackageBase:
now = time.utcnow()
with db.begin():
- pkgbase = db.create(PackageBase, Name="test-pkg", Maintainer=user,
- SubmittedTS=now, ModifiedTS=now)
+ pkgbase = db.create(
+ PackageBase,
+ Name="test-pkg",
+ Maintainer=user,
+ SubmittedTS=now,
+ ModifiedTS=now,
+ )
yield pkgbase
@@ -79,9 +87,10 @@ def create_license(pkg: Package, license_name: str) -> PackageLicense:
def test_register_function_exists_key_error():
- """ Most instances of register_filter are tested through module
- imports or template renders, so we only test failures here. """
+ """Most instances of register_filter are tested through module
+ imports or template renders, so we only test failures here."""
with pytest.raises(KeyError):
+
@register_function("function")
def some_func():
pass
@@ -93,8 +102,9 @@ def test_commit_hash():
commit_hash = "abcdefg"
long_commit_hash = commit_hash + "1234567"
- def config_get_with_fallback(section: str, option: str,
- fallback: str = None) -> str:
+ def config_get_with_fallback(
+ section: str, option: str, fallback: str = None
+ ) -> str:
if section == "devel" and option == "commit_hash":
return long_commit_hash
return config.original_get_with_fallback(section, option, fallback)
@@ -134,12 +144,12 @@ def pager_context(num_packages: int) -> dict[str, Any]:
"prefix": "/packages",
"total": num_packages,
"O": 0,
- "PP": 50
+ "PP": 50,
}
def test_pager_no_results():
- """ Test the pager partial with no results. """
+ """Test the pager partial with no results."""
num_packages = 0
context = pager_context(num_packages)
body = base_template("partials/pager.html").render(context)
@@ -151,7 +161,7 @@ def test_pager_no_results():
def test_pager():
- """ Test the pager partial with two pages of results. """
+ """Test the pager partial with two pages of results."""
num_packages = 100
context = pager_context(num_packages)
body = base_template("partials/pager.html").render(context)
@@ -274,17 +284,19 @@ def check_package_details(content: str, pkg: Package) -> None:
def test_package_details(user: User, package: Package):
- """ Test package details with most fields populated, but not all. """
+ """Test package details with most fields populated, but not all."""
request = Request(user=user, authenticated=True)
context = make_context(request, "Test Details")
- context.update({
- "request": request,
- "git_clone_uri_anon": GIT_CLONE_URI_ANON,
- "git_clone_uri_priv": GIT_CLONE_URI_PRIV,
- "pkgbase": package.PackageBase,
- "pkg": package,
- "comaintainers": [],
- })
+ context.update(
+ {
+ "request": request,
+ "git_clone_uri_anon": GIT_CLONE_URI_ANON,
+ "git_clone_uri_priv": GIT_CLONE_URI_PRIV,
+ "pkgbase": package.PackageBase,
+ "pkg": package,
+ "comaintainers": [],
+ }
+ )
base = base_template("partials/packages/details.html")
body = base.render(context, show_package_details=True)
@@ -292,7 +304,7 @@ def test_package_details(user: User, package: Package):
def test_package_details_filled(user: User, package: Package):
- """ Test package details with all fields populated. """
+ """Test package details with all fields populated."""
pkgbase = package.PackageBase
with db.begin():
@@ -311,19 +323,23 @@ def test_package_details_filled(user: User, package: Package):
request = Request(user=user, authenticated=True)
context = make_context(request, "Test Details")
- context.update({
- "request": request,
- "git_clone_uri_anon": GIT_CLONE_URI_ANON,
- "git_clone_uri_priv": GIT_CLONE_URI_PRIV,
- "pkgbase": package.PackageBase,
- "pkg": package,
- "comaintainers": [],
- "licenses": package.package_licenses,
- "provides": package.package_relations.filter(
- PackageRelation.RelTypeID == PROVIDES_ID),
- "replaces": package.package_relations.filter(
- PackageRelation.RelTypeID == REPLACES_ID),
- })
+ context.update(
+ {
+ "request": request,
+ "git_clone_uri_anon": GIT_CLONE_URI_ANON,
+ "git_clone_uri_priv": GIT_CLONE_URI_PRIV,
+ "pkgbase": package.PackageBase,
+ "pkg": package,
+ "comaintainers": [],
+ "licenses": package.package_licenses,
+ "provides": package.package_relations.filter(
+ PackageRelation.RelTypeID == PROVIDES_ID
+ ),
+ "replaces": package.package_relations.filter(
+ PackageRelation.RelTypeID == REPLACES_ID
+ ),
+ }
+ )
base = base_template("partials/packages/details.html")
body = base.render(context, show_package_details=True)
diff --git a/test/test_term.py b/test/test_term.py
index bfa73a76..4b608a9a 100644
--- a/test/test_term.py
+++ b/test/test_term.py
@@ -1,5 +1,4 @@
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db
@@ -13,8 +12,9 @@ def setup(db_test):
def test_term_creation():
with db.begin():
- term = db.create(Term, Description="Term description",
- URL="https://fake_url.io")
+ term = db.create(
+ Term, Description="Term description", URL="https://fake_url.io"
+ )
assert bool(term.ID)
assert term.Description == "Term description"
assert term.URL == "https://fake_url.io"
diff --git a/test/test_time.py b/test/test_time.py
index 2134d217..db7b30bf 100644
--- a/test/test_time.py
+++ b/test/test_time.py
@@ -1,5 +1,4 @@
import aurweb.config
-
from aurweb.testing.requests import Request
from aurweb.time import get_request_timezone, tz_offset
diff --git a/test/test_trusted_user_routes.py b/test/test_trusted_user_routes.py
index 2e7dc193..203008e3 100644
--- a/test/test_trusted_user_routes.py
+++ b/test/test_trusted_user_routes.py
@@ -1,12 +1,10 @@
import re
-
from http import HTTPStatus
from io import StringIO
from typing import Tuple
import lxml.etree
import pytest
-
from fastapi.testclient import TestClient
from aurweb import config, db, filters, time
@@ -16,8 +14,8 @@ from aurweb.models.tu_voteinfo import TUVoteInfo
from aurweb.models.user import User
from aurweb.testing.requests import Request
-DATETIME_REGEX = r'^[0-9]{4}-[0-9]{2}-[0-9]{2} \(.+\)$'
-PARTICIPATION_REGEX = r'^1?[0-9]{2}[%]$' # 0% - 100%
+DATETIME_REGEX = r"^[0-9]{4}-[0-9]{2}-[0-9]{2} \(.+\)$"
+PARTICIPATION_REGEX = r"^1?[0-9]{2}[%]$" # 0% - 100%
def parse_root(html):
@@ -43,11 +41,11 @@ def get_pkglist_directions(table):
def get_a(node):
- return node.xpath('./a')[0].text.strip()
+ return node.xpath("./a")[0].text.strip()
def get_span(node):
- return node.xpath('./span')[0].text.strip()
+ return node.xpath("./span")[0].text.strip()
def assert_current_vote_html(row, expected):
@@ -82,39 +80,51 @@ def setup(db_test):
@pytest.fixture
def client():
from aurweb.asgi import app
+
yield TestClient(app=app)
@pytest.fixture
def tu_user():
- tu_type = db.query(AccountType,
- AccountType.AccountType == "Trusted User").first()
+ tu_type = db.query(AccountType, AccountType.AccountType == "Trusted User").first()
with db.begin():
- tu_user = db.create(User, Username="test_tu",
- Email="test_tu@example.org",
- RealName="Test TU", Passwd="testPassword",
- AccountType=tu_type)
+ tu_user = db.create(
+ User,
+ Username="test_tu",
+ Email="test_tu@example.org",
+ RealName="Test TU",
+ Passwd="testPassword",
+ AccountType=tu_type,
+ )
yield tu_user
@pytest.fixture
def tu_user2():
with db.begin():
- tu_user2 = db.create(User, Username="test_tu2",
- Email="test_tu2@example.org",
- RealName="Test TU 2", Passwd="testPassword",
- AccountTypeID=TRUSTED_USER_ID)
+ tu_user2 = db.create(
+ User,
+ Username="test_tu2",
+ Email="test_tu2@example.org",
+ RealName="Test TU 2",
+ Passwd="testPassword",
+ AccountTypeID=TRUSTED_USER_ID,
+ )
yield tu_user2
@pytest.fixture
def user():
- user_type = db.query(AccountType,
- AccountType.AccountType == "User").first()
+ user_type = db.query(AccountType, AccountType.AccountType == "User").first()
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- RealName="Test User", Passwd="testPassword",
- AccountType=user_type)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User",
+ Passwd="testPassword",
+ AccountType=user_type,
+ )
yield user
@@ -126,10 +136,15 @@ def proposal(user, tu_user):
end = ts + 1000
with db.begin():
- voteinfo = db.create(TUVoteInfo,
- Agenda=agenda, Quorum=0.0,
- User=user.Username, Submitter=tu_user,
- Submitted=start, End=end)
+ voteinfo = db.create(
+ TUVoteInfo,
+ Agenda=agenda,
+ Quorum=0.0,
+ User=user.Username,
+ Submitter=tu_user,
+ Submitted=start,
+ End=end,
+ )
yield (tu_user, user, voteinfo)
@@ -153,7 +168,7 @@ def test_tu_index_unauthorized(client: TestClient, user: User):
def test_tu_empty_index(client, tu_user):
- """ Check an empty index when we don't create any records. """
+ """Check an empty index when we don't create any records."""
# Make a default get request to /tu.
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
@@ -179,18 +194,23 @@ def test_tu_index(client, tu_user):
# Create some test votes: (Agenda, Start, End).
votes = [
("Test agenda 1", ts - 5, ts + 1000), # Still running.
- ("Test agenda 2", ts - 1000, ts - 5) # Not running anymore.
+ ("Test agenda 2", ts - 1000, ts - 5), # Not running anymore.
]
vote_records = []
with db.begin():
for vote in votes:
agenda, start, end = vote
vote_records.append(
- db.create(TUVoteInfo, Agenda=agenda,
- User=tu_user.Username,
- Submitted=start, End=end,
- Quorum=0.0,
- Submitter=tu_user))
+ db.create(
+ TUVoteInfo,
+ Agenda=agenda,
+ User=tu_user.Username,
+ Submitted=start,
+ End=end,
+ Quorum=0.0,
+ Submitter=tu_user,
+ )
+ )
with db.begin():
# Vote on an ended proposal.
@@ -202,21 +222,23 @@ def test_tu_index(client, tu_user):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
# Pass an invalid cby and pby; let them default to "desc".
- response = request.get("/tu", cookies=cookies, params={
- "cby": "BAD!",
- "pby": "blah"
- }, allow_redirects=False)
+ response = request.get(
+ "/tu",
+ cookies=cookies,
+ params={"cby": "BAD!", "pby": "blah"},
+ allow_redirects=False,
+ )
assert response.status_code == int(HTTPStatus.OK)
# Rows we expect to exist in HTML produced by /tu for current votes.
expected_rows = [
(
- r'Test agenda 1',
+ r"Test agenda 1",
DATETIME_REGEX,
DATETIME_REGEX,
tu_user.Username,
- r'^(Yes|No)$'
+ r"^(Yes|No)$",
)
]
@@ -239,13 +261,13 @@ def test_tu_index(client, tu_user):
# Rows we expect to exist in HTML produced by /tu for past votes.
expected_rows = [
(
- r'Test agenda 2',
+ r"Test agenda 2",
DATETIME_REGEX,
DATETIME_REGEX,
tu_user.Username,
- r'^\d+$',
- r'^\d+$',
- r'^(Yes|No)$'
+ r"^\d+$",
+ r"^\d+$",
+ r"^(Yes|No)$",
)
]
@@ -315,19 +337,27 @@ def test_tu_index_table_paging(client, tu_user):
with db.begin():
for i in range(25):
# Create 25 current votes.
- db.create(TUVoteInfo, Agenda=f"Agenda #{i}",
- User=tu_user.Username,
- Submitted=(ts - 5), End=(ts + 1000),
- Quorum=0.0,
- Submitter=tu_user)
+ db.create(
+ TUVoteInfo,
+ Agenda=f"Agenda #{i}",
+ User=tu_user.Username,
+ Submitted=(ts - 5),
+ End=(ts + 1000),
+ Quorum=0.0,
+ Submitter=tu_user,
+ )
for i in range(25):
# Create 25 past votes.
- db.create(TUVoteInfo, Agenda=f"Agenda #{25 + i}",
- User=tu_user.Username,
- Submitted=(ts - 1000), End=(ts - 5),
- Quorum=0.0,
- Submitter=tu_user)
+ db.create(
+ TUVoteInfo,
+ Agenda=f"Agenda #{25 + i}",
+ User=tu_user.Username,
+ Submitted=(ts - 1000),
+ End=(ts - 5),
+ Quorum=0.0,
+ Submitter=tu_user,
+ )
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
@@ -347,7 +377,7 @@ def test_tu_index_table_paging(client, tu_user):
DATETIME_REGEX,
DATETIME_REGEX,
tu_user.Username,
- r'^(Yes|No)$'
+ r"^(Yes|No)$",
]
for i, row in enumerate(rows):
@@ -361,9 +391,9 @@ def test_tu_index_table_paging(client, tu_user):
# Now, get the next page of current votes.
offset = 10 # Specify coff=10
with client as request:
- response = request.get("/tu", cookies=cookies, params={
- "coff": offset
- }, allow_redirects=False)
+ response = request.get(
+ "/tu", cookies=cookies, params={"coff": offset}, allow_redirects=False
+ )
assert response.status_code == int(HTTPStatus.OK)
old_rows = rows
@@ -390,9 +420,9 @@ def test_tu_index_table_paging(client, tu_user):
offset = 20 # Specify coff=10
with client as request:
- response = request.get("/tu", cookies=cookies, params={
- "coff": offset
- }, allow_redirects=False)
+ response = request.get(
+ "/tu", cookies=cookies, params={"coff": offset}, allow_redirects=False
+ )
assert response.status_code == int(HTTPStatus.OK)
# Do it again, we only have five left.
@@ -423,11 +453,15 @@ def test_tu_index_sorting(client, tu_user):
with db.begin():
for i in range(2):
# Create 'Agenda #1' and 'Agenda #2'.
- db.create(TUVoteInfo, Agenda=f"Agenda #{i + 1}",
- User=tu_user.Username,
- Submitted=(ts + 5), End=(ts + 1000),
- Quorum=0.0,
- Submitter=tu_user)
+ db.create(
+ TUVoteInfo,
+ Agenda=f"Agenda #{i + 1}",
+ User=tu_user.Username,
+ Submitted=(ts + 5),
+ End=(ts + 1000),
+ Quorum=0.0,
+ Submitter=tu_user,
+ )
# Let's order each vote one day after the other.
# This will allow us to test the sorting nature
@@ -446,27 +480,27 @@ def test_tu_index_sorting(client, tu_user):
rows = get_table_rows(table)
# The latest Agenda is at the top by default.
- expected = [
- "Agenda #2",
- "Agenda #1"
- ]
+ expected = ["Agenda #2", "Agenda #1"]
assert len(rows) == len(expected)
for i, row in enumerate(rows):
- assert_current_vote_html(row, [
- expected[i],
- DATETIME_REGEX,
- DATETIME_REGEX,
- tu_user.Username,
- r'^(Yes|No)$'
- ])
+ assert_current_vote_html(
+ row,
+ [
+ expected[i],
+ DATETIME_REGEX,
+ DATETIME_REGEX,
+ tu_user.Username,
+ r"^(Yes|No)$",
+ ],
+ )
# Make another request; one that sorts the current votes
# in ascending order instead of the default descending order.
with client as request:
- response = request.get("/tu", cookies=cookies, params={
- "cby": "asc"
- }, allow_redirects=False)
+ response = request.get(
+ "/tu", cookies=cookies, params={"cby": "asc"}, allow_redirects=False
+ )
assert response.status_code == int(HTTPStatus.OK)
# Get lxml handles of the document.
@@ -478,30 +512,37 @@ def test_tu_index_sorting(client, tu_user):
rev_expected = list(reversed(expected))
assert len(rows) == len(rev_expected)
for i, row in enumerate(rows):
- assert_current_vote_html(row, [
- rev_expected[i],
- DATETIME_REGEX,
- DATETIME_REGEX,
- tu_user.Username,
- r'^(Yes|No)$'
- ])
+ assert_current_vote_html(
+ row,
+ [
+ rev_expected[i],
+ DATETIME_REGEX,
+ DATETIME_REGEX,
+ tu_user.Username,
+ r"^(Yes|No)$",
+ ],
+ )
-def test_tu_index_last_votes(client: TestClient, tu_user: User, tu_user2: User,
- user: User):
+def test_tu_index_last_votes(
+ client: TestClient, tu_user: User, tu_user2: User, user: User
+):
ts = time.utcnow()
with db.begin():
# Create a proposal which has ended.
- voteinfo = db.create(TUVoteInfo, Agenda="Test agenda",
- User=user.Username,
- Submitted=(ts - 1000),
- End=(ts - 5),
- Yes=1,
- No=1,
- ActiveTUs=1,
- Quorum=0.0,
- Submitter=tu_user)
+ voteinfo = db.create(
+ TUVoteInfo,
+ Agenda="Test agenda",
+ User=user.Username,
+ Submitted=(ts - 1000),
+ End=(ts - 5),
+ Yes=1,
+ No=1,
+ ActiveTUs=1,
+ Quorum=0.0,
+ Submitter=tu_user,
+ )
# Create a vote on it from tu_user.
db.create(TUVote, VoteInfo=voteinfo, User=tu_user)
@@ -536,26 +577,27 @@ def test_tu_proposal_not_found(client, tu_user):
assert response.status_code == int(HTTPStatus.NOT_FOUND)
-def test_tu_proposal_unauthorized(client: TestClient, user: User,
- proposal: Tuple[User, User, TUVoteInfo]):
+def test_tu_proposal_unauthorized(
+ client: TestClient, user: User, proposal: Tuple[User, User, TUVoteInfo]
+):
cookies = {"AURSID": user.login(Request(), "testPassword")}
endpoint = f"/tu/{proposal[2].ID}"
with client as request:
- response = request.get(endpoint, cookies=cookies,
- allow_redirects=False)
+ response = request.get(endpoint, cookies=cookies, allow_redirects=False)
assert response.status_code == int(HTTPStatus.SEE_OTHER)
assert response.headers.get("location") == "/tu"
with client as request:
- response = request.post(endpoint, cookies=cookies,
- data={"decision": False},
- allow_redirects=False)
+ response = request.post(
+ endpoint, cookies=cookies, data={"decision": False}, allow_redirects=False
+ )
assert response.status_code == int(HTTPStatus.SEE_OTHER)
assert response.headers.get("location") == "/tu"
-def test_tu_running_proposal(client: TestClient,
- proposal: Tuple[User, User, TUVoteInfo]):
+def test_tu_running_proposal(
+ client: TestClient, proposal: Tuple[User, User, TUVoteInfo]
+):
tu_user, user, voteinfo = proposal
with db.begin():
voteinfo.ActiveTUs = 1
@@ -576,8 +618,7 @@ def test_tu_running_proposal(client: TestClient,
assert vote_running.text.strip() == "This vote is still running."
# Verify User field.
- username = details.xpath(
- './div[contains(@class, "user")]/strong/a/text()')[0]
+ username = details.xpath('./div[contains(@class, "user")]/strong/a/text()')[0]
assert username.strip() == user.Username
active = details.xpath('./div[contains(@class, "field")]')[1]
@@ -585,10 +626,13 @@ def test_tu_running_proposal(client: TestClient,
assert "Active Trusted Users assigned:" in content
assert "1" in content
- submitted = details.xpath(
- './div[contains(@class, "submitted")]/text()')[0]
- assert re.match(r'^Submitted: \d{4}-\d{2}-\d{2} \d{2}:\d{2} \(.+\) by$',
- submitted.strip()) is not None
+ submitted = details.xpath('./div[contains(@class, "submitted")]/text()')[0]
+ assert (
+ re.match(
+ r"^Submitted: \d{4}-\d{2}-\d{2} \d{2}:\d{2} \(.+\) by$", submitted.strip()
+ )
+ is not None
+ )
submitter = details.xpath('./div[contains(@class, "submitted")]/a')[0]
assert submitter.text.strip() == tu_user.Username
assert submitter.attrib["href"] == f"/account/{tu_user.Username}"
@@ -598,8 +642,10 @@ def test_tu_running_proposal(client: TestClient,
assert end_label.strip() == "End:"
end_datetime = end.xpath("./strong/text()")[0]
- assert re.match(r'^\d{4}-\d{2}-\d{2} \d{2}:\d{2} \(.+\)$',
- end_datetime.strip()) is not None
+ assert (
+ re.match(r"^\d{4}-\d{2}-\d{2} \d{2}:\d{2} \(.+\)$", end_datetime.strip())
+ is not None
+ )
# We have not voted yet. Assert that our voting form is shown.
form = root.xpath('//form[contains(@class, "action-form")]')[0]
@@ -630,8 +676,7 @@ def test_tu_running_proposal(client: TestClient,
# Make another request now that we've voted.
with client as request:
- response = request.get(
- "/tu", params={"id": voteinfo.ID}, cookies=cookies)
+ response = request.get("/tu", params={"id": voteinfo.ID}, cookies=cookies)
assert response.status_code == int(HTTPStatus.OK)
# Parse our new root.
@@ -685,12 +730,13 @@ def test_tu_ended_proposal(client, proposal):
def test_tu_proposal_vote_not_found(client, tu_user):
- """ Test POST request to a missing vote. """
+ """Test POST request to a missing vote."""
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
data = {"decision": "Yes"}
- response = request.post("/tu/1", cookies=cookies,
- data=data, allow_redirects=False)
+ response = request.post(
+ "/tu/1", cookies=cookies, data=data, allow_redirects=False
+ )
assert response.status_code == int(HTTPStatus.NOT_FOUND)
@@ -703,16 +749,14 @@ def test_tu_proposal_vote(client, proposal):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
data = {"decision": "Yes"}
- response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies,
- data=data)
+ response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, data=data)
assert response.status_code == int(HTTPStatus.OK)
# Check that the proposal record got updated.
assert voteinfo.Yes == yes + 1
# Check that the new TUVote exists.
- vote = db.query(TUVote, TUVote.VoteInfo == voteinfo,
- TUVote.User == tu_user).first()
+ vote = db.query(TUVote, TUVote.VoteInfo == voteinfo, TUVote.User == tu_user).first()
assert vote is not None
root = parse_root(response.text)
@@ -723,7 +767,8 @@ def test_tu_proposal_vote(client, proposal):
def test_tu_proposal_vote_unauthorized(
- client: TestClient, proposal: Tuple[User, User, TUVoteInfo]):
+ client: TestClient, proposal: Tuple[User, User, TUVoteInfo]
+):
tu_user, user, voteinfo = proposal
with db.begin():
@@ -732,8 +777,9 @@ def test_tu_proposal_vote_unauthorized(
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
data = {"decision": "Yes"}
- response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies,
- data=data, allow_redirects=False)
+ response = request.post(
+ f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False
+ )
assert response.status_code == int(HTTPStatus.UNAUTHORIZED)
root = parse_root(response.text)
@@ -742,8 +788,9 @@ def test_tu_proposal_vote_unauthorized(
with client as request:
data = {"decision": "Yes"}
- response = request.get(f"/tu/{voteinfo.ID}", cookies=cookies,
- data=data, allow_redirects=False)
+ response = request.get(
+ f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False
+ )
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
@@ -761,8 +808,9 @@ def test_tu_proposal_vote_cant_self_vote(client, proposal):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
data = {"decision": "Yes"}
- response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies,
- data=data, allow_redirects=False)
+ response = request.post(
+ f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False
+ )
assert response.status_code == int(HTTPStatus.BAD_REQUEST)
root = parse_root(response.text)
@@ -771,8 +819,9 @@ def test_tu_proposal_vote_cant_self_vote(client, proposal):
with client as request:
data = {"decision": "Yes"}
- response = request.get(f"/tu/{voteinfo.ID}", cookies=cookies,
- data=data, allow_redirects=False)
+ response = request.get(
+ f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False
+ )
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
@@ -791,8 +840,9 @@ def test_tu_proposal_vote_already_voted(client, proposal):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
data = {"decision": "Yes"}
- response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies,
- data=data, allow_redirects=False)
+ response = request.post(
+ f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False
+ )
assert response.status_code == int(HTTPStatus.BAD_REQUEST)
root = parse_root(response.text)
@@ -801,8 +851,9 @@ def test_tu_proposal_vote_already_voted(client, proposal):
with client as request:
data = {"decision": "Yes"}
- response = request.get(f"/tu/{voteinfo.ID}", cookies=cookies,
- data=data, allow_redirects=False)
+ response = request.get(
+ f"/tu/{voteinfo.ID}", cookies=cookies, data=data, allow_redirects=False
+ )
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
@@ -816,8 +867,7 @@ def test_tu_proposal_vote_invalid_decision(client, proposal):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
data = {"decision": "EVIL"}
- response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies,
- data=data)
+ response = request.post(f"/tu/{voteinfo.ID}", cookies=cookies, data=data)
assert response.status_code == int(HTTPStatus.BAD_REQUEST)
assert response.text == "Invalid 'decision' value."
@@ -829,18 +879,17 @@ def test_tu_addvote(client: TestClient, tu_user: User):
assert response.status_code == int(HTTPStatus.OK)
-def test_tu_addvote_unauthorized(client: TestClient, user: User,
- proposal: Tuple[User, User, TUVoteInfo]):
+def test_tu_addvote_unauthorized(
+ client: TestClient, user: User, proposal: Tuple[User, User, TUVoteInfo]
+):
cookies = {"AURSID": user.login(Request(), "testPassword")}
with client as request:
- response = request.get("/addvote", cookies=cookies,
- allow_redirects=False)
+ response = request.get("/addvote", cookies=cookies, allow_redirects=False)
assert response.status_code == int(HTTPStatus.SEE_OTHER)
assert response.headers.get("location") == "/tu"
with client as request:
- response = request.post("/addvote", cookies=cookies,
- allow_redirects=False)
+ response = request.post("/addvote", cookies=cookies, allow_redirects=False)
assert response.status_code == int(HTTPStatus.SEE_OTHER)
assert response.headers.get("location") == "/tu"
@@ -848,8 +897,7 @@ def test_tu_addvote_unauthorized(client: TestClient, user: User,
def test_tu_addvote_invalid_type(client: TestClient, tu_user: User):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
- response = request.get("/addvote", params={"type": "faketype"},
- cookies=cookies)
+ response = request.get("/addvote", params={"type": "faketype"}, cookies=cookies)
assert response.status_code == int(HTTPStatus.OK)
root = parse_root(response.text)
@@ -860,11 +908,7 @@ def test_tu_addvote_invalid_type(client: TestClient, tu_user: User):
def test_tu_addvote_post(client: TestClient, tu_user: User, user: User):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
- data = {
- "user": user.Username,
- "type": "add_tu",
- "agenda": "Blah"
- }
+ data = {"user": user.Username, "type": "add_tu", "agenda": "Blah"}
with client as request:
response = request.post("/addvote", cookies=cookies, data=data)
@@ -874,15 +918,12 @@ def test_tu_addvote_post(client: TestClient, tu_user: User, user: User):
assert voteinfo is not None
-def test_tu_addvote_post_cant_duplicate_username(client: TestClient,
- tu_user: User, user: User):
+def test_tu_addvote_post_cant_duplicate_username(
+ client: TestClient, tu_user: User, user: User
+):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
- data = {
- "user": user.Username,
- "type": "add_tu",
- "agenda": "Blah"
- }
+ data = {"user": user.Username, "type": "add_tu", "agenda": "Blah"}
with client as request:
response = request.post("/addvote", cookies=cookies, data=data)
@@ -904,8 +945,7 @@ def test_tu_addvote_post_invalid_username(client: TestClient, tu_user: User):
assert response.status_code == int(HTTPStatus.NOT_FOUND)
-def test_tu_addvote_post_invalid_type(client: TestClient, tu_user: User,
- user: User):
+def test_tu_addvote_post_invalid_type(client: TestClient, tu_user: User, user: User):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
data = {"user": user.Username}
with client as request:
@@ -913,8 +953,7 @@ def test_tu_addvote_post_invalid_type(client: TestClient, tu_user: User,
assert response.status_code == int(HTTPStatus.BAD_REQUEST)
-def test_tu_addvote_post_invalid_agenda(client: TestClient,
- tu_user: User, user: User):
+def test_tu_addvote_post_invalid_agenda(client: TestClient, tu_user: User, user: User):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
data = {"user": user.Username, "type": "add_tu"}
with client as request:
diff --git a/test/test_tu_vote.py b/test/test_tu_vote.py
index 91d73ecb..8c1c08de 100644
--- a/test/test_tu_vote.py
+++ b/test/test_tu_vote.py
@@ -1,5 +1,4 @@
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db, time
@@ -17,9 +16,14 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- RealName="Test User", Passwd="testPassword",
- AccountTypeID=TRUSTED_USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User",
+ Passwd="testPassword",
+ AccountTypeID=TRUSTED_USER_ID,
+ )
yield user
@@ -27,10 +31,15 @@ def user() -> User:
def tu_voteinfo(user: User) -> TUVoteInfo:
ts = time.utcnow()
with db.begin():
- tu_voteinfo = db.create(TUVoteInfo, Agenda="Blah blah.",
- User=user.Username,
- Submitted=ts, End=ts + 5,
- Quorum=0.5, Submitter=user)
+ tu_voteinfo = db.create(
+ TUVoteInfo,
+ Agenda="Blah blah.",
+ User=user.Username,
+ Submitted=ts,
+ End=ts + 5,
+ Quorum=0.5,
+ Submitter=user,
+ )
yield tu_voteinfo
diff --git a/test/test_tu_voteinfo.py b/test/test_tu_voteinfo.py
index 17226048..34845b86 100644
--- a/test/test_tu_voteinfo.py
+++ b/test/test_tu_voteinfo.py
@@ -1,5 +1,4 @@
import pytest
-
from sqlalchemy.exc import IntegrityError
from aurweb import db, time
@@ -17,21 +16,29 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = create(User, Username="test", Email="test@example.org",
- RealName="Test User", Passwd="testPassword",
- AccountTypeID=TRUSTED_USER_ID)
+ user = create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ RealName="Test User",
+ Passwd="testPassword",
+ AccountTypeID=TRUSTED_USER_ID,
+ )
yield user
def test_tu_voteinfo_creation(user: User):
ts = time.utcnow()
with db.begin():
- tu_voteinfo = create(TUVoteInfo,
- Agenda="Blah blah.",
- User=user.Username,
- Submitted=ts, End=ts + 5,
- Quorum=0.5,
- Submitter=user)
+ tu_voteinfo = create(
+ TUVoteInfo,
+ Agenda="Blah blah.",
+ User=user.Username,
+ Submitted=ts,
+ End=ts + 5,
+ Quorum=0.5,
+ Submitter=user,
+ )
assert bool(tu_voteinfo.ID)
assert tu_voteinfo.Agenda == "Blah blah."
assert tu_voteinfo.User == user.Username
@@ -50,12 +57,15 @@ def test_tu_voteinfo_creation(user: User):
def test_tu_voteinfo_is_running(user: User):
ts = time.utcnow()
with db.begin():
- tu_voteinfo = create(TUVoteInfo,
- Agenda="Blah blah.",
- User=user.Username,
- Submitted=ts, End=ts + 1000,
- Quorum=0.5,
- Submitter=user)
+ tu_voteinfo = create(
+ TUVoteInfo,
+ Agenda="Blah blah.",
+ User=user.Username,
+ Submitted=ts,
+ End=ts + 1000,
+ Quorum=0.5,
+ Submitter=user,
+ )
assert tu_voteinfo.is_running() is True
with db.begin():
@@ -66,12 +76,15 @@ def test_tu_voteinfo_is_running(user: User):
def test_tu_voteinfo_total_votes(user: User):
ts = time.utcnow()
with db.begin():
- tu_voteinfo = create(TUVoteInfo,
- Agenda="Blah blah.",
- User=user.Username,
- Submitted=ts, End=ts + 1000,
- Quorum=0.5,
- Submitter=user)
+ tu_voteinfo = create(
+ TUVoteInfo,
+ Agenda="Blah blah.",
+ User=user.Username,
+ Submitted=ts,
+ End=ts + 1000,
+ Quorum=0.5,
+ Submitter=user,
+ )
tu_voteinfo.Yes = 1
tu_voteinfo.No = 3
@@ -84,65 +97,81 @@ def test_tu_voteinfo_total_votes(user: User):
def test_tu_voteinfo_null_submitter_raises(user: User):
with pytest.raises(IntegrityError):
with db.begin():
- create(TUVoteInfo,
- Agenda="Blah blah.",
- User=user.Username,
- Submitted=0, End=0,
- Quorum=0.50)
+ create(
+ TUVoteInfo,
+ Agenda="Blah blah.",
+ User=user.Username,
+ Submitted=0,
+ End=0,
+ Quorum=0.50,
+ )
rollback()
def test_tu_voteinfo_null_agenda_raises(user: User):
with pytest.raises(IntegrityError):
with db.begin():
- create(TUVoteInfo,
- User=user.Username,
- Submitted=0, End=0,
- Quorum=0.50,
- Submitter=user)
+ create(
+ TUVoteInfo,
+ User=user.Username,
+ Submitted=0,
+ End=0,
+ Quorum=0.50,
+ Submitter=user,
+ )
rollback()
def test_tu_voteinfo_null_user_raises(user: User):
with pytest.raises(IntegrityError):
with db.begin():
- create(TUVoteInfo,
- Agenda="Blah blah.",
- Submitted=0, End=0,
- Quorum=0.50,
- Submitter=user)
+ create(
+ TUVoteInfo,
+ Agenda="Blah blah.",
+ Submitted=0,
+ End=0,
+ Quorum=0.50,
+ Submitter=user,
+ )
rollback()
def test_tu_voteinfo_null_submitted_raises(user: User):
with pytest.raises(IntegrityError):
with db.begin():
- create(TUVoteInfo,
- Agenda="Blah blah.",
- User=user.Username,
- End=0,
- Quorum=0.50,
- Submitter=user)
+ create(
+ TUVoteInfo,
+ Agenda="Blah blah.",
+ User=user.Username,
+ End=0,
+ Quorum=0.50,
+ Submitter=user,
+ )
rollback()
def test_tu_voteinfo_null_end_raises(user: User):
with pytest.raises(IntegrityError):
with db.begin():
- create(TUVoteInfo,
- Agenda="Blah blah.",
- User=user.Username,
- Submitted=0,
- Quorum=0.50,
- Submitter=user)
+ create(
+ TUVoteInfo,
+ Agenda="Blah blah.",
+ User=user.Username,
+ Submitted=0,
+ Quorum=0.50,
+ Submitter=user,
+ )
rollback()
def test_tu_voteinfo_null_quorum_default(user: User):
with db.begin():
- vi = create(TUVoteInfo,
- Agenda="Blah blah.",
- User=user.Username,
- Submitted=0, End=0,
- Submitter=user)
+ vi = create(
+ TUVoteInfo,
+ Agenda="Blah blah.",
+ User=user.Username,
+ Submitted=0,
+ End=0,
+ Submitter=user,
+ )
assert vi.Quorum == 0
diff --git a/test/test_tuvotereminder.py b/test/test_tuvotereminder.py
index a54c52a4..0233c8b2 100644
--- a/test/test_tuvotereminder.py
+++ b/test/test_tuvotereminder.py
@@ -19,8 +19,13 @@ def create_vote(user: User, voteinfo: TUVoteInfo) -> TUVote:
def create_user(username: str, type_id: int):
with db.begin():
- user = db.create(User, AccountTypeID=type_id, Username=username,
- Email=f"{username}@example.org", Passwd=str())
+ user = db.create(
+ User,
+ AccountTypeID=type_id,
+ Username=username,
+ Email=f"{username}@example.org",
+ Passwd=str(),
+ )
return user
@@ -32,9 +37,11 @@ def email_pieces(voteinfo: TUVoteInfo) -> Tuple[str, str]:
:return: tuple(subject, content)
"""
subject = f"TU Vote Reminder: Proposal {voteinfo.ID}"
- content = (f"Please remember to cast your vote on proposal {voteinfo.ID} "
- f"[1]. The voting period\nends in less than 48 hours.\n\n"
- f"[1] {aur_location}/tu/?id={voteinfo.ID}")
+ content = (
+ f"Please remember to cast your vote on proposal {voteinfo.ID} "
+ f"[1]. The voting period\nends in less than 48 hours.\n\n"
+ f"[1] {aur_location}/tu/?id={voteinfo.ID}"
+ )
return (subject, content)
@@ -58,14 +65,19 @@ def voteinfo(user: User) -> TUVoteInfo:
now = time.utcnow()
start = config.getint("tuvotereminder", "range_start")
with db.begin():
- voteinfo = db.create(TUVoteInfo, Agenda="Lorem ipsum.",
- User=user.Username, End=(now + start + 1),
- Quorum=0.00, Submitter=user, Submitted=0)
+ voteinfo = db.create(
+ TUVoteInfo,
+ Agenda="Lorem ipsum.",
+ User=user.Username,
+ End=(now + start + 1),
+ Quorum=0.00,
+ Submitter=user,
+ Submitted=0,
+ )
yield voteinfo
-def test_tu_vote_reminders(user: User, user2: User, user3: User,
- voteinfo: TUVoteInfo):
+def test_tu_vote_reminders(user: User, user2: User, user3: User, voteinfo: TUVoteInfo):
reminder.main()
assert Email.count() == 3
@@ -75,7 +87,7 @@ def test_tu_vote_reminders(user: User, user2: User, user3: User,
# (to, content)
(user.Email, subject, content),
(user2.Email, subject, content),
- (user3.Email, subject, content)
+ (user3.Email, subject, content),
]
for i, element in enumerate(expectations):
email, subject, content = element
@@ -84,8 +96,9 @@ def test_tu_vote_reminders(user: User, user2: User, user3: User,
assert emails[i].body == content
-def test_tu_vote_reminders_only_unvoted(user: User, user2: User, user3: User,
- voteinfo: TUVoteInfo):
+def test_tu_vote_reminders_only_unvoted(
+ user: User, user2: User, user3: User, voteinfo: TUVoteInfo
+):
# Vote with user2 and user3; leaving only user to be notified.
create_vote(user2, voteinfo)
create_vote(user3, voteinfo)
diff --git a/test/test_user.py b/test/test_user.py
index 5f25f3c9..17fd0c0e 100644
--- a/test/test_user.py
+++ b/test/test_user.py
@@ -1,6 +1,5 @@
import hashlib
import json
-
from datetime import datetime, timedelta
import bcrypt
@@ -9,10 +8,14 @@ import pytest
import aurweb.auth
import aurweb.config
import aurweb.models.account_type as at
-
from aurweb import db
from aurweb.auth import creds
-from aurweb.models.account_type import DEVELOPER_ID, TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID, USER_ID
+from aurweb.models.account_type import (
+ DEVELOPER_ID,
+ TRUSTED_USER_AND_DEV_ID,
+ TRUSTED_USER_ID,
+ USER_ID,
+)
from aurweb.models.ban import Ban
from aurweb.models.package import Package
from aurweb.models.package_base import PackageBase
@@ -31,10 +34,14 @@ def setup(db_test):
def create_user(username: str, account_type_id: int):
with db.begin():
- user = db.create(User, Username=username,
- Email=f"{username}@example.org",
- RealName=username.title(), Passwd="testPassword",
- AccountTypeID=account_type_id)
+ user = db.create(
+ User,
+ Username=username,
+ Email=f"{username}@example.org",
+ RealName=username.title(),
+ Passwd="testPassword",
+ AccountTypeID=account_type_id,
+ )
return user
@@ -71,7 +78,7 @@ def package(user: User) -> Package:
def test_user_login_logout(user: User):
- """ Test creating a user and reading its columns. """
+ """Test creating a user and reading its columns."""
# Assert that make_user created a valid user.
assert bool(user.ID)
@@ -89,8 +96,7 @@ def test_user_login_logout(user: User):
assert user.is_authenticated()
# Expect that User session relationships work right.
- user_session = db.query(Session,
- Session.UsersID == user.ID).first()
+ user_session = db.query(Session, Session.UsersID == user.ID).first()
assert user_session == user.session
assert user.session.SessionID == sid
assert user.session.User == user
@@ -111,8 +117,10 @@ def test_user_login_logout(user: User):
assert result.is_authenticated()
# Test out user string functions.
- assert repr(user) == f""
+ assert (
+ repr(user)
+ == f""
+ )
# Test logout.
user.logout(request)
@@ -145,9 +153,7 @@ def test_user_login_suspended(user: User):
def test_legacy_user_authentication(user: User):
with db.begin():
user.Salt = bcrypt.gensalt().decode()
- user.Passwd = hashlib.md5(
- f"{user.Salt}testPassword".encode()
- ).hexdigest()
+ user.Passwd = hashlib.md5(f"{user.Salt}testPassword".encode()).hexdigest()
assert not user.valid_password("badPassword")
assert user.valid_password("testPassword")
@@ -160,8 +166,12 @@ def test_user_login_with_outdated_sid(user: User):
# Make a session with a LastUpdateTS 5 seconds ago, causing
# user.login to update it with a new sid.
with db.begin():
- db.create(Session, UsersID=user.ID, SessionID="stub",
- LastUpdateTS=datetime.utcnow().timestamp() - 5)
+ db.create(
+ Session,
+ UsersID=user.ID,
+ SessionID="stub",
+ LastUpdateTS=datetime.utcnow().timestamp() - 5,
+ )
sid = user.login(Request(), "testPassword")
assert sid and user.is_authenticated()
assert sid != "stub"
@@ -186,9 +196,12 @@ def test_user_ssh_pub_key(user: User):
assert user.ssh_pub_keys.first() is None
with db.begin():
- ssh_pub_key = db.create(SSHPubKey, UserID=user.ID,
- Fingerprint="testFingerprint",
- PubKey="testPubKey")
+ ssh_pub_key = db.create(
+ SSHPubKey,
+ UserID=user.ID,
+ Fingerprint="testFingerprint",
+ PubKey="testPubKey",
+ )
assert user.ssh_pub_keys.first() == ssh_pub_key
@@ -283,8 +296,9 @@ def test_user_packages(user: User, package: Package):
assert package in user.packages()
-def test_can_edit_user(user: User, tu_user: User, dev_user: User,
- tu_and_dev_user: User):
+def test_can_edit_user(
+ user: User, tu_user: User, dev_user: User, tu_and_dev_user: User
+):
# User can edit.
assert user.can_edit_user(user)
diff --git a/test/test_usermaint.py b/test/test_usermaint.py
index e572569a..7d7bd135 100644
--- a/test/test_usermaint.py
+++ b/test/test_usermaint.py
@@ -14,13 +14,18 @@ def setup(db_test):
@pytest.fixture
def user() -> User:
with db.begin():
- user = db.create(User, Username="test", Email="test@example.org",
- Passwd="testPassword", AccountTypeID=USER_ID)
+ user = db.create(
+ User,
+ Username="test",
+ Email="test@example.org",
+ Passwd="testPassword",
+ AccountTypeID=USER_ID,
+ )
yield user
def test_usermaint_noop(user: User):
- """ Last[SSH]Login isn't expired in this test: usermaint is noop. """
+ """Last[SSH]Login isn't expired in this test: usermaint is noop."""
now = time.utcnow()
with db.begin():
diff --git a/test/test_util.py b/test/test_util.py
index ae1de81b..686e35b4 100644
--- a/test/test_util.py
+++ b/test/test_util.py
@@ -1,10 +1,8 @@
import json
-
from http import HTTPStatus
import fastapi
import pytest
-
from fastapi.responses import JSONResponse
from aurweb import filters, util
@@ -18,7 +16,7 @@ def test_round():
def test_git_search():
- """ Test that git_search matches the full commit if necessary. """
+ """Test that git_search matches the full commit if necessary."""
commit_hash = "0123456789abcdef"
repo = {commit_hash}
prefixlen = util.git_search(repo, commit_hash)
@@ -26,7 +24,7 @@ def test_git_search():
def test_git_search_double_commit():
- """ Test that git_search matches a shorter prefix length. """
+ """Test that git_search matches a shorter prefix length."""
commit_hash = "0123456789abcdef"
repo = {commit_hash[:13]}
# Locate the shortest prefix length that matches commit_hash.
@@ -36,7 +34,6 @@ def test_git_search_double_commit():
@pytest.mark.asyncio
async def test_error_or_result():
-
async def route(request: fastapi.Request):
raise RuntimeError("No response returned.")
diff --git a/util/fix-coverage b/util/fix-coverage
index 3446c4af..77cf29c1 100755
--- a/util/fix-coverage
+++ b/util/fix-coverage
@@ -48,9 +48,8 @@ def main():
files[i] = path
for _, i in enumerate(files.keys()):
- new_path = re.sub(r'^/aurweb', aurwebdir, files[i])
- cursor.execute("UPDATE file SET path = ? WHERE id = ?", (
- new_path, i))
+ new_path = re.sub(r"^/aurweb", aurwebdir, files[i])
+ cursor.execute("UPDATE file SET path = ? WHERE id = ?", (new_path, i))
db.commit()
db.close()
diff --git a/web/html/503.php b/web/html/503.php
index 80eb4369..23e7014e 100644
--- a/web/html/503.php
+++ b/web/html/503.php
@@ -12,4 +12,3 @@ html_header( __("Service Unavailable") );
-
diff --git a/web/template/flag_comment.php b/web/template/flag_comment.php
index 05eeacb2..dc285a97 100644
--- a/web/template/flag_comment.php
+++ b/web/template/flag_comment.php
@@ -24,4 +24,3 @@
-
diff --git a/web/template/header.php b/web/template/header.php
index afe7a9b6..9631be91 100644
--- a/web/template/header.php
+++ b/web/template/header.php
@@ -80,4 +80,3 @@
-
diff --git a/web/template/pkgreq_close_form.php b/web/template/pkgreq_close_form.php
index 6077b325..6228f6ab 100644
--- a/web/template/pkgreq_close_form.php
+++ b/web/template/pkgreq_close_form.php
@@ -29,4 +29,3 @@
-
diff --git a/web/template/template.phps b/web/template/template.phps
index 4f8117c8..f1a0bb0d 100644
--- a/web/template/template.phps
+++ b/web/template/template.phps
@@ -17,4 +17,3 @@ print __("Hi, this is worth reading!")."
\n";
html_footer(AURWEB_VERSION);
-