From 2373bdf400d1f55542024e7576f9b3d53e34525a Mon Sep 17 00:00:00 2001 From: moson-mo Date: Mon, 6 Feb 2023 09:12:00 +0100 Subject: [PATCH 001/178] fix(deps): bump pre-commit hooks Bump hooks with "pre-commit autoupdate". There is an issue with the latest poetry version and the "isort" hook module https://github.com/PyCQA/isort/issues/2077 Signed-off-by: moson-mo --- .pre-commit-config.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b2baec65..af14d704 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 + rev: v4.4.0 hooks: - id: check-added-large-files - id: check-case-conflict @@ -12,7 +12,7 @@ repos: - id: debug-statements - repo: https://github.com/myint/autoflake - rev: v1.7.7 + rev: v2.0.1 hooks: - id: autoflake args: @@ -21,16 +21,16 @@ repos: - --ignore-init-module-imports - repo: https://github.com/pycqa/isort - rev: 5.10.1 + rev: 5.12.0 hooks: - id: isort - repo: https://github.com/psf/black - rev: 22.10.0 + rev: 23.1.0 hooks: - id: black - repo: https://github.com/PyCQA/flake8 - rev: 5.0.4 + rev: 6.0.0 hooks: - id: flake8 From f9a5188fb7dbff771177937849482b3e41196b5b Mon Sep 17 00:00:00 2001 From: moson-mo Date: Mon, 6 Feb 2023 09:15:18 +0100 Subject: [PATCH 002/178] chore(lint): reformatting after black update Signed-off-by: moson-mo --- aurweb/auth/creds.py | 1 - aurweb/routers/packages.py | 1 - aurweb/routers/requests.py | 1 - aurweb/routers/rpc.py | 1 - aurweb/scripts/notify.py | 8 -------- test/test_mkpkglists.py | 6 +++--- test/test_packages_routes.py | 3 --- test/test_ratelimit.py | 1 - 8 files changed, 3 insertions(+), 19 deletions(-) diff --git a/aurweb/auth/creds.py b/aurweb/auth/creds.py index baa3b9bf..17d02a5b 100644 --- a/aurweb/auth/creds.py +++ b/aurweb/auth/creds.py @@ -75,7 +75,6 @@ cred_filters = { def has_credential(user: User, credential: int, approved: list = tuple()): - if user in approved: return True return user.AccountTypeID in cred_filters[credential] diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 837f9753..83bfe6e2 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -470,7 +470,6 @@ async def packages_post( 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. if action not in PACKAGE_ACTIONS: diff --git a/aurweb/routers/requests.py b/aurweb/routers/requests.py index 713f88d2..a259dd63 100644 --- a/aurweb/routers/requests.py +++ b/aurweb/routers/requests.py @@ -115,7 +115,6 @@ async def requests( @router.get("/requests/{id}/close") @requires_auth async def request_close(request: Request, id: int): - pkgreq = get_pkgreq_by_id(id) if not request.user.is_elevated() and request.user != pkgreq.User: # Request user doesn't have permission here: redirect to '/'. diff --git a/aurweb/routers/rpc.py b/aurweb/routers/rpc.py index f15b9781..1a960495 100644 --- a/aurweb/routers/rpc.py +++ b/aurweb/routers/rpc.py @@ -96,7 +96,6 @@ async def rpc_request( args: Optional[list[str]] = [], callback: Optional[str] = None, ): - # Create a handle to our RPC class. rpc = RPC(version=v, type=type) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index 93108cd3..ac9022c3 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -131,7 +131,6 @@ class Notification: class ResetKeyNotification(Notification): def __init__(self, uid): - user = ( db.query(User) .filter(and_(User.ID == uid, User.Suspended == 0)) @@ -194,7 +193,6 @@ class WelcomeNotification(ResetKeyNotification): 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 @@ -260,7 +258,6 @@ class CommentNotification(Notification): 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 @@ -319,7 +316,6 @@ class UpdateNotification(Notification): 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 @@ -375,7 +371,6 @@ class FlagNotification(Notification): 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 @@ -437,7 +432,6 @@ class DisownNotification(OwnershipEventNotification): class ComaintainershipEventNotification(Notification): def __init__(self, uid, pkgbase_id): - self._pkgbase = ( db.query(PackageBase.Name).filter(PackageBase.ID == pkgbase_id).first().Name ) @@ -482,7 +476,6 @@ class ComaintainerRemoveNotification(ComaintainershipEventNotification): 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) @@ -560,7 +553,6 @@ class DeleteNotification(Notification): 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 diff --git a/test/test_mkpkglists.py b/test/test_mkpkglists.py index 8edbcd81..310d9b04 100644 --- a/test/test_mkpkglists.py +++ b/test/test_mkpkglists.py @@ -131,7 +131,7 @@ def test_mkpkglists( (USERS, "test\n"), ] - for (file, expected_content) in expectations: + for file, expected_content in expectations: with gzip.open(file, "r") as f: file_content = f.read().decode() assert file_content == expected_content @@ -172,7 +172,7 @@ def test_mkpkglists_extended_empty(config_mock: None): (META_EXT, "[\n]"), ] - for (file, expected_content) in expectations: + for file, expected_content in expectations: with gzip.open(file, "r") as f: file_content = f.read().decode() assert file_content == expected_content, f"{file=} contents malformed" @@ -209,7 +209,7 @@ def test_mkpkglists_extended(config_mock: None, user: User, packages: list[Packa (USERS, "test\n"), ] - for (file, expected_content) in expectations: + for file, expected_content in expectations: with gzip.open(file, "r") as f: file_content = f.read().decode() assert file_content == expected_content diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index f21358f8..d4b0babc 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -322,7 +322,6 @@ def test_package(client: TestClient, package: Package): def test_package_split_description(client: TestClient, user: User): - with db.begin(): pkgbase = db.create( PackageBase, @@ -1178,7 +1177,6 @@ def test_packages_per_page(client: TestClient, maintainer: User): def test_packages_post_unknown_action(client: TestClient, user: User, package: Package): - cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: request.cookies = cookies @@ -1366,7 +1364,6 @@ def test_packages_post_unnotify(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: diff --git a/test/test_ratelimit.py b/test/test_ratelimit.py index b7cd7e7d..ab940773 100644 --- a/test/test_ratelimit.py +++ b/test/test_ratelimit.py @@ -107,7 +107,6 @@ def test_ratelimit_db( getint: mock.MagicMock, pipeline: Pipeline, ): - # We'll need a Request for everything here. request = Request() From cb16f42a27491bc0a2efa73bdf9aeda5efca0bb9 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Mon, 6 Feb 2023 16:40:43 +0000 Subject: [PATCH 003/178] fix: validate timezone before use Signed-off-by: Leonidas Spyropoulos --- aurweb/templates.py | 14 +++++++++++--- aurweb/testing/requests.py | 9 ++++++++- test/setup.sh | 1 + test/test_templates.py | 20 ++++++++++++++++++++ 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/aurweb/templates.py b/aurweb/templates.py index 781826ea..89316d6d 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -3,6 +3,7 @@ import functools import os from http import HTTPStatus from typing import Callable +from zoneinfo import ZoneInfoNotFoundError import jinja2 from fastapi import Request @@ -19,6 +20,8 @@ _env = jinja2.Environment( loader=_loader, autoescape=True, extensions=["jinja2.ext.i18n"] ) +DEFAULT_TIMEZONE = aurweb.config.get("options", "default_timezone") + def register_filter(name: str) -> Callable: """A decorator that can be used to register a filter. @@ -72,7 +75,10 @@ def make_context(request: Request, title: str, next: str = None): # Shorten commit_hash to a short Git hash. commit_hash = commit_hash[:7] - timezone = time.get_request_timezone(request) + try: + timezone = time.get_request_timezone(request) + except ZoneInfoNotFoundError: + timezone = DEFAULT_TIMEZONE language = l10n.get_request_language(request) return { "request": request, @@ -104,8 +110,10 @@ async def make_variable_context(request: Request, title: str, next: str = None): ) for k, v in to_copy.items(): - context[k] = v - + if k == "timezone": + context[k] = v if v in time.SUPPORTED_TIMEZONES else DEFAULT_TIMEZONE + else: + context[k] = v context["q"] = dict(request.query_params) return context diff --git a/aurweb/testing/requests.py b/aurweb/testing/requests.py index 98312e9e..da463928 100644 --- a/aurweb/testing/requests.py +++ b/aurweb/testing/requests.py @@ -23,7 +23,10 @@ class Client: class URL: - path = "/" + path: str + + def __init__(self, path: str = "/"): + self.path = path class Request: @@ -39,6 +42,8 @@ class Request: method: str = "GET", headers: dict[str, str] = dict(), cookies: dict[str, str] = dict(), + url: str = "/", + query_params: dict[str, str] = dict(), ) -> "Request": self.user = user self.user.authenticated = authenticated @@ -46,3 +51,5 @@ class Request: self.method = method.upper() self.headers = headers self.cookies = cookies + self.url = URL(path=url) + self.query_params = query_params diff --git a/test/setup.sh b/test/setup.sh index 232c33b7..2db897bf 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -34,6 +34,7 @@ aurwebdir = $TOPLEVEL aur_location = https://aur.archlinux.org aur_request_ml = aur-requests@lists.archlinux.org enable-maintenance = 0 +default_timezone = UTC maintenance-exceptions = 127.0.0.1 commit_uri = https://aur.archlinux.org/cgit/aur.git/log/?h=%s&id=%s localedir = $TOPLEVEL/web/locale/ diff --git a/test/test_templates.py b/test/test_templates.py index 2ff31fc9..6e0d27ac 100644 --- a/test/test_templates.py +++ b/test/test_templates.py @@ -16,6 +16,7 @@ from aurweb.models.relation_type import PROVIDES_ID, REPLACES_ID from aurweb.templates import ( base_template, make_context, + make_variable_context, register_filter, register_function, ) @@ -348,3 +349,22 @@ def test_package_details_filled(user: User, package: Package): base = base_template("partials/packages/details.html") body = base.render(context, show_package_details=True) check_package_details(body, package) + + +def test_make_context_timezone(user: User, package: Package): + request = Request( + user=user, authenticated=True, url="/packages/test?timezone=foobar" + ) + context = make_context(request, "Test Details") + assert context["timezone"] in time.SUPPORTED_TIMEZONES + + +@pytest.mark.asyncio +async def test_make_variable_context_timezone(user: User, package: Package): + request = Request( + user=user, authenticated=True, url="/packages/test?timezone=foobar" + ) + context = await make_variable_context( + request, "Test Details", next="/packages/test" + ) + assert context["timezone"] in time.SUPPORTED_TIMEZONES From 45218c4ce73e656af1d9109ef508172bbb5fcaa4 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Wed, 8 Feb 2023 15:13:21 +0000 Subject: [PATCH 004/178] fix: per-page needs to be non zero Signed-off-by: Leonidas Spyropoulos --- aurweb/util.py | 2 +- test/test_util.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/aurweb/util.py b/aurweb/util.py index abf48938..d80b0311 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -103,7 +103,7 @@ def sanitize_params(offset_str: str, per_page_str: str) -> Tuple[int, int]: offset = defaults.O try: - per_page = defaults.PP if int(per_page_str) < 0 else int(per_page_str) + per_page = defaults.PP if int(per_page_str) <= 0 else int(per_page_str) except ValueError: per_page = defaults.PP diff --git a/test/test_util.py b/test/test_util.py index fefa659a..a138d912 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -130,6 +130,7 @@ fRSo6OFcejKc= ("", "", (0, 50)), ("-1", "100", (0, 100)), ("5", "-100", (5, 50)), + ("0", "0", (0, 50)), ], ) def test_sanitize_params(offset_str: str, per_page_str: str, expected: tuple[int, int]): From 68813abcf04103d9e814af39a659130ef707c0f0 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Sun, 19 Feb 2023 02:14:47 +0000 Subject: [PATCH 005/178] fix(RTL): make RTL layout properly displayed Closes: #290 Signed-off-by: Leonidas Spyropoulos --- web/html/css/archweb.css | 44 ++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/web/html/css/archweb.css b/web/html/css/archweb.css index d7150599..0c0b235d 100644 --- a/web/html/css/archweb.css +++ b/web/html/css/archweb.css @@ -345,11 +345,14 @@ dl { border-top: 1px dotted #bbb; } - [dir="rtl"] dl dt {float: right; padding-left: 15px;} + [dir="rtl"] dl dt { + float: right; + padding-left: 15px; + } dl dt { color: #333; - float:left; - padding-right:15px; + float: left; + padding-right: 15px; } /* forms and input styling */ @@ -502,7 +505,9 @@ table thead th.sorter-false { #news .more { font-weight: normal; } - + [dir="rtl"] #news .rss-icon { + float: left; + } #news .rss-icon { float: right; margin-top: 1em; @@ -514,7 +519,10 @@ table thead th.sorter-false { margin-top: 1.5em; border-bottom: 1px dotted #bbb; } - + [dir="rtl"] #news .timestamp { + float: left; + margin: -1.8em 0 0 0.5em; + } #news .timestamp { float: right; font-size: 0.85em; @@ -559,7 +567,9 @@ h3 span.arrow { padding: 0.1em 0; } - [dir="rtl"] #pkgsearch input {float: left;} + [dir="rtl"] #pkgsearch input { + float: left; + } #pkgsearch input { width: 10em; float: right; @@ -569,7 +579,11 @@ h3 span.arrow { border: 1px solid #09c; } - [dir="rtl"] .pkgsearch-typeahead {right:0;float:right;text-align: right;} + [dir="rtl"] .pkgsearch-typeahead { + right: 0; + float: right; + text-align: right; + } .pkgsearch-typeahead { position: absolute; @@ -606,7 +620,8 @@ h3 span.arrow { font-weight: normal; } [dir="rtl"] #pkg-updates .rss-icon { - float: left;} + float: left; + } #pkg-updates .rss-icon { float: right; margin: -2em 0 0 0; @@ -741,6 +756,9 @@ div.news-article .article-info { width: 100%; } /* max 4 columns, but possibly fewer if screen size doesn't allow for more */ + [dir="rtl"] #donor-list li { + float: right; + } #donor-list li { float: left; width: 25%; @@ -845,7 +863,7 @@ table.results { /* pkgdetails: details links that float on the right */ [dir="rtl"] #pkgdetails #detailslinks { - float: right; + float: left; } #pkgdetails #detailslinks { float: right; @@ -952,6 +970,7 @@ table.results { [dir="rtl"] #pkgdetails #pkgdeps { float: right; + width: 48%; margin-left: 2%; } @@ -973,6 +992,7 @@ table.results { [dir="rtl"] #pkgdetails #pkgreqs { float: right; + width: 48%; } #pkgdetails #pkgreqs { @@ -981,7 +1001,7 @@ table.results { } #pkgdetails #pkgfiles { - clear: left; + clear: both; padding-top: 1em; } @@ -1114,7 +1134,9 @@ table.dash-stats .key { } /* dev dashboard: admin actions (add news items, todo list, etc) */ -[dir="rtl"] ul.admin-actions {float: left;} +[dir="rtl"] ul.admin-actions { + float: left; +} ul.admin-actions { float: right; list-style: none; From b1a9efd552d164016c010fea179622edc22328fd Mon Sep 17 00:00:00 2001 From: moson-mo Date: Wed, 8 Feb 2023 17:48:09 +0100 Subject: [PATCH 006/178] housekeep(git): remove deprecated "setup-repo" command Marked as deprecated about 6 years ago. Time to bury it. Issue report: #428 Signed-off-by: moson-mo --- aurweb/git/serve.py | 8 -------- doc/git-interface.txt | 1 - test/t1200-git-serve.t | 15 ++++++++++----- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/aurweb/git/serve.py b/aurweb/git/serve.py index a12b6d6e..8dbbf3f7 100755 --- a/aurweb/git/serve.py +++ b/aurweb/git/serve.py @@ -573,13 +573,6 @@ def serve(action, cmdargv, user, privileged, remote_addr): # noqa: C901 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) - ) - create_pkgbase(cmdargv[1], user) elif action == "restore": checkarg(cmdargv, "repository name") @@ -636,7 +629,6 @@ def serve(action, cmdargv, user, privileged, remote_addr): # noqa: C901 "restore ": "Restore a deleted package base.", "set-comaintainers [...]": "Set package base co-maintainers.", "set-keywords [...]": "Change package base keywords.", - "setup-repo ": "Create a repository (deprecated).", "unflag ": "Remove out-of-date flag from a package base.", "unvote ": "Remove vote from a package base.", "vote ": "Vote for a package base.", diff --git a/doc/git-interface.txt b/doc/git-interface.txt index 8c6806f7..028ffd0d 100644 --- a/doc/git-interface.txt +++ b/doc/git-interface.txt @@ -53,7 +53,6 @@ The git-serve command, the "aurweb shell", provides different subcommands: * The restore command can be used to restore a deleted package base. * The set-comaintainers command modifies the co-maintainers of a package base. * The set-keywords command modifies the keywords assigned to a package base. -* The setup-repo command can be used to create a new repository. * The vote/unvote command can be used to vote/unvote for a package base. * The git-{receive,upload}-pack commands are redirected to git-shell(1). diff --git a/test/t1200-git-serve.t b/test/t1200-git-serve.t index f1657412..f65096db 100755 --- a/test/t1200-git-serve.t +++ b/test/t1200-git-serve.t @@ -56,11 +56,16 @@ test_expect_success 'Test IP address bans.' ' SSH_CLIENT="$SSH_CLIENT_ORIG" ' -test_expect_success 'Test setup-repo and list-repos.' ' - SSH_ORIGINAL_COMMAND="setup-repo foobar" AUR_USER=user \ - cover "$GIT_SERVE" 2>&1 && - SSH_ORIGINAL_COMMAND="setup-repo foobar2" AUR_USER=tu \ - cover "$GIT_SERVE" 2>&1 && +test_expect_success 'Test list-repos.' ' + # insert our test packages + echo "INSERT INTO PackageBases (Name, SubmittedTS, \ + ModifiedTS, SubmitterUID, MaintainerUID, FlaggerComment) \ + VALUES (\"foobar\", 0, 0, 1, 1, \"\");" | \ + sqlite3 aur.db + echo "INSERT INTO PackageBases (Name, SubmittedTS, \ + ModifiedTS, SubmitterUID, MaintainerUID, FlaggerComment) \ + VALUES (\"foobar2\", 0, 0, 2, 2, \"\");" | \ + sqlite3 aur.db cat >expected <<-EOF && *foobar EOF From 8d2e176c2f1a213cecc7520d5b4e57c89ede43d4 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Thu, 9 Feb 2023 19:09:07 +0100 Subject: [PATCH 007/178] housekeep: stop "pkgmaint" script (cron job) With the removal of the "setup-repo" command this script becomes obsolete, because it is not possible to reserve a repo anymore. Hence we don't need cleanup. We've also seen issues in case the last packager's user account is removed, leading to the deletion of a Package. Let's deactivate this for now. Issue report: #425 Signed-off-by: moson-mo --- aurweb/scripts/pkgmaint.py | 6 ++++++ test/test_pkgmaint.py | 13 +++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/aurweb/scripts/pkgmaint.py b/aurweb/scripts/pkgmaint.py index 9d7cf53b..3d695f8f 100755 --- a/aurweb/scripts/pkgmaint.py +++ b/aurweb/scripts/pkgmaint.py @@ -17,6 +17,12 @@ def _main(): def main(): + # Previously used to clean up "reserved" packages which never got pushed. + # Let's deactivate this for now since "setup-repo" is gone and we see + # other issue where deletion of a user account might cause unintended + # removal of a package (where PackagerUID account was deleted) + return + db.get_engine() with db.begin(): _main() diff --git a/test/test_pkgmaint.py b/test/test_pkgmaint.py index a0fece78..e427b664 100644 --- a/test/test_pkgmaint.py +++ b/test/test_pkgmaint.py @@ -62,7 +62,12 @@ def test_pkgmaint(packages: list[Package]): # Query package objects again and assert that the # first package was deleted but all others are intact. packages = db.query(Package).all() - assert len(packages) == 4 - expected = ["pkg_1", "pkg_2", "pkg_3", "pkg_4"] - for i, pkgname in enumerate(expected): - assert packages[i].Name == pkgname + + # !Cleanup of packages without last packager deactivated. + # We should still have 5 packages + assert len(packages) == 5 + + # assert len(packages) == 4 + # expected = ["pkg_1", "pkg_2", "pkg_3", "pkg_4"] + # for i, pkgname in enumerate(expected): + # assert packages[i].Name == pkgname From 0c5b4721d6c58c8e7dfbdff3b6a184c3017f64ca Mon Sep 17 00:00:00 2001 From: moson-mo Date: Thu, 9 Feb 2023 23:14:48 +0100 Subject: [PATCH 008/178] fix: include package data without "Last Packager" Data for packages that do not have a "Last Packager" (e.g. because the user account was deleted) should still be available from the /rpc and metadata archives. Signed-off-by: moson-mo --- aurweb/archives/spec/pkgbases.py | 8 +------- aurweb/archives/spec/pkgnames.py | 2 -- aurweb/packages/search.py | 2 +- aurweb/packages/util.py | 1 - aurweb/routers/html.py | 24 +++++------------------- aurweb/rpc.py | 14 ++------------ aurweb/scripts/mkpkglists.py | 3 +-- test/test_rpc.py | 2 +- 8 files changed, 11 insertions(+), 45 deletions(-) diff --git a/aurweb/archives/spec/pkgbases.py b/aurweb/archives/spec/pkgbases.py index 9f02c1c6..db2085cc 100644 --- a/aurweb/archives/spec/pkgbases.py +++ b/aurweb/archives/spec/pkgbases.py @@ -15,13 +15,7 @@ class Spec(SpecBase): self.pkgbases_repo = GitInfo(config.get("git-archive", "pkgbases-repo")) def generate(self) -> Iterable[SpecOutput]: - filt = PackageBase.PackagerUID.isnot(None) - query = ( - db.query(PackageBase.Name) - .filter(filt) - .order_by(PackageBase.Name.asc()) - .all() - ) + query = db.query(PackageBase.Name).order_by(PackageBase.Name.asc()).all() pkgbases = [pkgbase.Name for pkgbase in query] self.add_output( diff --git a/aurweb/archives/spec/pkgnames.py b/aurweb/archives/spec/pkgnames.py index c7cd9ea7..3df62af6 100644 --- a/aurweb/archives/spec/pkgnames.py +++ b/aurweb/archives/spec/pkgnames.py @@ -15,11 +15,9 @@ class Spec(SpecBase): self.pkgnames_repo = GitInfo(config.get("git-archive", "pkgnames-repo")) def generate(self) -> Iterable[SpecOutput]: - filt = PackageBase.PackagerUID.isnot(None) query = ( db.query(Package.Name) .join(PackageBase, PackageBase.ID == Package.PackageBaseID) - .filter(filt) .order_by(Package.Name.asc()) .all() ) diff --git a/aurweb/packages/search.py b/aurweb/packages/search.py index d5e00110..62de1ea8 100644 --- a/aurweb/packages/search.py +++ b/aurweb/packages/search.py @@ -400,4 +400,4 @@ class RPCSearch(PackageSearch): return result def results(self) -> orm.Query: - return self.query.filter(models.PackageBase.PackagerUID.isnot(None)) + return self.query diff --git a/aurweb/packages/util.py b/aurweb/packages/util.py index e1d653bf..2cc00db9 100644 --- a/aurweb/packages/util.py +++ b/aurweb/packages/util.py @@ -135,7 +135,6 @@ def updated_packages(limit: int = 0, cache_ttl: int = 600) -> list[models.Packag query = ( db.query(models.Package) .join(models.PackageBase) - .filter(models.PackageBase.PackagerUID.isnot(None)) .order_by(models.PackageBase.ModifiedTS.desc()) ) diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index f5e6657f..33aeb904 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -12,7 +12,7 @@ from prometheus_client import ( generate_latest, multiprocess, ) -from sqlalchemy import and_, case, or_ +from sqlalchemy import case, or_ import aurweb.config import aurweb.models.package_request @@ -84,17 +84,11 @@ async def index(request: Request): cache_expire = 300 # Five minutes. # 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", bases, expire=cache_expire ) - query = bases.filter( - and_( - models.PackageBase.MaintainerUID.is_(None), - models.PackageBase.PackagerUID.isnot(None), - ) - ) + query = bases.filter(models.PackageBase.MaintainerUID.is_(None)) context["orphan_count"] = await db_count_cache( redis, "orphan_count", query, expire=cache_expire ) @@ -122,18 +116,10 @@ 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), - ) + models.PackageBase.ModifiedTS - models.PackageBase.SubmittedTS >= one_hour ) - query = bases.filter( - and_( - models.PackageBase.SubmittedTS >= seven_days_ago, - models.PackageBase.PackagerUID.isnot(None), - ) - ) + query = bases.filter(models.PackageBase.SubmittedTS >= seven_days_ago) context["seven_days_old_added"] = await db_count_cache( redis, "seven_days_old_added", query, expire=cache_expire ) diff --git a/aurweb/rpc.py b/aurweb/rpc.py index 1440703a..5fcbbb78 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -412,12 +412,7 @@ class RPC: packages = ( db.query(models.Package.Name) .join(models.PackageBase) - .filter( - and_( - models.PackageBase.PackagerUID.isnot(None), - models.Package.Name.like(f"{arg}%"), - ) - ) + .filter(models.Package.Name.like(f"{arg}%")) .order_by(models.Package.Name.asc()) .limit(20) ) @@ -430,12 +425,7 @@ class RPC: arg = args[0] packages = ( db.query(models.PackageBase.Name) - .filter( - and_( - models.PackageBase.PackagerUID.isnot(None), - models.PackageBase.Name.like(f"{arg}%"), - ) - ) + .filter(models.PackageBase.Name.like(f"{arg}%")) .order_by(models.PackageBase.Name.asc()) .limit(20) ) diff --git a/aurweb/scripts/mkpkglists.py b/aurweb/scripts/mkpkglists.py index d2d11c5e..d85a79b9 100755 --- a/aurweb/scripts/mkpkglists.py +++ b/aurweb/scripts/mkpkglists.py @@ -210,7 +210,6 @@ def _main(): .join(PackageBase, PackageBase.ID == Package.PackageBaseID) .join(User, PackageBase.MaintainerUID == User.ID, isouter=True) .join(Submitter, PackageBase.SubmitterUID == Submitter.ID, isouter=True) - .filter(PackageBase.PackagerUID.isnot(None)) .with_entities( Package.ID, Package.Name, @@ -294,7 +293,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).all() tmp_pkgbase = f"{PKGBASE}.tmp" pkgbase_gzip = gzip.GzipFile( filename=PKGBASE, mode="wb", fileobj=open(tmp_pkgbase, "wb") diff --git a/test/test_rpc.py b/test/test_rpc.py index 92714ff1..d33578d0 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -845,7 +845,7 @@ def test_rpc_msearch(client: TestClient, user: User, packages: list[Package]): params.pop("arg") response = request.get("/rpc", params=params) data = response.json() - assert data.get("resultcount") == 1 + assert data.get("resultcount") == 2 result = data.get("results")[0] assert result.get("Name") == "big-chungus" From 8aac84230738505f7b6b3d248470cbdd4cda504f Mon Sep 17 00:00:00 2001 From: moson-mo Date: Fri, 24 Feb 2023 10:11:33 +0100 Subject: [PATCH 009/178] fix(test): use single-quotes for strings in sql statements Currently, in the sharness test suites, we use double-quotes for string literals in SQL statements passed to sqlite3. With sqlite version 3.41 the usage of double-quotes for string literals is deactivated by default: We'll need to switch to single-quotes in our tests. Ref: Section 6.f. at https://www.sqlite.org/releaselog/3_41_0.html Signed-off-by: moson-mo --- test/t1200-git-serve.t | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/test/t1200-git-serve.t b/test/t1200-git-serve.t index f65096db..dbb465bc 100755 --- a/test/t1200-git-serve.t +++ b/test/t1200-git-serve.t @@ -38,7 +38,7 @@ test_expect_success 'Test IP address logging.' ' cat >expected <<-EOF && 1.2.3.4 EOF - echo "SELECT LastSSHLoginIPAddress FROM Users WHERE UserName = \"user\";" | \ + echo "SELECT LastSSHLoginIPAddress FROM Users WHERE UserName = '"'"'user'"'"';" | \ sqlite3 aur.db >actual && test_cmp expected actual ' @@ -60,11 +60,11 @@ test_expect_success 'Test list-repos.' ' # insert our test packages echo "INSERT INTO PackageBases (Name, SubmittedTS, \ ModifiedTS, SubmitterUID, MaintainerUID, FlaggerComment) \ - VALUES (\"foobar\", 0, 0, 1, 1, \"\");" | \ + VALUES ('"'"'foobar'"'"', 0, 0, 1, 1, '"'"''"'"');" | \ sqlite3 aur.db echo "INSERT INTO PackageBases (Name, SubmittedTS, \ ModifiedTS, SubmitterUID, MaintainerUID, FlaggerComment) \ - VALUES (\"foobar2\", 0, 0, 2, 2, \"\");" | \ + VALUES ('"'"'foobar2'"'"', 0, 0, 2, 2, '"'"''"'"');" | \ sqlite3 aur.db cat >expected <<-EOF && *foobar @@ -137,7 +137,7 @@ test_expect_success "Try to push to someone else's repository as Trusted User." ' test_expect_success "Test restore." ' - echo "DELETE FROM PackageBases WHERE Name = \"foobar\";" | \ + echo "DELETE FROM PackageBases WHERE Name = '"'"'foobar'"'"';" | \ sqlite3 aur.db && cat >expected <<-EOF && user @@ -373,9 +373,9 @@ test_expect_success "Check whether package requests are closed when disowning." SSH_ORIGINAL_COMMAND="adopt foobar" AUR_USER=user AUR_PRIVILEGED=0 \ cover "$GIT_SERVE" 2>&1 && cat <<-EOD | sqlite3 aur.db && - INSERT INTO PackageRequests (ID, ReqTypeID, PackageBaseID, PackageBaseName, UsersID, Comments, ClosureComment) VALUES (1, 2, 3, "foobar", 4, "", ""); - INSERT INTO PackageRequests (ID, ReqTypeID, PackageBaseID, PackageBaseName, UsersID, Comments, ClosureComment) VALUES (2, 3, 3, "foobar", 5, "", ""); - INSERT INTO PackageRequests (ID, ReqTypeID, PackageBaseID, PackageBaseName, UsersID, Comments, ClosureComment) VALUES (3, 2, 2, "foobar2", 6, "", ""); + INSERT INTO PackageRequests (ID, ReqTypeID, PackageBaseID, PackageBaseName, UsersID, Comments, ClosureComment) VALUES (1, 2, 3, '"'"'foobar'"'"', 4, '"'"''"'"', '"'"''"'"'); + INSERT INTO PackageRequests (ID, ReqTypeID, PackageBaseID, PackageBaseName, UsersID, Comments, ClosureComment) VALUES (2, 3, 3, '"'"'foobar'"'"', 5, '"'"''"'"', '"'"''"'"'); + INSERT INTO PackageRequests (ID, ReqTypeID, PackageBaseID, PackageBaseName, UsersID, Comments, ClosureComment) VALUES (3, 2, 2, '"'"'foobar2'"'"', 6, '"'"''"'"', '"'"''"'"'); EOD >sendmail.out && SSH_ORIGINAL_COMMAND="disown foobar" AUR_USER=user AUR_PRIVILEGED=0 \ @@ -469,7 +469,7 @@ test_expect_success "Vote for a package base." ' cat >expected <<-EOF && 1 EOF - echo "SELECT NumVotes FROM PackageBases WHERE Name = \"foobar\";" | \ + echo "SELECT NumVotes FROM PackageBases WHERE Name = '"'"'foobar'"'"';" | \ sqlite3 aur.db >actual && test_cmp expected actual ' @@ -487,7 +487,7 @@ test_expect_success "Vote for a package base twice." ' cat >expected <<-EOF && 1 EOF - echo "SELECT NumVotes FROM PackageBases WHERE Name = \"foobar\";" | \ + echo "SELECT NumVotes FROM PackageBases WHERE Name = '"'"'foobar'"'"';" | \ sqlite3 aur.db >actual && test_cmp expected actual ' @@ -503,7 +503,7 @@ test_expect_success "Remove vote from a package base." ' cat >expected <<-EOF && 0 EOF - echo "SELECT NumVotes FROM PackageBases WHERE Name = \"foobar\";" | \ + echo "SELECT NumVotes FROM PackageBases WHERE Name = '"'"'foobar'"'"';" | \ sqlite3 aur.db >actual && test_cmp expected actual ' @@ -521,7 +521,7 @@ test_expect_success "Try to remove the vote again." ' cat >expected <<-EOF && 0 EOF - echo "SELECT NumVotes FROM PackageBases WHERE Name = \"foobar\";" | \ + echo "SELECT NumVotes FROM PackageBases WHERE Name = '"'"'foobar'"'"';" | \ sqlite3 aur.db >actual && test_cmp expected actual ' From 7d06c9ab97e4b3dae13db97290494045833a9b75 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Wed, 1 Mar 2023 18:04:20 +0100 Subject: [PATCH 010/178] fix: encode package name in URL for source files Package(Base) names might include characters that require url-encoding Signed-off-by: moson-mo --- aurweb/packages/util.py | 3 ++- test/test_packages_util.py | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/aurweb/packages/util.py b/aurweb/packages/util.py index 2cc00db9..78d79508 100644 --- a/aurweb/packages/util.py +++ b/aurweb/packages/util.py @@ -1,6 +1,7 @@ from collections import defaultdict from http import HTTPStatus from typing import Tuple, Union +from urllib.parse import quote_plus import orjson from fastapi import HTTPException @@ -246,5 +247,5 @@ def source_uri(pkgsrc: models.PackageSource) -> Tuple[str, str]: elif "://" in pkgsrc.Source: return pkgsrc.Source, pkgsrc.Source path = config.get("options", "source_file_uri") - pkgbasename = pkgsrc.Package.PackageBase.Name + pkgbasename = quote_plus(pkgsrc.Package.PackageBase.Name) return pkgsrc.Source, path % (pkgsrc.Source, pkgbasename) diff --git a/test/test_packages_util.py b/test/test_packages_util.py index 23e85e1b..bae84614 100644 --- a/test/test_packages_util.py +++ b/test/test_packages_util.py @@ -109,6 +109,12 @@ def test_source_uri_file(package: Package): expected = source_file_uri % (pkgsrc.Source, package.PackageBase.Name) assert (file, uri) == (FILE, expected) + # test URL encoding + pkgsrc.Package.PackageBase.Name = "test++" + file, uri = util.source_uri(pkgsrc) + expected = source_file_uri % (pkgsrc.Source, "test%2B%2B") + assert uri == expected + def test_source_uri_named_uri(package: Package): FILE = "test" From c0390240bcf062626b3944e39cb6c6ce37ad5d55 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sat, 4 Mar 2023 09:52:22 +0100 Subject: [PATCH 011/178] housekeep(deps): bump dependencies update all poetry deps to the latest version (except of sqlalchemy) Signed-off-by: moson-mo --- poetry.lock | 586 +++++++++++++++++++++++++------------------------ pyproject.toml | 60 ++--- 2 files changed, 324 insertions(+), 322 deletions(-) diff --git a/poetry.lock b/poetry.lock index 4b98d288..75d6dcf3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,27 +1,27 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. +# This file is automatically @generated by Poetry 1.4.0 and should not be changed by hand. [[package]] name = "aiofiles" -version = "22.1.0" +version = "23.1.0" description = "File support for asyncio." category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "aiofiles-22.1.0-py3-none-any.whl", hash = "sha256:1142fa8e80dbae46bb6339573ad4c8c0841358f79c6eb50a493dceca14621bad"}, - {file = "aiofiles-22.1.0.tar.gz", hash = "sha256:9107f1ca0b2a5553987a94a3c9959fe5b491fdf731389aa5b7b1bd0733e32de6"}, + {file = "aiofiles-23.1.0-py3-none-any.whl", hash = "sha256:9312414ae06472eb6f1d163f555e466a23aed1c8f60c30cccf7121dba2e53eb2"}, + {file = "aiofiles-23.1.0.tar.gz", hash = "sha256:edd247df9a19e0db16534d4baaf536d6609a43e1de5401d7a4c1c148753a1635"}, ] [[package]] name = "alembic" -version = "1.9.2" +version = "1.9.4" description = "A database migration tool for SQLAlchemy." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "alembic-1.9.2-py3-none-any.whl", hash = "sha256:e8a6ff9f3b1887e1fed68bfb8fb9a000d8f61c21bdcc85b67bb9f87fcbc4fce3"}, - {file = "alembic-1.9.2.tar.gz", hash = "sha256:6880dec4f28dd7bd999d2ed13fbe7c9d4337700a44d11a524c0ce0c59aaf0dbd"}, + {file = "alembic-1.9.4-py3-none-any.whl", hash = "sha256:6f1c2207369bf4f49f952057a33bb017fbe5c148c2a773b46906b806ea6e825f"}, + {file = "alembic-1.9.4.tar.gz", hash = "sha256:4d3bd32ecdbb7bbfb48a9fe9e6d6fd6a831a1b59d03e26e292210237373e7db5"}, ] [package.dependencies] @@ -383,63 +383,63 @@ files = [ [[package]] name = "coverage" -version = "7.1.0" +version = "7.2.1" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "coverage-7.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3b946bbcd5a8231383450b195cfb58cb01cbe7f8949f5758566b881df4b33baf"}, - {file = "coverage-7.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ec8e767f13be637d056f7e07e61d089e555f719b387a7070154ad80a0ff31801"}, - {file = "coverage-7.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4a5a5879a939cb84959d86869132b00176197ca561c664fc21478c1eee60d75"}, - {file = "coverage-7.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b643cb30821e7570c0aaf54feaf0bfb630b79059f85741843e9dc23f33aaca2c"}, - {file = "coverage-7.1.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32df215215f3af2c1617a55dbdfb403b772d463d54d219985ac7cd3bf124cada"}, - {file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:33d1ae9d4079e05ac4cc1ef9e20c648f5afabf1a92adfaf2ccf509c50b85717f"}, - {file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:29571503c37f2ef2138a306d23e7270687c0efb9cab4bd8038d609b5c2393a3a"}, - {file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:63ffd21aa133ff48c4dff7adcc46b7ec8b565491bfc371212122dd999812ea1c"}, - {file = "coverage-7.1.0-cp310-cp310-win32.whl", hash = "sha256:4b14d5e09c656de5038a3f9bfe5228f53439282abcab87317c9f7f1acb280352"}, - {file = "coverage-7.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:8361be1c2c073919500b6601220a6f2f98ea0b6d2fec5014c1d9cfa23dd07038"}, - {file = "coverage-7.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:da9b41d4539eefd408c46725fb76ecba3a50a3367cafb7dea5f250d0653c1040"}, - {file = "coverage-7.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5b15ed7644ae4bee0ecf74fee95808dcc34ba6ace87e8dfbf5cb0dc20eab45a"}, - {file = "coverage-7.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d12d076582507ea460ea2a89a8c85cb558f83406c8a41dd641d7be9a32e1274f"}, - {file = "coverage-7.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2617759031dae1bf183c16cef8fcfb3de7617f394c813fa5e8e46e9b82d4222"}, - {file = "coverage-7.1.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4e4881fa9e9667afcc742f0c244d9364d197490fbc91d12ac3b5de0bf2df146"}, - {file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9d58885215094ab4a86a6aef044e42994a2bd76a446dc59b352622655ba6621b"}, - {file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ffeeb38ee4a80a30a6877c5c4c359e5498eec095878f1581453202bfacc8fbc2"}, - {file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3baf5f126f30781b5e93dbefcc8271cb2491647f8283f20ac54d12161dff080e"}, - {file = "coverage-7.1.0-cp311-cp311-win32.whl", hash = "sha256:ded59300d6330be27bc6cf0b74b89ada58069ced87c48eaf9344e5e84b0072f7"}, - {file = "coverage-7.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:6a43c7823cd7427b4ed763aa7fb63901ca8288591323b58c9cd6ec31ad910f3c"}, - {file = "coverage-7.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7a726d742816cb3a8973c8c9a97539c734b3a309345236cd533c4883dda05b8d"}, - {file = "coverage-7.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc7c85a150501286f8b56bd8ed3aa4093f4b88fb68c0843d21ff9656f0009d6a"}, - {file = "coverage-7.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5b4198d85a3755d27e64c52f8c95d6333119e49fd001ae5798dac872c95e0f8"}, - {file = "coverage-7.1.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddb726cb861c3117a553f940372a495fe1078249ff5f8a5478c0576c7be12050"}, - {file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:51b236e764840a6df0661b67e50697aaa0e7d4124ca95e5058fa3d7cbc240b7c"}, - {file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7ee5c9bb51695f80878faaa5598040dd6c9e172ddcf490382e8aedb8ec3fec8d"}, - {file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c31b75ae466c053a98bf26843563b3b3517b8f37da4d47b1c582fdc703112bc3"}, - {file = "coverage-7.1.0-cp37-cp37m-win32.whl", hash = "sha256:3b155caf3760408d1cb903b21e6a97ad4e2bdad43cbc265e3ce0afb8e0057e73"}, - {file = "coverage-7.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2a60d6513781e87047c3e630b33b4d1e89f39836dac6e069ffee28c4786715f5"}, - {file = "coverage-7.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f2cba5c6db29ce991029b5e4ac51eb36774458f0a3b8d3137241b32d1bb91f06"}, - {file = "coverage-7.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:beeb129cacea34490ffd4d6153af70509aa3cda20fdda2ea1a2be870dfec8d52"}, - {file = "coverage-7.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c45948f613d5d18c9ec5eaa203ce06a653334cf1bd47c783a12d0dd4fd9c851"}, - {file = "coverage-7.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef382417db92ba23dfb5864a3fc9be27ea4894e86620d342a116b243ade5d35d"}, - {file = "coverage-7.1.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c7c0d0827e853315c9bbd43c1162c006dd808dbbe297db7ae66cd17b07830f0"}, - {file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e5cdbb5cafcedea04924568d990e20ce7f1945a1dd54b560f879ee2d57226912"}, - {file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9817733f0d3ea91bea80de0f79ef971ae94f81ca52f9b66500c6a2fea8e4b4f8"}, - {file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:218fe982371ac7387304153ecd51205f14e9d731b34fb0568181abaf7b443ba0"}, - {file = "coverage-7.1.0-cp38-cp38-win32.whl", hash = "sha256:04481245ef966fbd24ae9b9e537ce899ae584d521dfbe78f89cad003c38ca2ab"}, - {file = "coverage-7.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:8ae125d1134bf236acba8b83e74c603d1b30e207266121e76484562bc816344c"}, - {file = "coverage-7.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2bf1d5f2084c3932b56b962a683074a3692bce7cabd3aa023c987a2a8e7612f6"}, - {file = "coverage-7.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:98b85dd86514d889a2e3dd22ab3c18c9d0019e696478391d86708b805f4ea0fa"}, - {file = "coverage-7.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38da2db80cc505a611938d8624801158e409928b136c8916cd2e203970dde4dc"}, - {file = "coverage-7.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3164d31078fa9efe406e198aecd2a02d32a62fecbdef74f76dad6a46c7e48311"}, - {file = "coverage-7.1.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db61a79c07331e88b9a9974815c075fbd812bc9dbc4dc44b366b5368a2936063"}, - {file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ccb092c9ede70b2517a57382a601619d20981f56f440eae7e4d7eaafd1d1d09"}, - {file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:33ff26d0f6cc3ca8de13d14fde1ff8efe1456b53e3f0273e63cc8b3c84a063d8"}, - {file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d47dd659a4ee952e90dc56c97d78132573dc5c7b09d61b416a9deef4ebe01a0c"}, - {file = "coverage-7.1.0-cp39-cp39-win32.whl", hash = "sha256:d248cd4a92065a4d4543b8331660121b31c4148dd00a691bfb7a5cdc7483cfa4"}, - {file = "coverage-7.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:7ed681b0f8e8bcbbffa58ba26fcf5dbc8f79e7997595bf071ed5430d8c08d6f3"}, - {file = "coverage-7.1.0-pp37.pp38.pp39-none-any.whl", hash = "sha256:755e89e32376c850f826c425ece2c35a4fc266c081490eb0a841e7c1cb0d3bda"}, - {file = "coverage-7.1.0.tar.gz", hash = "sha256:10188fe543560ec4874f974b5305cd1a8bdcfa885ee00ea3a03733464c4ca265"}, + {file = "coverage-7.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:49567ec91fc5e0b15356da07a2feabb421d62f52a9fff4b1ec40e9e19772f5f8"}, + {file = "coverage-7.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d2ef6cae70168815ed91388948b5f4fcc69681480a0061114db737f957719f03"}, + {file = "coverage-7.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3004765bca3acd9e015794e5c2f0c9a05587f5e698127ff95e9cfba0d3f29339"}, + {file = "coverage-7.2.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cca7c0b7f5881dfe0291ef09ba7bb1582cb92ab0aeffd8afb00c700bf692415a"}, + {file = "coverage-7.2.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2167d116309f564af56f9aa5e75ef710ef871c5f9b313a83050035097b56820"}, + {file = "coverage-7.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cb5f152fb14857cbe7f3e8c9a5d98979c4c66319a33cad6e617f0067c9accdc4"}, + {file = "coverage-7.2.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:87dc37f16fb5e3a28429e094145bf7c1753e32bb50f662722e378c5851f7fdc6"}, + {file = "coverage-7.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e191a63a05851f8bce77bc875e75457f9b01d42843f8bd7feed2fc26bbe60833"}, + {file = "coverage-7.2.1-cp310-cp310-win32.whl", hash = "sha256:e3ea04b23b114572b98a88c85379e9e9ae031272ba1fb9b532aa934c621626d4"}, + {file = "coverage-7.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:0cf557827be7eca1c38a2480484d706693e7bb1929e129785fe59ec155a59de6"}, + {file = "coverage-7.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:570c21a29493b350f591a4b04c158ce1601e8d18bdcd21db136fbb135d75efa6"}, + {file = "coverage-7.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9e872b082b32065ac2834149dc0adc2a2e6d8203080501e1e3c3c77851b466f9"}, + {file = "coverage-7.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fac6343bae03b176e9b58104a9810df3cdccd5cfed19f99adfa807ffbf43cf9b"}, + {file = "coverage-7.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abacd0a738e71b20e224861bc87e819ef46fedba2fb01bc1af83dfd122e9c319"}, + {file = "coverage-7.2.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9256d4c60c4bbfec92721b51579c50f9e5062c21c12bec56b55292464873508"}, + {file = "coverage-7.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:80559eaf6c15ce3da10edb7977a1548b393db36cbc6cf417633eca05d84dd1ed"}, + {file = "coverage-7.2.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:0bd7e628f6c3ec4e7d2d24ec0e50aae4e5ae95ea644e849d92ae4805650b4c4e"}, + {file = "coverage-7.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09643fb0df8e29f7417adc3f40aaf379d071ee8f0350ab290517c7004f05360b"}, + {file = "coverage-7.2.1-cp311-cp311-win32.whl", hash = "sha256:1b7fb13850ecb29b62a447ac3516c777b0e7a09ecb0f4bb6718a8654c87dfc80"}, + {file = "coverage-7.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:617a94ada56bbfe547aa8d1b1a2b8299e2ec1ba14aac1d4b26a9f7d6158e1273"}, + {file = "coverage-7.2.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8649371570551d2fd7dee22cfbf0b61f1747cdfb2b7587bb551e4beaaa44cb97"}, + {file = "coverage-7.2.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d2b9b5e70a21474c105a133ba227c61bc95f2ac3b66861143ce39a5ea4b3f84"}, + {file = "coverage-7.2.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae82c988954722fa07ec5045c57b6d55bc1a0890defb57cf4a712ced65b26ddd"}, + {file = "coverage-7.2.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:861cc85dfbf55a7a768443d90a07e0ac5207704a9f97a8eb753292a7fcbdfcfc"}, + {file = "coverage-7.2.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0339dc3237c0d31c3b574f19c57985fcbe494280153bbcad33f2cdf469f4ac3e"}, + {file = "coverage-7.2.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:5928b85416a388dd557ddc006425b0c37e8468bd1c3dc118c1a3de42f59e2a54"}, + {file = "coverage-7.2.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8d3843ca645f62c426c3d272902b9de90558e9886f15ddf5efe757b12dd376f5"}, + {file = "coverage-7.2.1-cp37-cp37m-win32.whl", hash = "sha256:6a034480e9ebd4e83d1aa0453fd78986414b5d237aea89a8fdc35d330aa13bae"}, + {file = "coverage-7.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:6fce673f79a0e017a4dc35e18dc7bb90bf6d307c67a11ad5e61ca8d42b87cbff"}, + {file = "coverage-7.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7f099da6958ddfa2ed84bddea7515cb248583292e16bb9231d151cd528eab657"}, + {file = "coverage-7.2.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:97a3189e019d27e914ecf5c5247ea9f13261d22c3bb0cfcfd2a9b179bb36f8b1"}, + {file = "coverage-7.2.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a81dbcf6c6c877986083d00b834ac1e84b375220207a059ad45d12f6e518a4e3"}, + {file = "coverage-7.2.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78d2c3dde4c0b9be4b02067185136b7ee4681978228ad5ec1278fa74f5ca3e99"}, + {file = "coverage-7.2.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a209d512d157379cc9ab697cbdbb4cfd18daa3e7eebaa84c3d20b6af0037384"}, + {file = "coverage-7.2.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f3d07edb912a978915576a776756069dede66d012baa503022d3a0adba1b6afa"}, + {file = "coverage-7.2.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8dca3c1706670297851bca1acff9618455122246bdae623be31eca744ade05ec"}, + {file = "coverage-7.2.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b1991a6d64231a3e5bbe3099fb0dd7c9aeaa4275ad0e0aeff4cb9ef885c62ba2"}, + {file = "coverage-7.2.1-cp38-cp38-win32.whl", hash = "sha256:22c308bc508372576ffa3d2dbc4824bb70d28eeb4fcd79d4d1aed663a06630d0"}, + {file = "coverage-7.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:b0c0d46de5dd97f6c2d1b560bf0fcf0215658097b604f1840365296302a9d1fb"}, + {file = "coverage-7.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4dd34a935de268a133e4741827ae951283a28c0125ddcdbcbba41c4b98f2dfef"}, + {file = "coverage-7.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0f8318ed0f3c376cfad8d3520f496946977abde080439d6689d7799791457454"}, + {file = "coverage-7.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:834c2172edff5a08d78e2f53cf5e7164aacabeb66b369f76e7bb367ca4e2d993"}, + {file = "coverage-7.2.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4d70c853f0546855f027890b77854508bdb4d6a81242a9d804482e667fff6e6"}, + {file = "coverage-7.2.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a6450da4c7afc4534305b2b7d8650131e130610cea448ff240b6ab73d7eab63"}, + {file = "coverage-7.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:99f4dd81b2bb8fc67c3da68b1f5ee1650aca06faa585cbc6818dbf67893c6d58"}, + {file = "coverage-7.2.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bdd3f2f285ddcf2e75174248b2406189261a79e7fedee2ceeadc76219b6faa0e"}, + {file = "coverage-7.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f29351393eb05e6326f044a7b45ed8e38cb4dcc38570d12791f271399dc41431"}, + {file = "coverage-7.2.1-cp39-cp39-win32.whl", hash = "sha256:e2b50ebc2b6121edf352336d503357321b9d8738bb7a72d06fc56153fd3f4cd8"}, + {file = "coverage-7.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:bd5a12239c0006252244f94863f1c518ac256160cd316ea5c47fb1a11b25889a"}, + {file = "coverage-7.2.1-pp37.pp38.pp39-none-any.whl", hash = "sha256:436313d129db7cf5b4ac355dd2bd3f7c7e5294af077b090b85de75f8458b8616"}, + {file = "coverage-7.2.1.tar.gz", hash = "sha256:c77f2a9093ccf329dd523a9b2b3c854c20d2a3d968b6def3b820272ca6732242"}, ] [package.dependencies] @@ -450,47 +450,49 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "39.0.0" +version = "39.0.2" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "cryptography-39.0.0-cp36-abi3-macosx_10_12_universal2.whl", hash = "sha256:c52a1a6f81e738d07f43dab57831c29e57d21c81a942f4602fac7ee21b27f288"}, - {file = "cryptography-39.0.0-cp36-abi3-macosx_10_12_x86_64.whl", hash = "sha256:80ee674c08aaef194bc4627b7f2956e5ba7ef29c3cc3ca488cf15854838a8f72"}, - {file = "cryptography-39.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:887cbc1ea60786e534b00ba8b04d1095f4272d380ebd5f7a7eb4cc274710fad9"}, - {file = "cryptography-39.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f97109336df5c178ee7c9c711b264c502b905c2d2a29ace99ed761533a3460f"}, - {file = "cryptography-39.0.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a6915075c6d3a5e1215eab5d99bcec0da26036ff2102a1038401d6ef5bef25b"}, - {file = "cryptography-39.0.0-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:76c24dd4fd196a80f9f2f5405a778a8ca132f16b10af113474005635fe7e066c"}, - {file = "cryptography-39.0.0-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:bae6c7f4a36a25291b619ad064a30a07110a805d08dc89984f4f441f6c1f3f96"}, - {file = "cryptography-39.0.0-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:875aea1039d78557c7c6b4db2fe0e9d2413439f4676310a5f269dd342ca7a717"}, - {file = "cryptography-39.0.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:f6c0db08d81ead9576c4d94bbb27aed8d7a430fa27890f39084c2d0e2ec6b0df"}, - {file = "cryptography-39.0.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f3ed2d864a2fa1666e749fe52fb8e23d8e06b8012e8bd8147c73797c506e86f1"}, - {file = "cryptography-39.0.0-cp36-abi3-win32.whl", hash = "sha256:f671c1bb0d6088e94d61d80c606d65baacc0d374e67bf895148883461cd848de"}, - {file = "cryptography-39.0.0-cp36-abi3-win_amd64.whl", hash = "sha256:e324de6972b151f99dc078defe8fb1b0a82c6498e37bff335f5bc6b1e3ab5a1e"}, - {file = "cryptography-39.0.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:754978da4d0457e7ca176f58c57b1f9de6556591c19b25b8bcce3c77d314f5eb"}, - {file = "cryptography-39.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ee1fd0de9851ff32dbbb9362a4d833b579b4a6cc96883e8e6d2ff2a6bc7104f"}, - {file = "cryptography-39.0.0-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:fec8b932f51ae245121c4671b4bbc030880f363354b2f0e0bd1366017d891458"}, - {file = "cryptography-39.0.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:407cec680e811b4fc829de966f88a7c62a596faa250fc1a4b520a0355b9bc190"}, - {file = "cryptography-39.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7dacfdeee048814563eaaec7c4743c8aea529fe3dd53127313a792f0dadc1773"}, - {file = "cryptography-39.0.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ad04f413436b0781f20c52a661660f1e23bcd89a0e9bb1d6d20822d048cf2856"}, - {file = "cryptography-39.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50386acb40fbabbceeb2986332f0287f50f29ccf1497bae31cf5c3e7b4f4b34f"}, - {file = "cryptography-39.0.0-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:e5d71c5d5bd5b5c3eebcf7c5c2bb332d62ec68921a8c593bea8c394911a005ce"}, - {file = "cryptography-39.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:844ad4d7c3850081dffba91cdd91950038ee4ac525c575509a42d3fc806b83c8"}, - {file = "cryptography-39.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e0a05aee6a82d944f9b4edd6a001178787d1546ec7c6223ee9a848a7ade92e39"}, - {file = "cryptography-39.0.0.tar.gz", hash = "sha256:f964c7dcf7802d133e8dbd1565914fa0194f9d683d82411989889ecd701e8adf"}, + {file = "cryptography-39.0.2-cp36-abi3-macosx_10_12_universal2.whl", hash = "sha256:2725672bb53bb92dc7b4150d233cd4b8c59615cd8288d495eaa86db00d4e5c06"}, + {file = "cryptography-39.0.2-cp36-abi3-macosx_10_12_x86_64.whl", hash = "sha256:23df8ca3f24699167daf3e23e51f7ba7334d504af63a94af468f468b975b7dd7"}, + {file = "cryptography-39.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:eb40fe69cfc6f5cdab9a5ebd022131ba21453cf7b8a7fd3631f45bbf52bed612"}, + {file = "cryptography-39.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc0521cce2c1d541634b19f3ac661d7a64f9555135e9d8af3980965be717fd4a"}, + {file = "cryptography-39.0.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffd394c7896ed7821a6d13b24657c6a34b6e2650bd84ae063cf11ccffa4f1a97"}, + {file = "cryptography-39.0.2-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:e8a0772016feeb106efd28d4a328e77dc2edae84dfbac06061319fdb669ff828"}, + {file = "cryptography-39.0.2-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8f35c17bd4faed2bc7797d2a66cbb4f986242ce2e30340ab832e5d99ae60e011"}, + {file = "cryptography-39.0.2-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b49a88ff802e1993b7f749b1eeb31134f03c8d5c956e3c125c75558955cda536"}, + {file = "cryptography-39.0.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:5f8c682e736513db7d04349b4f6693690170f95aac449c56f97415c6980edef5"}, + {file = "cryptography-39.0.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:d7d84a512a59f4412ca8549b01f94be4161c94efc598bf09d027d67826beddc0"}, + {file = "cryptography-39.0.2-cp36-abi3-win32.whl", hash = "sha256:c43ac224aabcbf83a947eeb8b17eaf1547bce3767ee2d70093b461f31729a480"}, + {file = "cryptography-39.0.2-cp36-abi3-win_amd64.whl", hash = "sha256:788b3921d763ee35dfdb04248d0e3de11e3ca8eb22e2e48fef880c42e1f3c8f9"}, + {file = "cryptography-39.0.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d15809e0dbdad486f4ad0979753518f47980020b7a34e9fc56e8be4f60702fac"}, + {file = "cryptography-39.0.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:50cadb9b2f961757e712a9737ef33d89b8190c3ea34d0fb6675e00edbe35d074"}, + {file = "cryptography-39.0.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:103e8f7155f3ce2ffa0049fe60169878d47a4364b277906386f8de21c9234aa1"}, + {file = "cryptography-39.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:6236a9610c912b129610eb1a274bdc1350b5df834d124fa84729ebeaf7da42c3"}, + {file = "cryptography-39.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e944fe07b6f229f4c1a06a7ef906a19652bdd9fd54c761b0ff87e83ae7a30354"}, + {file = "cryptography-39.0.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:35d658536b0a4117c885728d1a7032bdc9a5974722ae298d6c533755a6ee3915"}, + {file = "cryptography-39.0.2-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:30b1d1bfd00f6fc80d11300a29f1d8ab2b8d9febb6ed4a38a76880ec564fae84"}, + {file = "cryptography-39.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:e029b844c21116564b8b61216befabca4b500e6816fa9f0ba49527653cae2108"}, + {file = "cryptography-39.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fa507318e427169ade4e9eccef39e9011cdc19534f55ca2f36ec3f388c1f70f3"}, + {file = "cryptography-39.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8bc0008ef798231fac03fe7d26e82d601d15bd16f3afaad1c6113771566570f3"}, + {file = "cryptography-39.0.2.tar.gz", hash = "sha256:bc5b871e977c8ee5a1bbc42fa8d19bcc08baf0c51cbf1586b0e87a2694dde42f"}, ] [package.dependencies] cffi = ">=1.12" [package.extras] -docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1,!=5.2.0,!=5.2.0.post0)", "sphinx-rtd-theme"] +docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] -pep8test = ["black", "ruff"] +pep8test = ["black", "check-manifest", "mypy", "ruff", "types-pytz", "types-requests"] sdist = ["setuptools-rust (>=0.11.4)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pytz"] +test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-shard (>=0.1.2)", "pytest-subtests", "pytest-xdist", "pytz"] +test-randomorder = ["pytest-randomly"] +tox = ["tox"] [[package]] name = "dnspython" @@ -561,19 +563,19 @@ testing = ["pre-commit"] [[package]] name = "fakeredis" -version = "2.6.0" +version = "2.9.2" description = "Fake implementation of redis API for testing purposes." category = "main" optional = false -python-versions = ">=3.8.1,<4.0" +python-versions = ">=3.8,<4.0" files = [ - {file = "fakeredis-2.6.0-py3-none-any.whl", hash = "sha256:94c7867edc259b81c55b93902e81a727cc1986ba09de3fcf9df51a3ad8e29b03"}, - {file = "fakeredis-2.6.0.tar.gz", hash = "sha256:3f8f72c5b990a70ae69444dd1cfe0c9805811a53752d3d21fdcda29255b00e51"}, + {file = "fakeredis-2.9.2-py3-none-any.whl", hash = "sha256:35962e0ded572302c4461ad1a40308259cc10b7c546b13228e6d7880bf7b74bb"}, + {file = "fakeredis-2.9.2.tar.gz", hash = "sha256:3bcc2b5c10d5e03cc5b46697d77c651f48391b506ff931576d2869c7549e2e25"}, ] [package.dependencies] -redis = "<4.5" -sortedcontainers = ">=2.4.0,<3.0.0" +redis = ">=4,<5" +sortedcontainers = ">=2.4,<3.0" [package.extras] json = ["jsonpath-ng (>=1.5,<2.0)"] @@ -581,19 +583,19 @@ lua = ["lupa (>=1.14,<2.0)"] [[package]] name = "fastapi" -version = "0.89.1" +version = "0.92.0" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "fastapi-0.89.1-py3-none-any.whl", hash = "sha256:f9773ea22290635b2f48b4275b2bf69a8fa721fda2e38228bed47139839dc877"}, - {file = "fastapi-0.89.1.tar.gz", hash = "sha256:15d9271ee52b572a015ca2ae5c72e1ce4241dd8532a534ad4f7ec70c376a580f"}, + {file = "fastapi-0.92.0-py3-none-any.whl", hash = "sha256:ae7b97c778e2f2ec3fb3cb4fb14162129411d99907fb71920f6d69a524340ebf"}, + {file = "fastapi-0.92.0.tar.gz", hash = "sha256:023a0f5bd2c8b2609014d3bba1e14a1d7df96c6abea0a73070621c9862b9a4de"}, ] [package.dependencies] pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" -starlette = "0.22.0" +starlette = ">=0.25.0,<0.26.0" [package.extras] all = ["email-validator (>=1.1.1)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] @@ -634,77 +636,77 @@ testing = ["covdefaults (>=2.2.2)", "coverage (>=7.0.1)", "pytest (>=7.2)", "pyt [[package]] name = "greenlet" -version = "2.0.1" +version = "2.0.2" description = "Lightweight in-process concurrent programming" category = "main" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" files = [ - {file = "greenlet-2.0.1-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:9ed358312e63bf683b9ef22c8e442ef6c5c02973f0c2a939ec1d7b50c974015c"}, - {file = "greenlet-2.0.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:4f09b0010e55bec3239278f642a8a506b91034f03a4fb28289a7d448a67f1515"}, - {file = "greenlet-2.0.1-cp27-cp27m-win32.whl", hash = "sha256:1407fe45246632d0ffb7a3f4a520ba4e6051fc2cbd61ba1f806900c27f47706a"}, - {file = "greenlet-2.0.1-cp27-cp27m-win_amd64.whl", hash = "sha256:3001d00eba6bbf084ae60ec7f4bb8ed375748f53aeaefaf2a37d9f0370558524"}, - {file = "greenlet-2.0.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d566b82e92ff2e09dd6342df7e0eb4ff6275a3f08db284888dcd98134dbd4243"}, - {file = "greenlet-2.0.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:0722c9be0797f544a3ed212569ca3fe3d9d1a1b13942d10dd6f0e8601e484d26"}, - {file = "greenlet-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d37990425b4687ade27810e3b1a1c37825d242ebc275066cfee8cb6b8829ccd"}, - {file = "greenlet-2.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be35822f35f99dcc48152c9839d0171a06186f2d71ef76dc57fa556cc9bf6b45"}, - {file = "greenlet-2.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c140e7eb5ce47249668056edf3b7e9900c6a2e22fb0eaf0513f18a1b2c14e1da"}, - {file = "greenlet-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d21681f09e297a5adaa73060737e3aa1279a13ecdcfcc6ef66c292cb25125b2d"}, - {file = "greenlet-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fb412b7db83fe56847df9c47b6fe3f13911b06339c2aa02dcc09dce8bbf582cd"}, - {file = "greenlet-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:c6a08799e9e88052221adca55741bf106ec7ea0710bca635c208b751f0d5b617"}, - {file = "greenlet-2.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9e112e03d37987d7b90c1e98ba5e1b59e1645226d78d73282f45b326f7bddcb9"}, - {file = "greenlet-2.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56961cfca7da2fdd178f95ca407fa330c64f33289e1804b592a77d5593d9bd94"}, - {file = "greenlet-2.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:13ba6e8e326e2116c954074c994da14954982ba2795aebb881c07ac5d093a58a"}, - {file = "greenlet-2.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bf633a50cc93ed17e494015897361010fc08700d92676c87931d3ea464123ce"}, - {file = "greenlet-2.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9f2c221eecb7ead00b8e3ddb913c67f75cba078fd1d326053225a3f59d850d72"}, - {file = "greenlet-2.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:13ebf93c343dd8bd010cd98e617cb4c1c1f352a0cf2524c82d3814154116aa82"}, - {file = "greenlet-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:6f61d71bbc9b4a3de768371b210d906726535d6ca43506737682caa754b956cd"}, - {file = "greenlet-2.0.1-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:2d0bac0385d2b43a7bd1d651621a4e0f1380abc63d6fb1012213a401cbd5bf8f"}, - {file = "greenlet-2.0.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:f6327b6907b4cb72f650a5b7b1be23a2aab395017aa6f1adb13069d66360eb3f"}, - {file = "greenlet-2.0.1-cp35-cp35m-win32.whl", hash = "sha256:81b0ea3715bf6a848d6f7149d25bf018fd24554a4be01fcbbe3fdc78e890b955"}, - {file = "greenlet-2.0.1-cp35-cp35m-win_amd64.whl", hash = "sha256:38255a3f1e8942573b067510f9611fc9e38196077b0c8eb7a8c795e105f9ce77"}, - {file = "greenlet-2.0.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:04957dc96669be041e0c260964cfef4c77287f07c40452e61abe19d647505581"}, - {file = "greenlet-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:4aeaebcd91d9fee9aa768c1b39cb12214b30bf36d2b7370505a9f2165fedd8d9"}, - {file = "greenlet-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:974a39bdb8c90a85982cdb78a103a32e0b1be986d411303064b28a80611f6e51"}, - {file = "greenlet-2.0.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dca09dedf1bd8684767bc736cc20c97c29bc0c04c413e3276e0962cd7aeb148"}, - {file = "greenlet-2.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4c0757db9bd08470ff8277791795e70d0bf035a011a528ee9a5ce9454b6cba2"}, - {file = "greenlet-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:5067920de254f1a2dee8d3d9d7e4e03718e8fd2d2d9db962c8c9fa781ae82a39"}, - {file = "greenlet-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:5a8e05057fab2a365c81abc696cb753da7549d20266e8511eb6c9d9f72fe3e92"}, - {file = "greenlet-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:3d75b8d013086b08e801fbbb896f7d5c9e6ccd44f13a9241d2bf7c0df9eda928"}, - {file = "greenlet-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:097e3dae69321e9100202fc62977f687454cd0ea147d0fd5a766e57450c569fd"}, - {file = "greenlet-2.0.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:cb242fc2cda5a307a7698c93173d3627a2a90d00507bccf5bc228851e8304963"}, - {file = "greenlet-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:72b00a8e7c25dcea5946692a2485b1a0c0661ed93ecfedfa9b6687bd89a24ef5"}, - {file = "greenlet-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5b0ff9878333823226d270417f24f4d06f235cb3e54d1103b71ea537a6a86ce"}, - {file = "greenlet-2.0.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be9e0fb2ada7e5124f5282d6381903183ecc73ea019568d6d63d33f25b2a9000"}, - {file = "greenlet-2.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b493db84d124805865adc587532ebad30efa68f79ad68f11b336e0a51ec86c2"}, - {file = "greenlet-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0459d94f73265744fee4c2d5ec44c6f34aa8a31017e6e9de770f7bcf29710be9"}, - {file = "greenlet-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a20d33124935d27b80e6fdacbd34205732660e0a1d35d8b10b3328179a2b51a1"}, - {file = "greenlet-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:ea688d11707d30e212e0110a1aac7f7f3f542a259235d396f88be68b649e47d1"}, - {file = "greenlet-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:afe07421c969e259e9403c3bb658968702bc3b78ec0b6fde3ae1e73440529c23"}, - {file = "greenlet-2.0.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:cd4ccc364cf75d1422e66e247e52a93da6a9b73cefa8cad696f3cbbb75af179d"}, - {file = "greenlet-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:4c8b1c43e75c42a6cafcc71defa9e01ead39ae80bd733a2608b297412beede68"}, - {file = "greenlet-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:659f167f419a4609bc0516fb18ea69ed39dbb25594934bd2dd4d0401660e8a1e"}, - {file = "greenlet-2.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:356e4519d4dfa766d50ecc498544b44c0249b6de66426041d7f8b751de4d6b48"}, - {file = "greenlet-2.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:811e1d37d60b47cb8126e0a929b58c046251f28117cb16fcd371eed61f66b764"}, - {file = "greenlet-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d38ffd0e81ba8ef347d2be0772e899c289b59ff150ebbbbe05dc61b1246eb4e0"}, - {file = "greenlet-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0109af1138afbfb8ae647e31a2b1ab030f58b21dd8528c27beaeb0093b7938a9"}, - {file = "greenlet-2.0.1-cp38-cp38-win32.whl", hash = "sha256:88c8d517e78acdf7df8a2134a3c4b964415b575d2840a2746ddb1cc6175f8608"}, - {file = "greenlet-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:d6ee1aa7ab36475035eb48c01efae87d37936a8173fc4d7b10bb02c2d75dd8f6"}, - {file = "greenlet-2.0.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:b1992ba9d4780d9af9726bbcef6a1db12d9ab1ccc35e5773685a24b7fb2758eb"}, - {file = "greenlet-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:b5e83e4de81dcc9425598d9469a624826a0b1211380ac444c7c791d4a2137c19"}, - {file = "greenlet-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:505138d4fa69462447a562a7c2ef723c6025ba12ac04478bc1ce2fcc279a2db5"}, - {file = "greenlet-2.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cce1e90dd302f45716a7715517c6aa0468af0bf38e814ad4eab58e88fc09f7f7"}, - {file = "greenlet-2.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e9744c657d896c7b580455e739899e492a4a452e2dd4d2b3e459f6b244a638d"}, - {file = "greenlet-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:662e8f7cad915ba75d8017b3e601afc01ef20deeeabf281bd00369de196d7726"}, - {file = "greenlet-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:41b825d65f31e394b523c84db84f9383a2f7eefc13d987f308f4663794d2687e"}, - {file = "greenlet-2.0.1-cp39-cp39-win32.whl", hash = "sha256:db38f80540083ea33bdab614a9d28bcec4b54daa5aff1668d7827a9fc769ae0a"}, - {file = "greenlet-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b23d2a46d53210b498e5b701a1913697671988f4bf8e10f935433f6e7c332fb6"}, - {file = "greenlet-2.0.1.tar.gz", hash = "sha256:42e602564460da0e8ee67cb6d7236363ee5e131aa15943b6670e44e5c2ed0f67"}, + {file = "greenlet-2.0.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:bdfea8c661e80d3c1c99ad7c3ff74e6e87184895bbaca6ee8cc61209f8b9b85d"}, + {file = "greenlet-2.0.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:9d14b83fab60d5e8abe587d51c75b252bcc21683f24699ada8fb275d7712f5a9"}, + {file = "greenlet-2.0.2-cp27-cp27m-win32.whl", hash = "sha256:6c3acb79b0bfd4fe733dff8bc62695283b57949ebcca05ae5c129eb606ff2d74"}, + {file = "greenlet-2.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:283737e0da3f08bd637b5ad058507e578dd462db259f7f6e4c5c365ba4ee9343"}, + {file = "greenlet-2.0.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d27ec7509b9c18b6d73f2f5ede2622441de812e7b1a80bbd446cb0633bd3d5ae"}, + {file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:30bcf80dda7f15ac77ba5af2b961bdd9dbc77fd4ac6105cee85b0d0a5fcf74df"}, + {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26fbfce90728d82bc9e6c38ea4d038cba20b7faf8a0ca53a9c07b67318d46088"}, + {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9190f09060ea4debddd24665d6804b995a9c122ef5917ab26e1566dcc712ceeb"}, + {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d75209eed723105f9596807495d58d10b3470fa6732dd6756595e89925ce2470"}, + {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a51c9751078733d88e013587b108f1b7a1fb106d402fb390740f002b6f6551a"}, + {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:76ae285c8104046b3a7f06b42f29c7b73f77683df18c49ab5af7983994c2dd91"}, + {file = "greenlet-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:2d4686f195e32d36b4d7cf2d166857dbd0ee9f3d20ae349b6bf8afc8485b3645"}, + {file = "greenlet-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c4302695ad8027363e96311df24ee28978162cdcdd2006476c43970b384a244c"}, + {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c48f54ef8e05f04d6eff74b8233f6063cb1ed960243eacc474ee73a2ea8573ca"}, + {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1846f1b999e78e13837c93c778dcfc3365902cfb8d1bdb7dd73ead37059f0d0"}, + {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a06ad5312349fec0ab944664b01d26f8d1f05009566339ac6f63f56589bc1a2"}, + {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:eff4eb9b7eb3e4d0cae3d28c283dc16d9bed6b193c2e1ace3ed86ce48ea8df19"}, + {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5454276c07d27a740c5892f4907c86327b632127dd9abec42ee62e12427ff7e3"}, + {file = "greenlet-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:7cafd1208fdbe93b67c7086876f061f660cfddc44f404279c1585bbf3cdc64c5"}, + {file = "greenlet-2.0.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:910841381caba4f744a44bf81bfd573c94e10b3045ee00de0cbf436fe50673a6"}, + {file = "greenlet-2.0.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:18a7f18b82b52ee85322d7a7874e676f34ab319b9f8cce5de06067384aa8ff43"}, + {file = "greenlet-2.0.2-cp35-cp35m-win32.whl", hash = "sha256:03a8f4f3430c3b3ff8d10a2a86028c660355ab637cee9333d63d66b56f09d52a"}, + {file = "greenlet-2.0.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4b58adb399c4d61d912c4c331984d60eb66565175cdf4a34792cd9600f21b394"}, + {file = "greenlet-2.0.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:703f18f3fda276b9a916f0934d2fb6d989bf0b4fb5a64825260eb9bfd52d78f0"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:32e5b64b148966d9cccc2c8d35a671409e45f195864560829f395a54226408d3"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dd11f291565a81d71dab10b7033395b7a3a5456e637cf997a6f33ebdf06f8db"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0f72c9ddb8cd28532185f54cc1453f2c16fb417a08b53a855c4e6a418edd099"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd021c754b162c0fb55ad5d6b9d960db667faad0fa2ff25bb6e1301b0b6e6a75"}, + {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:3c9b12575734155d0c09d6c3e10dbd81665d5c18e1a7c6597df72fd05990c8cf"}, + {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b9ec052b06a0524f0e35bd8790686a1da006bd911dd1ef7d50b77bfbad74e292"}, + {file = "greenlet-2.0.2-cp36-cp36m-win32.whl", hash = "sha256:dbfcfc0218093a19c252ca8eb9aee3d29cfdcb586df21049b9d777fd32c14fd9"}, + {file = "greenlet-2.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:9f35ec95538f50292f6d8f2c9c9f8a3c6540bbfec21c9e5b4b751e0a7c20864f"}, + {file = "greenlet-2.0.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:d5508f0b173e6aa47273bdc0a0b5ba055b59662ba7c7ee5119528f466585526b"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:f82d4d717d8ef19188687aa32b8363e96062911e63ba22a0cff7802a8e58e5f1"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9c59a2120b55788e800d82dfa99b9e156ff8f2227f07c5e3012a45a399620b7"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2780572ec463d44c1d3ae850239508dbeb9fed38e294c68d19a24d925d9223ca"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937e9020b514ceedb9c830c55d5c9872abc90f4b5862f89c0887033ae33c6f73"}, + {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:36abbf031e1c0f79dd5d596bfaf8e921c41df2bdf54ee1eed921ce1f52999a86"}, + {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:18e98fb3de7dba1c0a852731c3070cf022d14f0d68b4c87a19cc1016f3bb8b33"}, + {file = "greenlet-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:3f6ea9bd35eb450837a3d80e77b517ea5bc56b4647f5502cd28de13675ee12f7"}, + {file = "greenlet-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:7492e2b7bd7c9b9916388d9df23fa49d9b88ac0640db0a5b4ecc2b653bf451e3"}, + {file = "greenlet-2.0.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b864ba53912b6c3ab6bcb2beb19f19edd01a6bfcbdfe1f37ddd1778abfe75a30"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ba2956617f1c42598a308a84c6cf021a90ff3862eddafd20c3333d50f0edb45b"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3a569657468b6f3fb60587e48356fe512c1754ca05a564f11366ac9e306526"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8eab883b3b2a38cc1e050819ef06a7e6344d4a990d24d45bc6f2cf959045a45b"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acd2162a36d3de67ee896c43effcd5ee3de247eb00354db411feb025aa319857"}, + {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0bf60faf0bc2468089bdc5edd10555bab6e85152191df713e2ab1fcc86382b5a"}, + {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0ef99cdbe2b682b9ccbb964743a6aca37905fda5e0452e5ee239b1654d37f2a"}, + {file = "greenlet-2.0.2-cp38-cp38-win32.whl", hash = "sha256:b80f600eddddce72320dbbc8e3784d16bd3fb7b517e82476d8da921f27d4b249"}, + {file = "greenlet-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:4d2e11331fc0c02b6e84b0d28ece3a36e0548ee1a1ce9ddde03752d9b79bba40"}, + {file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:88d9ab96491d38a5ab7c56dd7a3cc37d83336ecc564e4e8816dbed12e5aaefc8"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:561091a7be172ab497a3527602d467e2b3fbe75f9e783d8b8ce403fa414f71a6"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:971ce5e14dc5e73715755d0ca2975ac88cfdaefcaab078a284fea6cfabf866df"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be4ed120b52ae4d974aa40215fcdfde9194d63541c7ded40ee12eb4dda57b76b"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94c817e84245513926588caf1152e3b559ff794d505555211ca041f032abbb6b"}, + {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1a819eef4b0e0b96bb0d98d797bef17dc1b4a10e8d7446be32d1da33e095dbb8"}, + {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7efde645ca1cc441d6dc4b48c0f7101e8d86b54c8530141b09fd31cef5149ec9"}, + {file = "greenlet-2.0.2-cp39-cp39-win32.whl", hash = "sha256:ea9872c80c132f4663822dd2a08d404073a5a9b5ba6155bea72fb2a79d1093b5"}, + {file = "greenlet-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:db1a39669102a1d8d12b57de2bb7e2ec9066a6f2b3da35ae511ff93b01b5d564"}, + {file = "greenlet-2.0.2.tar.gz", hash = "sha256:e7c8dc13af7db097bed64a051d2dd49e9f0af495c26995c00a9ee842690d34c0"}, ] [package.extras] docs = ["Sphinx", "docutils (<0.18)"] -test = ["faulthandler", "objgraph", "psutil"] +test = ["objgraph", "psutil"] [[package]] name = "gunicorn" @@ -1134,56 +1136,56 @@ files = [ [[package]] name = "orjson" -version = "3.8.5" +version = "3.8.7" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "orjson-3.8.5-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:143639b9898b094883481fac37733231da1c2ae3aec78a1dd8d3b58c9c9fceef"}, - {file = "orjson-3.8.5-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:31f43e63e0d94784c55e86bd376df3f80b574bea8c0bc5ecd8041009fa8ec78a"}, - {file = "orjson-3.8.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c802ea6d4a0d40f096aceb5e7ef0a26c23d276cb9334e1cadcf256bb090b6426"}, - {file = "orjson-3.8.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bf298b55b371c2772420c5ace4d47b0a3ea1253667e20ded3c363160fd0575f6"}, - {file = "orjson-3.8.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68cb4a8501a463771d55bb22fc72795ec7e21d71ab083e000a2c3b651b6fb2af"}, - {file = "orjson-3.8.5-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:4f1427952b3bd92bfb63a61b7ffc33a9f54ec6de296fa8d924cbeba089866acb"}, - {file = "orjson-3.8.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c0a9f329468c8eb000742455b83546849bcd69495d6baa6e171c7ee8600a47bd"}, - {file = "orjson-3.8.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6535d527aa1e4a757a6ce9b61f3dd74edc762e7d2c6991643aae7c560c8440bd"}, - {file = "orjson-3.8.5-cp310-none-win_amd64.whl", hash = "sha256:2eee64c028adf6378dd714c8debc96d5b92b6bb4862debb65ca868e59bac6c63"}, - {file = "orjson-3.8.5-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:f5745ff473dd5c6718bf8c8d5bc183f638b4f3e03c7163ffcda4d4ef453f42ff"}, - {file = "orjson-3.8.5-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:544f1240b295083697027a5093ec66763218ff16f03521d5020e7a436d2e417b"}, - {file = "orjson-3.8.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c85c9c6bab97a831e7741089057347d99901b4db2451a076ca8adedc7d96297f"}, - {file = "orjson-3.8.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9bae7347764e7be6dada980fd071e865544c98317ab61af575c9cc5e1dc7e3fe"}, - {file = "orjson-3.8.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c67f6f6e9d26a06b63126112a7bc8d8529df048d31df2a257a8484b76adf3e5d"}, - {file = "orjson-3.8.5-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:758238364142fcbeca34c968beefc0875ffa10aa2f797c82f51cfb1d22d0934e"}, - {file = "orjson-3.8.5-cp311-none-win_amd64.whl", hash = "sha256:cc7579240fb88a626956a6cb4a181a11b62afbc409ce239a7b866568a2412fa2"}, - {file = "orjson-3.8.5-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:79aa3e47cbbd4eedbbde4f988f766d6cf38ccb51d52cfabfeb6b8d1b58654d25"}, - {file = "orjson-3.8.5-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:2544cd0d089faa862f5a39f508ee667419e3f9e11f119a6b1505cfce0eb26601"}, - {file = "orjson-3.8.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2be0025ca7e460bcacb250aba8ce0239be62957d58cf34045834cc9302611d3"}, - {file = "orjson-3.8.5-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b57bf72902d818506906e49c677a791f90dbd7f0997d60b14bc6c1ce4ce4cf9"}, - {file = "orjson-3.8.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93ae9832a11c6a9efa8c14224e5caf6e35046efd781de14e59eb69ab4e561cf3"}, - {file = "orjson-3.8.5-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:0e28330cc6d51741cad0edd1b57caf6c5531aff30afe41402acde0a03246b8ed"}, - {file = "orjson-3.8.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:155954d725627b5480e6cc1ca488afb4fa685099a4ace5f5bf21a182fabf6706"}, - {file = "orjson-3.8.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ece1b6ef9312df5d5274ca6786e613b7da7de816356e36bcad9ea8a73d15ab71"}, - {file = "orjson-3.8.5-cp37-none-win_amd64.whl", hash = "sha256:6f58d1f0702332496bc1e2d267c7326c851991b62cf6395370d59c47f9890007"}, - {file = "orjson-3.8.5-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:933f4ab98362f46a59a6d0535986e1f0cae2f6b42435e24a55922b4bc872af0c"}, - {file = "orjson-3.8.5-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:47a7ca236b25a138a74b2cb5169adcdc5b2b8abdf661de438ba65967a2cde9dc"}, - {file = "orjson-3.8.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b573ca942c626fcf8a86be4f180b86b2498b18ae180f37b4180c2aced5808710"}, - {file = "orjson-3.8.5-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a9bab11611d5452efe4ae5315f5eb806f66104c08a089fb84c648d2e8e00f106"}, - {file = "orjson-3.8.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eee2f5f6476617d01ca166266d70fd5605d3397a41f067022ce04a2e1ced4c8d"}, - {file = "orjson-3.8.5-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:ec0b0b6cd0b84f03537f22b719aca705b876c54ab5cf3471d551c9644127284f"}, - {file = "orjson-3.8.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:df3287dc304c8c4556dc85c4ab89eb333307759c1863f95e72e555c0cfce3e01"}, - {file = "orjson-3.8.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:09f40add3c2d208e20f8bf185df38f992bf5092202d2d30eced8f6959963f1d5"}, - {file = "orjson-3.8.5-cp38-none-win_amd64.whl", hash = "sha256:232ec1df0d708f74e0dd1fccac1e9a7008cd120d48fe695e8f0c9d80771da430"}, - {file = "orjson-3.8.5-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:8fba3e7aede3e88a01e94e6fe63d4580162b212e6da27ae85af50a1787e41416"}, - {file = "orjson-3.8.5-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:85e22c358cab170c8604e9edfffcc45dd7b0027ce57ed6bcacb556e8bfbbb704"}, - {file = "orjson-3.8.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eeab1d8247507a75926adf3ca995c74e91f5db1f168815bf3e774f992ba52b50"}, - {file = "orjson-3.8.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:daaaef15a41e9e8cadc7677cefe00065ae10bce914eefe8da1cd26b3d063970b"}, - {file = "orjson-3.8.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ccc9f52cf46bd353c6ae1153eaf9d18257ddc110d135198b0cd8718474685ce"}, - {file = "orjson-3.8.5-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:d48c182c7ff4ea0787806de8a2f9298ca44fd0068ecd5f23a4b2d8e03c745cb6"}, - {file = "orjson-3.8.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1848e3b4cc09cc82a67262ae56e2a772b0548bb5a6f9dcaee10dcaaf0a5177b7"}, - {file = "orjson-3.8.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:38480031bc8add58effe802291e4abf7042ef72ae1a4302efe9a36c8f8bfbfcc"}, - {file = "orjson-3.8.5-cp39-none-win_amd64.whl", hash = "sha256:0e9a1c2e649cbaed410c882cedc8f3b993d8f1426d9327f31762d3f46fe7cc88"}, - {file = "orjson-3.8.5.tar.gz", hash = "sha256:77a3b2bd0c4ef7723ea09081e3329dac568a62463aed127c1501441b07ffc64b"}, + {file = "orjson-3.8.7-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:f98c82850b7b4b7e27785ca43706fa86c893cdb88d54576bbb9b0d9c1070e421"}, + {file = "orjson-3.8.7-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:1dee503c6c1a0659c5b46f5f39d9ca9d3657b11ca8bb4af8506086df416887d9"}, + {file = "orjson-3.8.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc4fa83831f42ce5c938f8cefc2e175fa1df6f661fdeaba3badf26d2b8cfcf73"}, + {file = "orjson-3.8.7-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e432c6c9c8b97ad825276d5795286f7cc9689f377a97e3b7ecf14918413303f"}, + {file = "orjson-3.8.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee519964a5a0efb9633f38b1129fd242807c5c57162844efeeaab1c8de080051"}, + {file = "orjson-3.8.7-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:109b539ce5bf60a121454d008fa67c3b67e5a3249e47d277012645922cf74bd0"}, + {file = "orjson-3.8.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ad4d441fbde4133af6fee37f67dbf23181b9c537ecc317346ec8c3b4c8ec7705"}, + {file = "orjson-3.8.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:89dc786419e1ce2588345f58dd6a434e6728bce66b94989644234bcdbe39b603"}, + {file = "orjson-3.8.7-cp310-none-win_amd64.whl", hash = "sha256:697abde7350fb8076d44bcb6b4ab3ce415ae2b5a9bb91efc460e5ab0d96bb5d3"}, + {file = "orjson-3.8.7-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:1c19f47b35b9966a3abadf341b18ee4a860431bf2b00fd8d58906d51cf78aa70"}, + {file = "orjson-3.8.7-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:3ffaabb380cd0ee187b4fc362516df6bf739808130b1339445c7d8878fca36e7"}, + {file = "orjson-3.8.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d88837002c5a8af970745b8e0ca1b0fdb06aafbe7f1279e110d338ea19f3d23"}, + {file = "orjson-3.8.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff60187d1b7e0bfab376b6002b08c560b7de06c87cf3a8ac639ecf58f84c5f3b"}, + {file = "orjson-3.8.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0110970aed35dec293f30ed1e09f8604afd5d15c5ef83de7f6c427619b3ba47b"}, + {file = "orjson-3.8.7-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:51b275475d4e36118b65ad56f9764056a09d985c5d72e64579bf8816f1356a5e"}, + {file = "orjson-3.8.7-cp311-none-win_amd64.whl", hash = "sha256:63144d27735f3b60f079f247ac9a289d80dfe49a7f03880dfa0c0ba64d6491d5"}, + {file = "orjson-3.8.7-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:a16273d77db746bb1789a2bbfded81148a60743fd6f9d5185e02d92e3732fa18"}, + {file = "orjson-3.8.7-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:5bb32259ea22cc9dd47a6fdc4b8f9f1e2f798fcf56c7c1122a7df0f4c5d33bf3"}, + {file = "orjson-3.8.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad02e9102d4ba67db30a136e631e32aeebd1dce26c9f5942a457b02df131c5d0"}, + {file = "orjson-3.8.7-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dbcfcec2b7ac52deb7be3685b551addc28ee8fa454ef41f8b714df6ba0e32a27"}, + {file = "orjson-3.8.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1a0e5504a5fc86083cc210c6946e8d61e13fe9f1d7a7bf81b42f7050a49d4fb"}, + {file = "orjson-3.8.7-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:7bd4fd37adb03b1f2a1012d43c9f95973a02164e131dfe3ff804d7e180af5653"}, + {file = "orjson-3.8.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:188ed9f9a781333ad802af54c55d5a48991e292239aef41bd663b6e314377eb8"}, + {file = "orjson-3.8.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:cc52f58c688cb10afd810280e450f56fbcb27f52c053463e625c8335c95db0dc"}, + {file = "orjson-3.8.7-cp37-none-win_amd64.whl", hash = "sha256:403c8c84ac8a02c40613b0493b74d5256379e65196d39399edbf2ed3169cbeb5"}, + {file = "orjson-3.8.7-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:7d6ac5f8a2a17095cd927c4d52abbb38af45918e0d3abd60fb50cfd49d71ae24"}, + {file = "orjson-3.8.7-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:0295a7bfd713fa89231fd0822c995c31fc2343c59a1d13aa1b8b6651335654f5"}, + {file = "orjson-3.8.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feb32aaaa34cf2f891eb793ad320d4bb6731328496ae59b6c9eb1b620c42b529"}, + {file = "orjson-3.8.7-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7a3ab1a473894e609b6f1d763838c6689ba2b97620c256a32c4d9f10595ac179"}, + {file = "orjson-3.8.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e8c430d82b532c5ab95634e034bbf6ca7432ffe175a3e63eadd493e00b3a555"}, + {file = "orjson-3.8.7-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:366cc75f7e09106f9dac95a675aef413367b284f25507d21e55bd7f45f445e80"}, + {file = "orjson-3.8.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:84d154d07e8b17d97e990d5d710b719a031738eb1687d8a05b9089f0564ff3e0"}, + {file = "orjson-3.8.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06180014afcfdc167ca984b312218aa62ce20093965c437c5f9166764cb65ef7"}, + {file = "orjson-3.8.7-cp38-none-win_amd64.whl", hash = "sha256:41244431ba13f2e6ef22b52c5cf0202d17954489f4a3c0505bd28d0e805c3546"}, + {file = "orjson-3.8.7-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:b20f29fa8371b8023f1791df035a2c3ccbd98baa429ac3114fc104768f7db6f8"}, + {file = "orjson-3.8.7-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:226bfc1da2f21ee74918cee2873ea9a0fec1a8830e533cb287d192d593e99d02"}, + {file = "orjson-3.8.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e75c11023ac29e29fd3e75038d0e8dd93f9ea24d7b9a5e871967a8921a88df24"}, + {file = "orjson-3.8.7-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:78604d3acfd7cd502f6381eea0c42281fe2b74755b334074ab3ebc0224100be1"}, + {file = "orjson-3.8.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7129a6847f0494aa1427167486ef6aea2e835ba05f6c627df522692ee228f65"}, + {file = "orjson-3.8.7-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1a1a8f4980059f48483782c608145b0f74538c266e01c183d9bcd9f8b71dbada"}, + {file = "orjson-3.8.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d60304172a33705ce4bd25a6261ab84bed2dab0b3d3b79672ea16c7648af4832"}, + {file = "orjson-3.8.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4f733062d84389c32c0492e5a4929056fac217034a94523debe0430bcc602cda"}, + {file = "orjson-3.8.7-cp39-none-win_amd64.whl", hash = "sha256:010e2970ec9e826c332819e0da4b14b29b19641da0f1a6af4cec91629ef9b988"}, + {file = "orjson-3.8.7.tar.gz", hash = "sha256:8460c8810652dba59c38c80d27c325b5092d189308d8d4f3e688dbd8d4f3b2dc"}, ] [[package]] @@ -1281,14 +1283,14 @@ twisted = ["twisted"] [[package]] name = "prometheus-fastapi-instrumentator" -version = "5.9.1" -description = "Instrument your FastAPI with Prometheus metrics" +version = "5.10.0" +description = "Instrument your FastAPI with Prometheus metrics." category = "main" optional = false python-versions = ">=3.7.0,<4.0.0" files = [ - {file = "prometheus-fastapi-instrumentator-5.9.1.tar.gz", hash = "sha256:3651a72f73359a28e8afb0d370ebe3774147323ee2285e21236b229ce79172fc"}, - {file = "prometheus_fastapi_instrumentator-5.9.1-py3-none-any.whl", hash = "sha256:b5206ea9aa6975a0b07f3bf7376932b8a1b2983164b5abb04878e75ba336d9ed"}, + {file = "prometheus_fastapi_instrumentator-5.10.0-py3-none-any.whl", hash = "sha256:cf0fb37d506f8a999a16a47e71f75b140f0673cb4ecbce634f7b41a8b4caf8f6"}, + {file = "prometheus_fastapi_instrumentator-5.10.0.tar.gz", hash = "sha256:705d2e29ca11fba9110f425a283592b8f2067ed8144405aa71b5879f7271c2a1"}, ] [package.dependencies] @@ -1297,26 +1299,25 @@ prometheus-client = ">=0.8.0,<1.0.0" [[package]] name = "protobuf" -version = "4.21.12" +version = "4.22.0" description = "" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "protobuf-4.21.12-cp310-abi3-win32.whl", hash = "sha256:b135410244ebe777db80298297a97fbb4c862c881b4403b71bac9d4107d61fd1"}, - {file = "protobuf-4.21.12-cp310-abi3-win_amd64.whl", hash = "sha256:89f9149e4a0169cddfc44c74f230d7743002e3aa0b9472d8c28f0388102fc4c2"}, - {file = "protobuf-4.21.12-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:299ea899484ee6f44604deb71f424234f654606b983cb496ea2a53e3c63ab791"}, - {file = "protobuf-4.21.12-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:d1736130bce8cf131ac7957fa26880ca19227d4ad68b4888b3be0dea1f95df97"}, - {file = "protobuf-4.21.12-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:78a28c9fa223998472886c77042e9b9afb6fe4242bd2a2a5aced88e3f4422aa7"}, - {file = "protobuf-4.21.12-cp37-cp37m-win32.whl", hash = "sha256:3d164928ff0727d97022957c2b849250ca0e64777ee31efd7d6de2e07c494717"}, - {file = "protobuf-4.21.12-cp37-cp37m-win_amd64.whl", hash = "sha256:f45460f9ee70a0ec1b6694c6e4e348ad2019275680bd68a1d9314b8c7e01e574"}, - {file = "protobuf-4.21.12-cp38-cp38-win32.whl", hash = "sha256:6ab80df09e3208f742c98443b6166bcb70d65f52cfeb67357d52032ea1ae9bec"}, - {file = "protobuf-4.21.12-cp38-cp38-win_amd64.whl", hash = "sha256:1f22ac0ca65bb70a876060d96d914dae09ac98d114294f77584b0d2644fa9c30"}, - {file = "protobuf-4.21.12-cp39-cp39-win32.whl", hash = "sha256:27f4d15021da6d2b706ddc3860fac0a5ddaba34ab679dc182b60a8bb4e1121cc"}, - {file = "protobuf-4.21.12-cp39-cp39-win_amd64.whl", hash = "sha256:237216c3326d46808a9f7c26fd1bd4b20015fb6867dc5d263a493ef9a539293b"}, - {file = "protobuf-4.21.12-py2.py3-none-any.whl", hash = "sha256:a53fd3f03e578553623272dc46ac2f189de23862e68565e83dde203d41b76fc5"}, - {file = "protobuf-4.21.12-py3-none-any.whl", hash = "sha256:b98d0148f84e3a3c569e19f52103ca1feacdac0d2df8d6533cf983d1fda28462"}, - {file = "protobuf-4.21.12.tar.gz", hash = "sha256:7cd532c4566d0e6feafecc1059d04c7915aec8e182d1cf7adee8b24ef1e2e6ab"}, + {file = "protobuf-4.22.0-cp310-abi3-win32.whl", hash = "sha256:b2fea9dc8e3c0f32c38124790ef16cba2ee0628fe2022a52e435e1117bfef9b1"}, + {file = "protobuf-4.22.0-cp310-abi3-win_amd64.whl", hash = "sha256:a33a273d21852f911b8bda47f39f4383fe7c061eb1814db2c76c9875c89c2491"}, + {file = "protobuf-4.22.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:e894e9ae603e963f0842498c4cd5d39c6a60f0d7e4c103df50ee939564298658"}, + {file = "protobuf-4.22.0-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:7c535d126e7dcc714105ab20b418c4fedbd28f8b8afc42b7350b1e317bbbcc71"}, + {file = "protobuf-4.22.0-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:86c3d20428b007537ba6792b475c0853bba7f66b1f60e610d913b77d94b486e4"}, + {file = "protobuf-4.22.0-cp37-cp37m-win32.whl", hash = "sha256:1669cb7524221a8e2d9008d0842453dbefdd0fcdd64d67672f657244867635fb"}, + {file = "protobuf-4.22.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ab4d043865dd04e6b09386981fe8f80b39a1e46139fb4a3c206229d6b9f36ff6"}, + {file = "protobuf-4.22.0-cp38-cp38-win32.whl", hash = "sha256:29288813aacaa302afa2381db1d6e0482165737b0afdf2811df5fa99185c457b"}, + {file = "protobuf-4.22.0-cp38-cp38-win_amd64.whl", hash = "sha256:e474b63bab0a2ea32a7b26a4d8eec59e33e709321e5e16fb66e766b61b82a95e"}, + {file = "protobuf-4.22.0-cp39-cp39-win32.whl", hash = "sha256:47d31bdf58222dd296976aa1646c68c6ee80b96d22e0a3c336c9174e253fd35e"}, + {file = "protobuf-4.22.0-cp39-cp39-win_amd64.whl", hash = "sha256:c27f371f0159feb70e6ea52ed7e768b3f3a4c5676c1900a7e51a24740381650e"}, + {file = "protobuf-4.22.0-py3-none-any.whl", hash = "sha256:c3325803095fb4c2a48649c321d2fbde59f8fbfcb9bfc7a86df27d112831c571"}, + {file = "protobuf-4.22.0.tar.gz", hash = "sha256:652d8dfece122a24d98eebfef30e31e455d300efa41999d1182e015984ac5930"}, ] [[package]] @@ -1344,48 +1345,48 @@ files = [ [[package]] name = "pydantic" -version = "1.10.4" +version = "1.10.5" description = "Data validation and settings management using python type hints" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-1.10.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5635de53e6686fe7a44b5cf25fcc419a0d5e5c1a1efe73d49d48fe7586db854"}, - {file = "pydantic-1.10.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6dc1cc241440ed7ca9ab59d9929075445da6b7c94ced281b3dd4cfe6c8cff817"}, - {file = "pydantic-1.10.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51bdeb10d2db0f288e71d49c9cefa609bca271720ecd0c58009bd7504a0c464c"}, - {file = "pydantic-1.10.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78cec42b95dbb500a1f7120bdf95c401f6abb616bbe8785ef09887306792e66e"}, - {file = "pydantic-1.10.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8775d4ef5e7299a2f4699501077a0defdaac5b6c4321173bcb0f3c496fbadf85"}, - {file = "pydantic-1.10.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:572066051eeac73d23f95ba9a71349c42a3e05999d0ee1572b7860235b850cc6"}, - {file = "pydantic-1.10.4-cp310-cp310-win_amd64.whl", hash = "sha256:7feb6a2d401f4d6863050f58325b8d99c1e56f4512d98b11ac64ad1751dc647d"}, - {file = "pydantic-1.10.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:39f4a73e5342b25c2959529f07f026ef58147249f9b7431e1ba8414a36761f53"}, - {file = "pydantic-1.10.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:983e720704431a6573d626b00662eb78a07148c9115129f9b4351091ec95ecc3"}, - {file = "pydantic-1.10.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75d52162fe6b2b55964fbb0af2ee58e99791a3138588c482572bb6087953113a"}, - {file = "pydantic-1.10.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdf8d759ef326962b4678d89e275ffc55b7ce59d917d9f72233762061fd04a2d"}, - {file = "pydantic-1.10.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:05a81b006be15655b2a1bae5faa4280cf7c81d0e09fcb49b342ebf826abe5a72"}, - {file = "pydantic-1.10.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d88c4c0e5c5dfd05092a4b271282ef0588e5f4aaf345778056fc5259ba098857"}, - {file = "pydantic-1.10.4-cp311-cp311-win_amd64.whl", hash = "sha256:6a05a9db1ef5be0fe63e988f9617ca2551013f55000289c671f71ec16f4985e3"}, - {file = "pydantic-1.10.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:887ca463c3bc47103c123bc06919c86720e80e1214aab79e9b779cda0ff92a00"}, - {file = "pydantic-1.10.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdf88ab63c3ee282c76d652fc86518aacb737ff35796023fae56a65ced1a5978"}, - {file = "pydantic-1.10.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a48f1953c4a1d9bd0b5167ac50da9a79f6072c63c4cef4cf2a3736994903583e"}, - {file = "pydantic-1.10.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a9f2de23bec87ff306aef658384b02aa7c32389766af3c5dee9ce33e80222dfa"}, - {file = "pydantic-1.10.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:cd8702c5142afda03dc2b1ee6bc358b62b3735b2cce53fc77b31ca9f728e4bc8"}, - {file = "pydantic-1.10.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6e7124d6855b2780611d9f5e1e145e86667eaa3bd9459192c8dc1a097f5e9903"}, - {file = "pydantic-1.10.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b53e1d41e97063d51a02821b80538053ee4608b9a181c1005441f1673c55423"}, - {file = "pydantic-1.10.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:55b1625899acd33229c4352ce0ae54038529b412bd51c4915349b49ca575258f"}, - {file = "pydantic-1.10.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:301d626a59edbe5dfb48fcae245896379a450d04baeed50ef40d8199f2733b06"}, - {file = "pydantic-1.10.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6f9d649892a6f54a39ed56b8dfd5e08b5f3be5f893da430bed76975f3735d15"}, - {file = "pydantic-1.10.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d7b5a3821225f5c43496c324b0d6875fde910a1c2933d726a743ce328fbb2a8c"}, - {file = "pydantic-1.10.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f2f7eb6273dd12472d7f218e1fef6f7c7c2f00ac2e1ecde4db8824c457300416"}, - {file = "pydantic-1.10.4-cp38-cp38-win_amd64.whl", hash = "sha256:4b05697738e7d2040696b0a66d9f0a10bec0efa1883ca75ee9e55baf511909d6"}, - {file = "pydantic-1.10.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a9a6747cac06c2beb466064dda999a13176b23535e4c496c9d48e6406f92d42d"}, - {file = "pydantic-1.10.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:eb992a1ef739cc7b543576337bebfc62c0e6567434e522e97291b251a41dad7f"}, - {file = "pydantic-1.10.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:990406d226dea0e8f25f643b370224771878142155b879784ce89f633541a024"}, - {file = "pydantic-1.10.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e82a6d37a95e0b1b42b82ab340ada3963aea1317fd7f888bb6b9dfbf4fff57c"}, - {file = "pydantic-1.10.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9193d4f4ee8feca58bc56c8306bcb820f5c7905fd919e0750acdeeeef0615b28"}, - {file = "pydantic-1.10.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2b3ce5f16deb45c472dde1a0ee05619298c864a20cded09c4edd820e1454129f"}, - {file = "pydantic-1.10.4-cp39-cp39-win_amd64.whl", hash = "sha256:9cbdc268a62d9a98c56e2452d6c41c0263d64a2009aac69246486f01b4f594c4"}, - {file = "pydantic-1.10.4-py3-none-any.whl", hash = "sha256:4948f264678c703f3877d1c8877c4e3b2e12e549c57795107f08cf70c6ec7774"}, - {file = "pydantic-1.10.4.tar.gz", hash = "sha256:b9a3859f24eb4e097502a3be1fb4b2abb79b6103dd9e2e0edb70613a4459a648"}, + {file = "pydantic-1.10.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5920824fe1e21cbb3e38cf0f3dd24857c8959801d1031ce1fac1d50857a03bfb"}, + {file = "pydantic-1.10.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3bb99cf9655b377db1a9e47fa4479e3330ea96f4123c6c8200e482704bf1eda2"}, + {file = "pydantic-1.10.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2185a3b3d98ab4506a3f6707569802d2d92c3a7ba3a9a35683a7709ea6c2aaa2"}, + {file = "pydantic-1.10.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f582cac9d11c227c652d3ce8ee223d94eb06f4228b52a8adaafa9fa62e73d5c9"}, + {file = "pydantic-1.10.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c9e5b778b6842f135902e2d82624008c6a79710207e28e86966cd136c621bfee"}, + {file = "pydantic-1.10.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:72ef3783be8cbdef6bca034606a5de3862be6b72415dc5cb1fb8ddbac110049a"}, + {file = "pydantic-1.10.5-cp310-cp310-win_amd64.whl", hash = "sha256:45edea10b75d3da43cfda12f3792833a3fa70b6eee4db1ed6aed528cef17c74e"}, + {file = "pydantic-1.10.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:63200cd8af1af2c07964546b7bc8f217e8bda9d0a2ef0ee0c797b36353914984"}, + {file = "pydantic-1.10.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:305d0376c516b0dfa1dbefeae8c21042b57b496892d721905a6ec6b79494a66d"}, + {file = "pydantic-1.10.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fd326aff5d6c36f05735c7c9b3d5b0e933b4ca52ad0b6e4b38038d82703d35b"}, + {file = "pydantic-1.10.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6bb0452d7b8516178c969d305d9630a3c9b8cf16fcf4713261c9ebd465af0d73"}, + {file = "pydantic-1.10.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9a9d9155e2a9f38b2eb9374c88f02fd4d6851ae17b65ee786a87d032f87008f8"}, + {file = "pydantic-1.10.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f836444b4c5ece128b23ec36a446c9ab7f9b0f7981d0d27e13a7c366ee163f8a"}, + {file = "pydantic-1.10.5-cp311-cp311-win_amd64.whl", hash = "sha256:8481dca324e1c7b715ce091a698b181054d22072e848b6fc7895cd86f79b4449"}, + {file = "pydantic-1.10.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:87f831e81ea0589cd18257f84386bf30154c5f4bed373b7b75e5cb0b5d53ea87"}, + {file = "pydantic-1.10.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ce1612e98c6326f10888df951a26ec1a577d8df49ddcaea87773bfbe23ba5cc"}, + {file = "pydantic-1.10.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58e41dd1e977531ac6073b11baac8c013f3cd8706a01d3dc74e86955be8b2c0c"}, + {file = "pydantic-1.10.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6a4b0aab29061262065bbdede617ef99cc5914d1bf0ddc8bcd8e3d7928d85bd6"}, + {file = "pydantic-1.10.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:36e44a4de37b8aecffa81c081dbfe42c4d2bf9f6dff34d03dce157ec65eb0f15"}, + {file = "pydantic-1.10.5-cp37-cp37m-win_amd64.whl", hash = "sha256:261f357f0aecda005934e413dfd7aa4077004a174dafe414a8325e6098a8e419"}, + {file = "pydantic-1.10.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b429f7c457aebb7fbe7cd69c418d1cd7c6fdc4d3c8697f45af78b8d5a7955760"}, + {file = "pydantic-1.10.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:663d2dd78596c5fa3eb996bc3f34b8c2a592648ad10008f98d1348be7ae212fb"}, + {file = "pydantic-1.10.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51782fd81f09edcf265823c3bf43ff36d00db246eca39ee765ef58dc8421a642"}, + {file = "pydantic-1.10.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c428c0f64a86661fb4873495c4fac430ec7a7cef2b8c1c28f3d1a7277f9ea5ab"}, + {file = "pydantic-1.10.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:76c930ad0746c70f0368c4596020b736ab65b473c1f9b3872310a835d852eb19"}, + {file = "pydantic-1.10.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3257bd714de9db2102b742570a56bf7978e90441193acac109b1f500290f5718"}, + {file = "pydantic-1.10.5-cp38-cp38-win_amd64.whl", hash = "sha256:f5bee6c523d13944a1fdc6f0525bc86dbbd94372f17b83fa6331aabacc8fd08e"}, + {file = "pydantic-1.10.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:532e97c35719f137ee5405bd3eeddc5c06eb91a032bc755a44e34a712420daf3"}, + {file = "pydantic-1.10.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ca9075ab3de9e48b75fa8ccb897c34ccc1519177ad8841d99f7fd74cf43be5bf"}, + {file = "pydantic-1.10.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd46a0e6296346c477e59a954da57beaf9c538da37b9df482e50f836e4a7d4bb"}, + {file = "pydantic-1.10.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3353072625ea2a9a6c81ad01b91e5c07fa70deb06368c71307529abf70d23325"}, + {file = "pydantic-1.10.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:3f9d9b2be177c3cb6027cd67fbf323586417868c06c3c85d0d101703136e6b31"}, + {file = "pydantic-1.10.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b473d00ccd5c2061fd896ac127b7755baad233f8d996ea288af14ae09f8e0d1e"}, + {file = "pydantic-1.10.5-cp39-cp39-win_amd64.whl", hash = "sha256:5f3bc8f103b56a8c88021d481410874b1f13edf6e838da607dcb57ecff9b4594"}, + {file = "pydantic-1.10.5-py3-none-any.whl", hash = "sha256:7c5b94d598c90f2f46b3a983ffb46ab806a67099d118ae0da7ef21a2a4033b28"}, + {file = "pydantic-1.10.5.tar.gz", hash = "sha256:9e337ac83686645a46db0e825acceea8e02fca4062483f40e9ae178e8bd1103a"}, ] [package.dependencies] @@ -1441,14 +1442,14 @@ cffi = ">=1.9.1" [[package]] name = "pytest" -version = "7.2.1" +version = "7.2.2" description = "pytest: simple powerful testing with Python" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.2.1-py3-none-any.whl", hash = "sha256:c7c6ca206e93355074ae32f7403e8ea12163b1163c976fee7d4d84027c162be5"}, - {file = "pytest-7.2.1.tar.gz", hash = "sha256:d45e0952f3727241918b8fd0f376f5ff6b301cc0777c6f9a556935c92d8a7d42"}, + {file = "pytest-7.2.2-py3-none-any.whl", hash = "sha256:130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e"}, + {file = "pytest-7.2.2.tar.gz", hash = "sha256:c99ab0c73aceb050f68929bc93af19ab6db0558791c6a0715723abe9d0ade9d4"}, ] [package.dependencies] @@ -1519,14 +1520,14 @@ pytest = ">=3.0" [[package]] name = "pytest-xdist" -version = "3.1.0" +version = "3.2.0" description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-xdist-3.1.0.tar.gz", hash = "sha256:40fdb8f3544921c5dfcd486ac080ce22870e71d82ced6d2e78fa97c2addd480c"}, - {file = "pytest_xdist-3.1.0-py3-none-any.whl", hash = "sha256:70a76f191d8a1d2d6be69fc440cdf85f3e4c03c08b520fd5dc5d338d6cf07d89"}, + {file = "pytest-xdist-3.2.0.tar.gz", hash = "sha256:fa10f95a2564cd91652f2d132725183c3b590d9fdcdec09d3677386ecf4c1ce9"}, + {file = "pytest_xdist-3.2.0-py3-none-any.whl", hash = "sha256:336098e3bbd8193276867cc87db8b22903c3927665dff9d1ac8684c02f597b68"}, ] [package.dependencies] @@ -1555,28 +1556,29 @@ six = ">=1.5" [[package]] name = "python-multipart" -version = "0.0.5" +version = "0.0.6" description = "A streaming multipart parser for Python" category = "main" optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "python-multipart-0.0.5.tar.gz", hash = "sha256:f7bb5f611fc600d15fa47b3974c8aa16e93724513b49b5f95c81e6624c83fa43"}, + {file = "python_multipart-0.0.6-py3-none-any.whl", hash = "sha256:ee698bab5ef148b0a760751c261902cd096e57e10558e11aca17646b74ee1c18"}, + {file = "python_multipart-0.0.6.tar.gz", hash = "sha256:e9925a80bb668529f1b67c7fdb0a5dacdd7cbfc6fb0bff3ea443fe22bdd62132"}, ] -[package.dependencies] -six = ">=1.4.0" +[package.extras] +dev = ["atomicwrites (==1.2.1)", "attrs (==19.2.0)", "coverage (==6.5.0)", "hatch", "invoke (==1.7.3)", "more-itertools (==4.3.0)", "pbr (==4.3.0)", "pluggy (==1.0.0)", "py (==1.11.0)", "pytest (==7.2.0)", "pytest-cov (==4.0.0)", "pytest-timeout (==2.1.0)", "pyyaml (==5.1)"] [[package]] name = "redis" -version = "4.4.2" +version = "4.5.1" description = "Python client for Redis database and key-value store" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "redis-4.4.2-py3-none-any.whl", hash = "sha256:e6206448e2f8a432871d07d432c13ed6c2abcf6b74edb436c99752b1371be387"}, - {file = "redis-4.4.2.tar.gz", hash = "sha256:a010f6cb7378065040a02839c3f75c7e0fb37a87116fb4a95be82a95552776c7"}, + {file = "redis-4.5.1-py3-none-any.whl", hash = "sha256:5deb072d26e67d2be1712603bfb7947ec3431fb0eec9c578994052e33035af6d"}, + {file = "redis-4.5.1.tar.gz", hash = "sha256:1eec3741cda408d3a5f84b78d089c8b8d895f21b3b050988351e925faf202864"}, ] [package.dependencies] @@ -1628,14 +1630,14 @@ idna2008 = ["idna"] [[package]] name = "setuptools" -version = "66.1.1" +version = "67.4.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-66.1.1-py3-none-any.whl", hash = "sha256:6f590d76b713d5de4e49fe4fbca24474469f53c83632d5d0fd056f7ff7e8112b"}, - {file = "setuptools-66.1.1.tar.gz", hash = "sha256:ac4008d396bc9cd983ea483cb7139c0240a07bbc74ffb6232fceffedc6cf03a8"}, + {file = "setuptools-67.4.0-py3-none-any.whl", hash = "sha256:f106dee1b506dee5102cc3f3e9e68137bbad6d47b616be7991714b0c62204251"}, + {file = "setuptools-67.4.0.tar.gz", hash = "sha256:e5fd0a713141a4a105412233c63dc4e17ba0090c8e8334594ac790ec97792330"}, ] [package.extras] @@ -1731,7 +1733,7 @@ files = [ ] [package.dependencies] -greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} +greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and platform_machine == \"aarch64\" or python_version >= \"3\" and platform_machine == \"ppc64le\" or python_version >= \"3\" and platform_machine == \"x86_64\" or python_version >= \"3\" and platform_machine == \"amd64\" or python_version >= \"3\" and platform_machine == \"AMD64\" or python_version >= \"3\" and platform_machine == \"win32\" or python_version >= \"3\" and platform_machine == \"WIN32\""} [package.extras] aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] @@ -1771,14 +1773,14 @@ parse = ">=1.19.0,<2.0.0" [[package]] name = "starlette" -version = "0.22.0" +version = "0.25.0" description = "The little ASGI library that shines." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "starlette-0.22.0-py3-none-any.whl", hash = "sha256:b5eda991ad5f0ee5d8ce4c4540202a573bb6691ecd0c712262d0bc85cf8f2c50"}, - {file = "starlette-0.22.0.tar.gz", hash = "sha256:b092cbc365bea34dd6840b42861bdabb2f507f8671e642e8272d2442e08ea4ff"}, + {file = "starlette-0.25.0-py3-none-any.whl", hash = "sha256:774f1df1983fd594b9b6fb3ded39c2aa1979d10ac45caac0f4255cbe2acb8628"}, + {file = "starlette-0.25.0.tar.gz", hash = "sha256:854c71e73736c429c2bdb07801f2c76c9cba497e7c3cf4988fde5e95fe4cdb3c"}, ] [package.dependencies] @@ -1841,14 +1843,14 @@ files = [ [[package]] name = "typing-extensions" -version = "4.4.0" +version = "4.5.0" description = "Backported and Experimental Type Hints for Python 3.7+" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, - {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, + {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"}, + {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"}, ] [[package]] @@ -1932,14 +1934,14 @@ files = [ [[package]] name = "werkzeug" -version = "2.2.2" +version = "2.2.3" description = "The comprehensive WSGI web application library." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "Werkzeug-2.2.2-py3-none-any.whl", hash = "sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5"}, - {file = "Werkzeug-2.2.2.tar.gz", hash = "sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f"}, + {file = "Werkzeug-2.2.3-py3-none-any.whl", hash = "sha256:56433961bc1f12533306c624f3be5e744389ac61d722175d543e1751285da612"}, + {file = "Werkzeug-2.2.3.tar.gz", hash = "sha256:2e1ccc9417d4da358b9de6f174e3ac094391ea1d4fbef2d667865d819dfd0afe"}, ] [package.dependencies] @@ -1965,21 +1967,21 @@ h11 = ">=0.9.0,<1" [[package]] name = "zipp" -version = "3.11.0" +version = "3.15.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "zipp-3.11.0-py3-none-any.whl", hash = "sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa"}, - {file = "zipp-3.11.0.tar.gz", hash = "sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766"}, + {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, + {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] -testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.11" -content-hash = "b948985f8468d1fba21b699ce7394519ab58a62c1445ee0ab76fbcc7b7f759f2" +content-hash = "c868a7569c7dcaa34c5fae297e81e180b2d111bf850aa0f02759d422143e7a12" diff --git a/pyproject.toml b/pyproject.toml index 7133612f..f63d61fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,52 +57,52 @@ python = ">=3.9,<3.11" # based on git tags. # General -aiofiles = "^22.0.0" -asgiref = "^3.4.1" -bcrypt = "^4.0.0" +aiofiles = "^23.1.0" +asgiref = "^3.6.0" +bcrypt = "^4.0.1" bleach = "^6.0.0" -email-validator = "^1.3.0" -fakeredis = "^2.0.0" +email-validator = "^1.3.1" +fakeredis = "^2.9.2" feedgen = "^0.9.0" -httpx = "^0.23.1" -itsdangerous = "^2.0.1" -lxml = "^4.6.3" -orjson = "^3.8.2" -protobuf = "^4.21.9" +httpx = "^0.23.3" +itsdangerous = "^2.1.2" +lxml = "^4.9.2" +orjson = "^3.8.7" +protobuf = "^4.22.0" pygit2 = "^1.11.1" -python-multipart = "^0.0.5" -redis = "^4.3.5" -requests = "^2.28.1" +python-multipart = "^0.0.6" +redis = "^4.5.1" +requests = "^2.28.2" paginate = "^0.5.6" # SQL -alembic = "^1.7.4" -mysqlclient = "^2.0.3" -Authlib = "^1.0.0" -Jinja2 = "^3.0.2" -Markdown = "^3.3.6" -Werkzeug = "^2.0.2" -SQLAlchemy = "^1.4.26" +alembic = "^1.9.4" +mysqlclient = "^2.1.1" +Authlib = "^1.2.0" +Jinja2 = "^3.1.2" +Markdown = "^3.4.1" +Werkzeug = "^2.2.3" +SQLAlchemy = "^1.4.46" # ASGI uvicorn = "^0.20.0" gunicorn = "^20.1.0" -Hypercorn = "^0.14.0" -prometheus-fastapi-instrumentator = "^5.7.1" -pytest-xdist = "^3.0.2" -filelock = "^3.3.2" -posix-ipc = "^1.0.5" +Hypercorn = "^0.14.3" +prometheus-fastapi-instrumentator = "^5.10.0" +pytest-xdist = "^3.2.0" +filelock = "^3.9.0" +posix-ipc = "^1.1.1" pyalpm = "^0.10.6" -fastapi = "^0.89.1" +fastapi = "^0.92.0" srcinfo = "^0.1.2" tomlkit = "^0.11.6" [tool.poetry.dev-dependencies] -coverage = "^7.1.0" -pytest = "^7.2.0" -pytest-asyncio = "^0.20.2" +coverage = "^7.2.1" +pytest = "^7.2.2" +pytest-asyncio = "^0.20.3" pytest-cov = "^4.0.0" -pytest-tap = "^3.2" +pytest-tap = "^3.3" watchfiles = "^0.18.1" [tool.poetry.scripts] From 52c962a59026cb3fa279aa3f50fa13fc416381b7 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sat, 4 Mar 2023 10:29:54 +0100 Subject: [PATCH 012/178] fix(deps): fastapi 0.92.0 upgrade middleware must be added before startup: fixes: "RuntimeError: Cannot add middleware after an application has started" https://fastapi.tiangolo.com/release-notes/#0910 Signed-off-by: moson-mo --- aurweb/asgi.py | 12 +++++++----- test/test_asgi.py | 19 +++++++++++++------ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/aurweb/asgi.py b/aurweb/asgi.py index b172626f..b6578f33 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -38,6 +38,8 @@ logger = aur_logging.get_logger(__name__) # Setup the FastAPI app. app = FastAPI() +session_secret = aurweb.config.get("fastapi", "session_secret") + # Instrument routes with the prometheus-fastapi-instrumentator # library with custom collectors and expose /metrics. instrumentator().add(prometheus.http_api_requests_total()) @@ -68,7 +70,6 @@ async def app_startup(): 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") @@ -84,10 +85,6 @@ async def app_startup(): "/static/images", StaticFiles(directory="web/html/images"), name="static_images" ) - # Add application middlewares. - app.add_middleware(AuthenticationMiddleware, backend=BasicAuthBackend()) - app.add_middleware(SessionMiddleware, secret_key=session_secret) - # Add application routes. def add_router(module): app.include_router(module.router) @@ -320,3 +317,8 @@ async def id_redirect_middleware(request: Request, call_next: typing.Callable): return RedirectResponse(f"{path}/{id}{qs}") return await util.error_or_result(call_next, request) + + +# Add application middlewares. +app.add_middleware(AuthenticationMiddleware, backend=BasicAuthBackend()) +app.add_middleware(SessionMiddleware, secret_key=session_secret) diff --git a/test/test_asgi.py b/test/test_asgi.py index 3b794c76..840e6608 100644 --- a/test/test_asgi.py +++ b/test/test_asgi.py @@ -68,12 +68,19 @@ async def test_asgi_startup_session_secret_exception(monkeypatch): @pytest.mark.asyncio -async def test_asgi_startup_exception(monkeypatch): - with mock.patch.dict(os.environ, {"AUR_CONFIG": "conf/config.defaults"}): - aurweb.config.rehash() - with pytest.raises(Exception): - await aurweb.asgi.app_startup() - aurweb.config.rehash() +async def test_asgi_startup_exception(): + # save proper session secret + prev_secret = aurweb.asgi.session_secret + + # remove secret + aurweb.asgi.session_secret = None + + # startup should fail + with pytest.raises(Exception): + await aurweb.asgi.app_startup() + + # restore previous session secret after test + aurweb.asgi.session_secret = prev_secret @pytest.mark.asyncio From 7d1827ffc54617b58328f44e993bde6bc97fe927 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Wed, 8 Mar 2023 18:40:35 +0100 Subject: [PATCH 013/178] feat: cancel button for comment editing Adds button that allows cancellation while editing a comment Signed-off-by: moson-mo --- aurweb/routers/pkgbase.py | 6 ++++++ po/aurweb.pot | 4 ++++ templates/partials/packages/comment_form.html | 5 +++++ test/test_pkgbase_routes.py | 20 +++++++++++++++++++ 4 files changed, 35 insertions(+) diff --git a/aurweb/routers/pkgbase.py b/aurweb/routers/pkgbase.py index 4e018a64..6073aed5 100644 --- a/aurweb/routers/pkgbase.py +++ b/aurweb/routers/pkgbase.py @@ -293,8 +293,14 @@ async def pkgbase_comment_post( comment: str = Form(default=str()), enable_notifications: bool = Form(default=False), next: str = Form(default=None), + cancel: bool = Form(default=False), ): """Edit an existing comment.""" + if cancel: + return RedirectResponse( + f"/pkgbase/{name}#comment-{id}", status_code=HTTPStatus.SEE_OTHER + ) + pkgbase = get_pkg_or_base(name, PackageBase) db_comment = get_pkgbase_comment(pkgbase, id) diff --git a/po/aurweb.pot b/po/aurweb.pot index ff1bde8b..7e798a21 100644 --- a/po/aurweb.pot +++ b/po/aurweb.pot @@ -2354,3 +2354,7 @@ msgstr "" #: aurweb/routers/accounts.py msgid "The account has not been deleted, check the confirmation checkbox." msgstr "" + +#: templates/partials/packages/comment_form.html +msgid "Cancel" +msgstr "" diff --git a/templates/partials/packages/comment_form.html b/templates/partials/packages/comment_form.html index 9222d6e9..bf9a14d0 100644 --- a/templates/partials/packages/comment_form.html +++ b/templates/partials/packages/comment_form.html @@ -33,6 +33,11 @@ Routes: + {% if comment %} + + {% endif %} {% if not request.user.notified(pkgbase) %} Date: Tue, 14 Mar 2023 11:17:45 +0100 Subject: [PATCH 014/178] fix: add comments in email for direct deletion/merge TUs and Devs can delete and merge packages directly. Currently the comments they enter, don't end up in the ML notification. Include the comment in the notifications for direct deletion / merge Signed-off-by: moson-mo --- aurweb/packages/requests.py | 8 ++++-- aurweb/pkgbase/actions.py | 4 +-- test/test_requests.py | 52 +++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/aurweb/packages/requests.py b/aurweb/packages/requests.py index c09082f5..be35a3d3 100644 --- a/aurweb/packages/requests.py +++ b/aurweb/packages/requests.py @@ -153,7 +153,11 @@ def close_pkgreq( @db.retry_deadlock def handle_request( - request: Request, reqtype_id: int, pkgbase: PackageBase, target: PackageBase = None + request: Request, + reqtype_id: int, + pkgbase: PackageBase, + target: PackageBase = None, + comments: str = str(), ) -> list[notify.Notification]: """ Handle package requests before performing an action. @@ -228,7 +232,7 @@ def handle_request( PackageBase=pkgbase, PackageBaseName=pkgbase.Name, Comments="Autogenerated by aurweb.", - ClosureComment=str(), + ClosureComment=comments, ) # If it's a merge request, set MergeBaseName to `target`.Name. diff --git a/aurweb/pkgbase/actions.py b/aurweb/pkgbase/actions.py index 56ba738d..00efc1ff 100644 --- a/aurweb/pkgbase/actions.py +++ b/aurweb/pkgbase/actions.py @@ -133,7 +133,7 @@ def pkgbase_delete_instance( request: Request, pkgbase: PackageBase, comments: str = str() ) -> list[notify.Notification]: notif = notify.DeleteNotification(request.user.ID, pkgbase.ID) - notifs = handle_request(request, DELETION_ID, pkgbase) + [notif] + notifs = handle_request(request, DELETION_ID, pkgbase, comments=comments) + [notif] _retry_delete(pkgbase, comments) @@ -181,7 +181,7 @@ def pkgbase_merge_instance( pkgbasename = str(pkgbase.Name) # Create notifications. - notifs = handle_request(request, MERGE_ID, pkgbase, target) + notifs = handle_request(request, MERGE_ID, pkgbase, target, comments) _retry_merge(pkgbase, target) diff --git a/test/test_requests.py b/test/test_requests.py index 18b860f2..eb05596c 100644 --- a/test/test_requests.py +++ b/test/test_requests.py @@ -479,6 +479,27 @@ def test_deletion_autorequest(client: TestClient, tu_user: User, pkgbase: Packag assert "[Autogenerated]" in email.body +def test_deletion_autorequest_with_comment( + client: TestClient, tu_user: User, pkgbase: PackageBase +): + """Test deleting a package without a request and a comment.""" + # `pkgreq`.ReqTypeID is already DELETION_ID. + endpoint = f"/pkgbase/{pkgbase.Name}/delete" + data = {"confirm": True, "comments": "deleted with comment"} + with client as request: + request.cookies = tu_user.cookies + resp = request.post(endpoint, data=data) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + + assert resp.headers.get("location") == "/packages" + assert Email.count() == 1 + + email = Email(1).parse() + subject = r"^\[PRQ#\d+\] Deletion Request for [^ ]+ Accepted$" + assert re.match(subject, email.headers.get("Subject")) + assert "deleted with comment" in email.body + + def test_merge_request( client: TestClient, user: User, @@ -568,6 +589,37 @@ def test_merge_autorequest( assert "[Autogenerated]" in email.body +def test_merge_autorequest_with_comment( + 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 + + # `pkgreq`.ReqTypeID is already DELETION_ID. + endpoint = f"/pkgbase/{pkgbase.Name}/merge" + data = {"into": target.Name, "confirm": True, "comments": "merged with comment"} + with client as request: + request.cookies = tu_user.cookies + resp = request.post(endpoint, data=data) + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert resp.headers.get("location") == f"/pkgbase/{target.Name}" + + # Should've gotten one email with our comment + assert Email.count() == 1 + + # Test accepted merge request notification. + email = Email(1).parse() + subj = r"^\[PRQ#\d+\] Merge Request for [^ ]+ Accepted$" + assert re.match(subj, email.headers.get("Subject")) + assert "merged with comment" in email.body + + def test_orphan_request( client: TestClient, user: User, From bf0d4a2be7d51ab640f999a31caefdc8a4caffcc Mon Sep 17 00:00:00 2001 From: moson-mo Date: Tue, 14 Mar 2023 11:47:46 +0100 Subject: [PATCH 015/178] fix(deps): bump dependencies bump all deps except sqlalchemy. - Updating exceptiongroup (1.1.0 -> 1.1.1) - Updating pydantic (1.10.5 -> 1.10.6) - Updating starlette (0.25.0 -> 0.26.1) - Updating charset-normalizer (3.0.1 -> 3.1.0) - Updating fastapi (0.92.0 -> 0.94.1) - Updating setuptools (67.4.0 -> 67.6.0) - Updating urllib3 (1.26.14 -> 1.26.15) - Updating alembic (1.9.4 -> 1.10.2) - Updating fakeredis (2.9.2 -> 2.10.0) - Updating prometheus-fastapi-instrumentator (5.10.0 -> 5.11.1) - Updating protobuf (4.22.0 -> 4.22.1) - Updating pytest-xdist (3.2.0 -> 3.2.1) - Updating uvicorn (0.20.0 -> 0.21.0) - Updating filelock (3.9.0 -> 3.9.1) Signed-off-by: moson-mo --- poetry.lock | 348 ++++++++++++++++++++++++------------------------- pyproject.toml | 16 +-- 2 files changed, 176 insertions(+), 188 deletions(-) diff --git a/poetry.lock b/poetry.lock index 75d6dcf3..fe81898e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -14,19 +14,20 @@ files = [ [[package]] name = "alembic" -version = "1.9.4" +version = "1.10.2" description = "A database migration tool for SQLAlchemy." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "alembic-1.9.4-py3-none-any.whl", hash = "sha256:6f1c2207369bf4f49f952057a33bb017fbe5c148c2a773b46906b806ea6e825f"}, - {file = "alembic-1.9.4.tar.gz", hash = "sha256:4d3bd32ecdbb7bbfb48a9fe9e6d6fd6a831a1b59d03e26e292210237373e7db5"}, + {file = "alembic-1.10.2-py3-none-any.whl", hash = "sha256:8b48368f6533c064b39c024e1daba15ae7f947eac84185c28c06bbe1301a5497"}, + {file = "alembic-1.10.2.tar.gz", hash = "sha256:457eafbdc0769d855c2c92cbafe6b7f319f916c80cf4ed02b8f394f38b51b89d"}, ] [package.dependencies] Mako = "*" SQLAlchemy = ">=1.3.0" +typing-extensions = ">=4" [package.extras] tz = ["python-dateutil"] @@ -258,100 +259,87 @@ pycparser = "*" [[package]] name = "charset-normalizer" -version = "3.0.1" +version = "3.1.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "main" optional = false -python-versions = "*" +python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.0.1.tar.gz", hash = "sha256:ebea339af930f8ca5d7a699b921106c6e29c617fe9606fa7baa043c1cdae326f"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88600c72ef7587fe1708fd242b385b6ed4b8904976d5da0893e31df8b3480cb6"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c75ffc45f25324e68ab238cb4b5c0a38cd1c3d7f1fb1f72b5541de469e2247db"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db72b07027db150f468fbada4d85b3b2729a3db39178abf5c543b784c1254539"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62595ab75873d50d57323a91dd03e6966eb79c41fa834b7a1661ed043b2d404d"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff6f3db31555657f3163b15a6b7c6938d08df7adbfc9dd13d9d19edad678f1e8"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:772b87914ff1152b92a197ef4ea40efe27a378606c39446ded52c8f80f79702e"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70990b9c51340e4044cfc394a81f614f3f90d41397104d226f21e66de668730d"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:292d5e8ba896bbfd6334b096e34bffb56161c81408d6d036a7dfa6929cff8783"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2edb64ee7bf1ed524a1da60cdcd2e1f6e2b4f66ef7c077680739f1641f62f555"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:31a9ddf4718d10ae04d9b18801bd776693487cbb57d74cc3458a7673f6f34639"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:44ba614de5361b3e5278e1241fda3dc1838deed864b50a10d7ce92983797fa76"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:12db3b2c533c23ab812c2b25934f60383361f8a376ae272665f8e48b88e8e1c6"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c512accbd6ff0270939b9ac214b84fb5ada5f0409c44298361b2f5e13f9aed9e"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-win32.whl", hash = "sha256:502218f52498a36d6bf5ea77081844017bf7982cdbe521ad85e64cabee1b608b"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:601f36512f9e28f029d9481bdaf8e89e5148ac5d89cffd3b05cd533eeb423b59"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0298eafff88c99982a4cf66ba2efa1128e4ddaca0b05eec4c456bbc7db691d8d"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a8d0fc946c784ff7f7c3742310cc8a57c5c6dc31631269876a88b809dbeff3d3"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:87701167f2a5c930b403e9756fab1d31d4d4da52856143b609e30a1ce7160f3c"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e76c0f23218b8f46c4d87018ca2e441535aed3632ca134b10239dfb6dadd6b"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c0a590235ccd933d9892c627dec5bc7511ce6ad6c1011fdf5b11363022746c1"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c7fe7afa480e3e82eed58e0ca89f751cd14d767638e2550c77a92a9e749c317"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79909e27e8e4fcc9db4addea88aa63f6423ebb171db091fb4373e3312cb6d603"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ac7b6a045b814cf0c47f3623d21ebd88b3e8cf216a14790b455ea7ff0135d18"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:72966d1b297c741541ca8cf1223ff262a6febe52481af742036a0b296e35fa5a"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f9d0c5c045a3ca9bedfc35dca8526798eb91a07aa7a2c0fee134c6c6f321cbd7"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5995f0164fa7df59db4746112fec3f49c461dd6b31b841873443bdb077c13cfc"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4a8fcf28c05c1f6d7e177a9a46a1c52798bfe2ad80681d275b10dcf317deaf0b"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:761e8904c07ad053d285670f36dd94e1b6ab7f16ce62b9805c475b7aa1cffde6"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-win32.whl", hash = "sha256:71140351489970dfe5e60fc621ada3e0f41104a5eddaca47a7acb3c1b851d6d3"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:9ab77acb98eba3fd2a85cd160851816bfce6871d944d885febf012713f06659c"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:84c3990934bae40ea69a82034912ffe5a62c60bbf6ec5bc9691419641d7d5c9a"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74292fc76c905c0ef095fe11e188a32ebd03bc38f3f3e9bcb85e4e6db177b7ea"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c95a03c79bbe30eec3ec2b7f076074f4281526724c8685a42872974ef4d36b72"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c39b0e3eac288fedc2b43055cfc2ca7a60362d0e5e87a637beac5d801ef478"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df2c707231459e8a4028eabcd3cfc827befd635b3ef72eada84ab13b52e1574d"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93ad6d87ac18e2a90b0fe89df7c65263b9a99a0eb98f0a3d2e079f12a0735837"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:59e5686dd847347e55dffcc191a96622f016bc0ad89105e24c14e0d6305acbc6"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:cd6056167405314a4dc3c173943f11249fa0f1b204f8b51ed4bde1a9cd1834dc"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:083c8d17153ecb403e5e1eb76a7ef4babfc2c48d58899c98fcaa04833e7a2f9a"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:f5057856d21e7586765171eac8b9fc3f7d44ef39425f85dbcccb13b3ebea806c"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:7eb33a30d75562222b64f569c642ff3dc6689e09adda43a082208397f016c39a"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-win32.whl", hash = "sha256:95dea361dd73757c6f1c0a1480ac499952c16ac83f7f5f4f84f0658a01b8ef41"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:eaa379fcd227ca235d04152ca6704c7cb55564116f8bc52545ff357628e10602"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3e45867f1f2ab0711d60c6c71746ac53537f1684baa699f4f668d4c6f6ce8e14"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cadaeaba78750d58d3cc6ac4d1fd867da6fc73c88156b7a3212a3cd4819d679d"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:911d8a40b2bef5b8bbae2e36a0b103f142ac53557ab421dc16ac4aafee6f53dc"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:503e65837c71b875ecdd733877d852adbc465bd82c768a067badd953bf1bc5a3"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a60332922359f920193b1d4826953c507a877b523b2395ad7bc716ddd386d866"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16a8663d6e281208d78806dbe14ee9903715361cf81f6d4309944e4d1e59ac5b"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a16418ecf1329f71df119e8a65f3aa68004a3f9383821edcb20f0702934d8087"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9d9153257a3f70d5f69edf2325357251ed20f772b12e593f3b3377b5f78e7ef8"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:02a51034802cbf38db3f89c66fb5d2ec57e6fe7ef2f4a44d070a593c3688667b"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:2e396d70bc4ef5325b72b593a72c8979999aa52fb8bcf03f701c1b03e1166918"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:11b53acf2411c3b09e6af37e4b9005cba376c872503c8f28218c7243582df45d"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-win32.whl", hash = "sha256:0bf2dae5291758b6f84cf923bfaa285632816007db0330002fa1de38bfcb7154"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:2c03cc56021a4bd59be889c2b9257dae13bf55041a3372d3295416f86b295fb5"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:024e606be3ed92216e2b6952ed859d86b4cfa52cd5bc5f050e7dc28f9b43ec42"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4b0d02d7102dd0f997580b51edc4cebcf2ab6397a7edf89f1c73b586c614272c"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:358a7c4cb8ba9b46c453b1dd8d9e431452d5249072e4f56cfda3149f6ab1405e"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81d6741ab457d14fdedc215516665050f3822d3e56508921cc7239f8c8e66a58"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8b8af03d2e37866d023ad0ddea594edefc31e827fee64f8de5611a1dbc373174"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9cf4e8ad252f7c38dd1f676b46514f92dc0ebeb0db5552f5f403509705e24753"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e696f0dd336161fca9adbb846875d40752e6eba585843c768935ba5c9960722b"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c22d3fe05ce11d3671297dc8973267daa0f938b93ec716e12e0f6dee81591dc1"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:109487860ef6a328f3eec66f2bf78b0b72400280d8f8ea05f69c51644ba6521a"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:37f8febc8ec50c14f3ec9637505f28e58d4f66752207ea177c1d67df25da5aed"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:f97e83fa6c25693c7a35de154681fcc257c1c41b38beb0304b9c4d2d9e164479"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a152f5f33d64a6be73f1d30c9cc82dfc73cec6477ec268e7c6e4c7d23c2d2291"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:39049da0ffb96c8cbb65cbf5c5f3ca3168990adf3551bd1dee10c48fce8ae820"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-win32.whl", hash = "sha256:4457ea6774b5611f4bed5eaa5df55f70abde42364d498c5134b7ef4c6958e20e"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:e62164b50f84e20601c1ff8eb55620d2ad25fb81b59e3cd776a1902527a788af"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8eade758719add78ec36dc13201483f8e9b5d940329285edcd5f70c0a9edbd7f"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8499ca8f4502af841f68135133d8258f7b32a53a1d594aa98cc52013fff55678"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3fc1c4a2ffd64890aebdb3f97e1278b0cc72579a08ca4de8cd2c04799a3a22be"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00d3ffdaafe92a5dc603cb9bd5111aaa36dfa187c8285c543be562e61b755f6b"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2ac1b08635a8cd4e0cbeaf6f5e922085908d48eb05d44c5ae9eabab148512ca"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6f45710b4459401609ebebdbcfb34515da4fc2aa886f95107f556ac69a9147e"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ae1de54a77dc0d6d5fcf623290af4266412a7c4be0b1ff7444394f03f5c54e3"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b590df687e3c5ee0deef9fc8c547d81986d9a1b56073d82de008744452d6541"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab5de034a886f616a5668aa5d098af2b5385ed70142090e2a31bcbd0af0fdb3d"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9cb3032517f1627cc012dbc80a8ec976ae76d93ea2b5feaa9d2a5b8882597579"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:608862a7bf6957f2333fc54ab4399e405baad0163dc9f8d99cb236816db169d4"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0f438ae3532723fb6ead77e7c604be7c8374094ef4ee2c5e03a3a17f1fca256c"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:356541bf4381fa35856dafa6a965916e54bed415ad8a24ee6de6e37deccf2786"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-win32.whl", hash = "sha256:39cf9ed17fe3b1bc81f33c9ceb6ce67683ee7526e65fde1447c772afc54a1bb8"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:0a11e971ed097d24c534c037d298ad32c6ce81a45736d31e0ff0ad37ab437d59"}, - {file = "charset_normalizer-3.0.1-py3-none-any.whl", hash = "sha256:7e189e2e1d3ed2f4aebabd2d5b0f931e883676e51c7624826e0a4e5fe8a0bf24"}, + {file = "charset-normalizer-3.1.0.tar.gz", hash = "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-win32.whl", hash = "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-win32.whl", hash = "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-win32.whl", hash = "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-win32.whl", hash = "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b"}, + {file = "charset_normalizer-3.1.0-py3-none-any.whl", hash = "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d"}, ] [[package]] @@ -533,14 +521,14 @@ idna = ">=2.0.0" [[package]] name = "exceptiongroup" -version = "1.1.0" +version = "1.1.1" description = "Backport of PEP 654 (exception groups)" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.0-py3-none-any.whl", hash = "sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e"}, - {file = "exceptiongroup-1.1.0.tar.gz", hash = "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23"}, + {file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"}, + {file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"}, ] [package.extras] @@ -563,14 +551,14 @@ testing = ["pre-commit"] [[package]] name = "fakeredis" -version = "2.9.2" +version = "2.10.0" description = "Fake implementation of redis API for testing purposes." category = "main" optional = false python-versions = ">=3.8,<4.0" files = [ - {file = "fakeredis-2.9.2-py3-none-any.whl", hash = "sha256:35962e0ded572302c4461ad1a40308259cc10b7c546b13228e6d7880bf7b74bb"}, - {file = "fakeredis-2.9.2.tar.gz", hash = "sha256:3bcc2b5c10d5e03cc5b46697d77c651f48391b506ff931576d2869c7549e2e25"}, + {file = "fakeredis-2.10.0-py3-none-any.whl", hash = "sha256:7e66c96793688703a1da41256323ddaa1b3a2cab4ef793866839a937bb273915"}, + {file = "fakeredis-2.10.0.tar.gz", hash = "sha256:722644759bba4ad61fa38f0bb34939b7657f166ba35892f747e282407a196845"}, ] [package.dependencies] @@ -583,25 +571,25 @@ lua = ["lupa (>=1.14,<2.0)"] [[package]] name = "fastapi" -version = "0.92.0" +version = "0.94.1" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "fastapi-0.92.0-py3-none-any.whl", hash = "sha256:ae7b97c778e2f2ec3fb3cb4fb14162129411d99907fb71920f6d69a524340ebf"}, - {file = "fastapi-0.92.0.tar.gz", hash = "sha256:023a0f5bd2c8b2609014d3bba1e14a1d7df96c6abea0a73070621c9862b9a4de"}, + {file = "fastapi-0.94.1-py3-none-any.whl", hash = "sha256:451387550c2d25a972193f22e408a82e75a8e7867c834a03076704fe20df3256"}, + {file = "fastapi-0.94.1.tar.gz", hash = "sha256:4a75936dbf9eb74be5eb0d41a793adefe9f3fc6ba66dbdabd160120fd3c2d9cd"}, ] [package.dependencies] pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" -starlette = ">=0.25.0,<0.26.0" +starlette = ">=0.26.1,<0.27.0" [package.extras] all = ["email-validator (>=1.1.1)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] dev = ["pre-commit (>=2.17.0,<3.0.0)", "ruff (==0.0.138)", "uvicorn[standard] (>=0.12.0,<0.21.0)"] -doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer[all] (>=0.6.1,<0.8.0)"] -test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.10.0)", "coverage[toml] (>=6.5.0,<8.0)", "databases[sqlite] (>=0.3.2,<0.7.0)", "email-validator (>=1.1.1,<2.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.23.0,<0.24.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.982)", "orjson (>=3.2.1,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=7.1.3,<8.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "ruff (==0.0.138)", "sqlalchemy (>=1.3.18,<1.4.43)", "types-orjson (==3.6.2)", "types-ujson (==5.6.0.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] +doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer-cli (>=0.0.13,<0.0.14)", "typer[all] (>=0.6.1,<0.8.0)"] +test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==23.1.0)", "coverage[toml] (>=6.5.0,<8.0)", "databases[sqlite] (>=0.3.2,<0.7.0)", "email-validator (>=1.1.1,<2.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.23.0,<0.24.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.982)", "orjson (>=3.2.1,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=7.1.3,<8.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.7)", "pyyaml (>=5.3.1,<7.0.0)", "ruff (==0.0.138)", "sqlalchemy (>=1.3.18,<1.4.43)", "types-orjson (==3.6.2)", "types-ujson (==5.7.0.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] [[package]] name = "feedgen" @@ -620,19 +608,19 @@ python-dateutil = "*" [[package]] name = "filelock" -version = "3.9.0" +version = "3.9.1" description = "A platform independent file lock." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "filelock-3.9.0-py3-none-any.whl", hash = "sha256:f58d535af89bb9ad5cd4df046f741f8553a418c01a7856bf0d173bbc9f6bd16d"}, - {file = "filelock-3.9.0.tar.gz", hash = "sha256:7b319f24340b51f55a2bf7a12ac0755a9b03e718311dac567a0f4f7fabd2f5de"}, + {file = "filelock-3.9.1-py3-none-any.whl", hash = "sha256:4427cdda14a1c68e264845142842d6de2d0fa2c15ba31571a3d9c9a1ec9d191c"}, + {file = "filelock-3.9.1.tar.gz", hash = "sha256:e393782f76abea324dee598d2ea145b857a20df0e0ee4f80fcf35e72a341d2c7"}, ] [package.extras] -docs = ["furo (>=2022.12.7)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"] -testing = ["covdefaults (>=2.2.2)", "coverage (>=7.0.1)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2022.12.7)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.2.1)", "pytest (>=7.2.2)", "pytest-cov (>=4)", "pytest-timeout (>=2.1)"] [[package]] name = "greenlet" @@ -1283,14 +1271,14 @@ twisted = ["twisted"] [[package]] name = "prometheus-fastapi-instrumentator" -version = "5.10.0" +version = "5.11.1" description = "Instrument your FastAPI with Prometheus metrics." category = "main" optional = false python-versions = ">=3.7.0,<4.0.0" files = [ - {file = "prometheus_fastapi_instrumentator-5.10.0-py3-none-any.whl", hash = "sha256:cf0fb37d506f8a999a16a47e71f75b140f0673cb4ecbce634f7b41a8b4caf8f6"}, - {file = "prometheus_fastapi_instrumentator-5.10.0.tar.gz", hash = "sha256:705d2e29ca11fba9110f425a283592b8f2067ed8144405aa71b5879f7271c2a1"}, + {file = "prometheus_fastapi_instrumentator-5.11.1-py3-none-any.whl", hash = "sha256:8a58dc34b75620f634bd9c9d77978172bc5a6de05b921e301a1e4de896ca97ce"}, + {file = "prometheus_fastapi_instrumentator-5.11.1.tar.gz", hash = "sha256:34026f8735aff89a08ed71bd16a1f454d5eaaec20a9a52eb5c40aa2d585dfbba"}, ] [package.dependencies] @@ -1299,25 +1287,25 @@ prometheus-client = ">=0.8.0,<1.0.0" [[package]] name = "protobuf" -version = "4.22.0" +version = "4.22.1" description = "" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "protobuf-4.22.0-cp310-abi3-win32.whl", hash = "sha256:b2fea9dc8e3c0f32c38124790ef16cba2ee0628fe2022a52e435e1117bfef9b1"}, - {file = "protobuf-4.22.0-cp310-abi3-win_amd64.whl", hash = "sha256:a33a273d21852f911b8bda47f39f4383fe7c061eb1814db2c76c9875c89c2491"}, - {file = "protobuf-4.22.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:e894e9ae603e963f0842498c4cd5d39c6a60f0d7e4c103df50ee939564298658"}, - {file = "protobuf-4.22.0-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:7c535d126e7dcc714105ab20b418c4fedbd28f8b8afc42b7350b1e317bbbcc71"}, - {file = "protobuf-4.22.0-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:86c3d20428b007537ba6792b475c0853bba7f66b1f60e610d913b77d94b486e4"}, - {file = "protobuf-4.22.0-cp37-cp37m-win32.whl", hash = "sha256:1669cb7524221a8e2d9008d0842453dbefdd0fcdd64d67672f657244867635fb"}, - {file = "protobuf-4.22.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ab4d043865dd04e6b09386981fe8f80b39a1e46139fb4a3c206229d6b9f36ff6"}, - {file = "protobuf-4.22.0-cp38-cp38-win32.whl", hash = "sha256:29288813aacaa302afa2381db1d6e0482165737b0afdf2811df5fa99185c457b"}, - {file = "protobuf-4.22.0-cp38-cp38-win_amd64.whl", hash = "sha256:e474b63bab0a2ea32a7b26a4d8eec59e33e709321e5e16fb66e766b61b82a95e"}, - {file = "protobuf-4.22.0-cp39-cp39-win32.whl", hash = "sha256:47d31bdf58222dd296976aa1646c68c6ee80b96d22e0a3c336c9174e253fd35e"}, - {file = "protobuf-4.22.0-cp39-cp39-win_amd64.whl", hash = "sha256:c27f371f0159feb70e6ea52ed7e768b3f3a4c5676c1900a7e51a24740381650e"}, - {file = "protobuf-4.22.0-py3-none-any.whl", hash = "sha256:c3325803095fb4c2a48649c321d2fbde59f8fbfcb9bfc7a86df27d112831c571"}, - {file = "protobuf-4.22.0.tar.gz", hash = "sha256:652d8dfece122a24d98eebfef30e31e455d300efa41999d1182e015984ac5930"}, + {file = "protobuf-4.22.1-cp310-abi3-win32.whl", hash = "sha256:85aa9acc5a777adc0c21b449dafbc40d9a0b6413ff3a4f77ef9df194be7f975b"}, + {file = "protobuf-4.22.1-cp310-abi3-win_amd64.whl", hash = "sha256:8bc971d76c03f1dd49f18115b002254f2ddb2d4b143c583bb860b796bb0d399e"}, + {file = "protobuf-4.22.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:5917412347e1da08ce2939eb5cd60650dfb1a9ab4606a415b9278a1041fb4d19"}, + {file = "protobuf-4.22.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:9e12e2810e7d297dbce3c129ae5e912ffd94240b050d33f9ecf023f35563b14f"}, + {file = "protobuf-4.22.1-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:953fc7904ef46900262a26374b28c2864610b60cdc8b272f864e22143f8373c4"}, + {file = "protobuf-4.22.1-cp37-cp37m-win32.whl", hash = "sha256:6e100f7bc787cd0a0ae58dbf0ab8bbf1ee7953f862b89148b6cf5436d5e9eaa1"}, + {file = "protobuf-4.22.1-cp37-cp37m-win_amd64.whl", hash = "sha256:87a6393fa634f294bf24d1cfe9fdd6bb605cbc247af81b9b10c4c0f12dfce4b3"}, + {file = "protobuf-4.22.1-cp38-cp38-win32.whl", hash = "sha256:e3fb58076bdb550e75db06ace2a8b3879d4c4f7ec9dd86e4254656118f4a78d7"}, + {file = "protobuf-4.22.1-cp38-cp38-win_amd64.whl", hash = "sha256:651113695bc2e5678b799ee5d906b5d3613f4ccfa61b12252cfceb6404558af0"}, + {file = "protobuf-4.22.1-cp39-cp39-win32.whl", hash = "sha256:67b7d19da0fda2733702c2299fd1ef6cb4b3d99f09263eacaf1aa151d9d05f02"}, + {file = "protobuf-4.22.1-cp39-cp39-win_amd64.whl", hash = "sha256:b8700792f88e59ccecfa246fa48f689d6eee6900eddd486cdae908ff706c482b"}, + {file = "protobuf-4.22.1-py3-none-any.whl", hash = "sha256:3e19dcf4adbf608924d3486ece469dd4f4f2cf7d2649900f0efcd1a84e8fd3ba"}, + {file = "protobuf-4.22.1.tar.gz", hash = "sha256:dce7a55d501c31ecf688adb2f6c3f763cf11bc0be815d1946a84d74772ab07a7"}, ] [[package]] @@ -1345,48 +1333,48 @@ files = [ [[package]] name = "pydantic" -version = "1.10.5" +version = "1.10.6" description = "Data validation and settings management using python type hints" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-1.10.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5920824fe1e21cbb3e38cf0f3dd24857c8959801d1031ce1fac1d50857a03bfb"}, - {file = "pydantic-1.10.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3bb99cf9655b377db1a9e47fa4479e3330ea96f4123c6c8200e482704bf1eda2"}, - {file = "pydantic-1.10.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2185a3b3d98ab4506a3f6707569802d2d92c3a7ba3a9a35683a7709ea6c2aaa2"}, - {file = "pydantic-1.10.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f582cac9d11c227c652d3ce8ee223d94eb06f4228b52a8adaafa9fa62e73d5c9"}, - {file = "pydantic-1.10.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c9e5b778b6842f135902e2d82624008c6a79710207e28e86966cd136c621bfee"}, - {file = "pydantic-1.10.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:72ef3783be8cbdef6bca034606a5de3862be6b72415dc5cb1fb8ddbac110049a"}, - {file = "pydantic-1.10.5-cp310-cp310-win_amd64.whl", hash = "sha256:45edea10b75d3da43cfda12f3792833a3fa70b6eee4db1ed6aed528cef17c74e"}, - {file = "pydantic-1.10.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:63200cd8af1af2c07964546b7bc8f217e8bda9d0a2ef0ee0c797b36353914984"}, - {file = "pydantic-1.10.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:305d0376c516b0dfa1dbefeae8c21042b57b496892d721905a6ec6b79494a66d"}, - {file = "pydantic-1.10.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fd326aff5d6c36f05735c7c9b3d5b0e933b4ca52ad0b6e4b38038d82703d35b"}, - {file = "pydantic-1.10.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6bb0452d7b8516178c969d305d9630a3c9b8cf16fcf4713261c9ebd465af0d73"}, - {file = "pydantic-1.10.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9a9d9155e2a9f38b2eb9374c88f02fd4d6851ae17b65ee786a87d032f87008f8"}, - {file = "pydantic-1.10.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f836444b4c5ece128b23ec36a446c9ab7f9b0f7981d0d27e13a7c366ee163f8a"}, - {file = "pydantic-1.10.5-cp311-cp311-win_amd64.whl", hash = "sha256:8481dca324e1c7b715ce091a698b181054d22072e848b6fc7895cd86f79b4449"}, - {file = "pydantic-1.10.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:87f831e81ea0589cd18257f84386bf30154c5f4bed373b7b75e5cb0b5d53ea87"}, - {file = "pydantic-1.10.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ce1612e98c6326f10888df951a26ec1a577d8df49ddcaea87773bfbe23ba5cc"}, - {file = "pydantic-1.10.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58e41dd1e977531ac6073b11baac8c013f3cd8706a01d3dc74e86955be8b2c0c"}, - {file = "pydantic-1.10.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6a4b0aab29061262065bbdede617ef99cc5914d1bf0ddc8bcd8e3d7928d85bd6"}, - {file = "pydantic-1.10.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:36e44a4de37b8aecffa81c081dbfe42c4d2bf9f6dff34d03dce157ec65eb0f15"}, - {file = "pydantic-1.10.5-cp37-cp37m-win_amd64.whl", hash = "sha256:261f357f0aecda005934e413dfd7aa4077004a174dafe414a8325e6098a8e419"}, - {file = "pydantic-1.10.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b429f7c457aebb7fbe7cd69c418d1cd7c6fdc4d3c8697f45af78b8d5a7955760"}, - {file = "pydantic-1.10.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:663d2dd78596c5fa3eb996bc3f34b8c2a592648ad10008f98d1348be7ae212fb"}, - {file = "pydantic-1.10.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51782fd81f09edcf265823c3bf43ff36d00db246eca39ee765ef58dc8421a642"}, - {file = "pydantic-1.10.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c428c0f64a86661fb4873495c4fac430ec7a7cef2b8c1c28f3d1a7277f9ea5ab"}, - {file = "pydantic-1.10.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:76c930ad0746c70f0368c4596020b736ab65b473c1f9b3872310a835d852eb19"}, - {file = "pydantic-1.10.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3257bd714de9db2102b742570a56bf7978e90441193acac109b1f500290f5718"}, - {file = "pydantic-1.10.5-cp38-cp38-win_amd64.whl", hash = "sha256:f5bee6c523d13944a1fdc6f0525bc86dbbd94372f17b83fa6331aabacc8fd08e"}, - {file = "pydantic-1.10.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:532e97c35719f137ee5405bd3eeddc5c06eb91a032bc755a44e34a712420daf3"}, - {file = "pydantic-1.10.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ca9075ab3de9e48b75fa8ccb897c34ccc1519177ad8841d99f7fd74cf43be5bf"}, - {file = "pydantic-1.10.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd46a0e6296346c477e59a954da57beaf9c538da37b9df482e50f836e4a7d4bb"}, - {file = "pydantic-1.10.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3353072625ea2a9a6c81ad01b91e5c07fa70deb06368c71307529abf70d23325"}, - {file = "pydantic-1.10.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:3f9d9b2be177c3cb6027cd67fbf323586417868c06c3c85d0d101703136e6b31"}, - {file = "pydantic-1.10.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b473d00ccd5c2061fd896ac127b7755baad233f8d996ea288af14ae09f8e0d1e"}, - {file = "pydantic-1.10.5-cp39-cp39-win_amd64.whl", hash = "sha256:5f3bc8f103b56a8c88021d481410874b1f13edf6e838da607dcb57ecff9b4594"}, - {file = "pydantic-1.10.5-py3-none-any.whl", hash = "sha256:7c5b94d598c90f2f46b3a983ffb46ab806a67099d118ae0da7ef21a2a4033b28"}, - {file = "pydantic-1.10.5.tar.gz", hash = "sha256:9e337ac83686645a46db0e825acceea8e02fca4062483f40e9ae178e8bd1103a"}, + {file = "pydantic-1.10.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9289065611c48147c1dd1fd344e9d57ab45f1d99b0fb26c51f1cf72cd9bcd31"}, + {file = "pydantic-1.10.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8c32b6bba301490d9bb2bf5f631907803135e8085b6aa3e5fe5a770d46dd0160"}, + {file = "pydantic-1.10.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd9b9e98068fa1068edfc9eabde70a7132017bdd4f362f8b4fd0abed79c33083"}, + {file = "pydantic-1.10.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c84583b9df62522829cbc46e2b22e0ec11445625b5acd70c5681ce09c9b11c4"}, + {file = "pydantic-1.10.6-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b41822064585fea56d0116aa431fbd5137ce69dfe837b599e310034171996084"}, + {file = "pydantic-1.10.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:61f1f08adfaa9cc02e0cbc94f478140385cbd52d5b3c5a657c2fceb15de8d1fb"}, + {file = "pydantic-1.10.6-cp310-cp310-win_amd64.whl", hash = "sha256:32937835e525d92c98a1512218db4eed9ddc8f4ee2a78382d77f54341972c0e7"}, + {file = "pydantic-1.10.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bbd5c531b22928e63d0cb1868dee76123456e1de2f1cb45879e9e7a3f3f1779b"}, + {file = "pydantic-1.10.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e277bd18339177daa62a294256869bbe84df1fb592be2716ec62627bb8d7c81d"}, + {file = "pydantic-1.10.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f15277d720aa57e173954d237628a8d304896364b9de745dcb722f584812c7"}, + {file = "pydantic-1.10.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b243b564cea2576725e77aeeda54e3e0229a168bc587d536cd69941e6797543d"}, + {file = "pydantic-1.10.6-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3ce13a558b484c9ae48a6a7c184b1ba0e5588c5525482681db418268e5f86186"}, + {file = "pydantic-1.10.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3ac1cd4deed871dfe0c5f63721e29debf03e2deefa41b3ed5eb5f5df287c7b70"}, + {file = "pydantic-1.10.6-cp311-cp311-win_amd64.whl", hash = "sha256:b1eb6610330a1dfba9ce142ada792f26bbef1255b75f538196a39e9e90388bf4"}, + {file = "pydantic-1.10.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4ca83739c1263a044ec8b79df4eefc34bbac87191f0a513d00dd47d46e307a65"}, + {file = "pydantic-1.10.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea4e2a7cb409951988e79a469f609bba998a576e6d7b9791ae5d1e0619e1c0f2"}, + {file = "pydantic-1.10.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53de12b4608290992a943801d7756f18a37b7aee284b9ffa794ee8ea8153f8e2"}, + {file = "pydantic-1.10.6-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:60184e80aac3b56933c71c48d6181e630b0fbc61ae455a63322a66a23c14731a"}, + {file = "pydantic-1.10.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:415a3f719ce518e95a92effc7ee30118a25c3d032455d13e121e3840985f2efd"}, + {file = "pydantic-1.10.6-cp37-cp37m-win_amd64.whl", hash = "sha256:72cb30894a34d3a7ab6d959b45a70abac8a2a93b6480fc5a7bfbd9c935bdc4fb"}, + {file = "pydantic-1.10.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3091d2eaeda25391405e36c2fc2ed102b48bac4b384d42b2267310abae350ca6"}, + {file = "pydantic-1.10.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:751f008cd2afe812a781fd6aa2fb66c620ca2e1a13b6a2152b1ad51553cb4b77"}, + {file = "pydantic-1.10.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12e837fd320dd30bd625be1b101e3b62edc096a49835392dcf418f1a5ac2b832"}, + {file = "pydantic-1.10.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:587d92831d0115874d766b1f5fddcdde0c5b6c60f8c6111a394078ec227fca6d"}, + {file = "pydantic-1.10.6-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:476f6674303ae7965730a382a8e8d7fae18b8004b7b69a56c3d8fa93968aa21c"}, + {file = "pydantic-1.10.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3a2be0a0f32c83265fd71a45027201e1278beaa82ea88ea5b345eea6afa9ac7f"}, + {file = "pydantic-1.10.6-cp38-cp38-win_amd64.whl", hash = "sha256:0abd9c60eee6201b853b6c4be104edfba4f8f6c5f3623f8e1dba90634d63eb35"}, + {file = "pydantic-1.10.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6195ca908045054dd2d57eb9c39a5fe86409968b8040de8c2240186da0769da7"}, + {file = "pydantic-1.10.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43cdeca8d30de9a897440e3fb8866f827c4c31f6c73838e3a01a14b03b067b1d"}, + {file = "pydantic-1.10.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c19eb5163167489cb1e0161ae9220dadd4fc609a42649e7e84a8fa8fff7a80f"}, + {file = "pydantic-1.10.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:012c99a9c0d18cfde7469aa1ebff922e24b0c706d03ead96940f5465f2c9cf62"}, + {file = "pydantic-1.10.6-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:528dcf7ec49fb5a84bf6fe346c1cc3c55b0e7603c2123881996ca3ad79db5bfc"}, + {file = "pydantic-1.10.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:163e79386c3547c49366e959d01e37fc30252285a70619ffc1b10ede4758250a"}, + {file = "pydantic-1.10.6-cp39-cp39-win_amd64.whl", hash = "sha256:189318051c3d57821f7233ecc94708767dd67687a614a4e8f92b4a020d4ffd06"}, + {file = "pydantic-1.10.6-py3-none-any.whl", hash = "sha256:acc6783751ac9c9bc4680379edd6d286468a1dc8d7d9906cd6f1186ed682b2b0"}, + {file = "pydantic-1.10.6.tar.gz", hash = "sha256:cf95adb0d1671fc38d8c43dd921ad5814a735e7d9b4d9e437c088002863854fd"}, ] [package.dependencies] @@ -1520,14 +1508,14 @@ pytest = ">=3.0" [[package]] name = "pytest-xdist" -version = "3.2.0" +version = "3.2.1" description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-xdist-3.2.0.tar.gz", hash = "sha256:fa10f95a2564cd91652f2d132725183c3b590d9fdcdec09d3677386ecf4c1ce9"}, - {file = "pytest_xdist-3.2.0-py3-none-any.whl", hash = "sha256:336098e3bbd8193276867cc87db8b22903c3927665dff9d1ac8684c02f597b68"}, + {file = "pytest-xdist-3.2.1.tar.gz", hash = "sha256:1849bd98d8b242b948e472db7478e090bf3361912a8fed87992ed94085f54727"}, + {file = "pytest_xdist-3.2.1-py3-none-any.whl", hash = "sha256:37290d161638a20b672401deef1cba812d110ac27e35d213f091d15b8beb40c9"}, ] [package.dependencies] @@ -1630,14 +1618,14 @@ idna2008 = ["idna"] [[package]] name = "setuptools" -version = "67.4.0" +version = "67.6.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-67.4.0-py3-none-any.whl", hash = "sha256:f106dee1b506dee5102cc3f3e9e68137bbad6d47b616be7991714b0c62204251"}, - {file = "setuptools-67.4.0.tar.gz", hash = "sha256:e5fd0a713141a4a105412233c63dc4e17ba0090c8e8334594ac790ec97792330"}, + {file = "setuptools-67.6.0-py3-none-any.whl", hash = "sha256:b78aaa36f6b90a074c1fa651168723acbf45d14cb1196b6f02c0fd07f17623b2"}, + {file = "setuptools-67.6.0.tar.gz", hash = "sha256:2ee892cd5f29f3373097f5a814697e397cf3ce313616df0af11231e2ad118077"}, ] [package.extras] @@ -1773,14 +1761,14 @@ parse = ">=1.19.0,<2.0.0" [[package]] name = "starlette" -version = "0.25.0" +version = "0.26.1" description = "The little ASGI library that shines." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "starlette-0.25.0-py3-none-any.whl", hash = "sha256:774f1df1983fd594b9b6fb3ded39c2aa1979d10ac45caac0f4255cbe2acb8628"}, - {file = "starlette-0.25.0.tar.gz", hash = "sha256:854c71e73736c429c2bdb07801f2c76c9cba497e7c3cf4988fde5e95fe4cdb3c"}, + {file = "starlette-0.26.1-py3-none-any.whl", hash = "sha256:e87fce5d7cbdde34b76f0ac69013fd9d190d581d80681493016666e6f96c6d5e"}, + {file = "starlette-0.26.1.tar.gz", hash = "sha256:41da799057ea8620e4667a3e69a5b1923ebd32b1819c8fa75634bbe8d8bea9bd"}, ] [package.dependencies] @@ -1855,14 +1843,14 @@ files = [ [[package]] name = "urllib3" -version = "1.26.14" +version = "1.26.15" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ - {file = "urllib3-1.26.14-py2.py3-none-any.whl", hash = "sha256:75edcdc2f7d85b137124a6c3c9fc3933cdeaa12ecb9a6a959f22797a0feca7e1"}, - {file = "urllib3-1.26.14.tar.gz", hash = "sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72"}, + {file = "urllib3-1.26.15-py2.py3-none-any.whl", hash = "sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42"}, + {file = "urllib3-1.26.15.tar.gz", hash = "sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305"}, ] [package.extras] @@ -1872,14 +1860,14 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "uvicorn" -version = "0.20.0" +version = "0.21.0" description = "The lightning-fast ASGI server." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "uvicorn-0.20.0-py3-none-any.whl", hash = "sha256:c3ed1598a5668208723f2bb49336f4509424ad198d6ab2615b7783db58d919fd"}, - {file = "uvicorn-0.20.0.tar.gz", hash = "sha256:a4e12017b940247f836bc90b72e725d7dfd0c8ed1c51eb365f5ba30d9f5127d8"}, + {file = "uvicorn-0.21.0-py3-none-any.whl", hash = "sha256:e69e955cb621ae7b75f5590a814a4fcbfb14cb8f44a36dfe3c5c75ab8aee3ad5"}, + {file = "uvicorn-0.21.0.tar.gz", hash = "sha256:8635a388062222082f4b06225b867b74a7e4ef942124453d4d1d1a5cb3750932"}, ] [package.dependencies] @@ -1984,4 +1972,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.11" -content-hash = "c868a7569c7dcaa34c5fae297e81e180b2d111bf850aa0f02759d422143e7a12" +content-hash = "b82180015aa365bf55c890e8a3be5e549fa52f4e62cf4619fb71870939dda170" diff --git a/pyproject.toml b/pyproject.toml index f63d61fc..0d0ab36c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,13 +62,13 @@ asgiref = "^3.6.0" bcrypt = "^4.0.1" bleach = "^6.0.0" email-validator = "^1.3.1" -fakeredis = "^2.9.2" +fakeredis = "^2.10.0" feedgen = "^0.9.0" httpx = "^0.23.3" itsdangerous = "^2.1.2" lxml = "^4.9.2" orjson = "^3.8.7" -protobuf = "^4.22.0" +protobuf = "^4.22.1" pygit2 = "^1.11.1" python-multipart = "^0.0.6" redis = "^4.5.1" @@ -76,7 +76,7 @@ requests = "^2.28.2" paginate = "^0.5.6" # SQL -alembic = "^1.9.4" +alembic = "^1.10.2" mysqlclient = "^2.1.1" Authlib = "^1.2.0" Jinja2 = "^3.1.2" @@ -85,15 +85,15 @@ Werkzeug = "^2.2.3" SQLAlchemy = "^1.4.46" # ASGI -uvicorn = "^0.20.0" +uvicorn = "^0.21.0" gunicorn = "^20.1.0" Hypercorn = "^0.14.3" -prometheus-fastapi-instrumentator = "^5.10.0" -pytest-xdist = "^3.2.0" -filelock = "^3.9.0" +prometheus-fastapi-instrumentator = "^5.11.1" +pytest-xdist = "^3.2.1" +filelock = "^3.9.1" posix-ipc = "^1.1.1" pyalpm = "^0.10.6" -fastapi = "^0.92.0" +fastapi = "^0.94.1" srcinfo = "^0.1.2" tomlkit = "^0.11.6" From 993a044680bf231a639c71edfc8a424391c39c0b Mon Sep 17 00:00:00 2001 From: moson-mo Date: Tue, 14 Mar 2023 11:53:18 +0100 Subject: [PATCH 016/178] fix(poetry): use classic installer The "install" module (v0.6.0) which is being used by poetry 1.4.0 has problems installing certain packages. Disable the modern installer for now, until things are fixed. https://github.com/python-poetry/poetry/issues/7572 Signed-off-by: moson-mo --- poetry.toml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 poetry.toml diff --git a/poetry.toml b/poetry.toml new file mode 100644 index 00000000..8d4747a6 --- /dev/null +++ b/poetry.toml @@ -0,0 +1,5 @@ +# disable the modern installer until python-installer is fixed +# https://github.com/python-poetry/poetry/issues/7572 + +[installer] +modern-installation = false From 174af5f02572de81e968a50d72d69025844aaf44 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Wed, 15 Mar 2023 12:09:47 +0000 Subject: [PATCH 017/178] chore(release): prepare for 6.2.2 Signed-off-by: Leonidas Spyropoulos --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 0d0ab36c..eaaa7221 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ combine_as_imports = true # [tool.poetry] name = "aurweb" -version = "v6.2.1" +version = "v6.2.2" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From 6ede837b4f50c61d9110d0e048dee3f3b570c519 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Fri, 21 Apr 2023 19:47:55 +0100 Subject: [PATCH 018/178] feat: allow users to hide deleted comments Closes: #435 Signed-off-by: Leonidas Spyropoulos --- aurweb/routers/accounts.py | 6 ++ aurweb/schema.py | 6 ++ aurweb/users/update.py | 2 + ...ffce091_add_hidedeletedcomments_to_user.py | 33 ++++++++++ po/aurweb.pot | 4 ++ templates/partials/account/comment.html | 3 +- templates/partials/account_form.html | 19 +++++- templates/partials/packages/comment.html | 2 + test/test_packages_routes.py | 62 ++++++++++++++++++- 9 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 migrations/versions/e4e49ffce091_add_hidedeletedcomments_to_user.py diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 07962c37..77988d7f 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -209,6 +209,7 @@ def make_account_form_context( context["cn"] = args.get("CN", user.CommentNotify) context["un"] = args.get("UN", user.UpdateNotify) context["on"] = args.get("ON", user.OwnershipNotify) + context["hdc"] = args.get("HDC", user.HideDeletedComments) context["inactive"] = args.get("J", user.InactivityTS != 0) else: context["username"] = args.get("U", str()) @@ -227,6 +228,7 @@ def make_account_form_context( context["cn"] = args.get("CN", True) context["un"] = args.get("UN", False) context["on"] = args.get("ON", True) + context["hdc"] = args.get("HDC", False) context["inactive"] = args.get("J", False) context["password"] = args.get("P", str()) @@ -253,6 +255,7 @@ async def account_register( CN: bool = Form(default=False), # Comment Notify CU: bool = Form(default=False), # Update Notify CO: bool = Form(default=False), # Owner Notify + HDC: bool = Form(default=False), # Hide Deleted Comments captcha: str = Form(default=str()), ): context = await make_variable_context(request, "Register") @@ -281,6 +284,7 @@ async def account_register_post( CN: bool = Form(default=False), UN: bool = Form(default=False), ON: bool = Form(default=False), + HDC: bool = Form(default=False), captcha: str = Form(default=None), captcha_salt: str = Form(...), ): @@ -334,6 +338,7 @@ async def account_register_post( CommentNotify=CN, UpdateNotify=UN, OwnershipNotify=ON, + HideDeletedComments=HDC, ResetKey=resetkey, AccountType=atype, ) @@ -417,6 +422,7 @@ async def account_edit_post( CN: bool = Form(default=False), # Comment Notify UN: bool = Form(default=False), # Update Notify ON: bool = Form(default=False), # Owner Notify + HDC: bool = Form(default=False), # Hide Deleted Comments T: int = Form(default=None), passwd: str = Form(default=str()), ): diff --git a/aurweb/schema.py b/aurweb/schema.py index 0ba3e9c2..d01d07c9 100644 --- a/aurweb/schema.py +++ b/aurweb/schema.py @@ -108,6 +108,12 @@ Users = Table( Column("OwnershipNotify", TINYINT(1), nullable=False, server_default=text("1")), Column("SSOAccountID", String(255), nullable=True, unique=True), Index("UsersAccountTypeID", "AccountTypeID"), + Column( + "HideDeletedComments", + TINYINT(unsigned=True), + nullable=False, + server_default=text("0"), + ), mysql_engine="InnoDB", mysql_charset="utf8mb4", mysql_collate="utf8mb4_general_ci", diff --git a/aurweb/users/update.py b/aurweb/users/update.py index df41f843..21349a39 100644 --- a/aurweb/users/update.py +++ b/aurweb/users/update.py @@ -22,6 +22,7 @@ def simple( CN: bool = False, UN: bool = False, ON: bool = False, + HDC: bool = False, S: bool = False, user: models.User = None, **kwargs, @@ -41,6 +42,7 @@ def simple( user.CommentNotify = strtobool(CN) user.UpdateNotify = strtobool(UN) user.OwnershipNotify = strtobool(ON) + user.HideDeletedComments = strtobool(HDC) @db.retry_deadlock diff --git a/migrations/versions/e4e49ffce091_add_hidedeletedcomments_to_user.py b/migrations/versions/e4e49ffce091_add_hidedeletedcomments_to_user.py new file mode 100644 index 00000000..bc18b519 --- /dev/null +++ b/migrations/versions/e4e49ffce091_add_hidedeletedcomments_to_user.py @@ -0,0 +1,33 @@ +"""Add HideDeletedComments to User + +Revision ID: e4e49ffce091 +Revises: 9e3158957fd7 +Create Date: 2023-04-19 23:24:25.854874 + +""" +from alembic import op +from sqlalchemy.exc import OperationalError + +from aurweb.models.user import User + +# revision identifiers, used by Alembic. +revision = "e4e49ffce091" +down_revision = "9e3158957fd7" +branch_labels = None +depends_on = None + +table = User.__table__ + + +def upgrade(): + try: + op.add_column(table.name, table.c.HideDeletedComments) + except OperationalError: + print( + f"Column HideDeletedComments already exists in '{table.name}'," + f" skipping migration." + ) + + +def downgrade(): + op.drop_column(table.name, "HideDeletedComments") diff --git a/po/aurweb.pot b/po/aurweb.pot index 7e798a21..f4e3c1ba 100644 --- a/po/aurweb.pot +++ b/po/aurweb.pot @@ -1402,6 +1402,10 @@ msgstr "" msgid "Specify multiple SSH Keys separated by new line, empty lines are ignored." msgstr "" +#: templates/partials/account_form.html +msgid "Hide deleted comments" +msgstr "" + #: template/account_edit_form.php msgid "SSH Public Key" msgstr "" diff --git a/templates/partials/account/comment.html b/templates/partials/account/comment.html index f88aab02..41c9ac08 100644 --- a/templates/partials/account/comment.html +++ b/templates/partials/account/comment.html @@ -4,7 +4,7 @@ {% endif %} {% if not comment.Deleter or request.user.has_credential(creds.COMMENT_VIEW_DELETED, approved=[comment.Deleter]) %} - +{% if not (request.user.HideDeletedComments and comment.DelTS) %} {% set commented_at = comment.CommentTS | dt | as_timezone(timezone) %}

{{ @@ -38,3 +38,4 @@ {% include "partials/comment_content.html" %} {% endif %} +{% endif %} diff --git a/templates/partials/account_form.html b/templates/partials/account_form.html index a433a57d..4d135a56 100644 --- a/templates/partials/account_form.html +++ b/templates/partials/account_form.html @@ -182,7 +182,7 @@ maxlength="50" name="K" value="{{ pgp }}">

- +

- +

+ +

+ + + +

+ {% if form_type == "UpdateAccount" %} diff --git a/templates/partials/packages/comment.html b/templates/partials/packages/comment.html index e4818837..faac0753 100644 --- a/templates/partials/packages/comment.html +++ b/templates/partials/packages/comment.html @@ -6,6 +6,7 @@ {% endif %} {% if not comment.Deleter or request.user.has_credential(creds.COMMENT_VIEW_DELETED, approved=[comment.Deleter]) %} +{% if not (request.user.HideDeletedComments and comment.DelTS) %}

{% set commented_at = comment.CommentTS | dt | as_timezone(timezone) %} {% set view_account_info = 'View account information for %s' | tr | format(comment.User.Username) %} @@ -41,3 +42,4 @@ {% include "partials/comment_content.html" %} {% endif %} +{% endif %} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index d4b0babc..21ccdd7b 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -122,6 +122,22 @@ def tu_user(): yield tu_user +@pytest.fixture +def user_who_hates_grey_comments() -> User: + """Yield a specific User who doesn't like grey comments.""" + account_type = db.query(AccountType, AccountType.ID == USER_ID).first() + with db.begin(): + user_who_hates_grey_comments = db.create( + User, + Username="test_hater", + Email="test_hater@example.org", + Passwd="testPassword", + AccountType=account_type, + HideDeletedComments=True, + ) + yield user_who_hates_grey_comments + + @pytest.fixture def package(maintainer: User) -> Package: """Yield a Package created by user.""" @@ -193,6 +209,23 @@ def comment(user: User, package: Package) -> PackageComment: yield comment +@pytest.fixture +def deleted_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, + DelTS=now, + ) + yield comment + + @pytest.fixture def packages(maintainer: User) -> list[Package]: """Yield 55 packages named pkg_0 .. pkg_54.""" @@ -409,7 +442,9 @@ def test_paged_depends_required(client: TestClient, package: Package): assert "Show 6 more" not in resp.text -def test_package_comments(client: TestClient, user: User, package: Package): +def test_package_comments( + client: TestClient, user: User, user_who_hates_grey_comments: User, package: Package +): now = time.utcnow() with db.begin(): comment = db.create( @@ -419,6 +454,14 @@ def test_package_comments(client: TestClient, user: User, package: Package): Comments="Test comment", CommentTS=now, ) + deleted_comment = db.create( + PackageComment, + PackageBase=package.PackageBase, + User=user, + Comments="Deleted Test comment", + CommentTS=now, + DelTS=now - 1, + ) cookies = {"AURSID": user.login(Request(), "testPassword")} with client as request: @@ -426,12 +469,29 @@ def test_package_comments(client: TestClient, user: User, package: Package): resp = request.get(package_endpoint(package)) assert resp.status_code == int(HTTPStatus.OK) + root = parse_root(resp.text) + expected = [comment.Comments, deleted_comment.Comments] + comments = root.xpath( + './/div[contains(@class, "package-comments")]' + '/div[@class="article-content"]/div/text()' + ) + assert len(comments) == 2 + for i, row in enumerate(expected): + assert comments[i].strip() == row + + cookies = {"AURSID": user_who_hates_grey_comments.login(Request(), "testPassword")} + with client as request: + request.cookies = cookies + resp = request.get(package_endpoint(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()' ) + assert len(comments) == 1 # Deleted comment is hidden for i, row in enumerate(expected): assert comments[i].strip() == row From 1325c71712a12c529d7a3defa9cbabfad296922e Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Fri, 21 Apr 2023 23:55:02 +0100 Subject: [PATCH 019/178] chore: update poetry.lock Signed-off-by: Leonidas Spyropoulos --- poetry.lock | 616 ++++++++++++++++++++++++++-------------------------- 1 file changed, 302 insertions(+), 314 deletions(-) diff --git a/poetry.lock b/poetry.lock index fe81898e..1b98a5b8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.4.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. [[package]] name = "aiofiles" @@ -14,14 +14,14 @@ files = [ [[package]] name = "alembic" -version = "1.10.2" +version = "1.10.3" description = "A database migration tool for SQLAlchemy." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "alembic-1.10.2-py3-none-any.whl", hash = "sha256:8b48368f6533c064b39c024e1daba15ae7f947eac84185c28c06bbe1301a5497"}, - {file = "alembic-1.10.2.tar.gz", hash = "sha256:457eafbdc0769d855c2c92cbafe6b7f319f916c80cf4ed02b8f394f38b51b89d"}, + {file = "alembic-1.10.3-py3-none-any.whl", hash = "sha256:b2e0a6cfd3a8ce936a1168320bcbe94aefa3f4463cd773a968a55071beb3cd37"}, + {file = "alembic-1.10.3.tar.gz", hash = "sha256:32a69b13a613aeb7e8093f242da60eff9daed13c0df02fff279c1b06c32965d2"}, ] [package.dependencies] @@ -80,25 +80,6 @@ files = [ {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, ] -[[package]] -name = "attrs" -version = "22.2.0" -description = "Classes Without Boilerplate" -category = "main" -optional = false -python-versions = ">=3.6" -files = [ - {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"}, - {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"}, -] - -[package.extras] -cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"] -tests = ["attrs[tests-no-zope]", "zope.interface"] -tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"] - [[package]] name = "authlib" version = "1.2.0" @@ -371,63 +352,63 @@ files = [ [[package]] name = "coverage" -version = "7.2.1" +version = "7.2.3" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "coverage-7.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:49567ec91fc5e0b15356da07a2feabb421d62f52a9fff4b1ec40e9e19772f5f8"}, - {file = "coverage-7.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d2ef6cae70168815ed91388948b5f4fcc69681480a0061114db737f957719f03"}, - {file = "coverage-7.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3004765bca3acd9e015794e5c2f0c9a05587f5e698127ff95e9cfba0d3f29339"}, - {file = "coverage-7.2.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cca7c0b7f5881dfe0291ef09ba7bb1582cb92ab0aeffd8afb00c700bf692415a"}, - {file = "coverage-7.2.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2167d116309f564af56f9aa5e75ef710ef871c5f9b313a83050035097b56820"}, - {file = "coverage-7.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cb5f152fb14857cbe7f3e8c9a5d98979c4c66319a33cad6e617f0067c9accdc4"}, - {file = "coverage-7.2.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:87dc37f16fb5e3a28429e094145bf7c1753e32bb50f662722e378c5851f7fdc6"}, - {file = "coverage-7.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e191a63a05851f8bce77bc875e75457f9b01d42843f8bd7feed2fc26bbe60833"}, - {file = "coverage-7.2.1-cp310-cp310-win32.whl", hash = "sha256:e3ea04b23b114572b98a88c85379e9e9ae031272ba1fb9b532aa934c621626d4"}, - {file = "coverage-7.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:0cf557827be7eca1c38a2480484d706693e7bb1929e129785fe59ec155a59de6"}, - {file = "coverage-7.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:570c21a29493b350f591a4b04c158ce1601e8d18bdcd21db136fbb135d75efa6"}, - {file = "coverage-7.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9e872b082b32065ac2834149dc0adc2a2e6d8203080501e1e3c3c77851b466f9"}, - {file = "coverage-7.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fac6343bae03b176e9b58104a9810df3cdccd5cfed19f99adfa807ffbf43cf9b"}, - {file = "coverage-7.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abacd0a738e71b20e224861bc87e819ef46fedba2fb01bc1af83dfd122e9c319"}, - {file = "coverage-7.2.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9256d4c60c4bbfec92721b51579c50f9e5062c21c12bec56b55292464873508"}, - {file = "coverage-7.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:80559eaf6c15ce3da10edb7977a1548b393db36cbc6cf417633eca05d84dd1ed"}, - {file = "coverage-7.2.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:0bd7e628f6c3ec4e7d2d24ec0e50aae4e5ae95ea644e849d92ae4805650b4c4e"}, - {file = "coverage-7.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09643fb0df8e29f7417adc3f40aaf379d071ee8f0350ab290517c7004f05360b"}, - {file = "coverage-7.2.1-cp311-cp311-win32.whl", hash = "sha256:1b7fb13850ecb29b62a447ac3516c777b0e7a09ecb0f4bb6718a8654c87dfc80"}, - {file = "coverage-7.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:617a94ada56bbfe547aa8d1b1a2b8299e2ec1ba14aac1d4b26a9f7d6158e1273"}, - {file = "coverage-7.2.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8649371570551d2fd7dee22cfbf0b61f1747cdfb2b7587bb551e4beaaa44cb97"}, - {file = "coverage-7.2.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d2b9b5e70a21474c105a133ba227c61bc95f2ac3b66861143ce39a5ea4b3f84"}, - {file = "coverage-7.2.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae82c988954722fa07ec5045c57b6d55bc1a0890defb57cf4a712ced65b26ddd"}, - {file = "coverage-7.2.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:861cc85dfbf55a7a768443d90a07e0ac5207704a9f97a8eb753292a7fcbdfcfc"}, - {file = "coverage-7.2.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0339dc3237c0d31c3b574f19c57985fcbe494280153bbcad33f2cdf469f4ac3e"}, - {file = "coverage-7.2.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:5928b85416a388dd557ddc006425b0c37e8468bd1c3dc118c1a3de42f59e2a54"}, - {file = "coverage-7.2.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8d3843ca645f62c426c3d272902b9de90558e9886f15ddf5efe757b12dd376f5"}, - {file = "coverage-7.2.1-cp37-cp37m-win32.whl", hash = "sha256:6a034480e9ebd4e83d1aa0453fd78986414b5d237aea89a8fdc35d330aa13bae"}, - {file = "coverage-7.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:6fce673f79a0e017a4dc35e18dc7bb90bf6d307c67a11ad5e61ca8d42b87cbff"}, - {file = "coverage-7.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7f099da6958ddfa2ed84bddea7515cb248583292e16bb9231d151cd528eab657"}, - {file = "coverage-7.2.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:97a3189e019d27e914ecf5c5247ea9f13261d22c3bb0cfcfd2a9b179bb36f8b1"}, - {file = "coverage-7.2.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a81dbcf6c6c877986083d00b834ac1e84b375220207a059ad45d12f6e518a4e3"}, - {file = "coverage-7.2.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78d2c3dde4c0b9be4b02067185136b7ee4681978228ad5ec1278fa74f5ca3e99"}, - {file = "coverage-7.2.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a209d512d157379cc9ab697cbdbb4cfd18daa3e7eebaa84c3d20b6af0037384"}, - {file = "coverage-7.2.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f3d07edb912a978915576a776756069dede66d012baa503022d3a0adba1b6afa"}, - {file = "coverage-7.2.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8dca3c1706670297851bca1acff9618455122246bdae623be31eca744ade05ec"}, - {file = "coverage-7.2.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b1991a6d64231a3e5bbe3099fb0dd7c9aeaa4275ad0e0aeff4cb9ef885c62ba2"}, - {file = "coverage-7.2.1-cp38-cp38-win32.whl", hash = "sha256:22c308bc508372576ffa3d2dbc4824bb70d28eeb4fcd79d4d1aed663a06630d0"}, - {file = "coverage-7.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:b0c0d46de5dd97f6c2d1b560bf0fcf0215658097b604f1840365296302a9d1fb"}, - {file = "coverage-7.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4dd34a935de268a133e4741827ae951283a28c0125ddcdbcbba41c4b98f2dfef"}, - {file = "coverage-7.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0f8318ed0f3c376cfad8d3520f496946977abde080439d6689d7799791457454"}, - {file = "coverage-7.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:834c2172edff5a08d78e2f53cf5e7164aacabeb66b369f76e7bb367ca4e2d993"}, - {file = "coverage-7.2.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4d70c853f0546855f027890b77854508bdb4d6a81242a9d804482e667fff6e6"}, - {file = "coverage-7.2.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a6450da4c7afc4534305b2b7d8650131e130610cea448ff240b6ab73d7eab63"}, - {file = "coverage-7.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:99f4dd81b2bb8fc67c3da68b1f5ee1650aca06faa585cbc6818dbf67893c6d58"}, - {file = "coverage-7.2.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bdd3f2f285ddcf2e75174248b2406189261a79e7fedee2ceeadc76219b6faa0e"}, - {file = "coverage-7.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f29351393eb05e6326f044a7b45ed8e38cb4dcc38570d12791f271399dc41431"}, - {file = "coverage-7.2.1-cp39-cp39-win32.whl", hash = "sha256:e2b50ebc2b6121edf352336d503357321b9d8738bb7a72d06fc56153fd3f4cd8"}, - {file = "coverage-7.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:bd5a12239c0006252244f94863f1c518ac256160cd316ea5c47fb1a11b25889a"}, - {file = "coverage-7.2.1-pp37.pp38.pp39-none-any.whl", hash = "sha256:436313d129db7cf5b4ac355dd2bd3f7c7e5294af077b090b85de75f8458b8616"}, - {file = "coverage-7.2.1.tar.gz", hash = "sha256:c77f2a9093ccf329dd523a9b2b3c854c20d2a3d968b6def3b820272ca6732242"}, + {file = "coverage-7.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e58c0d41d336569d63d1b113bd573db8363bc4146f39444125b7f8060e4e04f5"}, + {file = "coverage-7.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:344e714bd0fe921fc72d97404ebbdbf9127bac0ca1ff66d7b79efc143cf7c0c4"}, + {file = "coverage-7.2.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:974bc90d6f6c1e59ceb1516ab00cf1cdfbb2e555795d49fa9571d611f449bcb2"}, + {file = "coverage-7.2.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0743b0035d4b0e32bc1df5de70fba3059662ace5b9a2a86a9f894cfe66569013"}, + {file = "coverage-7.2.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d0391fb4cfc171ce40437f67eb050a340fdbd0f9f49d6353a387f1b7f9dd4fa"}, + {file = "coverage-7.2.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4a42e1eff0ca9a7cb7dc9ecda41dfc7cbc17cb1d02117214be0561bd1134772b"}, + {file = "coverage-7.2.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:be19931a8dcbe6ab464f3339966856996b12a00f9fe53f346ab3be872d03e257"}, + {file = "coverage-7.2.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:72fcae5bcac3333a4cf3b8f34eec99cea1187acd55af723bcbd559adfdcb5535"}, + {file = "coverage-7.2.3-cp310-cp310-win32.whl", hash = "sha256:aeae2aa38395b18106e552833f2a50c27ea0000122bde421c31d11ed7e6f9c91"}, + {file = "coverage-7.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:83957d349838a636e768251c7e9979e899a569794b44c3728eaebd11d848e58e"}, + {file = "coverage-7.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dfd393094cd82ceb9b40df4c77976015a314b267d498268a076e940fe7be6b79"}, + {file = "coverage-7.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:182eb9ac3f2b4874a1f41b78b87db20b66da6b9cdc32737fbbf4fea0c35b23fc"}, + {file = "coverage-7.2.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bb1e77a9a311346294621be905ea8a2c30d3ad371fc15bb72e98bfcfae532df"}, + {file = "coverage-7.2.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca0f34363e2634deffd390a0fef1aa99168ae9ed2af01af4a1f5865e362f8623"}, + {file = "coverage-7.2.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55416d7385774285b6e2a5feca0af9652f7f444a4fa3d29d8ab052fafef9d00d"}, + {file = "coverage-7.2.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:06ddd9c0249a0546997fdda5a30fbcb40f23926df0a874a60a8a185bc3a87d93"}, + {file = "coverage-7.2.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fff5aaa6becf2c6a1699ae6a39e2e6fb0672c2d42eca8eb0cafa91cf2e9bd312"}, + {file = "coverage-7.2.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ea53151d87c52e98133eb8ac78f1206498c015849662ca8dc246255265d9c3c4"}, + {file = "coverage-7.2.3-cp311-cp311-win32.whl", hash = "sha256:8f6c930fd70d91ddee53194e93029e3ef2aabe26725aa3c2753df057e296b925"}, + {file = "coverage-7.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:fa546d66639d69aa967bf08156eb8c9d0cd6f6de84be9e8c9819f52ad499c910"}, + {file = "coverage-7.2.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2317d5ed777bf5a033e83d4f1389fd4ef045763141d8f10eb09a7035cee774c"}, + {file = "coverage-7.2.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be9824c1c874b73b96288c6d3de793bf7f3a597770205068c6163ea1f326e8b9"}, + {file = "coverage-7.2.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c3b2803e730dc2797a017335827e9da6da0e84c745ce0f552e66400abdfb9a1"}, + {file = "coverage-7.2.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f69770f5ca1994cb32c38965e95f57504d3aea96b6c024624fdd5bb1aa494a1"}, + {file = "coverage-7.2.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1127b16220f7bfb3f1049ed4a62d26d81970a723544e8252db0efde853268e21"}, + {file = "coverage-7.2.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:aa784405f0c640940595fa0f14064d8e84aff0b0f762fa18393e2760a2cf5841"}, + {file = "coverage-7.2.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3146b8e16fa60427e03884301bf8209221f5761ac754ee6b267642a2fd354c48"}, + {file = "coverage-7.2.3-cp37-cp37m-win32.whl", hash = "sha256:1fd78b911aea9cec3b7e1e2622c8018d51c0d2bbcf8faaf53c2497eb114911c1"}, + {file = "coverage-7.2.3-cp37-cp37m-win_amd64.whl", hash = "sha256:0f3736a5d34e091b0a611964c6262fd68ca4363df56185902528f0b75dbb9c1f"}, + {file = "coverage-7.2.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:981b4df72c93e3bc04478153df516d385317628bd9c10be699c93c26ddcca8ab"}, + {file = "coverage-7.2.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0045f8f23a5fb30b2eb3b8a83664d8dc4fb58faddf8155d7109166adb9f2040"}, + {file = "coverage-7.2.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f760073fcf8f3d6933178d67754f4f2d4e924e321f4bb0dcef0424ca0215eba1"}, + {file = "coverage-7.2.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c86bd45d1659b1ae3d0ba1909326b03598affbc9ed71520e0ff8c31a993ad911"}, + {file = "coverage-7.2.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:172db976ae6327ed4728e2507daf8a4de73c7cc89796483e0a9198fd2e47b462"}, + {file = "coverage-7.2.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d2a3a6146fe9319926e1d477842ca2a63fe99af5ae690b1f5c11e6af074a6b5c"}, + {file = "coverage-7.2.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f649dd53833b495c3ebd04d6eec58479454a1784987af8afb77540d6c1767abd"}, + {file = "coverage-7.2.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7c4ed4e9f3b123aa403ab424430b426a1992e6f4c8fd3cb56ea520446e04d152"}, + {file = "coverage-7.2.3-cp38-cp38-win32.whl", hash = "sha256:eb0edc3ce9760d2f21637766c3aa04822030e7451981ce569a1b3456b7053f22"}, + {file = "coverage-7.2.3-cp38-cp38-win_amd64.whl", hash = "sha256:63cdeaac4ae85a179a8d6bc09b77b564c096250d759eed343a89d91bce8b6367"}, + {file = "coverage-7.2.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:20d1a2a76bb4eb00e4d36b9699f9b7aba93271c9c29220ad4c6a9581a0320235"}, + {file = "coverage-7.2.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ea748802cc0de4de92ef8244dd84ffd793bd2e7be784cd8394d557a3c751e21"}, + {file = "coverage-7.2.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21b154aba06df42e4b96fc915512ab39595105f6c483991287021ed95776d934"}, + {file = "coverage-7.2.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd214917cabdd6f673a29d708574e9fbdb892cb77eb426d0eae3490d95ca7859"}, + {file = "coverage-7.2.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c2e58e45fe53fab81f85474e5d4d226eeab0f27b45aa062856c89389da2f0d9"}, + {file = "coverage-7.2.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:87ecc7c9a1a9f912e306997ffee020297ccb5ea388421fe62a2a02747e4d5539"}, + {file = "coverage-7.2.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:387065e420aed3c71b61af7e82c7b6bc1c592f7e3c7a66e9f78dd178699da4fe"}, + {file = "coverage-7.2.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ea3f5bc91d7d457da7d48c7a732beaf79d0c8131df3ab278e6bba6297e23c6c4"}, + {file = "coverage-7.2.3-cp39-cp39-win32.whl", hash = "sha256:ae7863a1d8db6a014b6f2ff9c1582ab1aad55a6d25bac19710a8df68921b6e30"}, + {file = "coverage-7.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:3f04becd4fcda03c0160d0da9c8f0c246bc78f2f7af0feea1ec0930e7c93fa4a"}, + {file = "coverage-7.2.3-pp37.pp38.pp39-none-any.whl", hash = "sha256:965ee3e782c7892befc25575fa171b521d33798132692df428a09efacaffe8d0"}, + {file = "coverage-7.2.3.tar.gz", hash = "sha256:d298c2815fa4891edd9abe5ad6e6cb4207104c7dd9fd13aea3fdebf6f9b91259"}, ] [package.dependencies] @@ -438,35 +419,31 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "39.0.2" +version = "40.0.2" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "cryptography-39.0.2-cp36-abi3-macosx_10_12_universal2.whl", hash = "sha256:2725672bb53bb92dc7b4150d233cd4b8c59615cd8288d495eaa86db00d4e5c06"}, - {file = "cryptography-39.0.2-cp36-abi3-macosx_10_12_x86_64.whl", hash = "sha256:23df8ca3f24699167daf3e23e51f7ba7334d504af63a94af468f468b975b7dd7"}, - {file = "cryptography-39.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:eb40fe69cfc6f5cdab9a5ebd022131ba21453cf7b8a7fd3631f45bbf52bed612"}, - {file = "cryptography-39.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc0521cce2c1d541634b19f3ac661d7a64f9555135e9d8af3980965be717fd4a"}, - {file = "cryptography-39.0.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffd394c7896ed7821a6d13b24657c6a34b6e2650bd84ae063cf11ccffa4f1a97"}, - {file = "cryptography-39.0.2-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:e8a0772016feeb106efd28d4a328e77dc2edae84dfbac06061319fdb669ff828"}, - {file = "cryptography-39.0.2-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8f35c17bd4faed2bc7797d2a66cbb4f986242ce2e30340ab832e5d99ae60e011"}, - {file = "cryptography-39.0.2-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b49a88ff802e1993b7f749b1eeb31134f03c8d5c956e3c125c75558955cda536"}, - {file = "cryptography-39.0.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:5f8c682e736513db7d04349b4f6693690170f95aac449c56f97415c6980edef5"}, - {file = "cryptography-39.0.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:d7d84a512a59f4412ca8549b01f94be4161c94efc598bf09d027d67826beddc0"}, - {file = "cryptography-39.0.2-cp36-abi3-win32.whl", hash = "sha256:c43ac224aabcbf83a947eeb8b17eaf1547bce3767ee2d70093b461f31729a480"}, - {file = "cryptography-39.0.2-cp36-abi3-win_amd64.whl", hash = "sha256:788b3921d763ee35dfdb04248d0e3de11e3ca8eb22e2e48fef880c42e1f3c8f9"}, - {file = "cryptography-39.0.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d15809e0dbdad486f4ad0979753518f47980020b7a34e9fc56e8be4f60702fac"}, - {file = "cryptography-39.0.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:50cadb9b2f961757e712a9737ef33d89b8190c3ea34d0fb6675e00edbe35d074"}, - {file = "cryptography-39.0.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:103e8f7155f3ce2ffa0049fe60169878d47a4364b277906386f8de21c9234aa1"}, - {file = "cryptography-39.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:6236a9610c912b129610eb1a274bdc1350b5df834d124fa84729ebeaf7da42c3"}, - {file = "cryptography-39.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e944fe07b6f229f4c1a06a7ef906a19652bdd9fd54c761b0ff87e83ae7a30354"}, - {file = "cryptography-39.0.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:35d658536b0a4117c885728d1a7032bdc9a5974722ae298d6c533755a6ee3915"}, - {file = "cryptography-39.0.2-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:30b1d1bfd00f6fc80d11300a29f1d8ab2b8d9febb6ed4a38a76880ec564fae84"}, - {file = "cryptography-39.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:e029b844c21116564b8b61216befabca4b500e6816fa9f0ba49527653cae2108"}, - {file = "cryptography-39.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fa507318e427169ade4e9eccef39e9011cdc19534f55ca2f36ec3f388c1f70f3"}, - {file = "cryptography-39.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8bc0008ef798231fac03fe7d26e82d601d15bd16f3afaad1c6113771566570f3"}, - {file = "cryptography-39.0.2.tar.gz", hash = "sha256:bc5b871e977c8ee5a1bbc42fa8d19bcc08baf0c51cbf1586b0e87a2694dde42f"}, + {file = "cryptography-40.0.2-cp36-abi3-macosx_10_12_universal2.whl", hash = "sha256:8f79b5ff5ad9d3218afb1e7e20ea74da5f76943ee5edb7f76e56ec5161ec782b"}, + {file = "cryptography-40.0.2-cp36-abi3-macosx_10_12_x86_64.whl", hash = "sha256:05dc219433b14046c476f6f09d7636b92a1c3e5808b9a6536adf4932b3b2c440"}, + {file = "cryptography-40.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4df2af28d7bedc84fe45bd49bc35d710aede676e2a4cb7fc6d103a2adc8afe4d"}, + {file = "cryptography-40.0.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dcca15d3a19a66e63662dc8d30f8036b07be851a8680eda92d079868f106288"}, + {file = "cryptography-40.0.2-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:a04386fb7bc85fab9cd51b6308633a3c271e3d0d3eae917eebab2fac6219b6d2"}, + {file = "cryptography-40.0.2-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:adc0d980fd2760c9e5de537c28935cc32b9353baaf28e0814df417619c6c8c3b"}, + {file = "cryptography-40.0.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:d5a1bd0e9e2031465761dfa920c16b0065ad77321d8a8c1f5ee331021fda65e9"}, + {file = "cryptography-40.0.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:a95f4802d49faa6a674242e25bfeea6fc2acd915b5e5e29ac90a32b1139cae1c"}, + {file = "cryptography-40.0.2-cp36-abi3-win32.whl", hash = "sha256:aecbb1592b0188e030cb01f82d12556cf72e218280f621deed7d806afd2113f9"}, + {file = "cryptography-40.0.2-cp36-abi3-win_amd64.whl", hash = "sha256:b12794f01d4cacfbd3177b9042198f3af1c856eedd0a98f10f141385c809a14b"}, + {file = "cryptography-40.0.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:142bae539ef28a1c76794cca7f49729e7c54423f615cfd9b0b1fa90ebe53244b"}, + {file = "cryptography-40.0.2-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:956ba8701b4ffe91ba59665ed170a2ebbdc6fc0e40de5f6059195d9f2b33ca0e"}, + {file = "cryptography-40.0.2-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4f01c9863da784558165f5d4d916093737a75203a5c5286fde60e503e4276c7a"}, + {file = "cryptography-40.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3daf9b114213f8ba460b829a02896789751626a2a4e7a43a28ee77c04b5e4958"}, + {file = "cryptography-40.0.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48f388d0d153350f378c7f7b41497a54ff1513c816bcbbcafe5b829e59b9ce5b"}, + {file = "cryptography-40.0.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c0764e72b36a3dc065c155e5b22f93df465da9c39af65516fe04ed3c68c92636"}, + {file = "cryptography-40.0.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:cbaba590180cba88cb99a5f76f90808a624f18b169b90a4abb40c1fd8c19420e"}, + {file = "cryptography-40.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7a38250f433cd41df7fcb763caa3ee9362777fdb4dc642b9a349721d2bf47404"}, + {file = "cryptography-40.0.2.tar.gz", hash = "sha256:c33c0d32b8594fa647d2e01dbccc303478e16fdd7cf98652d5b3ed11aa5e5c99"}, ] [package.dependencies] @@ -475,10 +452,10 @@ cffi = ">=1.12" [package.extras] docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] -pep8test = ["black", "check-manifest", "mypy", "ruff", "types-pytz", "types-requests"] +pep8test = ["black", "check-manifest", "mypy", "ruff"] sdist = ["setuptools-rust (>=0.11.4)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-shard (>=0.1.2)", "pytest-subtests", "pytest-xdist", "pytz"] +test = ["iso8601", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-shard (>=0.1.2)", "pytest-subtests", "pytest-xdist"] test-randomorder = ["pytest-randomly"] tox = ["tox"] @@ -551,18 +528,18 @@ testing = ["pre-commit"] [[package]] name = "fakeredis" -version = "2.10.0" +version = "2.11.0" description = "Fake implementation of redis API for testing purposes." category = "main" optional = false -python-versions = ">=3.8,<4.0" +python-versions = ">=3.7,<4.0" files = [ - {file = "fakeredis-2.10.0-py3-none-any.whl", hash = "sha256:7e66c96793688703a1da41256323ddaa1b3a2cab4ef793866839a937bb273915"}, - {file = "fakeredis-2.10.0.tar.gz", hash = "sha256:722644759bba4ad61fa38f0bb34939b7657f166ba35892f747e282407a196845"}, + {file = "fakeredis-2.11.0-py3-none-any.whl", hash = "sha256:156ef67713dd53000c28dd341be61a365c20230bc17c8fb8320b0c123e667aff"}, + {file = "fakeredis-2.11.0.tar.gz", hash = "sha256:d25883dc52c31546e586b6ec3c49c5999b3025bfc4812532d71dedcfed56fee1"}, ] [package.dependencies] -redis = ">=4,<5" +redis = ">=4" sortedcontainers = ">=2.4,<3.0" [package.extras] @@ -608,19 +585,19 @@ python-dateutil = "*" [[package]] name = "filelock" -version = "3.9.1" +version = "3.12.0" description = "A platform independent file lock." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "filelock-3.9.1-py3-none-any.whl", hash = "sha256:4427cdda14a1c68e264845142842d6de2d0fa2c15ba31571a3d9c9a1ec9d191c"}, - {file = "filelock-3.9.1.tar.gz", hash = "sha256:e393782f76abea324dee598d2ea145b857a20df0e0ee4f80fcf35e72a341d2c7"}, + {file = "filelock-3.12.0-py3-none-any.whl", hash = "sha256:ad98852315c2ab702aeb628412cbf7e95b7ce8c3bf9565670b4eaecf1db370a9"}, + {file = "filelock-3.12.0.tar.gz", hash = "sha256:fc03ae43288c013d2ea83c8597001b1129db351aad9c57fe2409327916b8e718"}, ] [package.extras] -docs = ["furo (>=2022.12.7)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.1)", "pytest (>=7.2.2)", "pytest-cov (>=4)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.3.27)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] [[package]] name = "greenlet" @@ -854,14 +831,14 @@ files = [ [[package]] name = "importlib-metadata" -version = "6.0.0" +version = "6.6.0" description = "Read metadata from Python packages" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "importlib_metadata-6.0.0-py3-none-any.whl", hash = "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad"}, - {file = "importlib_metadata-6.0.0.tar.gz", hash = "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d"}, + {file = "importlib_metadata-6.6.0-py3-none-any.whl", hash = "sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed"}, + {file = "importlib_metadata-6.6.0.tar.gz", hash = "sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705"}, ] [package.dependencies] @@ -1029,14 +1006,14 @@ testing = ["pytest"] [[package]] name = "markdown" -version = "3.4.1" -description = "Python implementation of Markdown." +version = "3.4.3" +description = "Python implementation of John Gruber's Markdown." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "Markdown-3.4.1-py3-none-any.whl", hash = "sha256:08fb8465cffd03d10b9dd34a5c3fea908e20391a2a90b88d66362cb05beed186"}, - {file = "Markdown-3.4.1.tar.gz", hash = "sha256:3b809086bb6efad416156e00a0da66fe47618a5d6918dd688f53f40c8e4cfeff"}, + {file = "Markdown-3.4.3-py3-none-any.whl", hash = "sha256:065fd4df22da73a625f14890dd77eb8040edcbd68794bcd35943be14490608b2"}, + {file = "Markdown-3.4.3.tar.gz", hash = "sha256:8bf101198e004dc93e84a12a7395e31aac6a9c9942848ae1d99b9d72cf9b3520"}, ] [package.dependencies] @@ -1124,68 +1101,80 @@ files = [ [[package]] name = "orjson" -version = "3.8.7" +version = "3.8.10" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">= 3.7" files = [ - {file = "orjson-3.8.7-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:f98c82850b7b4b7e27785ca43706fa86c893cdb88d54576bbb9b0d9c1070e421"}, - {file = "orjson-3.8.7-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:1dee503c6c1a0659c5b46f5f39d9ca9d3657b11ca8bb4af8506086df416887d9"}, - {file = "orjson-3.8.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc4fa83831f42ce5c938f8cefc2e175fa1df6f661fdeaba3badf26d2b8cfcf73"}, - {file = "orjson-3.8.7-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e432c6c9c8b97ad825276d5795286f7cc9689f377a97e3b7ecf14918413303f"}, - {file = "orjson-3.8.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee519964a5a0efb9633f38b1129fd242807c5c57162844efeeaab1c8de080051"}, - {file = "orjson-3.8.7-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:109b539ce5bf60a121454d008fa67c3b67e5a3249e47d277012645922cf74bd0"}, - {file = "orjson-3.8.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ad4d441fbde4133af6fee37f67dbf23181b9c537ecc317346ec8c3b4c8ec7705"}, - {file = "orjson-3.8.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:89dc786419e1ce2588345f58dd6a434e6728bce66b94989644234bcdbe39b603"}, - {file = "orjson-3.8.7-cp310-none-win_amd64.whl", hash = "sha256:697abde7350fb8076d44bcb6b4ab3ce415ae2b5a9bb91efc460e5ab0d96bb5d3"}, - {file = "orjson-3.8.7-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:1c19f47b35b9966a3abadf341b18ee4a860431bf2b00fd8d58906d51cf78aa70"}, - {file = "orjson-3.8.7-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:3ffaabb380cd0ee187b4fc362516df6bf739808130b1339445c7d8878fca36e7"}, - {file = "orjson-3.8.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d88837002c5a8af970745b8e0ca1b0fdb06aafbe7f1279e110d338ea19f3d23"}, - {file = "orjson-3.8.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff60187d1b7e0bfab376b6002b08c560b7de06c87cf3a8ac639ecf58f84c5f3b"}, - {file = "orjson-3.8.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0110970aed35dec293f30ed1e09f8604afd5d15c5ef83de7f6c427619b3ba47b"}, - {file = "orjson-3.8.7-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:51b275475d4e36118b65ad56f9764056a09d985c5d72e64579bf8816f1356a5e"}, - {file = "orjson-3.8.7-cp311-none-win_amd64.whl", hash = "sha256:63144d27735f3b60f079f247ac9a289d80dfe49a7f03880dfa0c0ba64d6491d5"}, - {file = "orjson-3.8.7-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:a16273d77db746bb1789a2bbfded81148a60743fd6f9d5185e02d92e3732fa18"}, - {file = "orjson-3.8.7-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:5bb32259ea22cc9dd47a6fdc4b8f9f1e2f798fcf56c7c1122a7df0f4c5d33bf3"}, - {file = "orjson-3.8.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad02e9102d4ba67db30a136e631e32aeebd1dce26c9f5942a457b02df131c5d0"}, - {file = "orjson-3.8.7-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dbcfcec2b7ac52deb7be3685b551addc28ee8fa454ef41f8b714df6ba0e32a27"}, - {file = "orjson-3.8.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1a0e5504a5fc86083cc210c6946e8d61e13fe9f1d7a7bf81b42f7050a49d4fb"}, - {file = "orjson-3.8.7-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:7bd4fd37adb03b1f2a1012d43c9f95973a02164e131dfe3ff804d7e180af5653"}, - {file = "orjson-3.8.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:188ed9f9a781333ad802af54c55d5a48991e292239aef41bd663b6e314377eb8"}, - {file = "orjson-3.8.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:cc52f58c688cb10afd810280e450f56fbcb27f52c053463e625c8335c95db0dc"}, - {file = "orjson-3.8.7-cp37-none-win_amd64.whl", hash = "sha256:403c8c84ac8a02c40613b0493b74d5256379e65196d39399edbf2ed3169cbeb5"}, - {file = "orjson-3.8.7-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:7d6ac5f8a2a17095cd927c4d52abbb38af45918e0d3abd60fb50cfd49d71ae24"}, - {file = "orjson-3.8.7-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:0295a7bfd713fa89231fd0822c995c31fc2343c59a1d13aa1b8b6651335654f5"}, - {file = "orjson-3.8.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feb32aaaa34cf2f891eb793ad320d4bb6731328496ae59b6c9eb1b620c42b529"}, - {file = "orjson-3.8.7-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7a3ab1a473894e609b6f1d763838c6689ba2b97620c256a32c4d9f10595ac179"}, - {file = "orjson-3.8.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e8c430d82b532c5ab95634e034bbf6ca7432ffe175a3e63eadd493e00b3a555"}, - {file = "orjson-3.8.7-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:366cc75f7e09106f9dac95a675aef413367b284f25507d21e55bd7f45f445e80"}, - {file = "orjson-3.8.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:84d154d07e8b17d97e990d5d710b719a031738eb1687d8a05b9089f0564ff3e0"}, - {file = "orjson-3.8.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06180014afcfdc167ca984b312218aa62ce20093965c437c5f9166764cb65ef7"}, - {file = "orjson-3.8.7-cp38-none-win_amd64.whl", hash = "sha256:41244431ba13f2e6ef22b52c5cf0202d17954489f4a3c0505bd28d0e805c3546"}, - {file = "orjson-3.8.7-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:b20f29fa8371b8023f1791df035a2c3ccbd98baa429ac3114fc104768f7db6f8"}, - {file = "orjson-3.8.7-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:226bfc1da2f21ee74918cee2873ea9a0fec1a8830e533cb287d192d593e99d02"}, - {file = "orjson-3.8.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e75c11023ac29e29fd3e75038d0e8dd93f9ea24d7b9a5e871967a8921a88df24"}, - {file = "orjson-3.8.7-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:78604d3acfd7cd502f6381eea0c42281fe2b74755b334074ab3ebc0224100be1"}, - {file = "orjson-3.8.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7129a6847f0494aa1427167486ef6aea2e835ba05f6c627df522692ee228f65"}, - {file = "orjson-3.8.7-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1a1a8f4980059f48483782c608145b0f74538c266e01c183d9bcd9f8b71dbada"}, - {file = "orjson-3.8.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d60304172a33705ce4bd25a6261ab84bed2dab0b3d3b79672ea16c7648af4832"}, - {file = "orjson-3.8.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4f733062d84389c32c0492e5a4929056fac217034a94523debe0430bcc602cda"}, - {file = "orjson-3.8.7-cp39-none-win_amd64.whl", hash = "sha256:010e2970ec9e826c332819e0da4b14b29b19641da0f1a6af4cec91629ef9b988"}, - {file = "orjson-3.8.7.tar.gz", hash = "sha256:8460c8810652dba59c38c80d27c325b5092d189308d8d4f3e688dbd8d4f3b2dc"}, + {file = "orjson-3.8.10-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:4dfe0651e26492d5d929bbf4322de9afbd1c51ac2e3947a7f78492b20359711d"}, + {file = "orjson-3.8.10-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:bc30de5c7b3a402eb59cc0656b8ee53ca36322fc52ab67739c92635174f88336"}, + {file = "orjson-3.8.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c08b426fae7b9577b528f99af0f7e0ff3ce46858dd9a7d1bf86d30f18df89a4c"}, + {file = "orjson-3.8.10-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bce970f293825e008dbf739268dfa41dfe583aa2a1b5ef4efe53a0e92e9671ea"}, + {file = "orjson-3.8.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9b23fb0264bbdd7218aa685cb6fc71f0dcecf34182f0a8596a3a0dff010c06f9"}, + {file = "orjson-3.8.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0826ad2dc1cea1547edff14ce580374f0061d853cbac088c71162dbfe2e52205"}, + {file = "orjson-3.8.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7bce6e61cea6426309259b04c6ee2295b3f823ea51a033749459fe2dd0423b2"}, + {file = "orjson-3.8.10-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:0b470d31244a6f647e5402aac7d2abaf7bb4f52379acf67722a09d35a45c9417"}, + {file = "orjson-3.8.10-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:48824649019a25d3e52f6454435cf19fe1eb3d05ee697e65d257f58ae3aa94d9"}, + {file = "orjson-3.8.10-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:faee89e885796a9cc493c930013fa5cfcec9bfaee431ddf00f0fbfb57166a8b3"}, + {file = "orjson-3.8.10-cp310-none-win_amd64.whl", hash = "sha256:3cfe32b1227fe029a5ad989fbec0b453a34e5e6d9a977723f7c3046d062d3537"}, + {file = "orjson-3.8.10-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:2073b62822738d6740bd2492f6035af5c2fd34aa198322b803dc0e70559a17b7"}, + {file = "orjson-3.8.10-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:b2c4faf20b6bb5a2d7ac0c16f58eb1a3800abcef188c011296d1dc2bb2224d48"}, + {file = "orjson-3.8.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c1825997232a324911d11c75d91e1e0338c7b723c149cf53a5fc24496c048a4"}, + {file = "orjson-3.8.10-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f7e85d4682f3ed7321d36846cad0503e944ea9579ef435d4c162e1b73ead8ac9"}, + {file = "orjson-3.8.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8cdaacecb92997916603ab232bb096d0fa9e56b418ca956b9754187d65ca06"}, + {file = "orjson-3.8.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ddabc5e44702d13137949adee3c60b7091e73a664f6e07c7b428eebb2dea7bbf"}, + {file = "orjson-3.8.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27bb26e171e9cfdbec39c7ca4739b6bef8bd06c293d56d92d5e3a3fc017df17d"}, + {file = "orjson-3.8.10-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1810e5446fe68d61732e9743592da0ec807e63972eef076d09e02878c2f5958e"}, + {file = "orjson-3.8.10-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:61e2e51cefe7ef90c4fbbc9fd38ecc091575a3ea7751d56fad95cbebeae2a054"}, + {file = "orjson-3.8.10-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f3e9ac9483c2b4cd794e760316966b7bd1e6afb52b0218f068a4e80c9b2db4f6"}, + {file = "orjson-3.8.10-cp311-none-win_amd64.whl", hash = "sha256:26aee557cf8c93b2a971b5a4a8e3cca19780573531493ce6573aa1002f5c4378"}, + {file = "orjson-3.8.10-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:11ae68f995a50724032af297c92f20bcde31005e0bf3653b12bff9356394615b"}, + {file = "orjson-3.8.10-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:35d879b46b8029e1e01e9f6067928b470a4efa1ca749b6d053232b873c2dcf66"}, + {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:345e41abd1d9e3ecfb554e1e75ff818cf42e268bd06ad25a96c34e00f73a327e"}, + {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:45a5afc9cda6b8aac066dd50d8194432fbc33e71f7164f95402999b725232d78"}, + {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad632dc330a7b39da42530c8d146f76f727d476c01b719dc6743c2b5701aaf6b"}, + {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4bf2556ba99292c4dc550560384dd22e88b5cdbe6d98fb4e202e902b5775cf9f"}, + {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b88afd662190f19c3bb5036a903589f88b1d2c2608fbb97281ce000db6b08897"}, + {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:abce8d319aae800fd2d774db1106f926dee0e8a5ca85998fd76391fcb58ef94f"}, + {file = "orjson-3.8.10-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:e999abca892accada083f7079612307d94dd14cc105a699588a324f843216509"}, + {file = "orjson-3.8.10-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a3fdee68c4bb3c5d6f89ed4560f1384b5d6260e48fbf868bae1a245a3c693d4d"}, + {file = "orjson-3.8.10-cp37-none-win_amd64.whl", hash = "sha256:e5d7f82506212e047b184c06e4bcd48c1483e101969013623cebcf51cf12cad9"}, + {file = "orjson-3.8.10-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:d953e6c2087dcd990e794f8405011369ee11cf13e9aaae3172ee762ee63947f2"}, + {file = "orjson-3.8.10-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:81aa3f321d201bff0bd0f4014ea44e51d58a9a02d8f2b0eeab2cee22611be8e1"}, + {file = "orjson-3.8.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d27b6182f75896dd8c10ea0f78b9265a3454be72d00632b97f84d7031900dd4"}, + {file = "orjson-3.8.10-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1486600bc1dd1db26c588dd482689edba3d72d301accbe4301db4b2b28bd7aa4"}, + {file = "orjson-3.8.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:344ea91c556a2ce6423dc13401b83ab0392aa697a97fa4142c2c63a6fd0bbfef"}, + {file = "orjson-3.8.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:979f231e3bad1c835627eef1a30db12a8af58bfb475a6758868ea7e81897211f"}, + {file = "orjson-3.8.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fa3a26dcf0f5f2912a8ce8e87273e68b2a9526854d19fd09ea671b154418e88"}, + {file = "orjson-3.8.10-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:b6e79d8864794635974b18821b49a7f27859d17b93413d4603efadf2e92da7a5"}, + {file = "orjson-3.8.10-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ce49999bcbbc14791c61844bc8a69af44f5205d219be540e074660038adae6bf"}, + {file = "orjson-3.8.10-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c2ef690335b24f9272dbf6639353c1ffc3f196623a92b851063e28e9515cf7dd"}, + {file = "orjson-3.8.10-cp38-none-win_amd64.whl", hash = "sha256:5a0b1f4e4fa75e26f814161196e365fc0e1a16e3c07428154505b680a17df02f"}, + {file = "orjson-3.8.10-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:af7601a78b99f0515af2f8ab12c955c0072ffcc1e437fb2556f4465783a4d813"}, + {file = "orjson-3.8.10-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:6bbd7b3a3e2030b03c68c4d4b19a2ef5b89081cbb43c05fe2010767ef5e408db"}, + {file = "orjson-3.8.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4355c9aedfefe60904e8bd7901315ebbc8bb828f665e4c9bc94b1432e67cb6f7"}, + {file = "orjson-3.8.10-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b7b0ba074375e25c1594e770e2215941e2017c3cd121889150737fa1123e8bfe"}, + {file = "orjson-3.8.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34b6901c110c06ab9e8d7d0496db4bc9a0c162ca8d77f67539d22cb39e0a1ef4"}, + {file = "orjson-3.8.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cb62ec16a1c26ad9487727b529103cb6a94a1d4969d5b32dd0eab5c3f4f5a6f2"}, + {file = "orjson-3.8.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:595e1e7d04aaaa3d41113e4eb9f765ab642173c4001182684ae9ddc621bb11c8"}, + {file = "orjson-3.8.10-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:64ffd92328473a2f9af059410bd10c703206a4bbc7b70abb1bedcd8761e39eb8"}, + {file = "orjson-3.8.10-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b1f648ec89c6a426098868460c0ef8c86b457ce1378d7569ff4acb6c0c454048"}, + {file = "orjson-3.8.10-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6a286ad379972e4f46579e772f0477e6b505f1823aabcd64ef097dbb4549e1a4"}, + {file = "orjson-3.8.10-cp39-none-win_amd64.whl", hash = "sha256:d2874cee6856d7c386b596e50bc517d1973d73dc40b2bd6abec057b5e7c76b2f"}, + {file = "orjson-3.8.10.tar.gz", hash = "sha256:dcf6adb4471b69875034afab51a14b64f1026bc968175a2bb02c5f6b358bd413"}, ] [[package]] name = "packaging" -version = "23.0" +version = "23.1" description = "Core utilities for Python packages" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, - {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, + {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, + {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, ] [[package]] @@ -1271,14 +1260,14 @@ twisted = ["twisted"] [[package]] name = "prometheus-fastapi-instrumentator" -version = "5.11.1" +version = "5.11.2" description = "Instrument your FastAPI with Prometheus metrics." category = "main" optional = false python-versions = ">=3.7.0,<4.0.0" files = [ - {file = "prometheus_fastapi_instrumentator-5.11.1-py3-none-any.whl", hash = "sha256:8a58dc34b75620f634bd9c9d77978172bc5a6de05b921e301a1e4de896ca97ce"}, - {file = "prometheus_fastapi_instrumentator-5.11.1.tar.gz", hash = "sha256:34026f8735aff89a08ed71bd16a1f454d5eaaec20a9a52eb5c40aa2d585dfbba"}, + {file = "prometheus_fastapi_instrumentator-5.11.2-py3-none-any.whl", hash = "sha256:c84ae3dc98bebb44f29d0af0c17c9f0782c2fb964ef83353664d9858a632cf81"}, + {file = "prometheus_fastapi_instrumentator-5.11.2.tar.gz", hash = "sha256:9d8d0df8de7d6a73ae387121629dbf32fe022cdfc63e8bacd51f4b8ff21059ea"}, ] [package.dependencies] @@ -1287,25 +1276,25 @@ prometheus-client = ">=0.8.0,<1.0.0" [[package]] name = "protobuf" -version = "4.22.1" +version = "4.22.3" description = "" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "protobuf-4.22.1-cp310-abi3-win32.whl", hash = "sha256:85aa9acc5a777adc0c21b449dafbc40d9a0b6413ff3a4f77ef9df194be7f975b"}, - {file = "protobuf-4.22.1-cp310-abi3-win_amd64.whl", hash = "sha256:8bc971d76c03f1dd49f18115b002254f2ddb2d4b143c583bb860b796bb0d399e"}, - {file = "protobuf-4.22.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:5917412347e1da08ce2939eb5cd60650dfb1a9ab4606a415b9278a1041fb4d19"}, - {file = "protobuf-4.22.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:9e12e2810e7d297dbce3c129ae5e912ffd94240b050d33f9ecf023f35563b14f"}, - {file = "protobuf-4.22.1-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:953fc7904ef46900262a26374b28c2864610b60cdc8b272f864e22143f8373c4"}, - {file = "protobuf-4.22.1-cp37-cp37m-win32.whl", hash = "sha256:6e100f7bc787cd0a0ae58dbf0ab8bbf1ee7953f862b89148b6cf5436d5e9eaa1"}, - {file = "protobuf-4.22.1-cp37-cp37m-win_amd64.whl", hash = "sha256:87a6393fa634f294bf24d1cfe9fdd6bb605cbc247af81b9b10c4c0f12dfce4b3"}, - {file = "protobuf-4.22.1-cp38-cp38-win32.whl", hash = "sha256:e3fb58076bdb550e75db06ace2a8b3879d4c4f7ec9dd86e4254656118f4a78d7"}, - {file = "protobuf-4.22.1-cp38-cp38-win_amd64.whl", hash = "sha256:651113695bc2e5678b799ee5d906b5d3613f4ccfa61b12252cfceb6404558af0"}, - {file = "protobuf-4.22.1-cp39-cp39-win32.whl", hash = "sha256:67b7d19da0fda2733702c2299fd1ef6cb4b3d99f09263eacaf1aa151d9d05f02"}, - {file = "protobuf-4.22.1-cp39-cp39-win_amd64.whl", hash = "sha256:b8700792f88e59ccecfa246fa48f689d6eee6900eddd486cdae908ff706c482b"}, - {file = "protobuf-4.22.1-py3-none-any.whl", hash = "sha256:3e19dcf4adbf608924d3486ece469dd4f4f2cf7d2649900f0efcd1a84e8fd3ba"}, - {file = "protobuf-4.22.1.tar.gz", hash = "sha256:dce7a55d501c31ecf688adb2f6c3f763cf11bc0be815d1946a84d74772ab07a7"}, + {file = "protobuf-4.22.3-cp310-abi3-win32.whl", hash = "sha256:8b54f56d13ae4a3ec140076c9d937221f887c8f64954673d46f63751209e839a"}, + {file = "protobuf-4.22.3-cp310-abi3-win_amd64.whl", hash = "sha256:7760730063329d42a9d4c4573b804289b738d4931e363ffbe684716b796bde51"}, + {file = "protobuf-4.22.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:d14fc1a41d1a1909998e8aff7e80d2a7ae14772c4a70e4bf7db8a36690b54425"}, + {file = "protobuf-4.22.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:70659847ee57a5262a65954538088a1d72dfc3e9882695cab9f0c54ffe71663b"}, + {file = "protobuf-4.22.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:13233ee2b9d3bd9a5f216c1fa2c321cd564b93d8f2e4f521a85b585447747997"}, + {file = "protobuf-4.22.3-cp37-cp37m-win32.whl", hash = "sha256:ecae944c6c2ce50dda6bf76ef5496196aeb1b85acb95df5843cd812615ec4b61"}, + {file = "protobuf-4.22.3-cp37-cp37m-win_amd64.whl", hash = "sha256:d4b66266965598ff4c291416be429cef7989d8fae88b55b62095a2331511b3fa"}, + {file = "protobuf-4.22.3-cp38-cp38-win32.whl", hash = "sha256:f08aa300b67f1c012100d8eb62d47129e53d1150f4469fd78a29fa3cb68c66f2"}, + {file = "protobuf-4.22.3-cp38-cp38-win_amd64.whl", hash = "sha256:f2f4710543abec186aee332d6852ef5ae7ce2e9e807a3da570f36de5a732d88e"}, + {file = "protobuf-4.22.3-cp39-cp39-win32.whl", hash = "sha256:7cf56e31907c532e460bb62010a513408e6cdf5b03fb2611e4b67ed398ad046d"}, + {file = "protobuf-4.22.3-cp39-cp39-win_amd64.whl", hash = "sha256:e0e630d8e6a79f48c557cd1835865b593d0547dce221c66ed1b827de59c66c97"}, + {file = "protobuf-4.22.3-py3-none-any.whl", hash = "sha256:52f0a78141078077cfe15fe333ac3e3a077420b9a3f5d1bf9b5fe9d286b4d881"}, + {file = "protobuf-4.22.3.tar.gz", hash = "sha256:23452f2fdea754a8251d0fc88c0317735ae47217e0d27bf330a30eec2848811a"}, ] [[package]] @@ -1333,48 +1322,48 @@ files = [ [[package]] name = "pydantic" -version = "1.10.6" +version = "1.10.7" description = "Data validation and settings management using python type hints" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-1.10.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9289065611c48147c1dd1fd344e9d57ab45f1d99b0fb26c51f1cf72cd9bcd31"}, - {file = "pydantic-1.10.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8c32b6bba301490d9bb2bf5f631907803135e8085b6aa3e5fe5a770d46dd0160"}, - {file = "pydantic-1.10.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd9b9e98068fa1068edfc9eabde70a7132017bdd4f362f8b4fd0abed79c33083"}, - {file = "pydantic-1.10.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c84583b9df62522829cbc46e2b22e0ec11445625b5acd70c5681ce09c9b11c4"}, - {file = "pydantic-1.10.6-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b41822064585fea56d0116aa431fbd5137ce69dfe837b599e310034171996084"}, - {file = "pydantic-1.10.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:61f1f08adfaa9cc02e0cbc94f478140385cbd52d5b3c5a657c2fceb15de8d1fb"}, - {file = "pydantic-1.10.6-cp310-cp310-win_amd64.whl", hash = "sha256:32937835e525d92c98a1512218db4eed9ddc8f4ee2a78382d77f54341972c0e7"}, - {file = "pydantic-1.10.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bbd5c531b22928e63d0cb1868dee76123456e1de2f1cb45879e9e7a3f3f1779b"}, - {file = "pydantic-1.10.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e277bd18339177daa62a294256869bbe84df1fb592be2716ec62627bb8d7c81d"}, - {file = "pydantic-1.10.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f15277d720aa57e173954d237628a8d304896364b9de745dcb722f584812c7"}, - {file = "pydantic-1.10.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b243b564cea2576725e77aeeda54e3e0229a168bc587d536cd69941e6797543d"}, - {file = "pydantic-1.10.6-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3ce13a558b484c9ae48a6a7c184b1ba0e5588c5525482681db418268e5f86186"}, - {file = "pydantic-1.10.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3ac1cd4deed871dfe0c5f63721e29debf03e2deefa41b3ed5eb5f5df287c7b70"}, - {file = "pydantic-1.10.6-cp311-cp311-win_amd64.whl", hash = "sha256:b1eb6610330a1dfba9ce142ada792f26bbef1255b75f538196a39e9e90388bf4"}, - {file = "pydantic-1.10.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4ca83739c1263a044ec8b79df4eefc34bbac87191f0a513d00dd47d46e307a65"}, - {file = "pydantic-1.10.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea4e2a7cb409951988e79a469f609bba998a576e6d7b9791ae5d1e0619e1c0f2"}, - {file = "pydantic-1.10.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53de12b4608290992a943801d7756f18a37b7aee284b9ffa794ee8ea8153f8e2"}, - {file = "pydantic-1.10.6-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:60184e80aac3b56933c71c48d6181e630b0fbc61ae455a63322a66a23c14731a"}, - {file = "pydantic-1.10.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:415a3f719ce518e95a92effc7ee30118a25c3d032455d13e121e3840985f2efd"}, - {file = "pydantic-1.10.6-cp37-cp37m-win_amd64.whl", hash = "sha256:72cb30894a34d3a7ab6d959b45a70abac8a2a93b6480fc5a7bfbd9c935bdc4fb"}, - {file = "pydantic-1.10.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3091d2eaeda25391405e36c2fc2ed102b48bac4b384d42b2267310abae350ca6"}, - {file = "pydantic-1.10.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:751f008cd2afe812a781fd6aa2fb66c620ca2e1a13b6a2152b1ad51553cb4b77"}, - {file = "pydantic-1.10.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12e837fd320dd30bd625be1b101e3b62edc096a49835392dcf418f1a5ac2b832"}, - {file = "pydantic-1.10.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:587d92831d0115874d766b1f5fddcdde0c5b6c60f8c6111a394078ec227fca6d"}, - {file = "pydantic-1.10.6-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:476f6674303ae7965730a382a8e8d7fae18b8004b7b69a56c3d8fa93968aa21c"}, - {file = "pydantic-1.10.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3a2be0a0f32c83265fd71a45027201e1278beaa82ea88ea5b345eea6afa9ac7f"}, - {file = "pydantic-1.10.6-cp38-cp38-win_amd64.whl", hash = "sha256:0abd9c60eee6201b853b6c4be104edfba4f8f6c5f3623f8e1dba90634d63eb35"}, - {file = "pydantic-1.10.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6195ca908045054dd2d57eb9c39a5fe86409968b8040de8c2240186da0769da7"}, - {file = "pydantic-1.10.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43cdeca8d30de9a897440e3fb8866f827c4c31f6c73838e3a01a14b03b067b1d"}, - {file = "pydantic-1.10.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c19eb5163167489cb1e0161ae9220dadd4fc609a42649e7e84a8fa8fff7a80f"}, - {file = "pydantic-1.10.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:012c99a9c0d18cfde7469aa1ebff922e24b0c706d03ead96940f5465f2c9cf62"}, - {file = "pydantic-1.10.6-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:528dcf7ec49fb5a84bf6fe346c1cc3c55b0e7603c2123881996ca3ad79db5bfc"}, - {file = "pydantic-1.10.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:163e79386c3547c49366e959d01e37fc30252285a70619ffc1b10ede4758250a"}, - {file = "pydantic-1.10.6-cp39-cp39-win_amd64.whl", hash = "sha256:189318051c3d57821f7233ecc94708767dd67687a614a4e8f92b4a020d4ffd06"}, - {file = "pydantic-1.10.6-py3-none-any.whl", hash = "sha256:acc6783751ac9c9bc4680379edd6d286468a1dc8d7d9906cd6f1186ed682b2b0"}, - {file = "pydantic-1.10.6.tar.gz", hash = "sha256:cf95adb0d1671fc38d8c43dd921ad5814a735e7d9b4d9e437c088002863854fd"}, + {file = "pydantic-1.10.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e79e999e539872e903767c417c897e729e015872040e56b96e67968c3b918b2d"}, + {file = "pydantic-1.10.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:01aea3a42c13f2602b7ecbbea484a98169fb568ebd9e247593ea05f01b884b2e"}, + {file = "pydantic-1.10.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:516f1ed9bc2406a0467dd777afc636c7091d71f214d5e413d64fef45174cfc7a"}, + {file = "pydantic-1.10.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae150a63564929c675d7f2303008d88426a0add46efd76c3fc797cd71cb1b46f"}, + {file = "pydantic-1.10.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ecbbc51391248116c0a055899e6c3e7ffbb11fb5e2a4cd6f2d0b93272118a209"}, + {file = "pydantic-1.10.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f4a2b50e2b03d5776e7f21af73e2070e1b5c0d0df255a827e7c632962f8315af"}, + {file = "pydantic-1.10.7-cp310-cp310-win_amd64.whl", hash = "sha256:a7cd2251439988b413cb0a985c4ed82b6c6aac382dbaff53ae03c4b23a70e80a"}, + {file = "pydantic-1.10.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:68792151e174a4aa9e9fc1b4e653e65a354a2fa0fed169f7b3d09902ad2cb6f1"}, + {file = "pydantic-1.10.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe2507b8ef209da71b6fb5f4e597b50c5a34b78d7e857c4f8f3115effaef5fe"}, + {file = "pydantic-1.10.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10a86d8c8db68086f1e30a530f7d5f83eb0685e632e411dbbcf2d5c0150e8dcd"}, + {file = "pydantic-1.10.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75ae19d2a3dbb146b6f324031c24f8a3f52ff5d6a9f22f0683694b3afcb16fb"}, + {file = "pydantic-1.10.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:464855a7ff7f2cc2cf537ecc421291b9132aa9c79aef44e917ad711b4a93163b"}, + {file = "pydantic-1.10.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:193924c563fae6ddcb71d3f06fa153866423ac1b793a47936656e806b64e24ca"}, + {file = "pydantic-1.10.7-cp311-cp311-win_amd64.whl", hash = "sha256:b4a849d10f211389502059c33332e91327bc154acc1845f375a99eca3afa802d"}, + {file = "pydantic-1.10.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cc1dde4e50a5fc1336ee0581c1612215bc64ed6d28d2c7c6f25d2fe3e7c3e918"}, + {file = "pydantic-1.10.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0cfe895a504c060e5d36b287ee696e2fdad02d89e0d895f83037245218a87fe"}, + {file = "pydantic-1.10.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:670bb4683ad1e48b0ecb06f0cfe2178dcf74ff27921cdf1606e527d2617a81ee"}, + {file = "pydantic-1.10.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:950ce33857841f9a337ce07ddf46bc84e1c4946d2a3bba18f8280297157a3fd1"}, + {file = "pydantic-1.10.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c15582f9055fbc1bfe50266a19771bbbef33dd28c45e78afbe1996fd70966c2a"}, + {file = "pydantic-1.10.7-cp37-cp37m-win_amd64.whl", hash = "sha256:82dffb306dd20bd5268fd6379bc4bfe75242a9c2b79fec58e1041fbbdb1f7914"}, + {file = "pydantic-1.10.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c7f51861d73e8b9ddcb9916ae7ac39fb52761d9ea0df41128e81e2ba42886cd"}, + {file = "pydantic-1.10.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6434b49c0b03a51021ade5c4daa7d70c98f7a79e95b551201fff682fc1661245"}, + {file = "pydantic-1.10.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64d34ab766fa056df49013bb6e79921a0265204c071984e75a09cbceacbbdd5d"}, + {file = "pydantic-1.10.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:701daea9ffe9d26f97b52f1d157e0d4121644f0fcf80b443248434958fd03dc3"}, + {file = "pydantic-1.10.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf135c46099ff3f919d2150a948ce94b9ce545598ef2c6c7bf55dca98a304b52"}, + {file = "pydantic-1.10.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0f85904f73161817b80781cc150f8b906d521fa11e3cdabae19a581c3606209"}, + {file = "pydantic-1.10.7-cp38-cp38-win_amd64.whl", hash = "sha256:9f6f0fd68d73257ad6685419478c5aece46432f4bdd8d32c7345f1986496171e"}, + {file = "pydantic-1.10.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c230c0d8a322276d6e7b88c3f7ce885f9ed16e0910354510e0bae84d54991143"}, + {file = "pydantic-1.10.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:976cae77ba6a49d80f461fd8bba183ff7ba79f44aa5cfa82f1346b5626542f8e"}, + {file = "pydantic-1.10.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d45fc99d64af9aaf7e308054a0067fdcd87ffe974f2442312372dfa66e1001d"}, + {file = "pydantic-1.10.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2a5ebb48958754d386195fe9e9c5106f11275867051bf017a8059410e9abf1f"}, + {file = "pydantic-1.10.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:abfb7d4a7cd5cc4e1d1887c43503a7c5dd608eadf8bc615413fc498d3e4645cd"}, + {file = "pydantic-1.10.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:80b1fab4deb08a8292d15e43a6edccdffa5377a36a4597bb545b93e79c5ff0a5"}, + {file = "pydantic-1.10.7-cp39-cp39-win_amd64.whl", hash = "sha256:d71e69699498b020ea198468e2480a2f1e7433e32a3a99760058c6520e2bea7e"}, + {file = "pydantic-1.10.7-py3-none-any.whl", hash = "sha256:0cd181f1d0b1d00e2b705f1bf1ac7799a2d938cce3376b8007df62b29be3c2c6"}, + {file = "pydantic-1.10.7.tar.gz", hash = "sha256:cfc83c0678b6ba51b0532bea66860617c4cd4251ecf76e9846fa5a9f3454e97e"}, ] [package.dependencies] @@ -1386,43 +1375,43 @@ email = ["email-validator (>=1.0.3)"] [[package]] name = "pygit2" -version = "1.11.1" +version = "1.12.0" description = "Python bindings for libgit2." category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "pygit2-1.11.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:263e05ac655a4ce0a1083aaaedfd0a900b8dee2c3bb3ecf4f4e504a404467d1f"}, - {file = "pygit2-1.11.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ee6b4a0e181c576cdb64b1568bfbff3d1c2cd7e99808f578c8b08875c0f43739"}, - {file = "pygit2-1.11.1-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:d1b5fcaac1f29337f2d1465fa095e2e375b76a06385bda9391cb418c7937fb54"}, - {file = "pygit2-1.11.1-cp310-cp310-manylinux_2_24_x86_64.whl", hash = "sha256:96ff745d3199909d06cab5e419a6b953be99992414a08ec4dddb682f395de8f1"}, - {file = "pygit2-1.11.1-cp310-cp310-win32.whl", hash = "sha256:b3c8726f0c9a2b0e04aac37b18027c58c2697b9c021d3458b28bc250b9b6aecf"}, - {file = "pygit2-1.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:f42409d25bbfc090fd1af1f5f47584d7e0c4212b037a7f86639a02c30420c6ee"}, - {file = "pygit2-1.11.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:29f89d96bbb404ca1566418463521039903094fad2f81a76d7083810d2ea3aad"}, - {file = "pygit2-1.11.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d5c158b9430c5e76ca728b1a214bf21d355af6ac6e2da86ed17775b870b6c6eb"}, - {file = "pygit2-1.11.1-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:6c3434b143e7570ec45cd1a0e344fe7a12e64b99e7155fa38b74f724c8fc243c"}, - {file = "pygit2-1.11.1-cp311-cp311-manylinux_2_24_x86_64.whl", hash = "sha256:550aa503c86ef0061ce64d61c3672b15b500c2b1e4224c405acecfac2211b5d9"}, - {file = "pygit2-1.11.1-cp311-cp311-win32.whl", hash = "sha256:f270f86a0185ca2064e1aa6b8db3bb677b1bf76ee35f48ca5ce28a921fad5632"}, - {file = "pygit2-1.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:56b9deeab214653805214f05337f5e9552b47bf268c285551f20ea51a6056c3e"}, - {file = "pygit2-1.11.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3c5838e6516abc4384498f4b4c7f88578221596dc2ba8db2320ff2cfebe9787e"}, - {file = "pygit2-1.11.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a886aab5aae8d8db572e20b9f56c13cd506775265222ea7f35b2c781e4fa3a5e"}, - {file = "pygit2-1.11.1-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:3be4534180edd53e3e1da93c5b091975566bfdffdc73f21930d79fef096a25d2"}, - {file = "pygit2-1.11.1-cp38-cp38-manylinux_2_24_x86_64.whl", hash = "sha256:4d6209c703764ae0ba57b17038482f3e54f432f80f88ccd490d7f8b70b167db6"}, - {file = "pygit2-1.11.1-cp38-cp38-win32.whl", hash = "sha256:ddb032fa71d4b4a64bf101e37eaa21f5369f20a862b5e34bbc33854a3a35f641"}, - {file = "pygit2-1.11.1-cp38-cp38-win_amd64.whl", hash = "sha256:f8de0091e5eeaea2004f63f7dcb4540780f2124f68c0bcb670ae0fa9ada8bf66"}, - {file = "pygit2-1.11.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9b44674e53efa9eca36e44f2f3d1a29e53e78649ba13105ae0b037d557f2c076"}, - {file = "pygit2-1.11.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0170f31c2efb15f6779689df328c05a8005ecb2b92784a37ff967d713cdafe82"}, - {file = "pygit2-1.11.1-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:960a55ff78f48887a7aa8ece952aad0f52f0a2ba1ad7bddd7064fbbefd85dfbb"}, - {file = "pygit2-1.11.1-cp39-cp39-manylinux_2_24_x86_64.whl", hash = "sha256:df722c90fb54a42fa019dcf8d8f82961c3099c3024f1fda46c53e0886ff8f0f3"}, - {file = "pygit2-1.11.1-cp39-cp39-win32.whl", hash = "sha256:3b091e7fd00dd2a2cd3a6b5e235b6cbfbc1c07f15ee83a5cb3f188e1d6d1bca1"}, - {file = "pygit2-1.11.1-cp39-cp39-win_amd64.whl", hash = "sha256:da040dc28800831bcbefef0850466739f103bfc769d952bd10c449646d52ce8f"}, - {file = "pygit2-1.11.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:585daa3956f1dc10d08e3459c20b57be42c7f9c0fbde21e797b3a00b5948f061"}, - {file = "pygit2-1.11.1-pp38-pypy38_pp73-manylinux_2_24_aarch64.whl", hash = "sha256:273878adeced2aec7885745b73fffb91a8e67868c105bf881b61008d42497ad6"}, - {file = "pygit2-1.11.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:48cfd72283a08a9226aca115870799ee92898d692699f541a3b3f519805108ec"}, - {file = "pygit2-1.11.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a9ca4cb2481d2df14d23c765facef325f717d9a3966a986b86e88d92eef11929"}, - {file = "pygit2-1.11.1-pp39-pypy39_pp73-manylinux_2_24_aarch64.whl", hash = "sha256:d5f64a424d9123b047458b0107c5dd33559184b56a1f58b10056ea5cbac74360"}, - {file = "pygit2-1.11.1-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:f13e190cc080bde093138e12bcb609500276227e3e8e8bd8765a2fd49ae2efb8"}, - {file = "pygit2-1.11.1.tar.gz", hash = "sha256:793f583fd33620f0ac38376db0f57768ef2922b89b459e75b1ac440377eb64ec"}, + {file = "pygit2-1.12.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b44a3b38e62dbf8cb559a40d2b39506a638d13542502ddb927f1c05565048f27"}, + {file = "pygit2-1.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:834cf5b54d9b49c562669ec986be54c7915585638690c11f1dc4e6a55bc5d79d"}, + {file = "pygit2-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ecb096cdbbf142d8787cf879ab927fc9777d36580d2e5758d02c9474a3b015c"}, + {file = "pygit2-1.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15620696743ffac71cfdaf270944d9363b70442c1fbe96f5e4a69639c2fe7c23"}, + {file = "pygit2-1.12.0-cp310-cp310-win32.whl", hash = "sha256:de21194e18e4d93f793740b2b979dbe9dd6607f342a4fad3ecedeaf26ec743df"}, + {file = "pygit2-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:0a9d49f71bec7c4f2ff8273e0c7caba4b2f21bfc56e2071e429028b20ab9d762"}, + {file = "pygit2-1.12.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a428970b44827b703cc3267de8d71648f491546d5b9276505ef5f232a921a34e"}, + {file = "pygit2-1.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2bb7b674124a38b12a5aaacca3b8c1e29674f3b46cb907af0b3ba75d90e5952a"}, + {file = "pygit2-1.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de46940b46bee12f4c938aadf4f59617798f704c8ac5f08b5a84914459d604be"}, + {file = "pygit2-1.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fbfb3ebe7f57fe7873d86e84b476869f407d6bb204a39a3e7d04e4a7f0e43c1"}, + {file = "pygit2-1.12.0-cp311-cp311-win32.whl", hash = "sha256:db98978d559d6e84187d463fb3aa83cf6120dadf62058e3d05a97457f9f27247"}, + {file = "pygit2-1.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:8734a44e0dab8a5e6668e4a926f7171b59b87d65981bd3732efba57c327cec6d"}, + {file = "pygit2-1.12.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1bb73ffb345400f8c6fe391431e06b93e26bc4d2048b1ac3f7c54dae5f7b6dc2"}, + {file = "pygit2-1.12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fdeaf1631803616d303b808cd644ee17164fb675241ab1b0bb243d4a3d3de59f"}, + {file = "pygit2-1.12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:652b3f0510ad21ec6275b246aa3e7a2e20f2f9c37a9844804887fabc2db49ca3"}, + {file = "pygit2-1.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2419cd1034bf593847466b188a65bd9d512e13b7da0e8c3a74b487d8014a6c1"}, + {file = "pygit2-1.12.0-cp38-cp38-win32.whl", hash = "sha256:6a445a537de152364b334e73047af9225fe8c6f54c7d815d8c751cb23b79cbef"}, + {file = "pygit2-1.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:ad1cca4533beee034277fe01f0d4029da40d2bd1a944a8cd17bffccc0331cc53"}, + {file = "pygit2-1.12.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ad7b21e35e759d033dede5dc4971f6c9b3408f9096b26fabc7cedb49e319680"}, + {file = "pygit2-1.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e303aa9d7de6039cc4450a1fbd5911fab22867dc4e05f148b0cd7c56f7b84b2"}, + {file = "pygit2-1.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:869e68cfae7e0e00a799efa26bba3f829bdeafa1462225a7db1317dacb4e6a4e"}, + {file = "pygit2-1.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c779c15bf6ebce986cb753c8113ccfb329c12d4a73b303ee7ac2c8961288b8cd"}, + {file = "pygit2-1.12.0-cp39-cp39-win32.whl", hash = "sha256:c6ac2fd8ed30016235b06aacc28e5f10e1a17d0f02eab35f5f503138bbee763d"}, + {file = "pygit2-1.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:2483e4aa8bb4290ab157d575b00b830528c669869d710646a1d4af7209d59e81"}, + {file = "pygit2-1.12.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8fca4ca59928436fca5df3d54a7d591e7aa12ebaeaeb1801a99e09970fb8f1d3"}, + {file = "pygit2-1.12.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0746791741ba1879faafd12be0b7fb8edd06633508bbf8aabfd28415f1c0b13f"}, + {file = "pygit2-1.12.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b9d8b7e1d143415d462d82fc5d9dd5922c527474871c7b3c3a8aec009b74b1c"}, + {file = "pygit2-1.12.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:69ee34f8b77fc60dcf93524fd843eacc416be906b7471746d2ee8214d5a591a0"}, + {file = "pygit2-1.12.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c290dadcf42e9d857ea20c37781168de1d1ac31b196b450400f962279aa405f"}, + {file = "pygit2-1.12.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1d9bdd2837f9f1cacb571889ac4226844a41476509c325732af06b622293782"}, + {file = "pygit2-1.12.0.tar.gz", hash = "sha256:e9440d08665e35278989939590a53f37a938eada4f9446844930aa2ee30d73be"}, ] [package.dependencies] @@ -1430,18 +1419,17 @@ cffi = ">=1.9.1" [[package]] name = "pytest" -version = "7.2.2" +version = "7.3.1" description = "pytest: simple powerful testing with Python" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.2.2-py3-none-any.whl", hash = "sha256:130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e"}, - {file = "pytest-7.2.2.tar.gz", hash = "sha256:c99ab0c73aceb050f68929bc93af19ab6db0558791c6a0715723abe9d0ade9d4"}, + {file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"}, + {file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"}, ] [package.dependencies] -attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" @@ -1450,7 +1438,7 @@ pluggy = ">=0.12,<2.0" tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] [[package]] name = "pytest-asyncio" @@ -1559,18 +1547,18 @@ dev = ["atomicwrites (==1.2.1)", "attrs (==19.2.0)", "coverage (==6.5.0)", "hatc [[package]] name = "redis" -version = "4.5.1" +version = "4.5.4" description = "Python client for Redis database and key-value store" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "redis-4.5.1-py3-none-any.whl", hash = "sha256:5deb072d26e67d2be1712603bfb7947ec3431fb0eec9c578994052e33035af6d"}, - {file = "redis-4.5.1.tar.gz", hash = "sha256:1eec3741cda408d3a5f84b78d089c8b8d895f21b3b050988351e925faf202864"}, + {file = "redis-4.5.4-py3-none-any.whl", hash = "sha256:2c19e6767c474f2e85167909061d525ed65bea9301c0770bb151e041b7ac89a2"}, + {file = "redis-4.5.4.tar.gz", hash = "sha256:73ec35da4da267d6847e47f68730fdd5f62e2ca69e3ef5885c6a78a9374c3893"}, ] [package.dependencies] -async-timeout = ">=4.0.2" +async-timeout = {version = ">=4.0.2", markers = "python_version <= \"3.11.2\""} [package.extras] hiredis = ["hiredis (>=1.0.0)"] @@ -1618,14 +1606,14 @@ idna2008 = ["idna"] [[package]] name = "setuptools" -version = "67.6.0" +version = "67.7.1" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-67.6.0-py3-none-any.whl", hash = "sha256:b78aaa36f6b90a074c1fa651168723acbf45d14cb1196b6f02c0fd07f17623b2"}, - {file = "setuptools-67.6.0.tar.gz", hash = "sha256:2ee892cd5f29f3373097f5a814697e397cf3ce313616df0af11231e2ad118077"}, + {file = "setuptools-67.7.1-py3-none-any.whl", hash = "sha256:6f0839fbdb7e3cfef1fc38d7954f5c1c26bf4eebb155a55c9bf8faf997b9fb67"}, + {file = "setuptools-67.7.1.tar.gz", hash = "sha256:bb16732e8eb928922eabaa022f881ae2b7cdcfaf9993ef1f5e841a96d32b8e0c"}, ] [package.extras] @@ -1671,53 +1659,53 @@ files = [ [[package]] name = "sqlalchemy" -version = "1.4.46" +version = "1.4.47" description = "Database Abstraction Library" category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "SQLAlchemy-1.4.46-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:7001f16a9a8e06488c3c7154827c48455d1c1507d7228d43e781afbc8ceccf6d"}, - {file = "SQLAlchemy-1.4.46-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c7a46639ba058d320c9f53a81db38119a74b8a7a1884df44d09fbe807d028aaf"}, - {file = "SQLAlchemy-1.4.46-cp27-cp27m-win32.whl", hash = "sha256:c04144a24103135ea0315d459431ac196fe96f55d3213bfd6d39d0247775c854"}, - {file = "SQLAlchemy-1.4.46-cp27-cp27m-win_amd64.whl", hash = "sha256:7b81b1030c42b003fc10ddd17825571603117f848814a344d305262d370e7c34"}, - {file = "SQLAlchemy-1.4.46-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:939f9a018d2ad04036746e15d119c0428b1e557470361aa798e6e7d7f5875be0"}, - {file = "SQLAlchemy-1.4.46-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b7f4b6aa6e87991ec7ce0e769689a977776db6704947e562102431474799a857"}, - {file = "SQLAlchemy-1.4.46-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dbf17ac9a61e7a3f1c7ca47237aac93cabd7f08ad92ac5b96d6f8dea4287fc1"}, - {file = "SQLAlchemy-1.4.46-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7f8267682eb41a0584cf66d8a697fef64b53281d01c93a503e1344197f2e01fe"}, - {file = "SQLAlchemy-1.4.46-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64cb0ad8a190bc22d2112001cfecdec45baffdf41871de777239da6a28ed74b6"}, - {file = "SQLAlchemy-1.4.46-cp310-cp310-win32.whl", hash = "sha256:5f752676fc126edc1c4af0ec2e4d2adca48ddfae5de46bb40adbd3f903eb2120"}, - {file = "SQLAlchemy-1.4.46-cp310-cp310-win_amd64.whl", hash = "sha256:31de1e2c45e67a5ec1ecca6ec26aefc299dd5151e355eb5199cd9516b57340be"}, - {file = "SQLAlchemy-1.4.46-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d68e1762997bfebf9e5cf2a9fd0bcf9ca2fdd8136ce7b24bbd3bbfa4328f3e4a"}, - {file = "SQLAlchemy-1.4.46-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d112b0f3c1bc5ff70554a97344625ef621c1bfe02a73c5d97cac91f8cd7a41e"}, - {file = "SQLAlchemy-1.4.46-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69fac0a7054d86b997af12dc23f581cf0b25fb1c7d1fed43257dee3af32d3d6d"}, - {file = "SQLAlchemy-1.4.46-cp311-cp311-win32.whl", hash = "sha256:887865924c3d6e9a473dc82b70977395301533b3030d0f020c38fd9eba5419f2"}, - {file = "SQLAlchemy-1.4.46-cp311-cp311-win_amd64.whl", hash = "sha256:984ee13543a346324319a1fb72b698e521506f6f22dc37d7752a329e9cd00a32"}, - {file = "SQLAlchemy-1.4.46-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:9167d4227b56591a4cc5524f1b79ccd7ea994f36e4c648ab42ca995d28ebbb96"}, - {file = "SQLAlchemy-1.4.46-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d61e9ecc849d8d44d7f80894ecff4abe347136e9d926560b818f6243409f3c86"}, - {file = "SQLAlchemy-1.4.46-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3ec187acf85984263299a3f15c34a6c0671f83565d86d10f43ace49881a82718"}, - {file = "SQLAlchemy-1.4.46-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9883f5fae4fd8e3f875adc2add69f8b945625811689a6c65866a35ee9c0aea23"}, - {file = "SQLAlchemy-1.4.46-cp36-cp36m-win32.whl", hash = "sha256:535377e9b10aff5a045e3d9ada8a62d02058b422c0504ebdcf07930599890eb0"}, - {file = "SQLAlchemy-1.4.46-cp36-cp36m-win_amd64.whl", hash = "sha256:18cafdb27834fa03569d29f571df7115812a0e59fd6a3a03ccb0d33678ec8420"}, - {file = "SQLAlchemy-1.4.46-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:a1ad90c97029cc3ab4ffd57443a20fac21d2ec3c89532b084b073b3feb5abff3"}, - {file = "SQLAlchemy-1.4.46-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4847f4b1d822754e35707db913396a29d874ee77b9c3c3ef3f04d5a9a6209618"}, - {file = "SQLAlchemy-1.4.46-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c5a99282848b6cae0056b85da17392a26b2d39178394fc25700bcf967e06e97a"}, - {file = "SQLAlchemy-1.4.46-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4b1cc7835b39835c75cf7c20c926b42e97d074147c902a9ebb7cf2c840dc4e2"}, - {file = "SQLAlchemy-1.4.46-cp37-cp37m-win32.whl", hash = "sha256:c522e496f9b9b70296a7675272ec21937ccfc15da664b74b9f58d98a641ce1b6"}, - {file = "SQLAlchemy-1.4.46-cp37-cp37m-win_amd64.whl", hash = "sha256:ae067ab639fa499f67ded52f5bc8e084f045d10b5ac7bb928ae4ca2b6c0429a5"}, - {file = "SQLAlchemy-1.4.46-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:e3c1808008124850115a3f7e793a975cfa5c8a26ceeeb9ff9cbb4485cac556df"}, - {file = "SQLAlchemy-1.4.46-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d164df3d83d204c69f840da30b292ac7dc54285096c6171245b8d7807185aa"}, - {file = "SQLAlchemy-1.4.46-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b33ffbdbbf5446cf36cd4cc530c9d9905d3c2fe56ed09e25c22c850cdb9fac92"}, - {file = "SQLAlchemy-1.4.46-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d94682732d1a0def5672471ba42a29ff5e21bb0aae0afa00bb10796fc1e28dd"}, - {file = "SQLAlchemy-1.4.46-cp38-cp38-win32.whl", hash = "sha256:f8cb80fe8d14307e4124f6fad64dfd87ab749c9d275f82b8b4ec84c84ecebdbe"}, - {file = "SQLAlchemy-1.4.46-cp38-cp38-win_amd64.whl", hash = "sha256:07e48cbcdda6b8bc7a59d6728bd3f5f574ffe03f2c9fb384239f3789c2d95c2e"}, - {file = "SQLAlchemy-1.4.46-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:1b1e5e96e2789d89f023d080bee432e2fef64d95857969e70d3cadec80bd26f0"}, - {file = "SQLAlchemy-1.4.46-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3714e5b33226131ac0da60d18995a102a17dddd42368b7bdd206737297823ad"}, - {file = "SQLAlchemy-1.4.46-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:955162ad1a931fe416eded6bb144ba891ccbf9b2e49dc7ded39274dd9c5affc5"}, - {file = "SQLAlchemy-1.4.46-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6e4cb5c63f705c9d546a054c60d326cbde7421421e2d2565ce3e2eee4e1a01f"}, - {file = "SQLAlchemy-1.4.46-cp39-cp39-win32.whl", hash = "sha256:51e1ba2884c6a2b8e19109dc08c71c49530006c1084156ecadfaadf5f9b8b053"}, - {file = "SQLAlchemy-1.4.46-cp39-cp39-win_amd64.whl", hash = "sha256:315676344e3558f1f80d02535f410e80ea4e8fddba31ec78fe390eff5fb8f466"}, - {file = "SQLAlchemy-1.4.46.tar.gz", hash = "sha256:6913b8247d8a292ef8315162a51931e2b40ce91681f1b6f18f697045200c4a30"}, + {file = "SQLAlchemy-1.4.47-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:dcfb480bfc9e1fab726003ae00a6bfc67a29bad275b63a4e36d17fe7f13a624e"}, + {file = "SQLAlchemy-1.4.47-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:28fda5a69d6182589892422c5a9b02a8fd1125787aab1d83f1392aa955bf8d0a"}, + {file = "SQLAlchemy-1.4.47-cp27-cp27m-win32.whl", hash = "sha256:45e799c1a41822eba6bee4e59b0e38764e1a1ee69873ab2889079865e9ea0e23"}, + {file = "SQLAlchemy-1.4.47-cp27-cp27m-win_amd64.whl", hash = "sha256:10edbb92a9ef611f01b086e271a9f6c1c3e5157c3b0c5ff62310fb2187acbd4a"}, + {file = "SQLAlchemy-1.4.47-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7a4df53472c9030a8ddb1cce517757ba38a7a25699bbcabd57dcc8a5d53f324e"}, + {file = "SQLAlchemy-1.4.47-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:511d4abc823152dec49461209607bbfb2df60033c8c88a3f7c93293b8ecbb13d"}, + {file = "SQLAlchemy-1.4.47-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbe57f39f531c5d68d5594ea4613daa60aba33bb51a8cc42f96f17bbd6305e8d"}, + {file = "SQLAlchemy-1.4.47-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ca8ab6748e3ec66afccd8b23ec2f92787a58d5353ce9624dccd770427ee67c82"}, + {file = "SQLAlchemy-1.4.47-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:299b5c5c060b9fbe51808d0d40d8475f7b3873317640b9b7617c7f988cf59fda"}, + {file = "SQLAlchemy-1.4.47-cp310-cp310-win32.whl", hash = "sha256:684e5c773222781775c7f77231f412633d8af22493bf35b7fa1029fdf8066d10"}, + {file = "SQLAlchemy-1.4.47-cp310-cp310-win_amd64.whl", hash = "sha256:2bba39b12b879c7b35cde18b6e14119c5f1a16bd064a48dd2ac62d21366a5e17"}, + {file = "SQLAlchemy-1.4.47-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:795b5b9db573d3ed61fae74285d57d396829e3157642794d3a8f72ec2a5c719b"}, + {file = "SQLAlchemy-1.4.47-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:989c62b96596b7938cbc032e39431e6c2d81b635034571d6a43a13920852fb65"}, + {file = "SQLAlchemy-1.4.47-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3b67bda733da1dcdccaf354e71ef01b46db483a4f6236450d3f9a61efdba35a"}, + {file = "SQLAlchemy-1.4.47-cp311-cp311-win32.whl", hash = "sha256:9a198f690ac12a3a807e03a5a45df6a30cd215935f237a46f4248faed62e69c8"}, + {file = "SQLAlchemy-1.4.47-cp311-cp311-win_amd64.whl", hash = "sha256:03be6f3cb66e69fb3a09b5ea89d77e4bc942f3bf84b207dba84666a26799c166"}, + {file = "SQLAlchemy-1.4.47-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:16ee6fea316790980779268da47a9260d5dd665c96f225d28e7750b0bb2e2a04"}, + {file = "SQLAlchemy-1.4.47-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:557675e0befafa08d36d7a9284e8761c97490a248474d778373fb96b0d7fd8de"}, + {file = "SQLAlchemy-1.4.47-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bb2797fee8a7914fb2c3dc7de404d3f96eb77f20fc60e9ee38dc6b0ca720f2c2"}, + {file = "SQLAlchemy-1.4.47-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28297aa29e035f29cba6b16aacd3680fbc6a9db682258d5f2e7b49ec215dbe40"}, + {file = "SQLAlchemy-1.4.47-cp36-cp36m-win32.whl", hash = "sha256:998e782c8d9fd57fa8704d149ccd52acf03db30d7dd76f467fd21c1c21b414fa"}, + {file = "SQLAlchemy-1.4.47-cp36-cp36m-win_amd64.whl", hash = "sha256:dde4d02213f1deb49eaaf8be8a6425948963a7af84983b3f22772c63826944de"}, + {file = "SQLAlchemy-1.4.47-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:e98ef1babe34f37f443b7211cd3ee004d9577a19766e2dbacf62fce73c76245a"}, + {file = "SQLAlchemy-1.4.47-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14a3879853208a242b5913f3a17c6ac0eae9dc210ff99c8f10b19d4a1ed8ed9b"}, + {file = "SQLAlchemy-1.4.47-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7120a2f72599d4fed7c001fa1cbbc5b4d14929436135768050e284f53e9fbe5e"}, + {file = "SQLAlchemy-1.4.47-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:048509d7f3ac27b83ad82fd96a1ab90a34c8e906e4e09c8d677fc531d12c23c5"}, + {file = "SQLAlchemy-1.4.47-cp37-cp37m-win32.whl", hash = "sha256:6572d7c96c2e3e126d0bb27bfb1d7e2a195b68d951fcc64c146b94f088e5421a"}, + {file = "SQLAlchemy-1.4.47-cp37-cp37m-win_amd64.whl", hash = "sha256:a6c3929df5eeaf3867724003d5c19fed3f0c290f3edc7911616616684f200ecf"}, + {file = "SQLAlchemy-1.4.47-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:71d4bf7768169c4502f6c2b0709a02a33703544f611810fb0c75406a9c576ee1"}, + {file = "SQLAlchemy-1.4.47-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd45c60cc4f6d68c30d5179e2c2c8098f7112983532897566bb69c47d87127d3"}, + {file = "SQLAlchemy-1.4.47-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0fdbb8e9d4e9003f332a93d6a37bca48ba8095086c97a89826a136d8eddfc455"}, + {file = "SQLAlchemy-1.4.47-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f216a51451a0a0466e082e163591f6dcb2f9ec182adb3f1f4b1fd3688c7582c"}, + {file = "SQLAlchemy-1.4.47-cp38-cp38-win32.whl", hash = "sha256:bd988b3362d7e586ef581eb14771bbb48793a4edb6fcf62da75d3f0f3447060b"}, + {file = "SQLAlchemy-1.4.47-cp38-cp38-win_amd64.whl", hash = "sha256:32ab09f2863e3de51529aa84ff0e4fe89a2cb1bfbc11e225b6dbc60814e44c94"}, + {file = "SQLAlchemy-1.4.47-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:07764b240645627bc3e82596435bd1a1884646bfc0721642d24c26b12f1df194"}, + {file = "SQLAlchemy-1.4.47-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e2a42017984099ef6f56438a6b898ce0538f6fadddaa902870c5aa3e1d82583"}, + {file = "SQLAlchemy-1.4.47-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6b6d807c76c20b4bc143a49ad47782228a2ac98bdcdcb069da54280e138847fc"}, + {file = "SQLAlchemy-1.4.47-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a94632ba26a666e7be0a7d7cc3f7acab622a04259a3aa0ee50ff6d44ba9df0d"}, + {file = "SQLAlchemy-1.4.47-cp39-cp39-win32.whl", hash = "sha256:f80915681ea9001f19b65aee715115f2ad310730c8043127cf3e19b3009892dd"}, + {file = "SQLAlchemy-1.4.47-cp39-cp39-win_amd64.whl", hash = "sha256:fc700b862e0a859a37faf85367e205e7acaecae5a098794aff52fdd8aea77b12"}, + {file = "SQLAlchemy-1.4.47.tar.gz", hash = "sha256:95fc02f7fc1f3199aaa47a8a757437134cf618e9d994c84effd53f530c38586f"}, ] [package.dependencies] @@ -1819,14 +1807,14 @@ files = [ [[package]] name = "tomlkit" -version = "0.11.6" +version = "0.11.7" description = "Style preserving TOML library" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "tomlkit-0.11.6-py3-none-any.whl", hash = "sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b"}, - {file = "tomlkit-0.11.6.tar.gz", hash = "sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73"}, + {file = "tomlkit-0.11.7-py3-none-any.whl", hash = "sha256:5325463a7da2ef0c6bbfefb62a3dc883aebe679984709aee32a317907d0a8d3c"}, + {file = "tomlkit-0.11.7.tar.gz", hash = "sha256:f392ef70ad87a672f02519f99967d28a4d3047133e2d1df936511465fbb3791d"}, ] [[package]] @@ -1860,14 +1848,14 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "uvicorn" -version = "0.21.0" +version = "0.21.1" description = "The lightning-fast ASGI server." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "uvicorn-0.21.0-py3-none-any.whl", hash = "sha256:e69e955cb621ae7b75f5590a814a4fcbfb14cb8f44a36dfe3c5c75ab8aee3ad5"}, - {file = "uvicorn-0.21.0.tar.gz", hash = "sha256:8635a388062222082f4b06225b867b74a7e4ef942124453d4d1d1a5cb3750932"}, + {file = "uvicorn-0.21.1-py3-none-any.whl", hash = "sha256:e47cac98a6da10cd41e6fd036d472c6f58ede6c5dbee3dbee3ef7a100ed97742"}, + {file = "uvicorn-0.21.1.tar.gz", hash = "sha256:0fac9cb342ba099e0d582966005f3fdba5b0290579fed4a6266dc702ca7bb032"}, ] [package.dependencies] From 97d0eac303190f4af34d0814c77757e602f1384c Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sat, 22 Apr 2023 11:39:00 +0200 Subject: [PATCH 020/178] housekeep: copy static files we copy static files used by PHP and Python versions into /static preparation work for the removal of the PHP version Signed-off-by: moson-mo --- aurweb/asgi.py | 6 +- static/css/archnavbar/archlogo.png | Bin 0 -> 5359 bytes static/css/archnavbar/archnavbar.css | 26 + static/css/archnavbar/aurlogo.png | Bin 0 -> 5997 bytes static/css/archweb.css | 1255 ++++++++++++++++++++++++ static/css/aurweb.css | 292 ++++++ static/css/cgit.css | 866 ++++++++++++++++ static/images/ICON-LICENSE | 26 + static/images/action-undo.min.svg | 3 + static/images/action-undo.svg | 32 + static/images/ajax-loader.gif | Bin 0 -> 723 bytes static/images/favicon.ico | Bin 0 -> 575 bytes static/images/pencil.min.svg | 3 + static/images/pencil.svg | 55 ++ static/images/pin.min.svg | 1 + static/images/pin.svg | 3 + static/images/rss.svg | 3 + static/images/unpin.min.svg | 1 + static/images/unpin.svg | 4 + static/images/x.min.svg | 3 + static/images/x.svg | 31 + static/js/comment-edit.js | 61 ++ static/js/copy.js | 9 + static/js/typeahead-home.js | 6 + static/js/typeahead-pkgbase-merge.js | 6 + static/js/typeahead-pkgbase-request.js | 36 + static/js/typeahead.js | 151 +++ 27 files changed, 2874 insertions(+), 5 deletions(-) create mode 100644 static/css/archnavbar/archlogo.png create mode 100644 static/css/archnavbar/archnavbar.css create mode 100644 static/css/archnavbar/aurlogo.png create mode 100644 static/css/archweb.css create mode 100644 static/css/aurweb.css create mode 100644 static/css/cgit.css create mode 100644 static/images/ICON-LICENSE create mode 100644 static/images/action-undo.min.svg create mode 100644 static/images/action-undo.svg create mode 100644 static/images/ajax-loader.gif create mode 100644 static/images/favicon.ico create mode 100644 static/images/pencil.min.svg create mode 100644 static/images/pencil.svg create mode 100644 static/images/pin.min.svg create mode 100644 static/images/pin.svg create mode 100644 static/images/rss.svg create mode 100644 static/images/unpin.min.svg create mode 100644 static/images/unpin.svg create mode 100644 static/images/x.min.svg create mode 100644 static/images/x.svg create mode 100644 static/js/comment-edit.js create mode 100644 static/js/copy.js create mode 100644 static/js/typeahead-home.js create mode 100644 static/js/typeahead-pkgbase-merge.js create mode 100644 static/js/typeahead-pkgbase-request.js create mode 100644 static/js/typeahead.js diff --git a/aurweb/asgi.py b/aurweb/asgi.py index b6578f33..eb02413b 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -79,11 +79,7 @@ async def app_startup(): "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", StaticFiles(directory="static"), name="static_files") # Add application routes. def add_router(module): diff --git a/static/css/archnavbar/archlogo.png b/static/css/archnavbar/archlogo.png new file mode 100644 index 0000000000000000000000000000000000000000..3d2cd40fb499b2b37651ea67ec6f3b4400e3d157 GIT binary patch literal 5359 zcmZ{IS2!Hp_w|^fM(@4%HcCVgz4tPMgkaQ&HhM3EFiH?fM506sq7yX?BLq=`i12C| zL~o;a{(hI=#rK@O&w9?>10<3$laUEN!Q#6008Pn zbXOpBG|m5lHpl75-vVhpC(a!4x$h*`V2lakNUt?{-fw^e?ODm zN2l+hb*}S!PafO;yvB^)?EDQ@iLzn>_b!b9fT^^f*w@{?%2`uO4TKQ2Smxg5ikKW2 zQ*A?S8C;#@KdJ0k753J9XG*F&MOl%LT4?kK&;(>rVhi9U1?;<+SJ-zbGm)>gYnJLH z%w}?U0WeGe;1*6<3W^4axh(3Rm06q~vz;20p9m)iop2}sG)ey@z5ZEzGBay7^^(hv zOFvOQpz-HtC(no`dwszCljyn5{FA6S0{1JalqoLl^-)5KLk=qdBTC!pRYl~Zu4~eY z`jm=y&G7{n7Ek2g)hM=KE?#h6uBwFA4#F~l!gQh1QhEZ zVRX6TH*Dt7a2hD-{!i`M-_>j)z6g%ca~xCE?`N$AK|HXr$u$Q&P^B$#;&T%7mJM zuo8+h+l1P5KqsF_FkI5xbvE#m)@W=uI^t;J3`eFie;MX?$(u}bW!*u-&#nH?kt^%d zx|YaA-ExCV9U&V&;SIrCEb(@465tV50>|q>SR zoU@zOxr=q~2E8QP8G}nzeV$%*DuQQq|Tc`gx!LmYDeG= zxKY+=D~=fjPC4|=pTYudRG(20hFb0uLqD#-tI}K=Ka;(+@i-pI>=l)p6i$ z&9-~lq-@(Seb}1YT!Fy^x8xB-=ujz?L)W!@=ax`=LLfUDA2ZdD#!`(EzFdkzMFYWBytXn;~HGS8jwD~p^JH9 z(yY!Xaf-vSL#cK0=xru5#$e>dlTyIaB33aiIEI-;90sCX`viJ zA0i;5`@2n-HiiSnJS{XdI4WF@Dm#>@7=~DhfH|<5T9m?3X2M$XEY_)Boxvz8R1=d+ zB`^*2^JpfC?3HnEWQFUvg3{}9;A~0gk4%RM(^LTtAnciRWj)K8EL1z=nCL`vFJ0_8 z!lUO+=S6*pjK~uS5pwKHtY(>*-;1v^W&;MohRce{DXIOkviW#BfZjD`@$7ik~xbg$=6paDPdGZM^={xaJ@@q2g3F_z3%7tZk`C zur_-ZmzZiRoB!k5KDqsu&zw`4dhk;}>?d+hUXaSqbmfQjyn1xNf=oQU%Ay=+y!NUKi@<_oc32aa9U%msvJaVpldpOC0k^?27Mr#?k`zim@2j!tQM8L z>5NktPROk;Vy)csIG|uk19*2kOGxmT0O-PQd40OA%-8}209F~HZf=Td#(;;6XTF|h zGG5=G!a^xRAc~u#SS3Xwrx^tTPhb|}T=HW#cvOeJbg_ZtCNaD3TxyjDGOH`2F&N~i zK7%H?&d0K(b}N}2LKXZU=#8)o@P$KnIRtT-efg^}&%OhchdWNi^uZJJ5~ zsROEr60OfOob6dz%ll^ zw`BJj(gPB=SuLcx+ZjhamX2)_&8oO;QyKpP14>$%p2EHQWqkkVu`xg(V}oVi}Ri1z*S+I zg&vwS4$uun2<^C{X&aMF^DN3nO)lxHR>1oQ{Z?T`8iK%gj1M1j_B(}M{>u?&qPqCf z@uD>bS$InQJq`cN+P@oOa_&vEnx|U=u1hPu{XyV*CC>MBy&6G%>l26W*t=CBlXDDG z6=*#pihOP#lTE22?q`sZa3sigQ^t;7EsE0h^Jrtf7+{UX`CfGHD~LprH&0G2mS><_ zyZVj0jd5Wx@9sBtbgeo`9e}YJXj8`SWrhXbgC%E!X(`q$mp5gTKS>%Vl39a^@Fnh> zrQ}ro+g6k_&$ppZg>ZU`g8U#2p%uT|JE^pGL@X@KOl6nXY1 zV10N_gQU6nR({-gHmuQc?o@7=>Vm(tjfji_s`T&NmFf5I7ZHuF&zOH)4_MS*J1a5m zj^ydAYi5p=oW5!qyL@3mnsD;>k10{nJhlr|3H{Ut`O+P9Pj*qF5;xUngQOxl>`5OT z&)Tz_Gd^M50N7Kn(8`Ba!k$|~2>J){l{t}mhqLb8Xs!=Mz(vm42#U*y-ogL-AGoQQ8XB4ez$vAk@nHI82! z8d9IJr16mXG{~R@PZ>x}nY`_B1tCNdc4powbO1}zff z9u12=;9MC{dh4p~e6-0|uF6$`Pj{xAt0Jr+{39w6dq}am5a(PV>Um-HRfEPPS(G*8 z$>LlpE%mSB?%8W)=@7LK^+u-e%_XBp-gtU|1On9feMMGxLNVz3l0l#Z3wFJUrNZNq z=)&0bq%9%iA`=U@3afIyi?UKitiEN7$7@|MhLB9j`y0^mougfz51B1v%7Z-$^ZfI} zwQvKT$?R|7l%b=L+n|c)ZRmSslV|r|ir*yXkw!=j;o4)`)&9i&vQr`V;o?N7*4H~GRuFf>EYM8 z75NO70;8S&Z%M)#lxvZ-#&%;@_oFzzNuu?^L#dErg-H6l?T#=CR>*qr2Eb5oAS$-@ zoE>VjIJo&!`uPMVZlxmZYekd=eC_k5UPV}Oh21VDP6mFwYue2SrxK|*7%OfVUP{Lv z7Bo(pkXOYoC0`Q$Sho|f75Vm$&E>1!MS3I*0bA3=k`Ptq=` zl*jVdmYB(g`_Havu^{x)3A!sO&}>gg5Ju%aw8 z(+7dG`wX8zE`;xWtj@Ubij)aeaF&b*7q5Q`Z~xCB_jWZqY}f9 zM}Pd%k?O0iHVeBp^{Oh54+%Wb2-_%_+x|9(b-|WRit}c1S4wB}MUelnUs-3h^6Frg zO7;Vl?oT<|9WI z)L({xmKW)r8PZaTJv->_F7ufCkdUk_BqyGHn~#)mOu!*2f>+oWe;qhvDVW%|*AkrR zayWjz;XR8b51uDI6FGJC4NKRFx5m9Y>Jzus5nG5Cf@hoBqcE(*=Ir#pclmAOe)M@2 zY!S#sdBv{GRi1=+VAzIO^2(O7+;kBPd+Z|GuYN*qfJY~^SL6Ev(d0jSf^2IT>)CNT zZOqG06m_S5M@gi7+;62DdcmB@|KU<9sJEIwx(XDPyb?&a1H>~(pjJx$s`>iHwm@^- zh!zD$RqscY>gW+nnFhN?DKq<;laZ)~N3zETIFxNm7^d7(t?+14rhU(;bbM*VOZ%#q zn(GTJgf2XNsNRAaXk)G===ivdH|CQ1DJhk#!=yN9+%k33o3K-4GdEp*XQ|{0J)n)t zTUfA*VW55-_bEY^pleU?%!MJBBgK8ZE+d*_Yk`vF+dT5^v^R!j_S}SPDTDiJ4?&(a zdc)daUl3HUDW{@wn4x6v>y}V|;WQ1pVny=fX%=Tx=-I7HeC4#0q!Cd0sM3e7iim?E zr7WdCd-HrNeH@ZKjYy)>XB@q|?n>!{etU;K*_GiBSDEmy0qk1e`FXOHeiKL%&%M+) z84ChG>x!ZQ%&yHHk!p)30$b1nh^Uz~G}Q0kz?9BQmgBy=9b#6FI6KVC%gc#Lgdfj8 zlf8g_RGi3+ql39R3HP<(a1aLVeycB!uGTgx@KHD+5XB+kEmcJeuV>BU-?lNBnVz=>k(&9qn^S z7K2hxxY;uFiO@8m`**ob>EWLwtBYq-B*Bhvd_c|b{kywN<`Ue${v}YPZI;N(=AMsp zzt1^8&0lz`)WB6GE>KH_W~`CJ@i=Fd0~3=aTlTL?Hczl?@$ z@BcaT9p-r6)8HIU)FCvs6%bfX!F*8Cl4U^mgjr53K-SB@l%^OGPh^%ysA(2-InjRn z$L4ZSPF6O)%j7mrM<%UT_P5z%%R(~R3>Bb?TCPj$qsIG3j1jdM5^PKT%K)ZkYU%22 z1FY>E0pB-&9$NH}opdQ%zkIw&ZP?oUs>HGwsnzl+n&H;4zXZ4K8iH(%P-W&KX`Mvp4;W6k)w(@UKYq)zF%33UvR9^Vdk;p ze$x>&*Dolow}vb2^iK)dv>3j$e1f8)W_(v<&u&_R%F8QT-6et_4ugjT&e^(?)N74! zr2@lX=dG9+Sa7}CgE(~DW}Y>ntw@+ubsO7+u?M(0S$DLMecn?v9e*-+#A%EEo@0ha zx1FYSOT>&~{e@o~9eQl@oW}S|=?ihQX2$xo?Hbho4LBM{?XUEs)~MWMDzsd_Ps+)0 zm$z=F_RZ-tIx4Az(0(TKH&Tul@?vg`BH_PBN0ag(jz+7MvRw$+cbVT)b^MMkF%N^0 zn5`K-mQgtGmis_K@Q}hlM3J)?0H`$WM2|iBb-}+ajxO6#NnsY(sC%|`T~uY-SX@1z zc^lz?q7d#;BCtY4ota^k=$|s_$$Mft&vLi!yeM$eeL2pU1KwfN)Z!}^#Df}xSuXc8 zTfCh8LxwYVEYH_>0H3#aLxqFxW-=j4V+dh50`aTcMAjU=$Hd*a56>BsM}a|~4`SbF z%r@~aN+OVEgjMv158JDSyJK%X8vjgDdw4FyHQamUm-I~e{67C1Q|Jw27am{KRPd4G z&e!7)(6SD2Mg+JhIQhBU0YDlm^*|gda~Civ83m}cf~>44^q~S2+5z&A{(l5sKF;p0 zq5pruh}}fmoq+j&9V~oY1A-BLE`Z?RUR4J?A{`Jpl*=BG%MU(F5+Sz{!V)16=3lFeiZt5(_0ZH-#a$v|q>+9uvDnZ60#RRUswf)x%7pUU@TJ6OOWbM)&`B92~4tQuME0y@Gmst2;XK94s^n zOY~5t;;Ej-k{P77BRBGneohUNW?QAO@!S)DzanT>G*-OhvoI?qWZM!lNM3EPB9`nD zyJBe`KY7x%L9a*_I#up|5gPmq^ZIK(9<@pGQpA!ffzE%TS%+q{ei-rjQdEk0!ZJry zTXd3-a8k#059OQ@U)ANA+YCd-I$O~0cy00o9b_mb!drm{T2yvd!cFcj(d*vdh^4#I zu;)d>&D~98cZtN-UmX|;Z--uuZ^PUt;@HIcP-(d@hIQ3!NfmFS-C@YgXA^P-DA@QQ z?v7PKM|sozZ~EcQ59IXp1f>Q9RmMcX5tBbMHy4wdO8x1}mx7|AuDW>38n(|`qaz~< zO+D6CtQ64-$%TX0aIG>dYrM;sjFr0S}w*ye$Eo(&BRtdf#+HTHu_Q0Vh8B{sZ} z_G0bK#O!QmJ{CHOHfts^3zoV1WD|7Ss=4Kg`htw{mel`go zHR0&!DEjCq_{$d>2}Tk}M@Q(xeSpF1*NB3GPUd3aDDp6{B3(q#ODyV0($~+0zZj7+ z5F>kOvd(cyoPV^n$y?jlAWtNce>b?TlhM#bw)kJH)eOrCH$EH>JhR#8P2!wxZfU8q z=^+7w!D(+@ot?v9aAGNvrHMJyQ}dgIp-_;Tvxu-T+CYnX7bX%Wsj#>>B1o-Cje*0% z{asXieE0eO{Oamz2ZYww*LS8ZP~K(nXBYT&4fFEK29e#22ws_1`vK&jvD;J8VdZ2b zR%XQzHbRS`7r~{pE{JJz0Ya%Pv5GE29g&zNMHC@1?9jR0ceOi>0;qEatn6Nzd|vhU z2}+W&h;tI$wgdWJm!hMeYK)+gx|=ED6x-nEs9d?8L!xwWOlPeOy9$Tog2_$jWGcD! zY_*++R`mk4xVZS1kMfy?DTeUb)*P+N$~Hpvh+y`$kHNogH($By;T7&W@vsii%}- z939qJEp$~0hVH-(eIk?~Ti4E{eX+XRWRpF^Z;t;Kxv^o`U@l8iT|-P2 z8CmyR6vZqSp*RUzonU|mh|qC?Bx2 z2s%1Ce1R{7wIJd@4x6hzYq|SXS8inM;CxN(RZfBAH>*hPEYQq*gy-di5tyH$ppfz%#vb zjQ0L^OTOUycM_aX3^q14^uA%zw-l0$arB}D zMiu6wyGI|Dp~_fw&hruaB|3D9KLc*OYKFbMy&nq;Q#uUir~*V0p(ifXdrCn;k(io_ zBQGyc_2|)RLf~z|tfYp;Y>U5m>*X3DM1($N*Z<-`RZR^iObO9<*50lVArg7NJYX5Y za|(NgHT=l&5bD!=Posl;9TzaPW7vLoyF79kJ2;{lp}f0;9iKlsv7YjYser^vh>H!R zL2!{LxETOx?i`Ujc->%jT{a90PpIn~0EL7N4C=3(iMDeQ!(KyWJPtbZ+*u;jhRGW4 z(fkWBLPzLEgCN`VZBY`beDkoIE}}?KTT2U*Yx5D#-#_W0D=U^Y!yB8Mh}PB|wb*O= z5J_M33Wnh~V=Ia&4^L0kw{IEuXMxy$d)r9y@#9C%X;TvuD3AiZwnBVws=)wvL(N@% zDZGHp-~mt)VsP>71D4&!3yE3-1>HB8ARmcU`8@BW5dMmA)EJ_KW)h(x zMkRQ{V#@k5Dw2{q*q}DlG?3CU7cZ#Ly=7`*KX>!;|# zZTmU#_kN3;9)Y7kR_JTzH7Jb2S)b6uum3Nwr*n%&QO*rt;#dl@2+Jdg$MrDLIQ9nU zx7R%y#8uyqrUAZsL^%_ae4xOH9!uOpYe1&g;J`qv z*M9$J-pivN7A8YiBcm^mUXX&`hIy8a=XMhrzu2+FsnkY0aR1eV)8EEe>oN+Mm>U!O z-mc}K<~J)ke2vAw-ZPV-i5Z!JO0R7adOdP7^7CrW48Ga_nN|)aVUyKVT-=RQqA_a+ zz1#ddm`Nfk;j}MA`#xPkXq%N!?!Vb-OWYSO$mu=!>VK6iQ_6=s#4)=>=7XXQpK_T! z0!gEGJmPYQv0g#~ox%93e_$Fz@9WEbK70_`H}UnAtgfzx9xOHG%P zvbw$fuIt_GU&Qq|BS^Q@z$e2xw&VQx{GNGYZ)cbFB>bzKK_p6)@0a<4Fb#*NW5dFq z&dy75zkIoAcgC??F@Kos@FZJP`A zvfL;WJ64u?`7L}1HCm9%9ffNYA;Qp6WhoR|Aa%EPgr(LRZtd5K7lX2(eSlvs?B;2l zk7Kp6^K|X-AdyVPQ31Z~U4J$=vg8AqwTi~}PCkGB+~9xlU0K0Fz>S}Wr{6IQRjQw@ z4&q80SOX#={gGsbJbG-llHppUYEqJK1 zl*GSp5pDw@j7~TG`r41aH~kX+?4w}M;66gCtE=mWim;K9(Km~>CC6Eym6$Z&_a#t- z5&y7HH0b#TpXb*A!XR_J@S;MIE+_23sz4E90DX4LI2N+VI+2ZvOVhECJ$Nj`OzPs| z(oGuKDL6aMM@8U_1^3^B**s=?5|b9}e|H}%y55t}1GL*gxhAiDlZK`y=|UtE6B9QN zkC61%FL#7MD_{%%i+AzF(7DMV&{3DwfU@SCFRlWR#RPYgO`> zD_DHSl^{t;$**N)N-&sA@r(2jfS>d};YtYnAe`!9&w*6_sF;|1WKMB$vGwsrpM={Q z*k!qu__J1cW#w}YPELBt+2rKpcKezt_?=%jm7Th7wt2te*6AnDIiVGdykW=kgHbKv zSmIiByoNz<{`wSKMM=kqt1C>ushBy=3eXHA-ho+I-f`9Vs*y#+iXn!9mHtR-CDE9^ z={x)KNym>YpS7@oAbvIA!2@GTNJ}dtbd7O=2w;|{{wcr0NEV*|NJ#K&R}zw$hBMjw zG_?i32SeXmNuv`OB|~T|U`bw7>IMc>`T6;@1KHBvBtWq0GuJQlkQd8=ET;7?MRakw zxw(_CC*O@1uZp)_5zF18m78|z`Lp_dTQadsZZ`#WB~71)iQrR|C2AT5S48<2^$70N z%HmR;h8p=V@Q!HRcI-eROh@5@bTC_&0v*0dFuRVumvKYm2vonSz9J#bd$!;-NDGv(0aUB8_Q2oJ%KsgfT!q* z@9bl2Z0z3N%4hreWn~2Z=X+I|J2MjGmT4yx_Cfy<#~)k>!o7^7FB9|#q&kc9ZGQM( zmp;16d-9G+iXE^tvS6i(BAX%cYA!#>bA`8+427vVL24)wG8z~Ts#fuwqDv1&Vk$}(M_$J2ZEpkH~B=sEdsrq+A67-u)z<0VG`JxxCr=u?Gb;gaMbk;H%m zw#Tp^PGZi5Uq2liA9uU^xi391lp`CvIq;>Rw6xFV#r)b4KIgii6U4HRzOKqoKRcgy zIjCq)vmC-wPj*HqueLkk@uTM!6RDqya9i?+z_v;MX<&ei63bHm6=>spC!C{L!o&I+CglBl+hVD*AY+J32r|rH z1lsB!pN=_cj#cUysmN*#Q{yF3n2tIkGcc=e9B;ec;RX6@^VQ$XG)ebj!N{C^?)B8R zZ{PR~jEvSNO7$U*j!J+K;o;?dWoD+$fa$vU)9$#6^UE^}H4_v1Vx8<5-;=*=tgIk7 z9Nzt^$opm$NU_B9^uDk9CF2MnT;7LEU4TDw#%VP{s@d5+Sxh{2gl6z|?8}eo`BiRu zvWl83$1Fzgc=#OBg(0H6y?8V=@7*F_Yr>D`?%<#Y z4(|RUro3hE8`7UT{p;rPkWX$rwUP?R=+v_x)1A9BYW4|ss+TZ1SU|ul3kz2vibM|l zV1;(tU7FY~h?A4M#zrJ7o{z7uV#Rbpnkw2~h<4i=jt zGcqzT+~5S@eXwYZ<(Vy*6uO&}!v!vVC74BYlZ4O{|%qlSPK(q;obF zh^-4<9O#CpW$DI0v>Cr|$ekzLYT6RyP(Bt3>ppr)J^zB{Y;2tQ=~+(x_T9U8+1SVp@nyl70Pk=u;Pzy zV|_Y<4c{j<sl&c$9-HNKd(mT zg$D8m!2IyJ`1+KFkKWuv3=zZSy@tr zGW6qmW-%&mclblGnsLQf41bV1Ry+s#wt_=1N6?v%Wbhh#lw5Qe(UWvru5lPLAbr>z zT3s!)v9+a)G-Md(hrwXzDO1y0^SnbVJL0k{<4H#v7$N*Q>J2ce2Gg(efN7pxV-kO}7OPc2p82W-!_+6}IHYu}A zUTrojo`|TZ)%o6RgZoyzoAi!CI5Efs!6l{4l^Mox^{9)?OqRq;J*Cs)x#Fu8(NCe% zx+JT$l)5Tyc(2hM>u@tWWA?Z3KUk)-w||10yf+)XjlO7{`nXl(<$>Dn&ng7pjdA?$ z>av>p_67(_w-6GE1gI?%@~x?fVQ6Rw^yiQc#T#%qpYNJiKKH`;ut{@i=||kXvpk?Z z#>U3bJLMHh<&$ft+rh4?9Kkt-Y>9k9`Rx?~;nPRUih2z<(Lp)(zS&5!+y_ka9x)7q`OqmVRAgktG+dcw001Puhs9E#IcjKHk zJDs&o)4ImSQA0yIw`UcBUB{aPA8+CZ`uq1>Ist9t`q~0;4pS8tq`*c+O})0!m-3vJ zXr|GfD^MaV5?a!5!PV zm#>VBA^|H81dUBxd|GabJmZ|X%eg^y`0z4Xb)Otu>n-tipw*vKwoQdSSPAj`Z^|jD zVA-Uj$vuf?G8&BzQbJVvF-9Y;ChxBSsfs?Ewpecu#`=d)6?XFd7cA7V*wHFV1COdF zyqta&rf7=2p9z|+aj*eM>ve{Gvqiw?;@%~E_wXT|Bx-E;ERL$%^7)Lm>)vR|`1YSV z{fg;K?5{<2^Awxa*r#AcR&j9}>nd6c_*Ky&Nf2~H-iJ9kFktn_2bkQc1q8_Qr<`rE zpZpzE1}siYZ0tU1B@srT#ywLw<4y?MmG`FyT-<}Z*hdaU3&3C;q^YW-@?FU? a.headerlink { + visibility: visible; +} + +/* headings */ +h2 { + font-size: 1.5em; + margin-bottom: 0.5em; + border-bottom: 1px solid #888; +} + +h3 { + font-size: 1.25em; + margin-top: .5em; +} + +h4 { + font-size: 1.15em; + margin-top: 1em; +} + +h5 { + font-size: 1em; + margin-top: 1em; +} + +/* general layout */ +[dir="rtl"] #content { + text-align: right; +} + +#content { + width: 95%; + margin: 0 auto; + text-align: left; +} + +[dir="rtl"] #content-left-wrapper { + float: right; +} + +#content-left-wrapper { + float: left; + width: 100%; /* req to keep content above sidebar in source code */ +} + +[dir="rtl"] #content-left { + margin: 0 0 0 340px; +} + +#content-left { + margin: 0 340px 0 0; +} + +[dir="rtl"] #content-right { + float: right; + margin-right: -300px; +} + +#content-right { + float: left; + width: 300px; + margin-left: -300px; +} + +div.box { + margin-bottom: 1.5em; + padding: 0.65em; + background: #ecf2f5; + border: 1px solid #bcd; +} + +#footer { + clear: both; + margin: 2em 0 1em; +} + + #footer p { + margin: 0; + text-align: center; + font-size: 0.85em; + } + +/* alignment */ +div.center, +table.center, +img.center { + width: auto; + margin-left: auto; + margin-right: auto; +} + +p.center, +td.center, +th.center { + text-align: center; +} + +/* table generics */ +table { + width: 100%; + border-collapse: collapse; +} + + table .wrap { + white-space: normal; + } + +[dir="rtl"] th, +[dir="rtl"] td { + text-align: right; +} + +th, +td { + white-space: nowrap; + text-align: left; +} + + th { + vertical-align: middle; + font-weight: bold; + } + + td { + vertical-align: top; + } + +/* table pretty styles */ +table.pretty2 { + width: auto; + margin-top: 0.25em; + margin-bottom: 0.5em; + border-collapse: collapse; + border: 1px solid #bbb; +} + + .pretty2 th { + padding: 0.35em; + background: #eee; + border: 1px solid #bbb; + } + + .pretty2 td { + padding: 0.35em; + border: 1px dotted #bbb; + } + +table.compact { + width: auto; +} + + .compact td { + padding: 0.25em 0 0.25em 1.5em; + } + + +/* definition lists */ +dl { + clear: both; +} + + dl dt, + dl dd { + margin-bottom: 4px; + padding: 8px 0 4px; + font-weight: bold; + border-top: 1px dotted #bbb; + } + + [dir="rtl"] dl dt { + float: right; + padding-left: 15px; + } + dl dt { + color: #333; + float: left; + padding-right: 15px; + } + +/* forms and input styling */ +form p { + margin: 0.5em 0; +} + +fieldset { + border: 0; +} + +label { + width: 12em; + vertical-align: top; + display: inline-block; + font-weight: bold; +} + +input[type=text], +input[type=password], +input[type=email], +textarea { + padding: 0.10em; +} + +form.general-form label, +form.general-form .form-help { + width: 10em; + vertical-align: top; + display: inline-block; +} + +form.general-form input[type=text], +form.general-form textarea { + width: 45%; +} + +/* archdev navbar */ +#archdev-navbar { + margin: 1.5em 0; +} + + #archdev-navbar ul { + list-style: none; + margin: -0.5em 0; + padding: 0; + } + + #archdev-navbar li { + display: inline; + margin: 0; + padding: 0; + font-size: 0.9em; + } + + #archdev-navbar li a { + padding: 0 0.5em; + color: #07b; + } + +/* error/info messages (x pkg is already flagged out-of-date, etc) */ +#sys-message { + width: 35em; + text-align: center; + margin: 1em auto; + padding: 0.5em; + background: #fff; + border: 1px solid #f00; +} + + #sys-message p { + margin: 0; + } + +ul.errorlist { + color: red; +} + +form ul.errorlist { + margin: 0.5em 0; +} + +/* JS sorting via tablesorter */ +[dir="rtl"] table th.tablesorter-header { + padding-left: 20px; + background-position: center left ; +} +table th.tablesorter-header { + padding-right: 20px; + background-image: url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==); + background-repeat: no-repeat; + background-position: center right; + cursor: pointer; +} + +table thead th.tablesorter-headerAsc { + background-color: #e4eeff; + background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7); +} + +table thead th.tablesorter-headerDesc { + background-color: #e4eeff; + background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7); +} + +table thead th.sorter-false { + background-image: none; + cursor: default; +} + +.tablesorter-header:focus { + outline: none; +} + +/** + * PAGE SPECIFIC STYLES + */ + +/* home: introduction */ +[dir="rtl"] #intro p.readmore { + text-align: left; +} +#intro p.readmore { + margin: -0.5em 0 0 0; + font-size: .9em; + text-align: right; +} + +/* home: news */ +#news { + margin-top: 1.5em; +} + + [dir="rtl"] #news h3 { + float: right; + } + #news h3 { + float: left; + padding-bottom: .5em + } + + #news div { + margin-bottom: 1em; + } + + #news div p { + margin-bottom: 0.5em; + } + + #news .more { + font-weight: normal; + } + [dir="rtl"] #news .rss-icon { + float: left; + } + #news .rss-icon { + float: right; + margin-top: 1em; + } + + #news h4 { + clear: both; + font-size: 1em; + margin-top: 1.5em; + border-bottom: 1px dotted #bbb; + } + [dir="rtl"] #news .timestamp { + float: left; + margin: -1.8em 0 0 0.5em; + } + #news .timestamp { + float: right; + font-size: 0.85em; + margin: -1.8em 0.5em 0 0; + } + +/* home: arrowed headings */ +#news h3 a { + display: block; + background: #1794D1; + font-size: 15px; + padding: 2px 10px; + color: white; +} + + #news a:active { + color: white; + } + +h3 span.arrow { + display: block; + width: 0; + height: 0; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-top: 6px solid #1794D1; + margin: 0 auto; + font-size: 0; + line-height: 0px; +} + +/* home: pkgsearch box */ +#pkgsearch { + padding: 1em 0.75em; + background: #3ad; + color: #fff; + border: 1px solid #08b; +} + + #pkgsearch label { + width: auto; + padding: 0.1em 0; + } + + [dir="rtl"] #pkgsearch input { + float: left; + } + #pkgsearch input { + width: 10em; + float: right; + font-size: 1em; + color: #000; + background: #fff; + border: 1px solid #09c; + } + + [dir="rtl"] .pkgsearch-typeahead { + right: 0; + float: right; + text-align: right; + } + + .pkgsearch-typeahead { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + padding: 0.15em 0.1em; + margin: 0; + min-width: 10em; + font-size: 1em; + text-align: left; + list-style: none; + background-color: #f6f9fc; + border: 1px solid #09c; + } + + .pkgsearch-typeahead li a { + color: #000; + } + + .pkgsearch-typeahead li:hover a, + .pkgsearch-typeahead li.active a { + color: #07b; + } + +/* home: recent pkg updates */ +#pkg-updates h3 { + margin: 0 0 0.3em; +} + + #pkg-updates .more { + font-weight: normal; + } + [dir="rtl"] #pkg-updates .rss-icon { + float: left; + } + #pkg-updates .rss-icon { + float: right; + margin: -2em 0 0 0; + } + + [dir="rtl"] #pkg-updates .rss-icon.latest { + margin-left: 1em; + } + #pkg-updates .rss-icon.latest { + margin-right: 1em; + } + + #pkg-updates table { + margin: 0; + direction: ltr; + } + + #pkg-updates td.pkg-name { + white-space: normal; + text-align: left; + } + + [dir="rtl"] #pkg-updates td.pkg-arch { + text-align: left; + } + #pkg-updates td.pkg-arch { + text-align: right; + } + + #pkg-updates span.testing { + font-style: italic; + } + + #pkg-updates span.staging { + font-style: italic; + color: #ff8040; + } + +/* home: sidebar navigation */ +[dir="rtl"] #nav-sidebar ul { + margin: 0.5em 1em 0.5em 0; +} + +#nav-sidebar ul { + list-style: none; + margin: 0.5em 0 0.5em 1em; + padding: 0; +} + +/* home: sponsor banners */ +#arch-sponsors img { + padding: 0.3em 0; +} + +/* home: sidebar components (navlist, sponsors, pkgsearch, etc) */ +div.widget { + margin-bottom: 1.5em; +} + +/* feeds page */ +[dir="rtl"] #rss-feeds .rss { + padding-left: 20px; + background: url(rss.png) top left no-repeat; +} + +#rss-feeds .rss { + padding-right: 20px; + background: url(rss.png) top right no-repeat; +} + +/* artwork: logo images */ +#artwork img.inverted { + background: #333; + padding: 0; +} + +#artwork div.imagelist img { + display: inline; + margin: 0.75em; +} + +/* news: article list */ +[dir="rtl"] .news-nav { + float: left; +} +.news-nav { + float: right; + margin-top: -2.2em; +} + + .news-nav .prev, + .news-nav .next { + margin: 0 1em; + } + +/* news: article pages */ +div.news-article .article-info { + margin: 0; + color: #999; +} + +/* news: add/edit article */ +#newsform { + width: 60em; +} + + #newsform input[type=text], + #newsform textarea { + width: 75%; + } + +#news-preview { + display: none; +} + +/* todolists: list */ +[dir="rtl"] .todolist-nav { + float: left; +} +.todolist-nav { + float: right; + margin-top: -2.2em; +} + + .todolist-nav .prev, + .todolist-nav .next { + margin: 0 1em; + } + +/* donate: donor list */ +#donor-list ul { + width: 100%; +} + /* max 4 columns, but possibly fewer if screen size doesn't allow for more */ + [dir="rtl"] #donor-list li { + float: right; + } + #donor-list li { + float: left; + width: 25%; + min-width: 20em; + } + +/* download page */ +#arch-downloads h3 { + border-bottom: 1px dotted #bbb; +} + +/* pkglists/devlists */ +table.results { + font-size: 0.846em; + border-top: 1px dotted #999; + border-bottom: 1px dotted #999; + direction: ltr; +} + + [dir="rtl"] .results th {text-align: center; direction:rtl;} + .results th { + padding: 0.5em 1em 0.25em 0.25em; + border-bottom: 1px solid #999; + white-space: nowrap; + background-color:#fff; + } + + .results td { + padding: .3em 1em .3em 3px; + text-align: left; + } + + .results .flagged { + color: red; + } + + .results tr.empty td { + text-align: center; + } + +/* pkglist: layout */ +#pkglist-about { + margin-top: 1.5em; +} + +/* pkglist: results navigation */ +.pkglist-stats { + font-size: 0.85em; +} + +[dir="rtl"] #pkglist-results .pkglist-nav { + float: left; +} +#pkglist-results .pkglist-nav { + float: right; + margin-top: -2.2em; +} + +[dir="rtl"] .pkglist-nav .prev { + margin-left: 1em; +} + +.pkglist-nav .prev { + margin-right: 1em; +} + +[dir="rtl"] .pkglist-nav .next { + margin-left: 1em; +} +.pkglist-nav .next { + margin-right: 1em; +} + +/* search fields and other filter selections */ +.filter-criteria { + margin-bottom: 1em; +} + +.filter-criteria h3 { + font-size: 1em; + margin-top: 0; +} +[dir="rtl"] .filter-criteria div { + float: right; + margin-left: 1.65em; +} +.filter-criteria div { + float: left; + margin-right: 1.65em; + font-size: 0.85em; +} + +.filter-criteria legend { + display: none; +} + +.filter-criteria label { + width: auto; + display: block; + font-weight: normal; +} + +/* pkgdetails: details links that float on the right */ +[dir="rtl"] #pkgdetails #detailslinks { + float: left; +} +#pkgdetails #detailslinks { + float: right; +} + + #pkgdetails #detailslinks h4 { + margin-top: 0; + margin-bottom: 0.25em; + } + + #pkgdetails #detailslinks ul { + list-style: none; + padding: 0; + margin-bottom: 0; + font-size: 0.846em; + } + + #pkgdetails #detailslinks > div { + padding: 0.5em; + margin-bottom: 1em; + background: #eee; + border: 1px solid #bbb; + } + +#pkgdetails #actionlist .flagged { + color: red; + font-size: 0.9em; + font-style: italic; +} + +/* pkgdetails: pkg info */ +#pkgdetails #pkginfo { + width: auto; +} + +[dir="rtl"] #pkgdetails td { + padding: 0.25em 1.5em 0.25em 0; + } + + #pkgdetails #pkginfo td { + padding: 0.25em 0 0.25em 1.5em; + } + + #pkgdetails #pkginfo .userdata { + font-size: 0.85em; + padding: 0.5em; + } + +/* pkgdetails: flag package */ +#flag-pkg-form label { + width: 10em; +} + +#flag-pkg-form textarea, +#flag-pkg-form input[type=text] { + width: 45%; +} + +#flag-pkg-form #id_website { + display: none; +} + +/* pkgdetails: deps, required by and file lists */ +#pkgdetails #metadata { + clear: both; +} + +#pkgdetails #metadata h3 { + background: #555; + color: #fff; + font-size: 1em; + margin-bottom: 0.5em; + padding: 0.2em 0.35em; +} + +#pkgdetails #metadata ul { + list-style: none; + margin: 0; + padding: 0; +} + +[dir="rtl"] #pkgdetails #metadata li { + padding-right: 0.5em; +} + +#pkgdetails #metadata li { + padding-left: 0.5em; +} + +[dir="rtl"] #pkgdetails #metadata p { + padding-right: 0.5em; +} +#pkgdetails #metadata p { + padding-left: 0.5em; +} + +#pkgdetails #metadata .message { + font-style: italic; +} + +#pkgdetails #metadata br { + clear: both; +} + +[dir="rtl"] #pkgdetails #pkgdeps { + float: right; + width: 48%; + margin-left: 2%; + +} +#pkgdetails #pkgdeps { + float: left; + width: 48%; + margin-right: 2%; +} + +#pkgdetails #metadata .virtual-dep, +#pkgdetails #metadata .testing-dep, +#pkgdetails #metadata .staging-dep, +#pkgdetails #metadata .opt-dep, +#pkgdetails #metadata .make-dep, +#pkgdetails #metadata .check-dep, +#pkgdetails #metadata .dep-desc { + font-style: italic; +} + +[dir="rtl"] #pkgdetails #pkgreqs { + float: right; + width: 48%; +} + +#pkgdetails #pkgreqs { + float: left; + width: 50%; +} + +#pkgdetails #pkgfiles { + clear: both; + padding-top: 1em; +} + +#pkgfilelist li.d { + color: #666; +} + +#pkgfilelist li.f { +} + +/* mirror stuff */ +table td.country { + white-space: normal; +} + +#list-generator div ul { + list-style: none; + display: inline; + padding-left: 0; +} + + #list-generator div ul li { + display: inline; + } + +.visualize-mirror .axis path, +.visualize-mirror .axis line { + fill: none; + stroke: #000; + stroke-width: 3px; + shape-rendering: crispEdges; +} + +.visualize-mirror .url-dot { + stroke: #000; +} + +.visualize-mirror .url-line { + fill: none; + stroke-width: 1.5px; +} + +/* dev/TU biographies */ +#arch-bio-toc { + width: 75%; + margin: 0 auto; + text-align: center; +} + + #arch-bio-toc a { + white-space: nowrap; + } + +.arch-bio-entry { + width: 75%; + min-width: 640px; + margin: 0 auto; +} + .arch-bio-entry td.pic { + padding-left: 15px; + } + .arch-bio-entry td.pic { + vertical-align: top; + padding-right: 15px; + padding-top: 2.25em; + } + + .arch-bio-entry td.pic img { + padding: 4px; + border: 1px solid #ccc; + } + + .arch-bio-entry td h3 { + border-bottom: 1px dotted #ccc; + margin-bottom: 0.5em; + } + + .arch-bio-entry table.bio { + margin-bottom: 2em; + } + [dir="rtl"] .arch-bio-entry table.bio th { + text-align: left; + padding-left: 0.5em; + } + + .arch-bio-entry table.bio th { + color: #666; + font-weight: normal; + text-align: right; + padding-right: 0.5em; + vertical-align: top; + white-space: nowrap; + } + + .arch-bio-entry table.bio td { + width: 100%; + padding-bottom: 0.25em; + white-space: normal; + } + +/* dev: login/out */ +#dev-login { + width: auto; +} + +/* tables rows: highlight on mouse-vover */ +#article-list tr:hover, +#clocks-table tr:hover, +#dev-dashboard tr:hover, +#dev-todo-lists tr:hover, +#dev-todo-pkglist tr:hover, +#pkglist-results tr:hover, +#stats-area tr:hover { + background: #ffd; +} + +.results tr:nth-child(even), +#article-list tr:nth-child(even) { + background: #e4eeff; +} + +.results tr:nth-child(odd), +#article-list tr:nth-child(odd) { + background: #fff; +} + +/* dev dashboard: */ +table.dash-stats .key { + width: 50%; +} + +/* dev dashboard: admin actions (add news items, todo list, etc) */ +[dir="rtl"] ul.admin-actions { + float: left; +} +ul.admin-actions { + float: right; + list-style: none; + margin-top: -2.5em; +} + + ul.admin-actions li { + display: inline; + padding-left: 1.5em; + } + +/* colored yes/no type values */ +.todo-table .complete, +.signoff-yes, +#key-status .signed-yes, +#release-list .available-yes { + color: green; +} + +.todo-table .incomplete, +.signoff-no, +#key-status .signed-no, +#release-list .available-no { + color: red; +} + +.todo-table .inprogress, +.signoff-bad { + color: darkorange; +} + + +/* todo lists (public and private) */ +.todo-info { + color: #999; + border-bottom: 1px dotted #bbb; +} + +.todo-description { + margin-top: 1em; + padding-left: 2em; + max-width: 900px; +} + +.todo-pkgbases { + border-top: 1px dotted #bbb; +} + +.todo-list h4 { + margin-top: 0; + margin-bottom: 0.4em; +} + +/* dev: signoff page */ +#dev-signoffs tr:hover { + background: #ffd; +} + +ul.signoff-list { + list-style: none; + margin: 0; + padding: 0; +} + +.signoff-yes { + font-weight: bold; +} + +.signoff-disabled { + color: gray; +} + +/* highlight current website in the navbar */ +#archnavbar.anb-home ul li#anb-home a, +#archnavbar.anb-packages ul li#anb-packages a, +#archnavbar.anb-download ul li#anb-download a { + color: white !important; +} + +/* visualizations page */ +.visualize-buttons { + margin: 0.5em 0.33em; +} + +.visualize-chart { + position: relative; + height: 500px; + margin: 0.33em; +} + +#visualize-archrepo .treemap-cell { + border: solid 1px white; + overflow: hidden; + position: absolute; +} + + #visualize-archrepo .treemap-cell span { + padding: 3px; + font-size: 0.85em; + line-height: 1em; + } + +#visualize-keys svg { + width: 100%; + height: 100%; +} + +/* releases */ +#release-table th:first-of-type { + width: 30px; +} + +/* itemprops */ +.itemprop { + display: none; +} diff --git a/static/css/aurweb.css b/static/css/aurweb.css new file mode 100644 index 00000000..64a65742 --- /dev/null +++ b/static/css/aurweb.css @@ -0,0 +1,292 @@ +/* aurweb-specific customizations to archweb.css */ + +#archnavbar.anb-aur ul li#anb-aur a { + color: white !important; +} + +#archnavbarlogo { + background: url('archnavbar/aurlogo.png') !important; +} + +[dir="rtl"] #lang_sub { + float: left; + } +#lang_sub { + float: right; +} + +.pkglist-nav .page { + margin: 0 .25em; +} + +#pkg-stats td.stat-desc { + white-space: normal; +} + +#actionlist form { + margin: 0; + padding: 0; +} + +.arch-bio-entry ul { + list-style: none; + padding: 0; +} + +#pkg-updates table { + table-layout: fixed; + width:100%; +} + +#pkg-updates td.pkg-name { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +[dir="rtl"] #pkg-updates td.pkg-date { + text-align:left; +} +#pkg-updates td.pkg-date { + text-align:right; +} + +[dir="rtl"] .keyword:link, .keyword:visited { + float: right; +} + +.keyword:link, .keyword:visited { + float: left; + margin: 1px .5ex 1px 0; + padding: 0 1em; + color: white; + background-color: #36a; + border: 1px solid transparent; + border-radius: 2px; +} + +.keyword:hover { + cursor: pointer; +} + +.keyword:focus { + border: 1px dotted #000; +} + +.text-button { + background: transparent; + border: none !important; + margin: 0 !important; + padding: 0 !important; + font: normal 100% sans-serif; + text-decoration: none; + color: #07b; + cursor: pointer; +} + +.text-button:hover { + text-decoration: underline; + color: #666; +} + +.text-button::-moz-focus-inner { + padding: 0; + border: none; +} + +.comment-deleted { + color: #999; +} + +.edited { + font-size: 0.9em; + color: #999; +} + +[dir="rtl"] .delete-comment-form, .undelete-comment-form, .pin-comment-form, .edit-comment { + float: left; + margin-right: 8px; +} + +.delete-comment-form, .undelete-comment-form, .pin-comment-form, .edit-comment { + float: right; + margin-left: 8px; +} + +.edit-comment { + height: 11px; + position: relative; + top: 1px; +} + +.comment-enable-notifications { + display: inline-block; + margin-left: 1em; +} + +.rss-icon, .delete-comment, .undelete-comment, .edit-comment, .pin-comment { + filter: grayscale(100%); + opacity: 0.6; +} + +.rss-icon:hover, .delete-comment:hover, .undelete-comment:hover, .edit-comment:hover, .pin-comment:hover { + filter: none; + opacity: 1; +} + +[dir="rtl"] .ajax-loader { + float: left; +} + +.ajax-loader { + float: right; + position: relative; + top: 4px; +} + +.flagged a { + color: inherit; +} + +legend { + padding: 1em 0; +} + +p.important { + font-weight: bold; +} + +span.hover-help { + border-bottom: 1px dotted black; + cursor:help; +} + +label.confirmation { + width: auto; +} + +#pkgdepslist .broken { + color: red; + font-weight: bold; +} + +.package-comments { + margin-top: 1.5em; +} + +.comments-header { + display: flex; + justify-content: space-between; + align-items: flex-start; +} + +/* arrowed headings */ +.comments-header h3 span.text { + display: block; + background: #1794D1; + font-size: 15px; + padding: 2px 10px; + color: white; +} + +.comments-header .comments-header-nav { + align-self: flex-end; +} + +.comments-footer { + display: flex; + justify-content: flex-end; +} + +.comment-header { + clear: both; + font-size: 1em; + margin-top: 1.5em; + border-bottom: 1px dotted #bbb; +} + +.comments div { + margin-bottom: 1em; +} + +.comments div p { + margin-bottom: 0.5em; +} + +.comments .more { + font-weight: normal; +} + +.error { + color: red; +} + +.article-content > div { + overflow: hidden; + transition: height 1s; +} + +.proposal.details { + margin: .33em 0 1em; +} + +button[type="submit"], +button[type="reset"] { + padding: 0 0.6em; +} + +.results tr td[align="left"] fieldset { + text-align: left; +} + +.results tr td[align="right"] fieldset { + text-align: right; +} + +input#search-action-submit { + width: 80px; +} + +.success { + color: green; +} + +/* Styling used to clone styles for a form.link button. */ +form.link, form.link button { + display: inline; + font-family: sans-serif; +} +form.link button { + padding: 0 0.5em; + color: #07b; + background: none; + border: none; + font-family: inherit; + font-size: inherit; +} +form.link button:hover { + cursor: pointer; + text-decoration: underline; +} + +/* Customize form.link when used inside of a page. */ +div.box form.link p { + margin: .33em 0 1em; +} +div.box form.link button { + padding: 0; +} + +pre.traceback { + /* https://css-tricks.com/snippets/css/make-pre-text-wrap/ */ + white-space: pre-wrap; + word-wrap: break-all; +} + +/* By default, tables use 100% width, which we do not always want. */ +table.no-width { + width: auto; +} +table.no-width > tbody > tr > td { + padding-right: 2px; +} diff --git a/static/css/cgit.css b/static/css/cgit.css new file mode 100644 index 00000000..429b5f54 --- /dev/null +++ b/static/css/cgit.css @@ -0,0 +1,866 @@ +/* + * ARCH GLOBAL NAVBAR + * We're forcing all generic selectors with !important + * to help prevent other stylesheets from interfering. + */ + +/* container for the entire bar */ +#archnavbar { height: 40px !important; padding: 10px 15px !important; background: #333 !important; border-bottom: 5px #08c solid !important; } +#archnavbarlogo { float: left !important; margin: 0 !important; padding: 0 !important; height: 40px !important; width: 190px !important; background: url('archnavbar/archlogo.png') no-repeat !important; } + +/* move the heading text offscreen */ +#archnavbarlogo h1 { margin: 0 !important; padding: 0 !important; text-indent: -9999px !important; } + +/* make the link the same size as the logo */ +#archnavbarlogo a { display: block !important; height: 40px !important; width: 190px !important; } + +/* display the list inline, float it to the right and style it */ +#archnavbarlist { display: inline !important; float: right !important; list-style: none !important; margin: 0 !important; padding: 0 !important; } +#archnavbarlist li { float: left !important; font-size: 14px !important; font-family: sans-serif !important; line-height: 45px !important; padding-right: 15px !important; padding-left: 15px !important; } + +/* style the links */ +#archnavbarlist li a { color: #999; font-weight: bold !important; text-decoration: none !important; } +#archnavbarlist li a:hover { color: white !important; text-decoration: underline !important; } + +/* END ARCH GLOBAL NAVBAR */ + +#footer { + clear: both; + margin: 0; +} + +#footer p { + margin: 1em; +} + +#archnavbar.anb-aur ul li#anb-aur a { + color: white !important; +} + +#archnavbarlogo { + background: url('archnavbar/aurlogo.png') !important; +} + +body { + padding: 0; + margin: 0; + font-family: sans-serif; + font-size: 10pt; + color: #333; + background: white; +} + +div#cgit a { + color: blue; + text-decoration: none; +} + +div#cgit a:hover { + text-decoration: underline; +} + +div#cgit table { + border-collapse: collapse; +} + +div#cgit table#header { + width: 100%; + margin-bottom: 1em; +} + +div#cgit table#header td.logo { + width: 96px; + vertical-align: top; +} + +div#cgit table#header td.main { + font-size: 250%; + padding-left: 10px; + white-space: nowrap; +} + +div#cgit table#header td.main a { + color: #000; +} + +div#cgit table#header td.form { + text-align: right; + vertical-align: bottom; + padding-right: 1em; + padding-bottom: 2px; + white-space: nowrap; +} + +div#cgit table#header td.form form, +div#cgit table#header td.form input, +div#cgit table#header td.form select { + font-size: 90%; +} + +div#cgit table#header td.sub { + color: #777; + border-top: solid 1px #ccc; + padding-left: 10px; +} + +div#cgit table.tabs { + border-bottom: solid 3px #ccc; + border-collapse: collapse; + margin-top: 2em; + margin-bottom: 0px; + width: 100%; +} + +div#cgit table.tabs td { + padding: 0px 1em; + vertical-align: bottom; +} + +div#cgit table.tabs td a { + padding: 2px 0.75em; + color: #777; + font-size: 110%; +} + +div#cgit table.tabs td a.active { + color: #000; + background-color: #ccc; +} + +div#cgit table.tabs td.form { + text-align: right; +} + +div#cgit table.tabs td.form form { + padding-bottom: 2px; + font-size: 90%; + white-space: nowrap; +} + +div#cgit table.tabs td.form input, +div#cgit table.tabs td.form select { + font-size: 90%; +} + +div#cgit div.path { + margin: 0px; + padding: 5px 2em 2px 2em; + color: #000; + background-color: #eee; +} + +div#cgit div.content { + margin: 0px; + padding: 2em; + border-bottom: solid 3px #ccc; +} + + +div#cgit table.list { + width: 100%; + border: none; + border-collapse: collapse; +} + +div#cgit table.list tr { + background: white; +} + +div#cgit table.list tr.logheader { + background: #eee; +} + +div#cgit table.list tr:hover { + background: #eee; +} + +div#cgit table.list tr.nohover:hover { + background: white; +} + +div#cgit table.list th { + font-weight: bold; + /* color: #888; + border-top: dashed 1px #888; + border-bottom: dashed 1px #888; + */ + padding: 0.1em 0.5em 0.05em 0.5em; + vertical-align: baseline; +} + +div#cgit table.list td { + border: none; + padding: 0.1em 0.5em 0.1em 0.5em; +} + +div#cgit table.list td.commitgraph { + font-family: monospace; + white-space: pre; +} + +div#cgit table.list td.commitgraph .column1 { + color: #a00; +} + +div#cgit table.list td.commitgraph .column2 { + color: #0a0; +} + +div#cgit table.list td.commitgraph .column3 { + color: #aa0; +} + +div#cgit table.list td.commitgraph .column4 { + color: #00a; +} + +div#cgit table.list td.commitgraph .column5 { + color: #a0a; +} + +div#cgit table.list td.commitgraph .column6 { + color: #0aa; +} + +div#cgit table.list td.logsubject { + font-family: monospace; + font-weight: bold; +} + +div#cgit table.list td.logmsg { + font-family: monospace; + white-space: pre; + padding: 0 0.5em; +} + +div#cgit table.list td a { + color: black; +} + +div#cgit table.list td a.ls-dir { + font-weight: bold; + color: #00f; +} + +div#cgit table.list td a:hover { + color: #00f; +} + +div#cgit img { + border: none; +} + +div#cgit input#switch-btn { + margin: 2px 0px 0px 0px; +} + +div#cgit td#sidebar input.txt { + width: 100%; + margin: 2px 0px 0px 0px; +} + +div#cgit table#grid { + margin: 0px; +} + +div#cgit td#content { + vertical-align: top; + padding: 1em 2em 1em 1em; + border: none; +} + +div#cgit div#summary { + vertical-align: top; + margin-bottom: 1em; +} + +div#cgit table#downloads { + float: right; + border-collapse: collapse; + border: solid 1px #777; + margin-left: 0.5em; + margin-bottom: 0.5em; +} + +div#cgit table#downloads th { + background-color: #ccc; +} + +div#cgit div#blob { + border: solid 1px black; +} + +div#cgit div.error { + color: red; + font-weight: bold; + margin: 1em 2em; +} + +div#cgit a.ls-blob, div#cgit a.ls-dir, div#cgit a.ls-mod { + font-family: monospace; +} + +div#cgit td.ls-size { + text-align: right; + font-family: monospace; + width: 10em; +} + +div#cgit td.ls-mode { + font-family: monospace; + width: 10em; +} + +div#cgit table.blob { + margin-top: 0.5em; + border-top: solid 1px black; +} + +div#cgit table.blob td.lines { + margin: 0; padding: 0 0 0 0.5em; + vertical-align: top; + color: black; +} + +div#cgit table.blob td.linenumbers { + margin: 0; padding: 0 0.5em 0 0.5em; + vertical-align: top; + text-align: right; + border-right: 1px solid gray; +} + +div#cgit table.blob pre { + padding: 0; margin: 0; +} + +div#cgit table.blob a.no, div#cgit table.ssdiff a.no { + color: gray; + text-align: right; + text-decoration: none; +} + +div#cgit table.blob a.no a:hover { + color: black; +} + +div#cgit table.bin-blob { + margin-top: 0.5em; + border: solid 1px black; +} + +div#cgit table.bin-blob th { + font-family: monospace; + white-space: pre; + border: solid 1px #777; + padding: 0.5em 1em; +} + +div#cgit table.bin-blob td { + font-family: monospace; + white-space: pre; + border-left: solid 1px #777; + padding: 0em 1em; +} + +div#cgit table.nowrap td { + white-space: nowrap; +} + +div#cgit table.commit-info { + border-collapse: collapse; + margin-top: 1.5em; +} + +div#cgit div.cgit-panel { + float: right; + margin-top: 1.5em; +} + +div#cgit div.cgit-panel table { + border-collapse: collapse; + border: solid 1px #aaa; + background-color: #eee; +} + +div#cgit div.cgit-panel th { + text-align: center; +} + +div#cgit div.cgit-panel td { + padding: 0.25em 0.5em; +} + +div#cgit div.cgit-panel td.label { + padding-right: 0.5em; +} + +div#cgit div.cgit-panel td.ctrl { + padding-left: 0.5em; +} + +div#cgit table.commit-info th { + text-align: left; + font-weight: normal; + padding: 0.1em 1em 0.1em 0.1em; + vertical-align: top; +} + +div#cgit table.commit-info td { + font-weight: normal; + padding: 0.1em 1em 0.1em 0.1em; +} + +div#cgit div.commit-subject { + font-weight: bold; + font-size: 125%; + margin: 1.5em 0em 0.5em 0em; + padding: 0em; +} + +div#cgit div.commit-msg { + white-space: pre; + font-family: monospace; +} + +div#cgit div.notes-header { + font-weight: bold; + padding-top: 1.5em; +} + +div#cgit div.notes { + white-space: pre; + font-family: monospace; + border: solid 1px #ee9; + background-color: #ffd; + padding: 0.3em 2em 0.3em 1em; + float: left; +} + +div#cgit div.notes-footer { + clear: left; +} + +div#cgit div.diffstat-header { + font-weight: bold; + padding-top: 1.5em; +} + +div#cgit table.diffstat { + border-collapse: collapse; + border: solid 1px #aaa; + background-color: #eee; +} + +div#cgit table.diffstat th { + font-weight: normal; + text-align: left; + text-decoration: underline; + padding: 0.1em 1em 0.1em 0.1em; + font-size: 100%; +} + +div#cgit table.diffstat td { + padding: 0.2em 0.2em 0.1em 0.1em; + font-size: 100%; + border: none; +} + +div#cgit table.diffstat td.mode { + white-space: nowrap; +} + +div#cgit table.diffstat td span.modechange { + padding-left: 1em; + color: red; +} + +div#cgit table.diffstat td.add a { + color: green; +} + +div#cgit table.diffstat td.del a { + color: red; +} + +div#cgit table.diffstat td.upd a { + color: blue; +} + +div#cgit table.diffstat td.graph { + width: 500px; + vertical-align: middle; +} + +div#cgit table.diffstat td.graph table { + border: none; +} + +div#cgit table.diffstat td.graph td { + padding: 0px; + border: 0px; + height: 7pt; +} + +div#cgit table.diffstat td.graph td.add { + background-color: #5c5; +} + +div#cgit table.diffstat td.graph td.rem { + background-color: #c55; +} + +div#cgit div.diffstat-summary { + color: #888; + padding-top: 0.5em; +} + +div#cgit table.diff { + width: 100%; +} + +div#cgit table.diff td { + font-family: monospace; + white-space: pre; +} + +div#cgit table.diff td div.head { + font-weight: bold; + margin-top: 1em; + color: black; +} + +div#cgit table.diff td div.hunk { + color: #009; +} + +div#cgit table.diff td div.add { + color: green; +} + +div#cgit table.diff td div.del { + color: red; +} + +div#cgit .sha1 { + font-family: monospace; + font-size: 90%; +} + +div#cgit .left { + text-align: left; +} + +div#cgit .right { + text-align: right; + float: none !important; + width: auto !important; + padding: 0 !important; +} + +div#cgit table.list td.reposection { + font-style: italic; + color: #888; +} + +div#cgit a.button { + font-size: 80%; + padding: 0em 0.5em; +} + +div#cgit a.primary { + font-size: 100%; +} + +div#cgit a.secondary { + font-size: 90%; +} + +div#cgit td.toplevel-repo { + +} + +div#cgit table.list td.sublevel-repo { + padding-left: 1.5em; +} + +div#cgit ul.pager { + list-style-type: none; + text-align: center; + margin: 1em 0em 0em 0em; + padding: 0; +} + +div#cgit ul.pager li { + display: inline-block; + margin: 0.25em 0.5em; +} + +div#cgit ul.pager a { + color: #777; +} + +div#cgit ul.pager .current { + font-weight: bold; +} + +div#cgit span.age-mins { + font-weight: bold; + color: #080; +} + +div#cgit span.age-hours { + color: #080; +} + +div#cgit span.age-days { + color: #040; +} + +div#cgit span.age-weeks { + color: #444; +} + +div#cgit span.age-months { + color: #888; +} + +div#cgit span.age-years { + color: #bbb; +} +div#cgit div.footer { + margin-top: 0.5em; + text-align: center; + font-size: 80%; + color: #ccc; +} +div#cgit a.branch-deco { + color: #000; + margin: 0px 0.5em; + padding: 0px 0.25em; + background-color: #88ff88; + border: solid 1px #007700; +} +div#cgit a.tag-deco { + color: #000; + margin: 0px 0.5em; + padding: 0px 0.25em; + background-color: #ffff88; + border: solid 1px #777700; +} +div#cgit a.remote-deco { + color: #000; + margin: 0px 0.5em; + padding: 0px 0.25em; + background-color: #ccccff; + border: solid 1px #000077; +} +div#cgit a.deco { + color: #000; + margin: 0px 0.5em; + padding: 0px 0.25em; + background-color: #ff8888; + border: solid 1px #770000; +} + +div#cgit div.commit-subject a.branch-deco, +div#cgit div.commit-subject a.tag-deco, +div#cgit div.commit-subject a.remote-deco, +div#cgit div.commit-subject a.deco { + margin-left: 1em; + font-size: 75%; +} + +div#cgit table.stats { + border: solid 1px black; + border-collapse: collapse; +} + +div#cgit table.stats th { + text-align: left; + padding: 1px 0.5em; + background-color: #eee; + border: solid 1px black; +} + +div#cgit table.stats td { + text-align: right; + padding: 1px 0.5em; + border: solid 1px black; +} + +div#cgit table.stats td.total { + font-weight: bold; + text-align: left; +} + +div#cgit table.stats td.sum { + color: #c00; + font-weight: bold; +/* background-color: #eee; */ +} + +div#cgit table.stats td.left { + text-align: left; +} + +div#cgit table.vgraph { + border-collapse: separate; + border: solid 1px black; + height: 200px; +} + +div#cgit table.vgraph th { + background-color: #eee; + font-weight: bold; + border: solid 1px white; + padding: 1px 0.5em; +} + +div#cgit table.vgraph td { + vertical-align: bottom; + padding: 0px 10px; +} + +div#cgit table.vgraph div.bar { + background-color: #eee; +} + +div#cgit table.hgraph { + border: solid 1px black; + width: 800px; +} + +div#cgit table.hgraph th { + background-color: #eee; + font-weight: bold; + border: solid 1px black; + padding: 1px 0.5em; +} + +div#cgit table.hgraph td { + vertical-align: middle; + padding: 2px 2px; +} + +div#cgit table.hgraph div.bar { + background-color: #eee; + height: 1em; +} + +div#cgit table.ssdiff { + width: 100%; +} + +div#cgit table.ssdiff td { + font-size: 75%; + font-family: monospace; + white-space: pre; + padding: 1px 4px 1px 4px; + border-left: solid 1px #aaa; + border-right: solid 1px #aaa; +} + +div#cgit table.ssdiff td.add { + color: black; + background: #cfc; + min-width: 50%; +} + +div#cgit table.ssdiff td.add_dark { + color: black; + background: #aca; + min-width: 50%; +} + +div#cgit table.ssdiff span.add { + background: #cfc; + font-weight: bold; +} + +div#cgit table.ssdiff td.del { + color: black; + background: #fcc; + min-width: 50%; +} + +div#cgit table.ssdiff td.del_dark { + color: black; + background: #caa; + min-width: 50%; +} + +div#cgit table.ssdiff span.del { + background: #fcc; + font-weight: bold; +} + +div#cgit table.ssdiff td.changed { + color: black; + background: #ffc; + min-width: 50%; +} + +div#cgit table.ssdiff td.changed_dark { + color: black; + background: #cca; + min-width: 50%; +} + +div#cgit table.ssdiff td.lineno { + color: black; + background: #eee; + text-align: right; + width: 3em; + min-width: 3em; +} + +div#cgit table.ssdiff td.hunk { + color: black; + background: #ccf; + border-top: solid 1px #aaa; + border-bottom: solid 1px #aaa; +} + +div#cgit table.ssdiff td.head { + border-top: solid 1px #aaa; + border-bottom: solid 1px #aaa; +} + +div#cgit table.ssdiff td.head div.head { + font-weight: bold; + color: black; +} + +div#cgit table.ssdiff td.foot { + border-top: solid 1px #aaa; + border-left: none; + border-right: none; + border-bottom: none; +} + +div#cgit table.ssdiff td.space { + border: none; +} + +div#cgit table.ssdiff td.space div { + min-height: 3em; +} + +/* + * Style definitions generated by highlight 3.14, http://www.andre-simon.de/ + * Highlighting theme: Kwrite Editor + */ +div#cgit table.blob .num { color:#b07e00; } +div#cgit table.blob .esc { color:#ff00ff; } +div#cgit table.blob .str { color:#bf0303; } +div#cgit table.blob .pps { color:#818100; } +div#cgit table.blob .slc { color:#838183; font-style:italic; } +div#cgit table.blob .com { color:#838183; font-style:italic; } +div#cgit table.blob .ppc { color:#008200; } +div#cgit table.blob .opt { color:#000000; } +div#cgit table.blob .ipl { color:#0057ae; } +div#cgit table.blob .lin { color:#555555; } +div#cgit table.blob .kwa { color:#000000; font-weight:bold; } +div#cgit table.blob .kwb { color:#0057ae; } +div#cgit table.blob .kwc { color:#000000; font-weight:bold; } +div#cgit table.blob .kwd { color:#010181; } diff --git a/static/images/ICON-LICENSE b/static/images/ICON-LICENSE new file mode 100644 index 00000000..6b39f6fd --- /dev/null +++ b/static/images/ICON-LICENSE @@ -0,0 +1,26 @@ +The icons used in aurweb originate from the Open Iconic project and are +licensed under the following terms: + +---- +The MIT License (MIT) + +Copyright (c) 2014 Waybury + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +---- diff --git a/static/images/action-undo.min.svg b/static/images/action-undo.min.svg new file mode 100644 index 00000000..eb47bc47 --- /dev/null +++ b/static/images/action-undo.min.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/images/action-undo.svg b/static/images/action-undo.svg new file mode 100644 index 00000000..b93ebb78 --- /dev/null +++ b/static/images/action-undo.svg @@ -0,0 +1,32 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/static/images/ajax-loader.gif b/static/images/ajax-loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..df07e7ec2076177c99b53d4d29a45f0db6b06a9a GIT binary patch literal 723 zcmZ?wbhEHb6kyWo5uik&V|NP^(AHU+;_dI&}>C3lYM=m|vboAbp zdv88|`N04KivPL&TtkAL9RpmA^bD98f#Qn)q@0UV6H8K46v{J8G87WC5-W1@6I1ju z^V0Ge6o0aCasyTAfJ^{6l7UrML7^`tbKa5#T#rsMt#c4)wm4&2aJl;4?H%*^*q;ct zZ+YZ!f=91--8C-PwbPuinV^!8D8ZUAZ$+j|`^0?*ZXH_r=F;-s=Wq7D-W{Q@F^9F$ zTCh`s37bYUpw-=pI*&V4IF+P$l9wbc(l{x7eoOCbBdG(^nGZDWjsAGTTd?u$#mhT{ z{bn8t<<=6J=66T{n^C4fqn2>E3WhNCJ~l~G@x1uTreFAcY2|b4S-i`cPqf%2ZE*i3 z+J9zZu_cRCJ%=P)K~y-6jgvo!6G0Tle=|GDx_9PaSMatt8xuJ=jueWZ*0zF( zjc8@z38oPY2!}RWYjKN}g`kaCi1-H-uCNkOgxf0BeA-5$w9LxMMtXHz@2@3 zyz+UJPuh|vi*mtJavK=cNwf1dpEbZ!a<``>o|1IZ?Bv;J>;8WS9J=%2sOyMVt`f_h zlJvCko4lXZH(|7*(w!f`Tnu;_ptK?Jqw7?)K+hZAu%R^ukDjFp75q4Pbjddz93wNAlTi;8fmk1LdSvP5vdgJg^M# zaG-vgp9c5>)Q7GRMsXQ9!>~RL)NlL5fD7Ck3IMJGg}hz^t^pqh0-C^eU>&Fc%V89s z01(qlD|><0z!Ts~QmejXjKU~B2rL4Jfq5~#v~m%6p46(=A2%lGz#nlao8kSq3cLUS N002ovPDHLkV1na%{Dc4i literal 0 HcmV?d00001 diff --git a/static/images/pencil.min.svg b/static/images/pencil.min.svg new file mode 100644 index 00000000..06125ae0 --- /dev/null +++ b/static/images/pencil.min.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/images/pencil.svg b/static/images/pencil.svg new file mode 100644 index 00000000..91f08991 --- /dev/null +++ b/static/images/pencil.svg @@ -0,0 +1,55 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/static/images/pin.min.svg b/static/images/pin.min.svg new file mode 100644 index 00000000..ac08903d --- /dev/null +++ b/static/images/pin.min.svg @@ -0,0 +1 @@ + diff --git a/static/images/pin.svg b/static/images/pin.svg new file mode 100644 index 00000000..b4ee9eb7 --- /dev/null +++ b/static/images/pin.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/images/rss.svg b/static/images/rss.svg new file mode 100644 index 00000000..3c7f6ba1 --- /dev/null +++ b/static/images/rss.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/images/unpin.min.svg b/static/images/unpin.min.svg new file mode 100644 index 00000000..3cf2413c --- /dev/null +++ b/static/images/unpin.min.svg @@ -0,0 +1 @@ + diff --git a/static/images/unpin.svg b/static/images/unpin.svg new file mode 100644 index 00000000..de897152 --- /dev/null +++ b/static/images/unpin.svg @@ -0,0 +1,4 @@ + + + + diff --git a/static/images/x.min.svg b/static/images/x.min.svg new file mode 100644 index 00000000..833d4f22 --- /dev/null +++ b/static/images/x.min.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/images/x.svg b/static/images/x.svg new file mode 100644 index 00000000..e323fe19 --- /dev/null +++ b/static/images/x.svg @@ -0,0 +1,31 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/static/js/comment-edit.js b/static/js/comment-edit.js new file mode 100644 index 00000000..23ffdd34 --- /dev/null +++ b/static/js/comment-edit.js @@ -0,0 +1,61 @@ +function add_busy_indicator(sibling) { + const img = document.createElement('img'); + img.src = "/static/images/ajax-loader.gif"; + img.classList.add('ajax-loader'); + img.style.height = 11; + img.style.width = 16; + img.alt = "Busy…"; + + sibling.insertAdjacentElement('afterend', img); +} + +function remove_busy_indicator(sibling) { + const elem = sibling.nextElementSibling; + elem.parentNode.removeChild(elem); +} + +function getParentsUntil(elem, className) { + // Limit to 10 depth + for ( ; elem && elem !== document; elem = elem.parentNode) { + if (elem.matches(className)) { + break; + } + } + + return elem; +} + +function handleEditCommentClick(event, pkgbasename) { + event.preventDefault(); + const parent_element = getParentsUntil(event.target, '.comment-header'); + const parent_id = parent_element.id; + const comment_id = parent_id.substr(parent_id.indexOf('-') + 1); + // The div class="article-content" which contains the comment + const edit_form = parent_element.nextElementSibling; + + const url = "/pkgbase/" + pkgbasename + "/comments/" + comment_id + "/form?"; + + add_busy_indicator(event.target); + + fetch(url + new URLSearchParams({ next: window.location.pathname }), { + method: 'GET', + credentials: 'same-origin' + }) + .then(function(response) { + if (!response.ok) { + throw Error(response.statusText); + } + return response.json(); + }) + .then(function(data) { + remove_busy_indicator(event.target); + edit_form.innerHTML = data.form; + edit_form.querySelector('textarea').focus(); + }) + .catch(function(error) { + remove_busy_indicator(event.target); + console.error(error); + }); + + return false; +} diff --git a/static/js/copy.js b/static/js/copy.js new file mode 100644 index 00000000..3b659270 --- /dev/null +++ b/static/js/copy.js @@ -0,0 +1,9 @@ +document.addEventListener('DOMContentLoaded', function() { + let elements = document.querySelectorAll('.copy'); + elements.forEach(function(el) { + el.addEventListener('click', function(e) { + e.preventDefault(); + navigator.clipboard.writeText(e.target.text); + }); + }); +}); diff --git a/static/js/typeahead-home.js b/static/js/typeahead-home.js new file mode 100644 index 00000000..5af51c53 --- /dev/null +++ b/static/js/typeahead-home.js @@ -0,0 +1,6 @@ +document.addEventListener('DOMContentLoaded', function() { + const input = document.getElementById('pkgsearch-field'); + const form = document.getElementById('pkgsearch-form'); + const type = 'suggest'; + typeahead.init(type, input, form); +}); diff --git a/static/js/typeahead-pkgbase-merge.js b/static/js/typeahead-pkgbase-merge.js new file mode 100644 index 00000000..a8c87e4f --- /dev/null +++ b/static/js/typeahead-pkgbase-merge.js @@ -0,0 +1,6 @@ +document.addEventListener('DOMContentLoaded', function() { + const input = document.getElementById('merge_into'); + const form = document.getElementById('merge-form'); + const type = "suggest-pkgbase"; + typeahead.init(type, input, form, false); +}); diff --git a/static/js/typeahead-pkgbase-request.js b/static/js/typeahead-pkgbase-request.js new file mode 100644 index 00000000..e012d55f --- /dev/null +++ b/static/js/typeahead-pkgbase-request.js @@ -0,0 +1,36 @@ +function showHideMergeSection() { + const elem = document.getElementById('id_type'); + const merge_section = document.getElementById('merge_section'); + if (elem.value == 'merge') { + merge_section.style.display = ''; + } else { + merge_section.style.display = 'none'; + } +} + +function showHideRequestHints() { + document.getElementById('deletion_hint').style.display = 'none'; + document.getElementById('merge_hint').style.display = 'none'; + document.getElementById('orphan_hint').style.display = 'none'; + + const elem = document.getElementById('id_type'); + document.getElementById(elem.value + '_hint').style.display = ''; +} + +document.addEventListener('DOMContentLoaded', function() { + showHideMergeSection(); + showHideRequestHints(); + + const input = document.getElementById('id_merge_into'); + const form = document.getElementById('request-form'); + const type = "suggest-pkgbase"; + + typeahead.init(type, input, form, false); +}); + +// Bind the change event here, otherwise we have to inline javascript, +// which angers CSP (Content Security Policy). +document.getElementById("id_type").addEventListener("change", function() { + showHideMergeSection(); + showHideRequestHints(); +}); diff --git a/static/js/typeahead.js b/static/js/typeahead.js new file mode 100644 index 00000000..bfd3d156 --- /dev/null +++ b/static/js/typeahead.js @@ -0,0 +1,151 @@ +"use strict"; + +const typeahead = (function() { + var input; + var form; + var suggest_type; + var list; + var submit = true; + + function resetResults() { + if (!list) return; + list.style.display = "none"; + list.innerHTML = ""; + } + + function getCompleteList() { + if (!list) { + list = document.createElement("UL"); + list.setAttribute("class", "pkgsearch-typeahead"); + form.appendChild(list); + setListLocation(); + } + return list; + } + + function onListClick(e) { + let target = e.target; + while (!target.getAttribute('data-value')) { + target = target.parentNode; + } + input.value = target.getAttribute('data-value'); + if (submit) { + form.submit(); + } + } + + function setListLocation() { + if (!list) return; + const rects = input.getClientRects()[0]; + list.style.top = (rects.top + rects.height) + "px"; + list.style.left = rects.left + "px"; + } + + function loadData(letter, data) { + const pkgs = data.slice(0, 10); // Show maximum of 10 results + + resetResults(); + + if (pkgs.length === 0) { + return; + } + + const ul = getCompleteList(); + ul.style.display = "block"; + const fragment = document.createDocumentFragment(); + + for (let i = 0; i < pkgs.length; i++) { + const item = document.createElement("li"); + const text = pkgs[i].replace(letter, '' + letter + ''); + item.innerHTML = '' + text + ''; + item.setAttribute('data-value', pkgs[i]); + fragment.appendChild(item); + } + + ul.appendChild(fragment); + ul.addEventListener('click', onListClick); + } + + function fetchData(letter) { + const url = '/rpc?v=5&type=' + suggest_type + '&arg=' + letter; + fetch(url).then(function(response) { + return response.json(); + }).then(function(data) { + loadData(letter, data); + }); + } + + function onInputClick() { + if (input.value === "") { + resetResults(); + return; + } + fetchData(input.value); + } + + function onKeyDown(e) { + if (!list) return; + + const elem = document.querySelector(".pkgsearch-typeahead li.active"); + switch(e.keyCode) { + case 13: // enter + if (!submit) { + return; + } + if (elem) { + input.value = elem.getAttribute('data-value'); + form.submit(); + } else { + form.submit(); + } + e.preventDefault(); + break; + case 38: // up + if (elem && elem.previousElementSibling) { + elem.className = ""; + elem.previousElementSibling.className = "active"; + } + e.preventDefault(); + break; + case 40: // down + if (elem && elem.nextElementSibling) { + elem.className = ""; + elem.nextElementSibling.className = "active"; + } else if (!elem && list.childElementCount !== 0) { + list.children[0].className = "active"; + } + e.preventDefault(); + break; + } + } + + // debounce https://davidwalsh.name/javascript-debounce-function + function debounce(func, wait, immediate) { + var timeout; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + if (!immediate) func.apply(context, args); + }; + var callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) func.apply(context, args); + }; + } + + return { + init: function(type, inputfield, formfield, submitdata = true) { + suggest_type = type; + input = inputfield; + form = formfield; + submit = submitdata; + + input.addEventListener("input", onInputClick); + input.addEventListener("keydown", onKeyDown); + window.addEventListener('resize', debounce(setListLocation, 150)); + document.addEventListener("click", resetResults); + } + } +}()); From 8ca63075e907609ad6c81decff3bc7d027e1cde2 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Fri, 28 Apr 2023 16:10:32 +0200 Subject: [PATCH 021/178] housekeep: remove PHP implementation removal of the PHP codebase Signed-off-by: moson-mo --- .editorconfig | 3 - .env | 1 - .gitlab-ci.yml | 1 - CONTRIBUTING.md | 1 - INSTALL | 3 +- README.md | 1 - TESTING | 1 - aurweb/db.py | 4 +- aurweb/spawn.py | 59 +- conf/config.defaults | 16 +- conf/config.dev | 11 - doc/docker.md | 20 +- doc/maintenance.txt | 2 +- docker-compose.aur-dev.yml | 16 - docker-compose.override.yml | 14 - docker-compose.yml | 76 +- docker/README.md | 3 +- docker/config/nginx.conf | 52 - docker/health/memcached.sh | 2 - docker/health/php.sh | 2 - docker/mariadb-entrypoint.sh | 2 +- docker/php-entrypoint.sh | 32 - docker/scripts/install-deps.sh | 5 +- docker/scripts/run-memcached.sh | 2 - docker/scripts/run-nginx.sh | 2 - docker/scripts/run-php.sh | 4 - po/Makefile | 16 +- test/test_spawn.py | 35 +- web/html/404.php | 47 - web/html/503.php | 14 - web/html/account.php | 223 --- web/html/addvote.php | 116 -- web/html/comaintainers.php | 16 - web/html/commentedit.php | 18 - web/html/css/archnavbar/archlogo.png | Bin 5359 -> 0 bytes web/html/css/archnavbar/archnavbar.css | 26 - web/html/css/archnavbar/aurlogo.png | Bin 5997 -> 0 bytes web/html/css/archweb.css | 1255 ---------------- web/html/css/aurweb.css | 292 ---- web/html/css/cgit.css | 866 ----------- web/html/home.php | 215 --- web/html/images/ICON-LICENSE | 26 - web/html/images/action-undo.min.svg | 3 - web/html/images/action-undo.svg | 32 - web/html/images/ajax-loader.gif | Bin 723 -> 0 bytes web/html/images/favicon.ico | Bin 575 -> 0 bytes web/html/images/pencil.min.svg | 3 - web/html/images/pencil.svg | 55 - web/html/images/pin.min.svg | 1 - web/html/images/pin.svg | 3 - web/html/images/rss.svg | 3 - web/html/images/unpin.min.svg | 1 - web/html/images/unpin.svg | 4 - web/html/images/x.min.svg | 3 - web/html/images/x.svg | 31 - web/html/index.php | 205 --- web/html/js/comment-edit.js | 61 - web/html/js/copy.js | 9 - web/html/js/typeahead-home.js | 6 - web/html/js/typeahead-pkgbase-merge.js | 6 - web/html/js/typeahead-pkgbase-request.js | 36 - web/html/js/typeahead.js | 151 -- web/html/login.php | 68 - web/html/logout.php | 31 - web/html/modified-rss.php | 62 - web/html/packages.php | 173 --- web/html/passreset.php | 100 -- web/html/pkgbase.php | 195 --- web/html/pkgdel.php | 45 - web/html/pkgdisown.php | 59 - web/html/pkgflag.php | 91 -- web/html/pkgflagcomment.php | 16 - web/html/pkgmerge.php | 58 - web/html/pkgreq.php | 83 -- web/html/register.php | 87 -- web/html/rpc.php | 17 - web/html/rss.php | 61 - web/html/tos.php | 50 - web/html/tu.php | 122 -- web/html/voters.php | 34 - web/lib/DB.class.php | 59 - web/lib/acctfuncs.inc.php | 1522 ------------------- web/lib/aur.inc.php | 774 ---------- web/lib/aurjson.class.php | 710 --------- web/lib/cachefuncs.inc.php | 99 -- web/lib/confparser.inc.php | 59 - web/lib/credentials.inc.php | 91 -- web/lib/feedcreator.class.php | 1546 -------------------- web/lib/gettext.php | 432 ------ web/lib/pkgbasefuncs.inc.php | 1253 ---------------- web/lib/pkgfuncs.inc.php | 957 ------------ web/lib/pkgreqfuncs.inc.php | 260 ---- web/lib/routing.inc.php | 85 -- web/lib/stats.inc.php | 108 -- web/lib/streams.php | 167 --- web/lib/timezone.inc.php | 63 - web/lib/translator.inc.php | 139 -- web/lib/version.inc.php | 2 - web/locale/README | 5 - web/template/account_delete.php | 29 - web/template/account_details.php | 93 -- web/template/account_edit_form.php | 222 --- web/template/account_search_results.php | 87 -- web/template/cgit/footer.html | 6 - web/template/cgit/header.html | 15 - web/template/comaintainers_form.php | 19 - web/template/flag_comment.php | 26 - web/template/footer.php | 13 - web/template/header.php | 82 -- web/template/pkg_comment_box.php | 4 - web/template/pkg_comment_form.php | 28 - web/template/pkg_comments.php | 239 --- web/template/pkg_details.php | 317 ---- web/template/pkg_search_form.php | 120 -- web/template/pkg_search_results.php | 153 -- web/template/pkgbase_actions.php | 49 - web/template/pkgbase_details.php | 146 -- web/template/pkgreq_close_form.php | 31 - web/template/pkgreq_form.php | 81 - web/template/pkgreq_results.php | 129 -- web/template/search_accounts_form.php | 52 - web/template/stats/general_stats_table.php | 36 - web/template/stats/updates_table.php | 19 - web/template/stats/user_table.php | 21 - web/template/template.phps | 19 - web/template/tu_details.php | 123 -- web/template/tu_last_votes_list.php | 36 - web/template/tu_list.php | 82 -- 128 files changed, 27 insertions(+), 16046 deletions(-) delete mode 100755 docker/health/memcached.sh delete mode 100755 docker/health/php.sh delete mode 100755 docker/php-entrypoint.sh delete mode 100755 docker/scripts/run-memcached.sh delete mode 100755 docker/scripts/run-php.sh delete mode 100644 web/html/404.php delete mode 100644 web/html/503.php delete mode 100644 web/html/account.php delete mode 100644 web/html/addvote.php delete mode 100644 web/html/comaintainers.php delete mode 100644 web/html/commentedit.php delete mode 100644 web/html/css/archnavbar/archlogo.png delete mode 100644 web/html/css/archnavbar/archnavbar.css delete mode 100644 web/html/css/archnavbar/aurlogo.png delete mode 100644 web/html/css/archweb.css delete mode 100644 web/html/css/aurweb.css delete mode 100644 web/html/css/cgit.css delete mode 100644 web/html/home.php delete mode 100644 web/html/images/ICON-LICENSE delete mode 100644 web/html/images/action-undo.min.svg delete mode 100644 web/html/images/action-undo.svg delete mode 100644 web/html/images/ajax-loader.gif delete mode 100644 web/html/images/favicon.ico delete mode 100644 web/html/images/pencil.min.svg delete mode 100644 web/html/images/pencil.svg delete mode 100644 web/html/images/pin.min.svg delete mode 100644 web/html/images/pin.svg delete mode 100644 web/html/images/rss.svg delete mode 100644 web/html/images/unpin.min.svg delete mode 100644 web/html/images/unpin.svg delete mode 100644 web/html/images/x.min.svg delete mode 100644 web/html/images/x.svg delete mode 100644 web/html/index.php delete mode 100644 web/html/js/comment-edit.js delete mode 100644 web/html/js/copy.js delete mode 100644 web/html/js/typeahead-home.js delete mode 100644 web/html/js/typeahead-pkgbase-merge.js delete mode 100644 web/html/js/typeahead-pkgbase-request.js delete mode 100644 web/html/js/typeahead.js delete mode 100644 web/html/login.php delete mode 100644 web/html/logout.php delete mode 100644 web/html/modified-rss.php delete mode 100644 web/html/packages.php delete mode 100644 web/html/passreset.php delete mode 100644 web/html/pkgbase.php delete mode 100644 web/html/pkgdel.php delete mode 100644 web/html/pkgdisown.php delete mode 100644 web/html/pkgflag.php delete mode 100644 web/html/pkgflagcomment.php delete mode 100644 web/html/pkgmerge.php delete mode 100644 web/html/pkgreq.php delete mode 100644 web/html/register.php delete mode 100644 web/html/rpc.php delete mode 100644 web/html/rss.php delete mode 100644 web/html/tos.php delete mode 100644 web/html/tu.php delete mode 100644 web/html/voters.php delete mode 100644 web/lib/DB.class.php delete mode 100644 web/lib/acctfuncs.inc.php delete mode 100644 web/lib/aur.inc.php delete mode 100644 web/lib/aurjson.class.php delete mode 100644 web/lib/cachefuncs.inc.php delete mode 100644 web/lib/confparser.inc.php delete mode 100644 web/lib/credentials.inc.php delete mode 100644 web/lib/feedcreator.class.php delete mode 100644 web/lib/gettext.php delete mode 100644 web/lib/pkgbasefuncs.inc.php delete mode 100644 web/lib/pkgfuncs.inc.php delete mode 100644 web/lib/pkgreqfuncs.inc.php delete mode 100644 web/lib/routing.inc.php delete mode 100644 web/lib/stats.inc.php delete mode 100644 web/lib/streams.php delete mode 100644 web/lib/timezone.inc.php delete mode 100644 web/lib/translator.inc.php delete mode 100644 web/lib/version.inc.php delete mode 100644 web/locale/README delete mode 100644 web/template/account_delete.php delete mode 100644 web/template/account_details.php delete mode 100644 web/template/account_edit_form.php delete mode 100644 web/template/account_search_results.php delete mode 100644 web/template/cgit/footer.html delete mode 100644 web/template/cgit/header.html delete mode 100644 web/template/comaintainers_form.php delete mode 100644 web/template/flag_comment.php delete mode 100644 web/template/footer.php delete mode 100644 web/template/header.php delete mode 100644 web/template/pkg_comment_box.php delete mode 100644 web/template/pkg_comment_form.php delete mode 100644 web/template/pkg_comments.php delete mode 100644 web/template/pkg_details.php delete mode 100644 web/template/pkg_search_form.php delete mode 100644 web/template/pkg_search_results.php delete mode 100644 web/template/pkgbase_actions.php delete mode 100644 web/template/pkgbase_details.php delete mode 100644 web/template/pkgreq_close_form.php delete mode 100644 web/template/pkgreq_form.php delete mode 100644 web/template/pkgreq_results.php delete mode 100644 web/template/search_accounts_form.php delete mode 100644 web/template/stats/general_stats_table.php delete mode 100644 web/template/stats/updates_table.php delete mode 100644 web/template/stats/user_table.php delete mode 100644 web/template/template.phps delete mode 100644 web/template/tu_details.php delete mode 100644 web/template/tu_last_votes_list.php delete mode 100644 web/template/tu_list.php diff --git a/.editorconfig b/.editorconfig index 5a751aad..95f2c7dd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,6 +8,3 @@ root = true end_of_line = lf insert_final_newline = true charset = utf-8 - -[*.{php,t}] -indent_style = tab diff --git a/.env b/.env index 22846cb4..bf6c48c4 100644 --- a/.env +++ b/.env @@ -1,7 +1,6 @@ FASTAPI_BACKEND="uvicorn" FASTAPI_WORKERS=2 MARIADB_SOCKET_DIR="/var/run/mysqld/" -AURWEB_PHP_PREFIX=https://localhost:8443 AURWEB_FASTAPI_PREFIX=https://localhost:8444 AURWEB_SSHD_PREFIX=ssh://aur@localhost:2222 GIT_DATA_DIR="./aur.git/" diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index af722d99..10dd1787 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -71,7 +71,6 @@ deploy: variables: FASTAPI_BACKEND: gunicorn FASTAPI_WORKERS: 5 - AURWEB_PHP_PREFIX: https://aur-dev.archlinux.org AURWEB_FASTAPI_PREFIX: https://aur-dev.archlinux.org AURWEB_SSHD_PREFIX: ssh://aur@aur-dev.archlinux.org:2222 COMMIT_HASH: $CI_COMMIT_SHA diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c8d4f90d..a91e3eec 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -91,7 +91,6 @@ browser if desired. Accessible services (on the host): - https://localhost:8444 (python via nginx) -- https://localhost:8443 (php via nginx) - localhost:13306 (mariadb) - localhost:16379 (redis) diff --git a/INSTALL b/INSTALL index 03459726..107fab4b 100644 --- a/INSTALL +++ b/INSTALL @@ -14,8 +14,7 @@ read the instructions below. $ cd aurweb $ poetry install -2) Setup a web server with PHP and MySQL. Configure the web server to redirect - all URLs to /index.php/foo/bar/. The following block can be used with nginx: +2) Setup a web server with MySQL. The following block can be used with nginx: server { # https is preferred and can be done easily with LetsEncrypt diff --git a/README.md b/README.md index 2741efa2..4d732bb2 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,6 @@ Directory Layout * `schema`: schema for the SQL database * `test`: test suite and test cases * `upgrading`: instructions for upgrading setups from one release to another -* `web`: PHP-based web interface for the AUR Documentation ------------- diff --git a/TESTING b/TESTING index cb34c0e9..078d330b 100644 --- a/TESTING +++ b/TESTING @@ -29,7 +29,6 @@ docker-compose 4) Browse to local aurweb development server. Python: https://localhost:8444/ - PHP: https://localhost:8443/ 5) [Optionally] populate the database with dummy data: diff --git a/aurweb/db.py b/aurweb/db.py index ab0f80b8..8311f2be 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -364,7 +364,7 @@ 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. + # here to fund its support for the Sharness testsuite. if self._paramstyle in ("format", "pyformat"): query = query.replace("%", "%%").replace("?", "%s") elif self._paramstyle == "qmark": @@ -410,7 +410,7 @@ class Connection: ) 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. + # here to fund its support for Sharness testsuite. import math import sqlite3 diff --git a/aurweb/spawn.py b/aurweb/spawn.py index 29162f33..442d89a9 100644 --- a/aurweb/spawn.py +++ b/aurweb/spawn.py @@ -20,7 +20,6 @@ from typing import Iterable import aurweb.config import aurweb.schema -from aurweb.exceptions import AurwebException children = [] temporary_dir = None @@ -28,9 +27,6 @@ verbosity = 0 asgi_backend = "" workers = 1 -PHP_BINARY = os.environ.get("PHP_BINARY", "php") -PHP_MODULES = ["pdo_mysql", "pdo_sqlite"] -PHP_NGINX_PORT = int(os.environ.get("PHP_NGINX_PORT", 8001)) FASTAPI_NGINX_PORT = int(os.environ.get("FASTAPI_NGINX_PORT", 8002)) @@ -47,42 +43,12 @@ class ProcessExceptions(Exception): super().__init__("\n- ".join(messages)) -def validate_php_config() -> None: - """ - Perform a validation check against PHP_BINARY's configuration. - - AurwebException is raised here if checks fail to pass. We require - the 'pdo_mysql' and 'pdo_sqlite' modules to be enabled. - - :raises: AurwebException - :return: None - """ - try: - 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.") - - 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.") - - def generate_nginx_config(): """ Generate an nginx configuration based on aurweb's configuration. The file is generated under `temporary_dir`. Returns the path to the created configuration file. """ - php_bind = aurweb.config.get("php", "bind_address") - php_host = php_bind.split(":")[0] fastapi_bind = aurweb.config.get("fastapi", "bind_address") fastapi_host = fastapi_bind.split(":")[0] config_path = os.path.join(temporary_dir, "nginx.conf") @@ -101,12 +67,6 @@ def generate_nginx_config(): fastcgi_temp_path {os.path.join(temporary_dir, "fastcgi")}1 2; uwsgi_temp_path {os.path.join(temporary_dir, "uwsgi")}; scgi_temp_path {os.path.join(temporary_dir, "scgi")}; - server {{ - listen {php_host}:{PHP_NGINX_PORT}; - location / {{ - proxy_pass http://{php_bind}; - }} - }} server {{ listen {fastapi_host}:{FASTAPI_NGINX_PORT}; location / {{ @@ -154,7 +114,7 @@ def start(): terminal_width = 80 print( "{ruler}\n" - "Spawing PHP and FastAPI, then nginx as a reverse proxy.\n" + "Spawing FastAPI, then nginx as a reverse proxy.\n" "Check out {aur_location}\n" "Hit ^C to terminate everything.\n" "{ruler}".format( @@ -163,12 +123,6 @@ def start(): ) ) - # PHP - php_address = aurweb.config.get("php", "bind_address") - php_host = php_address.split(":")[0] - htmldir = aurweb.config.get("php", "htmldir") - spawn_child(["php", "-S", php_address, "-t", htmldir]) - # FastAPI fastapi_host, fastapi_port = aurweb.config.get("fastapi", "bind_address").rsplit( ":", 1 @@ -210,10 +164,7 @@ def start(): f""" > Started nginx. > - > PHP backend: http://{php_address} - > FastAPI backend: http://{fastapi_host}:{fastapi_port} - > - > PHP frontend: http://{php_host}:{PHP_NGINX_PORT} + > FastAPI backend: http://{fastapi_host}:{fastapi_port} > FastAPI frontend: http://{fastapi_host}:{FASTAPI_NGINX_PORT} > > Frontends are hosted via nginx and should be preferred. @@ -307,12 +258,6 @@ if __name__ == "__main__": ) args = parser.parse_args() - try: - validate_php_config() - except AurwebException as exc: - print(f"error: {str(exc)}") - sys.exit(1) - verbosity = args.verbose asgi_backend = args.backend workers = args.workers diff --git a/conf/config.defaults b/conf/config.defaults index 06e73afe..0cd4b9d4 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -38,11 +38,9 @@ enable-maintenance = 1 maintenance-exceptions = 127.0.0.1 render-comment-cmd = /usr/bin/aurweb-rendercomment localedir = /srv/http/aurweb/web/locale/ -; memcache, apc, or redis -; memcache/apc are supported in PHP, redis is supported in Python. +; cache: redis is supported in Python. cache = none cache_pkginfo_ttl = 86400 -memcache_servers = 127.0.0.1:11211 salt_rounds = 12 redis_address = redis://localhost ; Toggles traceback display in templates/errors/500.html. @@ -125,12 +123,12 @@ sync-dbs = core extra community multilib testing community-testing server = https://mirrors.kernel.org/archlinux/%s/os/x86_64 [mkpkglists] -archivedir = /srv/http/aurweb/web/html -packagesfile = /srv/http/aurweb/web/html/packages.gz -packagesmetafile = /srv/http/aurweb/web/html/packages-meta-v1.json.gz -packagesmetaextfile = /srv/http/aurweb/web/html/packages-meta-ext-v1.json.gz -pkgbasefile = /srv/http/aurweb/web/html/pkgbase.gz -userfile = /srv/http/aurweb/web/html/users.gz +archivedir = /srv/http/aurweb/archives +packagesfile = /srv/http/aurweb/archives/packages.gz +packagesmetafile = /srv/http/aurweb/archives/packages-meta-v1.json.gz +packagesmetaextfile = /srv/http/aurweb/archives/packages-meta-ext-v1.json.gz +pkgbasefile = /srv/http/aurweb/archives/pkgbase.gz +userfile = /srv/http/aurweb/archives/users.gz [git-archive] author = git_archive.py diff --git a/conf/config.dev b/conf/config.dev index b36bfe77..f3b0ee21 100644 --- a/conf/config.dev +++ b/conf/config.dev @@ -6,7 +6,6 @@ ; development-specific options too. [database] -; PHP options: mysql, sqlite. ; FastAPI options: mysql. backend = mysql @@ -31,9 +30,6 @@ localedir = YOUR_AUR_ROOT/web/locale salt_rounds = 4 ; See config.defaults comment about cache. cache = none -; In docker, the memcached host is available. On a user's system, -; this should be set to localhost (most likely). -memcache_servers = memcached:11211 ; If cache = 'redis' this address is used to connect to Redis. redis_address = redis://127.0.0.1 aur_request_ml = aur-requests@localhost @@ -51,13 +47,6 @@ openid_configuration = http://127.0.0.1:8083/auth/realms/aurweb/.well-known/open client_id = aurweb client_secret = -[php] -; Address PHP should bind when spawned in development mode by aurweb.spawn. -bind_address = 127.0.0.1:8081 - -; Directory containing aurweb's PHP code, required by aurweb.spawn. -htmldir = YOUR_AUR_ROOT/web/html - [fastapi] ; Address uvicorn should bind when spawned in development mode by aurweb.spawn. bind_address = 127.0.0.1:8082 diff --git a/doc/docker.md b/doc/docker.md index 22505f7a..c54184b8 100644 --- a/doc/docker.md +++ b/doc/docker.md @@ -65,12 +65,9 @@ Services | [mariadb](#mariadb) | 127.0.0.1:13306 | | [git](#git) | 127.0.0.1:2222 | | redis | 127.0.0.1:16379 | -| [php-fpm](#php-fpm) | 127.0.0.1:19000 | -| cgit-php | | | [fastapi](#fastapi) | 127.0.0.1:18000 | | cgit-fastapi | | | [nginx](#nginx) (fastapi) | 127.0.0.1:8444 | -| [nginx](#nginx) (php) | 127.0.0.1:8443 | There are more services which have not been referred to here; the services listed above encompass all notable services. Some @@ -113,16 +110,6 @@ to be used for the AUR. This service will perform setup in either case if the repository is not yet initialized. -#### php-fpm - -When running any services which use the _php-fpm_ backend or other -php-related services, users should define: - -- `AURWEB_PHP_PREFIX` - - Default: `https://localhost:8443` -- `AURWEB_SSHD_PREFIX` - - Default: `ssh://aur@localhost:2222` - #### fastapi The _fastapi_ service hosts a `gunicorn`, `uvicorn` or `hypercorn` @@ -145,20 +132,17 @@ backend or other fastapi-related services, users should define: #### nginx -The _nginx_ service binds to two host endpoints: 127.0.0.1:8444 (fastapi) -and 127.0.0.1:8443 (php). Each instance is available over the `https` +The _nginx_ service binds to host endpoint: 127.0.0.1:8444 (fastapi). +The instance is available over the `https` protocol as noted in the table below. | Impl | Host Binding | URL | |--------|----------------|------------------------| | Python | 127.0.0.1:8444 | https://localhost:8444 | -| PHP | 127.0.0.1:8443 | https://localhost:8443 | When running this service, the following variables should be defined: - `AURWEB_FASTAPI_PREFIX` - Default: `https://localhost:8444` -- `AURWEB_PHP_PREFIX` - - Default: `https://localhost:8443` - `AURWEB_SSHD_PREFIX` - Default: `ssh://aur@localhost:2222` diff --git a/doc/maintenance.txt b/doc/maintenance.txt index dacf2b60..39642f21 100644 --- a/doc/maintenance.txt +++ b/doc/maintenance.txt @@ -21,7 +21,7 @@ The RPC interface can be used to query package information via HTTP. Installation ------------ -The web backend requires a web server with PHP and an SQL database. The Git/SSH +The web backend requires a web server and an SQL database. The Git/SSH interface requires Python, several Python modules and an up-to-date version of Git. APCu or memcached can be used to reduce load on the database server. diff --git a/docker-compose.aur-dev.yml b/docker-compose.aur-dev.yml index 0b91dd93..1763f427 100644 --- a/docker-compose.aur-dev.yml +++ b/docker-compose.aur-dev.yml @@ -6,9 +6,6 @@ services: - data:/data - step:/root/.step - memcached: - restart: always - redis: restart: always @@ -32,11 +29,6 @@ services: - data:/data - smartgit_run:/var/run/smartgit - cgit-php: - restart: always - volumes: - - ${GIT_DATA_DIR}:/aurweb/aur.git - cgit-fastapi: restart: always volumes: @@ -48,14 +40,6 @@ services: - mariadb_run:/var/run/mysqld - archives:/var/lib/aurweb/archives - php-fpm: - restart: always - environment: - - AURWEB_PHP_PREFIX=${AURWEB_PHP_PREFIX} - - AURWEB_SSHD_PREFIX=${AURWEB_SSHD_PREFIX} - volumes: - - data:/data - fastapi: restart: always environment: diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 1e466730..6580de30 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -25,26 +25,12 @@ services: mariadb: condition: service_healthy - php-fpm: - volumes: - - ./data:/data - - ./aurweb:/aurweb/aurweb - - ./migrations:/aurweb/migrations - - ./test:/aurweb/test - - ./web/html:/aurweb/web/html - - ./web/template:/aurweb/web/template - - ./web/lib:/aurweb/web/lib - - ./templates:/aurweb/templates - fastapi: volumes: - ./data:/data - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test - - ./web/html:/aurweb/web/html - - ./web/template:/aurweb/web/template - - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates nginx: diff --git a/docker-compose.yml b/docker-compose.yml index a1c2bb42..0973fc0e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,11 +10,9 @@ # - `ca` - Certificate Authority generation # - `git` - `port 2222` - Git over SSH server # - `fastapi` - hypercorn service for aurweb's FastAPI app -# - `php-fpm` - Execution server for PHP aurweb -# - `nginx` - `ports 8444 (FastAPI), 8443 (PHP)` - Everything -# - You can reach `nginx` via FastAPI at `https://localhost:8444/` -# or via PHP at `https://localhost:8443/`. CGit can be reached -# via the `/cgit/` request uri on either server. +# - `nginx` - `port 8444 (FastAPI) +# - You can reach `nginx` via FastAPI at `https://localhost:8444/`. +# CGit can be reached via the `/cgit/` request uri on either server. # # Copyright (C) 2021 aurweb Development # All Rights Reserved. @@ -36,14 +34,6 @@ services: volumes: - step:/root/.step - memcached: - image: aurweb:latest - init: true - command: /docker/scripts/run-memcached.sh - healthcheck: - test: "bash /docker/health/memcached.sh" - interval: 3s - redis: image: aurweb:latest init: true @@ -133,26 +123,6 @@ services: test: "bash /docker/health/smartgit.sh" interval: 3s - cgit-php: - image: aurweb:latest - init: true - environment: - - AUR_CONFIG=/aurweb/conf/config - - CGIT_CLONE_PREFIX=${AURWEB_PHP_PREFIX} - - CGIT_CSS=/css/cgit.css - entrypoint: /docker/cgit-entrypoint.sh - command: /docker/scripts/run-cgit.sh 3000 - healthcheck: - test: "bash /docker/health/cgit.sh 3000" - interval: 3s - depends_on: - git: - condition: service_healthy - ports: - - "127.0.0.1:13000:3000" - volumes: - - git_data:/aurweb/aur.git - cgit-fastapi: image: aurweb:latest init: true @@ -189,32 +159,6 @@ services: - mariadb_run:/var/run/mysqld - archives:/var/lib/aurweb/archives - php-fpm: - image: aurweb:latest - init: true - environment: - - AUR_CONFIG=/aurweb/conf/config - - AURWEB_PHP_PREFIX=${AURWEB_PHP_PREFIX} - - AURWEB_SSHD_PREFIX=${AURWEB_SSHD_PREFIX} - - AUR_CONFIG_IMMUTABLE=${AUR_CONFIG_IMMUTABLE:-0} - entrypoint: /docker/php-entrypoint.sh - command: /docker/scripts/run-php.sh - healthcheck: - test: "bash /docker/health/php.sh" - interval: 3s - depends_on: - git: - condition: service_healthy - memcached: - condition: service_healthy - cron: - condition: service_started - volumes: - - mariadb_run:/var/run/mysqld - - archives:/var/lib/aurweb/archives - ports: - - "127.0.0.1:19000:9000" - fastapi: image: aurweb:latest init: true @@ -252,7 +196,6 @@ services: entrypoint: /docker/nginx-entrypoint.sh command: /docker/scripts/run-nginx.sh ports: - - "127.0.0.1:8443:8443" # PHP - "127.0.0.1:8444:8444" # FastAPI healthcheck: test: "bash /docker/health/nginx.sh" @@ -260,16 +203,12 @@ services: depends_on: ca: condition: service_healthy - cgit-php: - condition: service_healthy cgit-fastapi: condition: service_healthy smartgit: condition: service_healthy fastapi: condition: service_healthy - php-fpm: - condition: service_healthy sharness: image: aurweb:latest @@ -290,9 +229,6 @@ services: - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test - - ./web/html:/aurweb/web/html - - ./web/template:/aurweb/web/template - - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates pytest-mysql: @@ -319,9 +255,6 @@ services: - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test - - ./web/html:/aurweb/web/html - - ./web/template:/aurweb/web/template - - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates test: @@ -346,9 +279,6 @@ services: - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test - - ./web/html:/aurweb/web/html - - ./web/template:/aurweb/web/template - - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates volumes: diff --git a/docker/README.md b/docker/README.md index cc1f5df0..51e485f6 100644 --- a/docker/README.md +++ b/docker/README.md @@ -55,8 +55,7 @@ can proceed. ### Querying the RPC -The Fast (Python) API runs on Port 8444, while the legacy PHP version runs -on 8443. You can query one like so: +The Fast (Python) API runs on Port 8444. You can query one like so: ```sh curl -k "https://localhost:8444/rpc/?v=5&type=search&arg=python" diff --git a/docker/config/nginx.conf b/docker/config/nginx.conf index 99804d1d..9b167553 100644 --- a/docker/config/nginx.conf +++ b/docker/config/nginx.conf @@ -27,10 +27,6 @@ http { server fastapi:8000; } - upstream cgit-php { - server cgit-php:3000; - } - upstream cgit-fastapi { server cgit-fastapi:3000; } @@ -39,54 +35,6 @@ http { server unix:/var/run/smartgit/smartgit.sock; } - server { - listen 8443 ssl http2; - server_name localhost default_server; - - ssl_certificate /etc/ssl/certs/web.cert.pem; - ssl_certificate_key /etc/ssl/private/web.key.pem; - - root /aurweb/web/html; - index index.php; - - location ~ "^/([a-z0-9][a-z0-9.+_-]*?)(\.git)?/(git-(receive|upload)-pack|HEAD|info/refs|objects/(info/(http-)?alternates|packs)|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))$" { - include uwsgi_params; - uwsgi_pass smartgit; - uwsgi_modifier1 9; - uwsgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend; - uwsgi_param PATH_INFO /aur.git/$3; - uwsgi_param GIT_HTTP_EXPORT_ALL ""; - uwsgi_param GIT_NAMESPACE $1; - uwsgi_param GIT_PROJECT_ROOT /aurweb; - } - - location ~ ^/cgit { - include uwsgi_params; - rewrite ^/cgit/([^?/]+/[^?]*)?(?:\?(.*))?$ /cgit.cgi?url=$1&$2 last; - uwsgi_modifier1 9; - uwsgi_param CGIT_CONFIG /etc/cgitrc; - uwsgi_pass uwsgi://cgit-php; - } - - location ~ ^/[^/]+\.php($|/) { - fastcgi_pass php-fpm:9000; - fastcgi_index index.php; - fastcgi_split_path_info ^(/[^/]+\.php)(/.*)$; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_param PATH_INFO $fastcgi_path_info; - include fastcgi_params; - } - - location ~ .+\.(css|js?|jpe?g|png|svg|ico)/?$ { - try_files $uri =404; - } - - location ~ .* { - rewrite ^/(.*)$ /index.php/$1 last; - } - - } - server { listen 8444 ssl http2; server_name localhost default_server; diff --git a/docker/health/memcached.sh b/docker/health/memcached.sh deleted file mode 100755 index 00f8cd98..00000000 --- a/docker/health/memcached.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -exec pgrep memcached diff --git a/docker/health/php.sh b/docker/health/php.sh deleted file mode 100755 index 7325946b..00000000 --- a/docker/health/php.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -exec printf "" >>/dev/tcp/127.0.0.1/9000 diff --git a/docker/mariadb-entrypoint.sh b/docker/mariadb-entrypoint.sh index a00f6106..a6fb9a76 100755 --- a/docker/mariadb-entrypoint.sh +++ b/docker/mariadb-entrypoint.sh @@ -12,7 +12,7 @@ while ! mysqladmin ping 2>/dev/null; do done # Configure databases. -DATABASE="aurweb" # Persistent database for fastapi/php-fpm. +DATABASE="aurweb" # Persistent database for fastapi. echo "Taking care of primary database '${DATABASE}'..." mysql -u root -e "CREATE USER IF NOT EXISTS 'aur'@'localhost' IDENTIFIED BY 'aur';" diff --git a/docker/php-entrypoint.sh b/docker/php-entrypoint.sh deleted file mode 100755 index dc1a91de..00000000 --- a/docker/php-entrypoint.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -set -eou pipefail - -for archive in packages pkgbase users packages-meta-v1.json packages-meta-ext-v1.json; do - ln -vsf /var/lib/aurweb/archives/${archive}.gz /aurweb/web/html/${archive}.gz -done - -# Setup database. -NO_INITDB=1 /docker/mariadb-init-entrypoint.sh - -# Setup some other options. -aurweb-config set options cache 'memcache' -aurweb-config set options aur_location "$AURWEB_PHP_PREFIX" -aurweb-config set options git_clone_uri_anon "${AURWEB_PHP_PREFIX}/%s.git" -aurweb-config set options git_clone_uri_priv "${AURWEB_SSHD_PREFIX}/%s.git" - -# Listen on :9000. -sed -ri 's/^(listen).*/\1 = 0.0.0.0:9000/' /etc/php/php-fpm.d/www.conf -sed -ri 's/^;?(clear_env).*/\1 = no/' /etc/php/php-fpm.d/www.conf - -# Log to stderr. View logs via `docker-compose logs php-fpm`. -sed -ri 's|^(error_log) = .*$|\1 = /proc/self/fd/2|g' /etc/php/php-fpm.conf -sed -ri 's|^;?(access\.log) = .*$|\1 = /proc/self/fd/2|g' \ - /etc/php/php-fpm.d/www.conf - -sed -ri 's/^;?(extension=pdo_mysql)/\1/' /etc/php/php.ini -sed -ri 's/^;?(open_basedir).*$/\1 = \//' /etc/php/php.ini - -# Use the sqlite3 extension line for memcached. -sed -ri 's/^;(extension)=sqlite3$/\1=memcached/' /etc/php/php.ini - -exec "$@" diff --git a/docker/scripts/install-deps.sh b/docker/scripts/install-deps.sh index 85403969..7aa225fa 100755 --- a/docker/scripts/install-deps.sh +++ b/docker/scripts/install-deps.sh @@ -15,9 +15,8 @@ pacman -Sy --noconfirm --noprogressbar archlinux-keyring pacman -Syu --noconfirm --noprogressbar \ --cachedir .pkg-cache git gpgme nginx redis openssh \ mariadb mariadb-libs cgit-aurweb uwsgi uwsgi-plugin-cgi \ - php php-fpm memcached php-memcached python-pip pyalpm \ - python-srcinfo curl libeatmydata cronie python-poetry \ - python-poetry-core step-cli step-ca asciidoc \ + python-pip pyalpm python-srcinfo curl libeatmydata cronie \ + python-poetry python-poetry-core step-cli step-ca asciidoc \ python-virtualenv python-pre-commit exec "$@" diff --git a/docker/scripts/run-memcached.sh b/docker/scripts/run-memcached.sh deleted file mode 100755 index 90784b0f..00000000 --- a/docker/scripts/run-memcached.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -exec /usr/bin/memcached -u memcached -m 64 -c 1024 -l 0.0.0.0 diff --git a/docker/scripts/run-nginx.sh b/docker/scripts/run-nginx.sh index 6ece3303..e976f67d 100755 --- a/docker/scripts/run-nginx.sh +++ b/docker/scripts/run-nginx.sh @@ -5,8 +5,6 @@ echo echo " Services:" echo " - FastAPI : https://localhost:8444/" echo " (cgit) : https://localhost:8444/cgit/" -echo " - PHP : https://localhost:8443/" -echo " (cgit) : https://localhost:8443/cgit/" echo echo " Note: Copy root CA (./data/ca.root.pem) to ca-certificates or browser." echo diff --git a/docker/scripts/run-php.sh b/docker/scripts/run-php.sh deleted file mode 100755 index b86f8ce5..00000000 --- a/docker/scripts/run-php.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -set -eou pipefail - -exec php-fpm --fpm-config /etc/php/php-fpm.conf --nodaemonize diff --git a/po/Makefile b/po/Makefile index 0b579f48..8fd17515 100644 --- a/po/Makefile +++ b/po/Makefile @@ -48,20 +48,12 @@ all: ${MOFILES} lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ msgmerge -U --no-location --lang="$$lang" $< aurweb.pot -POTFILES-php: - find ../web -type f -name '*.php' -printf '%P\n' | sort >POTFILES-php - POTFILES-py: find ../aurweb -type f -name '*.py' -printf '%P\n' | sort >POTFILES-py -update-pot: POTFILES-php POTFILES-py +update-pot: POTFILES-py pkgname=AURWEB; \ - pkgver=`sed -n 's/.*"AURWEB_VERSION", "\(.*\)".*/\1/p' ../web/lib/version.inc.php`; \ - xgettext --default-domain=aurweb -L php --keyword=__ --keyword=_n:1,2 \ - --add-location=file --add-comments=TRANSLATORS: \ - --package-name="$$pkgname" --package-version="$$pkgver" \ - --msgid-bugs-address='${MSGID_BUGS_ADDRESS}' \ - --directory ../web --files-from POTFILES-php -o aurweb.pot; \ + pkgver=`sed -n 's/version\s*=\s*"\(.*\)"/\1/p' ../pyproject.toml`; \ xgettext --default-domain=aurweb -L python --join-existing \ --keyword=translate \ --add-location=file --add-comments=TRANSLATORS: \ @@ -73,7 +65,7 @@ update-po: ${MAKE} ${UPDATEPOFILES} clean: - rm -f *.mo *.po\~ POTFILES-php POTFILES-py + rm -f *.mo *.po\~ POTFILES-py install: all for l in ${LOCALES}; do mkdir -p ${DESTDIR}${PREFIX}/$$l/LC_MESSAGES/; done @@ -82,4 +74,4 @@ install: all uninstall: for l in ${LOCALES}; do rm -rf ${DESTDIR}${PREFIX}/$$l/LC_MESSAGES/; done -.PHONY: all update-pot update-po clean install uninstall POTFILES-php POTFILES-py +.PHONY: all update-pot update-po clean install uninstall POTFILES-py diff --git a/test/test_spawn.py b/test/test_spawn.py index 25b9ebfc..c57c9b52 100644 --- a/test/test_spawn.py +++ b/test/test_spawn.py @@ -7,10 +7,9 @@ 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 = {"FASTAPI_NGINX_PORT": "8002"} class FakeProcess: @@ -49,34 +48,6 @@ class MockFakeProcess: return proc -@mock.patch("aurweb.spawn.PHP_BINARY", "does-not-exist") -def test_spawn(): - match = r"^Unable to locate the '.*' executable\.$" - with pytest.raises(AurwebException, match=match): - aurweb.spawn.validate_php_config() - - -@mock.patch("subprocess.Popen", side_effect=MockFakeProcess(1).process) -def test_spawn_non_zero_php_binary(fake_process: FakeProcess): - match = r"^Received non-zero error code.*$" - with pytest.raises(AssertionError, match=match): - aurweb.spawn.validate_php_config() - - -def test_spawn_missing_modules(): - side_effect = MockFakeProcess(stdout=b"pdo_sqlite").process - with mock.patch("subprocess.Popen", side_effect=side_effect): - match = r"PHP does not have the 'pdo_mysql' module enabled\.$" - with pytest.raises(AurwebException, match=match): - aurweb.spawn.validate_php_config() - - side_effect = MockFakeProcess(stdout=b"pdo_mysql").process - with mock.patch("subprocess.Popen", side_effect=side_effect): - match = r"PHP does not have the 'pdo_sqlite' module enabled\.$" - with pytest.raises(AurwebException, match=match): - aurweb.spawn.validate_php_config() - - @mock.patch.dict("os.environ", TEST_ENVIRONMENT) def test_spawn_generate_nginx_config(): ctx = tempfile.TemporaryDirectory() @@ -86,13 +57,9 @@ def test_spawn_generate_nginx_config(): with open(nginx_config_path) as f: nginx_config = f.read().rstrip() - php_address = aurweb.config.get("php", "bind_address") - php_host = php_address.split(":")[0] fastapi_address = aurweb.config.get("fastapi", "bind_address") fastapi_host = fastapi_address.split(":")[0] expected_content = [ - 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}", ] diff --git a/web/html/404.php b/web/html/404.php deleted file mode 100644 index 9f81d115..00000000 --- a/web/html/404.php +++ /dev/null @@ -1,47 +0,0 @@ - - -
-

404 -

-

- -
    -
  • - : - -
  • -
  • - ' . htmlspecialchars($gitpkg) . '', - '' . htmlspecialchars($gitcmd) . '') ?> -
  • -
  • - ', '', - '' . htmlspecialchars($gitpkg) . '') ?> -
  • -
- -
- - - -
-

503 -

-

-
- -\n"; -echo "

".__("Accounts")."

\n"; - -if (isset($_COOKIE["AURSID"])) { - if ($action == "SearchAccounts") { - - # security check - # - if (has_credential(CRED_ACCOUNT_SEARCH)) { - # the user has entered search criteria, find any matching accounts - # - search_results_page(in_request("O"), in_request("SB"), - in_request("U"), in_request("T"), in_request("S"), - in_request("E"), in_request("R"), in_request("I"), - in_request("K")); - - } else { - # a non-privileged user is trying to access the search page - # - print __("You are not allowed to access this area.")."
\n"; - } - - } elseif ($action == "DisplayAccount") { - # the user has clicked 'edit', display the account details in a form - # - if (empty($row)) { - print __("Could not retrieve information for the specified user."); - } else { - /* Verify user has permission to edit the account */ - if (can_edit_account($row)) { - display_account_form("UpdateAccount", - $row["Username"], - $row["AccountTypeID"], - $row["Suspended"], - $row["Email"], - $row["BackupEmail"], - $row["HideEmail"], - "", - "", - $row["RealName"], - $row["LangPreference"], - $row["Timezone"], - $row["Homepage"], - $row["IRCNick"], - $row["PGPKey"], - $PK, - $row["InactivityTS"] ? 1 : 0, - $row["CommentNotify"], - $row["UpdateNotify"], - $row["OwnershipNotify"], - $row["ID"], - $row["Username"]); - } else { - print __("You do not have permission to edit this account."); - } - } - - } elseif ($action == "DeleteAccount") { - /* Details for account being deleted. */ - if ($row && can_edit_account($row)) { - $uid_removal = $row['ID']; - $uid_session = uid_from_sid($_COOKIE['AURSID']); - $username = $row['Username']; - - if (in_request('confirm') && check_token()) { - if (check_passwd($uid_session, $_REQUEST['passwd']) == 1) { - user_delete($uid_removal); - header('Location: /'); - } else { - echo "
  • "; - echo __("Invalid password."); - echo "
"; - include("account_delete.php"); - } - } else { - include("account_delete.php"); - } - } else { - print __("You do not have permission to edit this account."); - } - } elseif ($action == "AccountInfo") { - # no editing, just looking up user info - # - if (empty($row)) { - print __("Could not retrieve information for the specified user."); - } else { - include("account_details.php"); - } - - } elseif ($action == "UpdateAccount") { - print $update_account_message; - - if ($row && !$success) { - display_account_form("UpdateAccount", - in_request("U"), - in_request("T"), - in_request("S"), - in_request("E"), - in_request("BE"), - in_request("H"), - in_request("P"), - in_request("C"), - in_request("R"), - in_request("L"), - in_request("TZ"), - in_request("HP"), - in_request("I"), - in_request("K"), - in_request("PK"), - in_request("J"), - in_request("CN"), - in_request("UN"), - in_request("ON"), - in_request("ID"), - $row["Username"]); - } - - } elseif ($action == "ListComments") { - if ($row && has_credential(CRED_ACCOUNT_LIST_COMMENTS, array($row["ID"]))) { - # display the comment list if they're a TU/dev - - $total_comment_count = account_comments_count($row["ID"]); - list($pagination_templs, $per_page, $offset) = calculate_pagination($total_comment_count); - - $username = $row["Username"]; - $uid = $row["ID"]; - $comments = account_comments($uid, $per_page, $offset); - - $comment_section = "account"; - include('pkg_comments.php'); - - } else { - print __("You are not allowed to access this area."); - } - - } else { - if (has_credential(CRED_ACCOUNT_SEARCH)) { - # display the search page if they're a TU/dev - # - print __("Use this form to search existing accounts.")."
\n"; - include('search_accounts_form.php'); - - } else { - print __("You are not allowed to access this area."); - } - } - -} else { - # visitor is not logged in - # - print __("You must log in to view user information."); -} - -echo ""; - -html_footer(AURWEB_VERSION); - -?> diff --git a/web/html/addvote.php b/web/html/addvote.php deleted file mode 100644 index 4b52a3bb..00000000 --- a/web/html/addvote.php +++ /dev/null @@ -1,116 +0,0 @@ -" . __("New proposal submitted.") . "

\n"; - } else { -?> - - -

- - -
-

- -
-

- - - -

-

- - -

-

-
-
- - - " /> -

-
-
->10<3$laUEN!Q#6008Pn zbXOpBG|m5lHpl75-vVhpC(a!4x$h*`V2lakNUt?{-fw^e?ODm zN2l+hb*}S!PafO;yvB^)?EDQ@iLzn>_b!b9fT^^f*w@{?%2`uO4TKQ2Smxg5ikKW2 zQ*A?S8C;#@KdJ0k753J9XG*F&MOl%LT4?kK&;(>rVhi9U1?;<+SJ-zbGm)>gYnJLH z%w}?U0WeGe;1*6<3W^4axh(3Rm06q~vz;20p9m)iop2}sG)ey@z5ZEzGBay7^^(hv zOFvOQpz-HtC(no`dwszCljyn5{FA6S0{1JalqoLl^-)5KLk=qdBTC!pRYl~Zu4~eY z`jm=y&G7{n7Ek2g)hM=KE?#h6uBwFA4#F~l!gQh1QhEZ zVRX6TH*Dt7a2hD-{!i`M-_>j)z6g%ca~xCE?`N$AK|HXr$u$Q&P^B$#;&T%7mJM zuo8+h+l1P5KqsF_FkI5xbvE#m)@W=uI^t;J3`eFie;MX?$(u}bW!*u-&#nH?kt^%d zx|YaA-ExCV9U&V&;SIrCEb(@465tV50>|q>SR zoU@zOxr=q~2E8QP8G}nzeV$%*DuQQq|Tc`gx!LmYDeG= zxKY+=D~=fjPC4|=pTYudRG(20hFb0uLqD#-tI}K=Ka;(+@i-pI>=l)p6i$ z&9-~lq-@(Seb}1YT!Fy^x8xB-=ujz?L)W!@=ax`=LLfUDA2ZdD#!`(EzFdkzMFYWBytXn;~HGS8jwD~p^JH9 z(yY!Xaf-vSL#cK0=xru5#$e>dlTyIaB33aiIEI-;90sCX`viJ zA0i;5`@2n-HiiSnJS{XdI4WF@Dm#>@7=~DhfH|<5T9m?3X2M$XEY_)Boxvz8R1=d+ zB`^*2^JpfC?3HnEWQFUvg3{}9;A~0gk4%RM(^LTtAnciRWj)K8EL1z=nCL`vFJ0_8 z!lUO+=S6*pjK~uS5pwKHtY(>*-;1v^W&;MohRce{DXIOkviW#BfZjD`@$7ik~xbg$=6paDPdGZM^={xaJ@@q2g3F_z3%7tZk`C zur_-ZmzZiRoB!k5KDqsu&zw`4dhk;}>?d+hUXaSqbmfQjyn1xNf=oQU%Ay=+y!NUKi@<_oc32aa9U%msvJaVpldpOC0k^?27Mr#?k`zim@2j!tQM8L z>5NktPROk;Vy)csIG|uk19*2kOGxmT0O-PQd40OA%-8}209F~HZf=Td#(;;6XTF|h zGG5=G!a^xRAc~u#SS3Xwrx^tTPhb|}T=HW#cvOeJbg_ZtCNaD3TxyjDGOH`2F&N~i zK7%H?&d0K(b}N}2LKXZU=#8)o@P$KnIRtT-efg^}&%OhchdWNi^uZJJ5~ zsROEr60OfOob6dz%ll^ zw`BJj(gPB=SuLcx+ZjhamX2)_&8oO;QyKpP14>$%p2EHQWqkkVu`xg(V}oVi}Ri1z*S+I zg&vwS4$uun2<^C{X&aMF^DN3nO)lxHR>1oQ{Z?T`8iK%gj1M1j_B(}M{>u?&qPqCf z@uD>bS$InQJq`cN+P@oOa_&vEnx|U=u1hPu{XyV*CC>MBy&6G%>l26W*t=CBlXDDG z6=*#pihOP#lTE22?q`sZa3sigQ^t;7EsE0h^Jrtf7+{UX`CfGHD~LprH&0G2mS><_ zyZVj0jd5Wx@9sBtbgeo`9e}YJXj8`SWrhXbgC%E!X(`q$mp5gTKS>%Vl39a^@Fnh> zrQ}ro+g6k_&$ppZg>ZU`g8U#2p%uT|JE^pGL@X@KOl6nXY1 zV10N_gQU6nR({-gHmuQc?o@7=>Vm(tjfji_s`T&NmFf5I7ZHuF&zOH)4_MS*J1a5m zj^ydAYi5p=oW5!qyL@3mnsD;>k10{nJhlr|3H{Ut`O+P9Pj*qF5;xUngQOxl>`5OT z&)Tz_Gd^M50N7Kn(8`Ba!k$|~2>J){l{t}mhqLb8Xs!=Mz(vm42#U*y-ogL-AGoQQ8XB4ez$vAk@nHI82! z8d9IJr16mXG{~R@PZ>x}nY`_B1tCNdc4powbO1}zff z9u12=;9MC{dh4p~e6-0|uF6$`Pj{xAt0Jr+{39w6dq}am5a(PV>Um-HRfEPPS(G*8 z$>LlpE%mSB?%8W)=@7LK^+u-e%_XBp-gtU|1On9feMMGxLNVz3l0l#Z3wFJUrNZNq z=)&0bq%9%iA`=U@3afIyi?UKitiEN7$7@|MhLB9j`y0^mougfz51B1v%7Z-$^ZfI} zwQvKT$?R|7l%b=L+n|c)ZRmSslV|r|ir*yXkw!=j;o4)`)&9i&vQr`V;o?N7*4H~GRuFf>EYM8 z75NO70;8S&Z%M)#lxvZ-#&%;@_oFzzNuu?^L#dErg-H6l?T#=CR>*qr2Eb5oAS$-@ zoE>VjIJo&!`uPMVZlxmZYekd=eC_k5UPV}Oh21VDP6mFwYue2SrxK|*7%OfVUP{Lv z7Bo(pkXOYoC0`Q$Sho|f75Vm$&E>1!MS3I*0bA3=k`Ptq=` zl*jVdmYB(g`_Havu^{x)3A!sO&}>gg5Ju%aw8 z(+7dG`wX8zE`;xWtj@Ubij)aeaF&b*7q5Q`Z~xCB_jWZqY}f9 zM}Pd%k?O0iHVeBp^{Oh54+%Wb2-_%_+x|9(b-|WRit}c1S4wB}MUelnUs-3h^6Frg zO7;Vl?oT<|9WI z)L({xmKW)r8PZaTJv->_F7ufCkdUk_BqyGHn~#)mOu!*2f>+oWe;qhvDVW%|*AkrR zayWjz;XR8b51uDI6FGJC4NKRFx5m9Y>Jzus5nG5Cf@hoBqcE(*=Ir#pclmAOe)M@2 zY!S#sdBv{GRi1=+VAzIO^2(O7+;kBPd+Z|GuYN*qfJY~^SL6Ev(d0jSf^2IT>)CNT zZOqG06m_S5M@gi7+;62DdcmB@|KU<9sJEIwx(XDPyb?&a1H>~(pjJx$s`>iHwm@^- zh!zD$RqscY>gW+nnFhN?DKq<;laZ)~N3zETIFxNm7^d7(t?+14rhU(;bbM*VOZ%#q zn(GTJgf2XNsNRAaXk)G===ivdH|CQ1DJhk#!=yN9+%k33o3K-4GdEp*XQ|{0J)n)t zTUfA*VW55-_bEY^pleU?%!MJBBgK8ZE+d*_Yk`vF+dT5^v^R!j_S}SPDTDiJ4?&(a zdc)daUl3HUDW{@wn4x6v>y}V|;WQ1pVny=fX%=Tx=-I7HeC4#0q!Cd0sM3e7iim?E zr7WdCd-HrNeH@ZKjYy)>XB@q|?n>!{etU;K*_GiBSDEmy0qk1e`FXOHeiKL%&%M+) z84ChG>x!ZQ%&yHHk!p)30$b1nh^Uz~G}Q0kz?9BQmgBy=9b#6FI6KVC%gc#Lgdfj8 zlf8g_RGi3+ql39R3HP<(a1aLVeycB!uGTgx@KHD+5XB+kEmcJeuV>BU-?lNBnVz=>k(&9qn^S z7K2hxxY;uFiO@8m`**ob>EWLwtBYq-B*Bhvd_c|b{kywN<`Ue${v}YPZI;N(=AMsp zzt1^8&0lz`)WB6GE>KH_W~`CJ@i=Fd0~3=aTlTL?Hczl?@$ z@BcaT9p-r6)8HIU)FCvs6%bfX!F*8Cl4U^mgjr53K-SB@l%^OGPh^%ysA(2-InjRn z$L4ZSPF6O)%j7mrM<%UT_P5z%%R(~R3>Bb?TCPj$qsIG3j1jdM5^PKT%K)ZkYU%22 z1FY>E0pB-&9$NH}opdQ%zkIw&ZP?oUs>HGwsnzl+n&H;4zXZ4K8iH(%P-W&KX`Mvp4;W6k)w(@UKYq)zF%33UvR9^Vdk;p ze$x>&*Dolow}vb2^iK)dv>3j$e1f8)W_(v<&u&_R%F8QT-6et_4ugjT&e^(?)N74! zr2@lX=dG9+Sa7}CgE(~DW}Y>ntw@+ubsO7+u?M(0S$DLMecn?v9e*-+#A%EEo@0ha zx1FYSOT>&~{e@o~9eQl@oW}S|=?ihQX2$xo?Hbho4LBM{?XUEs)~MWMDzsd_Ps+)0 zm$z=F_RZ-tIx4Az(0(TKH&Tul@?vg`BH_PBN0ag(jz+7MvRw$+cbVT)b^MMkF%N^0 zn5`K-mQgtGmis_K@Q}hlM3J)?0H`$WM2|iBb-}+ajxO6#NnsY(sC%|`T~uY-SX@1z zc^lz?q7d#;BCtY4ota^k=$|s_$$Mft&vLi!yeM$eeL2pU1KwfN)Z!}^#Df}xSuXc8 zTfCh8LxwYVEYH_>0H3#aLxqFxW-=j4V+dh50`aTcMAjU=$Hd*a56>BsM}a|~4`SbF z%r@~aN+OVEgjMv158JDSyJK%X8vjgDdw4FyHQamUm-I~e{67C1Q|Jw27am{KRPd4G z&e!7)(6SD2Mg+JhIQhBU0YDlm^*|gda~Civ83m}cf~>44^q~S2+5z&A{(l5sKF;p0 zq5pruh}}fmoq+j&9V~oY1A-BLE`Z?RUR4J?A{`Jpl*=BG%MU(F5+Sz{!V)16=3lFeiZt5(_0ZH-#a$v|q>+9uvDnZ60#RRUswf)x%7pUU@TJ6OOWbM)&`B92~4tQuME0y@Gmst2;XK94s^n zOY~5t;;Ej-k{P77BRBGneohUNW?QAO@!S)DzanT>G*-OhvoI?qWZM!lNM3EPB9`nD zyJBe`KY7x%L9a*_I#up|5gPmq^ZIK(9<@pGQpA!ffzE%TS%+q{ei-rjQdEk0!ZJry zTXd3-a8k#059OQ@U)ANA+YCd-I$O~0cy00o9b_mb!drm{T2yvd!cFcj(d*vdh^4#I zu;)d>&D~98cZtN-UmX|;Z--uuZ^PUt;@HIcP-(d@hIQ3!NfmFS-C@YgXA^P-DA@QQ z?v7PKM|sozZ~EcQ59IXp1f>Q9RmMcX5tBbMHy4wdO8x1}mx7|AuDW>38n(|`qaz~< zO+D6CtQ64-$%TX0aIG>dYrM;sjFr0S}w*ye$Eo(&BRtdf#+HTHu_Q0Vh8B{sZ} z_G0bK#O!QmJ{CHOHfts^3zoV1WD|7Ss=4Kg`htw{mel`go zHR0&!DEjCq_{$d>2}Tk}M@Q(xeSpF1*NB3GPUd3aDDp6{B3(q#ODyV0($~+0zZj7+ z5F>kOvd(cyoPV^n$y?jlAWtNce>b?TlhM#bw)kJH)eOrCH$EH>JhR#8P2!wxZfU8q z=^+7w!D(+@ot?v9aAGNvrHMJyQ}dgIp-_;Tvxu-T+CYnX7bX%Wsj#>>B1o-Cje*0% z{asXieE0eO{Oamz2ZYww*LS8ZP~K(nXBYT&4fFEK29e#22ws_1`vK&jvD;J8VdZ2b zR%XQzHbRS`7r~{pE{JJz0Ya%Pv5GE29g&zNMHC@1?9jR0ceOi>0;qEatn6Nzd|vhU z2}+W&h;tI$wgdWJm!hMeYK)+gx|=ED6x-nEs9d?8L!xwWOlPeOy9$Tog2_$jWGcD! zY_*++R`mk4xVZS1kMfy?DTeUb)*P+N$~Hpvh+y`$kHNogH($By;T7&W@vsii%}- z939qJEp$~0hVH-(eIk?~Ti4E{eX+XRWRpF^Z;t;Kxv^o`U@l8iT|-P2 z8CmyR6vZqSp*RUzonU|mh|qC?Bx2 z2s%1Ce1R{7wIJd@4x6hzYq|SXS8inM;CxN(RZfBAH>*hPEYQq*gy-di5tyH$ppfz%#vb zjQ0L^OTOUycM_aX3^q14^uA%zw-l0$arB}D zMiu6wyGI|Dp~_fw&hruaB|3D9KLc*OYKFbMy&nq;Q#uUir~*V0p(ifXdrCn;k(io_ zBQGyc_2|)RLf~z|tfYp;Y>U5m>*X3DM1($N*Z<-`RZR^iObO9<*50lVArg7NJYX5Y za|(NgHT=l&5bD!=Posl;9TzaPW7vLoyF79kJ2;{lp}f0;9iKlsv7YjYser^vh>H!R zL2!{LxETOx?i`Ujc->%jT{a90PpIn~0EL7N4C=3(iMDeQ!(KyWJPtbZ+*u;jhRGW4 z(fkWBLPzLEgCN`VZBY`beDkoIE}}?KTT2U*Yx5D#-#_W0D=U^Y!yB8Mh}PB|wb*O= z5J_M33Wnh~V=Ia&4^L0kw{IEuXMxy$d)r9y@#9C%X;TvuD3AiZwnBVws=)wvL(N@% zDZGHp-~mt)VsP>71D4&!3yE3-1>HB8ARmcU`8@BW5dMmA)EJ_KW)h(x zMkRQ{V#@k5Dw2{q*q}DlG?3CU7cZ#Ly=7`*KX>!;|# zZTmU#_kN3;9)Y7kR_JTzH7Jb2S)b6uum3Nwr*n%&QO*rt;#dl@2+Jdg$MrDLIQ9nU zx7R%y#8uyqrUAZsL^%_ae4xOH9!uOpYe1&g;J`qv z*M9$J-pivN7A8YiBcm^mUXX&`hIy8a=XMhrzu2+FsnkY0aR1eV)8EEe>oN+Mm>U!O z-mc}K<~J)ke2vAw-ZPV-i5Z!JO0R7adOdP7^7CrW48Ga_nN|)aVUyKVT-=RQqA_a+ zz1#ddm`Nfk;j}MA`#xPkXq%N!?!Vb-OWYSO$mu=!>VK6iQ_6=s#4)=>=7XXQpK_T! z0!gEGJmPYQv0g#~ox%93e_$Fz@9WEbK70_`H}UnAtgfzx9xOHG%P zvbw$fuIt_GU&Qq|BS^Q@z$e2xw&VQx{GNGYZ)cbFB>bzKK_p6)@0a<4Fb#*NW5dFq z&dy75zkIoAcgC??F@Kos@FZJP`A zvfL;WJ64u?`7L}1HCm9%9ffNYA;Qp6WhoR|Aa%EPgr(LRZtd5K7lX2(eSlvs?B;2l zk7Kp6^K|X-AdyVPQ31Z~U4J$=vg8AqwTi~}PCkGB+~9xlU0K0Fz>S}Wr{6IQRjQw@ z4&q80SOX#={gGsbJbG-llHppUYEqJK1 zl*GSp5pDw@j7~TG`r41aH~kX+?4w}M;66gCtE=mWim;K9(Km~>CC6Eym6$Z&_a#t- z5&y7HH0b#TpXb*A!XR_J@S;MIE+_23sz4E90DX4LI2N+VI+2ZvOVhECJ$Nj`OzPs| z(oGuKDL6aMM@8U_1^3^B**s=?5|b9}e|H}%y55t}1GL*gxhAiDlZK`y=|UtE6B9QN zkC61%FL#7MD_{%%i+AzF(7DMV&{3DwfU@SCFRlWR#RPYgO`> zD_DHSl^{t;$**N)N-&sA@r(2jfS>d};YtYnAe`!9&w*6_sF;|1WKMB$vGwsrpM={Q z*k!qu__J1cW#w}YPELBt+2rKpcKezt_?=%jm7Th7wt2te*6AnDIiVGdykW=kgHbKv zSmIiByoNz<{`wSKMM=kqt1C>ushBy=3eXHA-ho+I-f`9Vs*y#+iXn!9mHtR-CDE9^ z={x)KNym>YpS7@oAbvIA!2@GTNJ}dtbd7O=2w;|{{wcr0NEV*|NJ#K&R}zw$hBMjw zG_?i32SeXmNuv`OB|~T|U`bw7>IMc>`T6;@1KHBvBtWq0GuJQlkQd8=ET;7?MRakw zxw(_CC*O@1uZp)_5zF18m78|z`Lp_dTQadsZZ`#WB~71)iQrR|C2AT5S48<2^$70N z%HmR;h8p=V@Q!HRcI-eROh@5@bTC_&0v*0dFuRVumvKYm2vonSz9J#bd$!;-NDGv(0aUB8_Q2oJ%KsgfT!q* z@9bl2Z0z3N%4hreWn~2Z=X+I|J2MjGmT4yx_Cfy<#~)k>!o7^7FB9|#q&kc9ZGQM( zmp;16d-9G+iXE^tvS6i(BAX%cYA!#>bA`8+427vVL24)wG8z~Ts#fuwqDv1&Vk$}(M_$J2ZEpkH~B=sEdsrq+A67-u)z<0VG`JxxCr=u?Gb;gaMbk;H%m zw#Tp^PGZi5Uq2liA9uU^xi391lp`CvIq;>Rw6xFV#r)b4KIgii6U4HRzOKqoKRcgy zIjCq)vmC-wPj*HqueLkk@uTM!6RDqya9i?+z_v;MX<&ei63bHm6=>spC!C{L!o&I+CglBl+hVD*AY+J32r|rH z1lsB!pN=_cj#cUysmN*#Q{yF3n2tIkGcc=e9B;ec;RX6@^VQ$XG)ebj!N{C^?)B8R zZ{PR~jEvSNO7$U*j!J+K;o;?dWoD+$fa$vU)9$#6^UE^}H4_v1Vx8<5-;=*=tgIk7 z9Nzt^$opm$NU_B9^uDk9CF2MnT;7LEU4TDw#%VP{s@d5+Sxh{2gl6z|?8}eo`BiRu zvWl83$1Fzgc=#OBg(0H6y?8V=@7*F_Yr>D`?%<#Y z4(|RUro3hE8`7UT{p;rPkWX$rwUP?R=+v_x)1A9BYW4|ss+TZ1SU|ul3kz2vibM|l zV1;(tU7FY~h?A4M#zrJ7o{z7uV#Rbpnkw2~h<4i=jt zGcqzT+~5S@eXwYZ<(Vy*6uO&}!v!vVC74BYlZ4O{|%qlSPK(q;obF zh^-4<9O#CpW$DI0v>Cr|$ekzLYT6RyP(Bt3>ppr)J^zB{Y;2tQ=~+(x_T9U8+1SVp@nyl70Pk=u;Pzy zV|_Y<4c{j<sl&c$9-HNKd(mT zg$D8m!2IyJ`1+KFkKWuv3=zZSy@tr zGW6qmW-%&mclblGnsLQf41bV1Ry+s#wt_=1N6?v%Wbhh#lw5Qe(UWvru5lPLAbr>z zT3s!)v9+a)G-Md(hrwXzDO1y0^SnbVJL0k{<4H#v7$N*Q>J2ce2Gg(efN7pxV-kO}7OPc2p82W-!_+6}IHYu}A zUTrojo`|TZ)%o6RgZoyzoAi!CI5Efs!6l{4l^Mox^{9)?OqRq;J*Cs)x#Fu8(NCe% zx+JT$l)5Tyc(2hM>u@tWWA?Z3KUk)-w||10yf+)XjlO7{`nXl(<$>Dn&ng7pjdA?$ z>av>p_67(_w-6GE1gI?%@~x?fVQ6Rw^yiQc#T#%qpYNJiKKH`;ut{@i=||kXvpk?Z z#>U3bJLMHh<&$ft+rh4?9Kkt-Y>9k9`Rx?~;nPRUih2z<(Lp)(zS&5!+y_ka9x)7q`OqmVRAgktG+dcw001Puhs9E#IcjKHk zJDs&o)4ImSQA0yIw`UcBUB{aPA8+CZ`uq1>Ist9t`q~0;4pS8tq`*c+O})0!m-3vJ zXr|GfD^MaV5?a!5!PV zm#>VBA^|H81dUBxd|GabJmZ|X%eg^y`0z4Xb)Otu>n-tipw*vKwoQdSSPAj`Z^|jD zVA-Uj$vuf?G8&BzQbJVvF-9Y;ChxBSsfs?Ewpecu#`=d)6?XFd7cA7V*wHFV1COdF zyqta&rf7=2p9z|+aj*eM>ve{Gvqiw?;@%~E_wXT|Bx-E;ERL$%^7)Lm>)vR|`1YSV z{fg;K?5{<2^Awxa*r#AcR&j9}>nd6c_*Ky&Nf2~H-iJ9kFktn_2bkQc1q8_Qr<`rE zpZpzE1}siYZ0tU1B@srT#ywLw<4y?MmG`FyT-<}Z*hdaU3&3C;q^YW-@?FU? a.headerlink { - visibility: visible; -} - -/* headings */ -h2 { - font-size: 1.5em; - margin-bottom: 0.5em; - border-bottom: 1px solid #888; -} - -h3 { - font-size: 1.25em; - margin-top: .5em; -} - -h4 { - font-size: 1.15em; - margin-top: 1em; -} - -h5 { - font-size: 1em; - margin-top: 1em; -} - -/* general layout */ -[dir="rtl"] #content { - text-align: right; -} - -#content { - width: 95%; - margin: 0 auto; - text-align: left; -} - -[dir="rtl"] #content-left-wrapper { - float: right; -} - -#content-left-wrapper { - float: left; - width: 100%; /* req to keep content above sidebar in source code */ -} - -[dir="rtl"] #content-left { - margin: 0 0 0 340px; -} - -#content-left { - margin: 0 340px 0 0; -} - -[dir="rtl"] #content-right { - float: right; - margin-right: -300px; -} - -#content-right { - float: left; - width: 300px; - margin-left: -300px; -} - -div.box { - margin-bottom: 1.5em; - padding: 0.65em; - background: #ecf2f5; - border: 1px solid #bcd; -} - -#footer { - clear: both; - margin: 2em 0 1em; -} - - #footer p { - margin: 0; - text-align: center; - font-size: 0.85em; - } - -/* alignment */ -div.center, -table.center, -img.center { - width: auto; - margin-left: auto; - margin-right: auto; -} - -p.center, -td.center, -th.center { - text-align: center; -} - -/* table generics */ -table { - width: 100%; - border-collapse: collapse; -} - - table .wrap { - white-space: normal; - } - -[dir="rtl"] th, -[dir="rtl"] td { - text-align: right; -} - -th, -td { - white-space: nowrap; - text-align: left; -} - - th { - vertical-align: middle; - font-weight: bold; - } - - td { - vertical-align: top; - } - -/* table pretty styles */ -table.pretty2 { - width: auto; - margin-top: 0.25em; - margin-bottom: 0.5em; - border-collapse: collapse; - border: 1px solid #bbb; -} - - .pretty2 th { - padding: 0.35em; - background: #eee; - border: 1px solid #bbb; - } - - .pretty2 td { - padding: 0.35em; - border: 1px dotted #bbb; - } - -table.compact { - width: auto; -} - - .compact td { - padding: 0.25em 0 0.25em 1.5em; - } - - -/* definition lists */ -dl { - clear: both; -} - - dl dt, - dl dd { - margin-bottom: 4px; - padding: 8px 0 4px; - font-weight: bold; - border-top: 1px dotted #bbb; - } - - [dir="rtl"] dl dt { - float: right; - padding-left: 15px; - } - dl dt { - color: #333; - float: left; - padding-right: 15px; - } - -/* forms and input styling */ -form p { - margin: 0.5em 0; -} - -fieldset { - border: 0; -} - -label { - width: 12em; - vertical-align: top; - display: inline-block; - font-weight: bold; -} - -input[type=text], -input[type=password], -input[type=email], -textarea { - padding: 0.10em; -} - -form.general-form label, -form.general-form .form-help { - width: 10em; - vertical-align: top; - display: inline-block; -} - -form.general-form input[type=text], -form.general-form textarea { - width: 45%; -} - -/* archdev navbar */ -#archdev-navbar { - margin: 1.5em 0; -} - - #archdev-navbar ul { - list-style: none; - margin: -0.5em 0; - padding: 0; - } - - #archdev-navbar li { - display: inline; - margin: 0; - padding: 0; - font-size: 0.9em; - } - - #archdev-navbar li a { - padding: 0 0.5em; - color: #07b; - } - -/* error/info messages (x pkg is already flagged out-of-date, etc) */ -#sys-message { - width: 35em; - text-align: center; - margin: 1em auto; - padding: 0.5em; - background: #fff; - border: 1px solid #f00; -} - - #sys-message p { - margin: 0; - } - -ul.errorlist { - color: red; -} - -form ul.errorlist { - margin: 0.5em 0; -} - -/* JS sorting via tablesorter */ -[dir="rtl"] table th.tablesorter-header { - padding-left: 20px; - background-position: center left ; -} -table th.tablesorter-header { - padding-right: 20px; - background-image: url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==); - background-repeat: no-repeat; - background-position: center right; - cursor: pointer; -} - -table thead th.tablesorter-headerAsc { - background-color: #e4eeff; - background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7); -} - -table thead th.tablesorter-headerDesc { - background-color: #e4eeff; - background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7); -} - -table thead th.sorter-false { - background-image: none; - cursor: default; -} - -.tablesorter-header:focus { - outline: none; -} - -/** - * PAGE SPECIFIC STYLES - */ - -/* home: introduction */ -[dir="rtl"] #intro p.readmore { - text-align: left; -} -#intro p.readmore { - margin: -0.5em 0 0 0; - font-size: .9em; - text-align: right; -} - -/* home: news */ -#news { - margin-top: 1.5em; -} - - [dir="rtl"] #news h3 { - float: right; - } - #news h3 { - float: left; - padding-bottom: .5em - } - - #news div { - margin-bottom: 1em; - } - - #news div p { - margin-bottom: 0.5em; - } - - #news .more { - font-weight: normal; - } - [dir="rtl"] #news .rss-icon { - float: left; - } - #news .rss-icon { - float: right; - margin-top: 1em; - } - - #news h4 { - clear: both; - font-size: 1em; - margin-top: 1.5em; - border-bottom: 1px dotted #bbb; - } - [dir="rtl"] #news .timestamp { - float: left; - margin: -1.8em 0 0 0.5em; - } - #news .timestamp { - float: right; - font-size: 0.85em; - margin: -1.8em 0.5em 0 0; - } - -/* home: arrowed headings */ -#news h3 a { - display: block; - background: #1794D1; - font-size: 15px; - padding: 2px 10px; - color: white; -} - - #news a:active { - color: white; - } - -h3 span.arrow { - display: block; - width: 0; - height: 0; - border-left: 6px solid transparent; - border-right: 6px solid transparent; - border-top: 6px solid #1794D1; - margin: 0 auto; - font-size: 0; - line-height: 0px; -} - -/* home: pkgsearch box */ -#pkgsearch { - padding: 1em 0.75em; - background: #3ad; - color: #fff; - border: 1px solid #08b; -} - - #pkgsearch label { - width: auto; - padding: 0.1em 0; - } - - [dir="rtl"] #pkgsearch input { - float: left; - } - #pkgsearch input { - width: 10em; - float: right; - font-size: 1em; - color: #000; - background: #fff; - border: 1px solid #09c; - } - - [dir="rtl"] .pkgsearch-typeahead { - right: 0; - float: right; - text-align: right; - } - - .pkgsearch-typeahead { - position: absolute; - top: 100%; - left: 0; - z-index: 1000; - display: none; - float: left; - padding: 0.15em 0.1em; - margin: 0; - min-width: 10em; - font-size: 1em; - text-align: left; - list-style: none; - background-color: #f6f9fc; - border: 1px solid #09c; - } - - .pkgsearch-typeahead li a { - color: #000; - } - - .pkgsearch-typeahead li:hover a, - .pkgsearch-typeahead li.active a { - color: #07b; - } - -/* home: recent pkg updates */ -#pkg-updates h3 { - margin: 0 0 0.3em; -} - - #pkg-updates .more { - font-weight: normal; - } - [dir="rtl"] #pkg-updates .rss-icon { - float: left; - } - #pkg-updates .rss-icon { - float: right; - margin: -2em 0 0 0; - } - - [dir="rtl"] #pkg-updates .rss-icon.latest { - margin-left: 1em; - } - #pkg-updates .rss-icon.latest { - margin-right: 1em; - } - - #pkg-updates table { - margin: 0; - direction: ltr; - } - - #pkg-updates td.pkg-name { - white-space: normal; - text-align: left; - } - - [dir="rtl"] #pkg-updates td.pkg-arch { - text-align: left; - } - #pkg-updates td.pkg-arch { - text-align: right; - } - - #pkg-updates span.testing { - font-style: italic; - } - - #pkg-updates span.staging { - font-style: italic; - color: #ff8040; - } - -/* home: sidebar navigation */ -[dir="rtl"] #nav-sidebar ul { - margin: 0.5em 1em 0.5em 0; -} - -#nav-sidebar ul { - list-style: none; - margin: 0.5em 0 0.5em 1em; - padding: 0; -} - -/* home: sponsor banners */ -#arch-sponsors img { - padding: 0.3em 0; -} - -/* home: sidebar components (navlist, sponsors, pkgsearch, etc) */ -div.widget { - margin-bottom: 1.5em; -} - -/* feeds page */ -[dir="rtl"] #rss-feeds .rss { - padding-left: 20px; - background: url(rss.png) top left no-repeat; -} - -#rss-feeds .rss { - padding-right: 20px; - background: url(rss.png) top right no-repeat; -} - -/* artwork: logo images */ -#artwork img.inverted { - background: #333; - padding: 0; -} - -#artwork div.imagelist img { - display: inline; - margin: 0.75em; -} - -/* news: article list */ -[dir="rtl"] .news-nav { - float: left; -} -.news-nav { - float: right; - margin-top: -2.2em; -} - - .news-nav .prev, - .news-nav .next { - margin: 0 1em; - } - -/* news: article pages */ -div.news-article .article-info { - margin: 0; - color: #999; -} - -/* news: add/edit article */ -#newsform { - width: 60em; -} - - #newsform input[type=text], - #newsform textarea { - width: 75%; - } - -#news-preview { - display: none; -} - -/* todolists: list */ -[dir="rtl"] .todolist-nav { - float: left; -} -.todolist-nav { - float: right; - margin-top: -2.2em; -} - - .todolist-nav .prev, - .todolist-nav .next { - margin: 0 1em; - } - -/* donate: donor list */ -#donor-list ul { - width: 100%; -} - /* max 4 columns, but possibly fewer if screen size doesn't allow for more */ - [dir="rtl"] #donor-list li { - float: right; - } - #donor-list li { - float: left; - width: 25%; - min-width: 20em; - } - -/* download page */ -#arch-downloads h3 { - border-bottom: 1px dotted #bbb; -} - -/* pkglists/devlists */ -table.results { - font-size: 0.846em; - border-top: 1px dotted #999; - border-bottom: 1px dotted #999; - direction: ltr; -} - - [dir="rtl"] .results th {text-align: center; direction:rtl;} - .results th { - padding: 0.5em 1em 0.25em 0.25em; - border-bottom: 1px solid #999; - white-space: nowrap; - background-color:#fff; - } - - .results td { - padding: .3em 1em .3em 3px; - text-align: left; - } - - .results .flagged { - color: red; - } - - .results tr.empty td { - text-align: center; - } - -/* pkglist: layout */ -#pkglist-about { - margin-top: 1.5em; -} - -/* pkglist: results navigation */ -.pkglist-stats { - font-size: 0.85em; -} - -[dir="rtl"] #pkglist-results .pkglist-nav { - float: left; -} -#pkglist-results .pkglist-nav { - float: right; - margin-top: -2.2em; -} - -[dir="rtl"] .pkglist-nav .prev { - margin-left: 1em; -} - -.pkglist-nav .prev { - margin-right: 1em; -} - -[dir="rtl"] .pkglist-nav .next { - margin-left: 1em; -} -.pkglist-nav .next { - margin-right: 1em; -} - -/* search fields and other filter selections */ -.filter-criteria { - margin-bottom: 1em; -} - -.filter-criteria h3 { - font-size: 1em; - margin-top: 0; -} -[dir="rtl"] .filter-criteria div { - float: right; - margin-left: 1.65em; -} -.filter-criteria div { - float: left; - margin-right: 1.65em; - font-size: 0.85em; -} - -.filter-criteria legend { - display: none; -} - -.filter-criteria label { - width: auto; - display: block; - font-weight: normal; -} - -/* pkgdetails: details links that float on the right */ -[dir="rtl"] #pkgdetails #detailslinks { - float: left; -} -#pkgdetails #detailslinks { - float: right; -} - - #pkgdetails #detailslinks h4 { - margin-top: 0; - margin-bottom: 0.25em; - } - - #pkgdetails #detailslinks ul { - list-style: none; - padding: 0; - margin-bottom: 0; - font-size: 0.846em; - } - - #pkgdetails #detailslinks > div { - padding: 0.5em; - margin-bottom: 1em; - background: #eee; - border: 1px solid #bbb; - } - -#pkgdetails #actionlist .flagged { - color: red; - font-size: 0.9em; - font-style: italic; -} - -/* pkgdetails: pkg info */ -#pkgdetails #pkginfo { - width: auto; -} - -[dir="rtl"] #pkgdetails td { - padding: 0.25em 1.5em 0.25em 0; - } - - #pkgdetails #pkginfo td { - padding: 0.25em 0 0.25em 1.5em; - } - - #pkgdetails #pkginfo .userdata { - font-size: 0.85em; - padding: 0.5em; - } - -/* pkgdetails: flag package */ -#flag-pkg-form label { - width: 10em; -} - -#flag-pkg-form textarea, -#flag-pkg-form input[type=text] { - width: 45%; -} - -#flag-pkg-form #id_website { - display: none; -} - -/* pkgdetails: deps, required by and file lists */ -#pkgdetails #metadata { - clear: both; -} - -#pkgdetails #metadata h3 { - background: #555; - color: #fff; - font-size: 1em; - margin-bottom: 0.5em; - padding: 0.2em 0.35em; -} - -#pkgdetails #metadata ul { - list-style: none; - margin: 0; - padding: 0; -} - -[dir="rtl"] #pkgdetails #metadata li { - padding-right: 0.5em; -} - -#pkgdetails #metadata li { - padding-left: 0.5em; -} - -[dir="rtl"] #pkgdetails #metadata p { - padding-right: 0.5em; -} -#pkgdetails #metadata p { - padding-left: 0.5em; -} - -#pkgdetails #metadata .message { - font-style: italic; -} - -#pkgdetails #metadata br { - clear: both; -} - -[dir="rtl"] #pkgdetails #pkgdeps { - float: right; - width: 48%; - margin-left: 2%; - -} -#pkgdetails #pkgdeps { - float: left; - width: 48%; - margin-right: 2%; -} - -#pkgdetails #metadata .virtual-dep, -#pkgdetails #metadata .testing-dep, -#pkgdetails #metadata .staging-dep, -#pkgdetails #metadata .opt-dep, -#pkgdetails #metadata .make-dep, -#pkgdetails #metadata .check-dep, -#pkgdetails #metadata .dep-desc { - font-style: italic; -} - -[dir="rtl"] #pkgdetails #pkgreqs { - float: right; - width: 48%; -} - -#pkgdetails #pkgreqs { - float: left; - width: 50%; -} - -#pkgdetails #pkgfiles { - clear: both; - padding-top: 1em; -} - -#pkgfilelist li.d { - color: #666; -} - -#pkgfilelist li.f { -} - -/* mirror stuff */ -table td.country { - white-space: normal; -} - -#list-generator div ul { - list-style: none; - display: inline; - padding-left: 0; -} - - #list-generator div ul li { - display: inline; - } - -.visualize-mirror .axis path, -.visualize-mirror .axis line { - fill: none; - stroke: #000; - stroke-width: 3px; - shape-rendering: crispEdges; -} - -.visualize-mirror .url-dot { - stroke: #000; -} - -.visualize-mirror .url-line { - fill: none; - stroke-width: 1.5px; -} - -/* dev/TU biographies */ -#arch-bio-toc { - width: 75%; - margin: 0 auto; - text-align: center; -} - - #arch-bio-toc a { - white-space: nowrap; - } - -.arch-bio-entry { - width: 75%; - min-width: 640px; - margin: 0 auto; -} - .arch-bio-entry td.pic { - padding-left: 15px; - } - .arch-bio-entry td.pic { - vertical-align: top; - padding-right: 15px; - padding-top: 2.25em; - } - - .arch-bio-entry td.pic img { - padding: 4px; - border: 1px solid #ccc; - } - - .arch-bio-entry td h3 { - border-bottom: 1px dotted #ccc; - margin-bottom: 0.5em; - } - - .arch-bio-entry table.bio { - margin-bottom: 2em; - } - [dir="rtl"] .arch-bio-entry table.bio th { - text-align: left; - padding-left: 0.5em; - } - - .arch-bio-entry table.bio th { - color: #666; - font-weight: normal; - text-align: right; - padding-right: 0.5em; - vertical-align: top; - white-space: nowrap; - } - - .arch-bio-entry table.bio td { - width: 100%; - padding-bottom: 0.25em; - white-space: normal; - } - -/* dev: login/out */ -#dev-login { - width: auto; -} - -/* tables rows: highlight on mouse-vover */ -#article-list tr:hover, -#clocks-table tr:hover, -#dev-dashboard tr:hover, -#dev-todo-lists tr:hover, -#dev-todo-pkglist tr:hover, -#pkglist-results tr:hover, -#stats-area tr:hover { - background: #ffd; -} - -.results tr:nth-child(even), -#article-list tr:nth-child(even) { - background: #e4eeff; -} - -.results tr:nth-child(odd), -#article-list tr:nth-child(odd) { - background: #fff; -} - -/* dev dashboard: */ -table.dash-stats .key { - width: 50%; -} - -/* dev dashboard: admin actions (add news items, todo list, etc) */ -[dir="rtl"] ul.admin-actions { - float: left; -} -ul.admin-actions { - float: right; - list-style: none; - margin-top: -2.5em; -} - - ul.admin-actions li { - display: inline; - padding-left: 1.5em; - } - -/* colored yes/no type values */ -.todo-table .complete, -.signoff-yes, -#key-status .signed-yes, -#release-list .available-yes { - color: green; -} - -.todo-table .incomplete, -.signoff-no, -#key-status .signed-no, -#release-list .available-no { - color: red; -} - -.todo-table .inprogress, -.signoff-bad { - color: darkorange; -} - - -/* todo lists (public and private) */ -.todo-info { - color: #999; - border-bottom: 1px dotted #bbb; -} - -.todo-description { - margin-top: 1em; - padding-left: 2em; - max-width: 900px; -} - -.todo-pkgbases { - border-top: 1px dotted #bbb; -} - -.todo-list h4 { - margin-top: 0; - margin-bottom: 0.4em; -} - -/* dev: signoff page */ -#dev-signoffs tr:hover { - background: #ffd; -} - -ul.signoff-list { - list-style: none; - margin: 0; - padding: 0; -} - -.signoff-yes { - font-weight: bold; -} - -.signoff-disabled { - color: gray; -} - -/* highlight current website in the navbar */ -#archnavbar.anb-home ul li#anb-home a, -#archnavbar.anb-packages ul li#anb-packages a, -#archnavbar.anb-download ul li#anb-download a { - color: white !important; -} - -/* visualizations page */ -.visualize-buttons { - margin: 0.5em 0.33em; -} - -.visualize-chart { - position: relative; - height: 500px; - margin: 0.33em; -} - -#visualize-archrepo .treemap-cell { - border: solid 1px white; - overflow: hidden; - position: absolute; -} - - #visualize-archrepo .treemap-cell span { - padding: 3px; - font-size: 0.85em; - line-height: 1em; - } - -#visualize-keys svg { - width: 100%; - height: 100%; -} - -/* releases */ -#release-table th:first-of-type { - width: 30px; -} - -/* itemprops */ -.itemprop { - display: none; -} diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css deleted file mode 100644 index 64a65742..00000000 --- a/web/html/css/aurweb.css +++ /dev/null @@ -1,292 +0,0 @@ -/* aurweb-specific customizations to archweb.css */ - -#archnavbar.anb-aur ul li#anb-aur a { - color: white !important; -} - -#archnavbarlogo { - background: url('archnavbar/aurlogo.png') !important; -} - -[dir="rtl"] #lang_sub { - float: left; - } -#lang_sub { - float: right; -} - -.pkglist-nav .page { - margin: 0 .25em; -} - -#pkg-stats td.stat-desc { - white-space: normal; -} - -#actionlist form { - margin: 0; - padding: 0; -} - -.arch-bio-entry ul { - list-style: none; - padding: 0; -} - -#pkg-updates table { - table-layout: fixed; - width:100%; -} - -#pkg-updates td.pkg-name { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -[dir="rtl"] #pkg-updates td.pkg-date { - text-align:left; -} -#pkg-updates td.pkg-date { - text-align:right; -} - -[dir="rtl"] .keyword:link, .keyword:visited { - float: right; -} - -.keyword:link, .keyword:visited { - float: left; - margin: 1px .5ex 1px 0; - padding: 0 1em; - color: white; - background-color: #36a; - border: 1px solid transparent; - border-radius: 2px; -} - -.keyword:hover { - cursor: pointer; -} - -.keyword:focus { - border: 1px dotted #000; -} - -.text-button { - background: transparent; - border: none !important; - margin: 0 !important; - padding: 0 !important; - font: normal 100% sans-serif; - text-decoration: none; - color: #07b; - cursor: pointer; -} - -.text-button:hover { - text-decoration: underline; - color: #666; -} - -.text-button::-moz-focus-inner { - padding: 0; - border: none; -} - -.comment-deleted { - color: #999; -} - -.edited { - font-size: 0.9em; - color: #999; -} - -[dir="rtl"] .delete-comment-form, .undelete-comment-form, .pin-comment-form, .edit-comment { - float: left; - margin-right: 8px; -} - -.delete-comment-form, .undelete-comment-form, .pin-comment-form, .edit-comment { - float: right; - margin-left: 8px; -} - -.edit-comment { - height: 11px; - position: relative; - top: 1px; -} - -.comment-enable-notifications { - display: inline-block; - margin-left: 1em; -} - -.rss-icon, .delete-comment, .undelete-comment, .edit-comment, .pin-comment { - filter: grayscale(100%); - opacity: 0.6; -} - -.rss-icon:hover, .delete-comment:hover, .undelete-comment:hover, .edit-comment:hover, .pin-comment:hover { - filter: none; - opacity: 1; -} - -[dir="rtl"] .ajax-loader { - float: left; -} - -.ajax-loader { - float: right; - position: relative; - top: 4px; -} - -.flagged a { - color: inherit; -} - -legend { - padding: 1em 0; -} - -p.important { - font-weight: bold; -} - -span.hover-help { - border-bottom: 1px dotted black; - cursor:help; -} - -label.confirmation { - width: auto; -} - -#pkgdepslist .broken { - color: red; - font-weight: bold; -} - -.package-comments { - margin-top: 1.5em; -} - -.comments-header { - display: flex; - justify-content: space-between; - align-items: flex-start; -} - -/* arrowed headings */ -.comments-header h3 span.text { - display: block; - background: #1794D1; - font-size: 15px; - padding: 2px 10px; - color: white; -} - -.comments-header .comments-header-nav { - align-self: flex-end; -} - -.comments-footer { - display: flex; - justify-content: flex-end; -} - -.comment-header { - clear: both; - font-size: 1em; - margin-top: 1.5em; - border-bottom: 1px dotted #bbb; -} - -.comments div { - margin-bottom: 1em; -} - -.comments div p { - margin-bottom: 0.5em; -} - -.comments .more { - font-weight: normal; -} - -.error { - color: red; -} - -.article-content > div { - overflow: hidden; - transition: height 1s; -} - -.proposal.details { - margin: .33em 0 1em; -} - -button[type="submit"], -button[type="reset"] { - padding: 0 0.6em; -} - -.results tr td[align="left"] fieldset { - text-align: left; -} - -.results tr td[align="right"] fieldset { - text-align: right; -} - -input#search-action-submit { - width: 80px; -} - -.success { - color: green; -} - -/* Styling used to clone styles for a form.link button. */ -form.link, form.link button { - display: inline; - font-family: sans-serif; -} -form.link button { - padding: 0 0.5em; - color: #07b; - background: none; - border: none; - font-family: inherit; - font-size: inherit; -} -form.link button:hover { - cursor: pointer; - text-decoration: underline; -} - -/* Customize form.link when used inside of a page. */ -div.box form.link p { - margin: .33em 0 1em; -} -div.box form.link button { - padding: 0; -} - -pre.traceback { - /* https://css-tricks.com/snippets/css/make-pre-text-wrap/ */ - white-space: pre-wrap; - word-wrap: break-all; -} - -/* By default, tables use 100% width, which we do not always want. */ -table.no-width { - width: auto; -} -table.no-width > tbody > tr > td { - padding-right: 2px; -} diff --git a/web/html/css/cgit.css b/web/html/css/cgit.css deleted file mode 100644 index 429b5f54..00000000 --- a/web/html/css/cgit.css +++ /dev/null @@ -1,866 +0,0 @@ -/* - * ARCH GLOBAL NAVBAR - * We're forcing all generic selectors with !important - * to help prevent other stylesheets from interfering. - */ - -/* container for the entire bar */ -#archnavbar { height: 40px !important; padding: 10px 15px !important; background: #333 !important; border-bottom: 5px #08c solid !important; } -#archnavbarlogo { float: left !important; margin: 0 !important; padding: 0 !important; height: 40px !important; width: 190px !important; background: url('archnavbar/archlogo.png') no-repeat !important; } - -/* move the heading text offscreen */ -#archnavbarlogo h1 { margin: 0 !important; padding: 0 !important; text-indent: -9999px !important; } - -/* make the link the same size as the logo */ -#archnavbarlogo a { display: block !important; height: 40px !important; width: 190px !important; } - -/* display the list inline, float it to the right and style it */ -#archnavbarlist { display: inline !important; float: right !important; list-style: none !important; margin: 0 !important; padding: 0 !important; } -#archnavbarlist li { float: left !important; font-size: 14px !important; font-family: sans-serif !important; line-height: 45px !important; padding-right: 15px !important; padding-left: 15px !important; } - -/* style the links */ -#archnavbarlist li a { color: #999; font-weight: bold !important; text-decoration: none !important; } -#archnavbarlist li a:hover { color: white !important; text-decoration: underline !important; } - -/* END ARCH GLOBAL NAVBAR */ - -#footer { - clear: both; - margin: 0; -} - -#footer p { - margin: 1em; -} - -#archnavbar.anb-aur ul li#anb-aur a { - color: white !important; -} - -#archnavbarlogo { - background: url('archnavbar/aurlogo.png') !important; -} - -body { - padding: 0; - margin: 0; - font-family: sans-serif; - font-size: 10pt; - color: #333; - background: white; -} - -div#cgit a { - color: blue; - text-decoration: none; -} - -div#cgit a:hover { - text-decoration: underline; -} - -div#cgit table { - border-collapse: collapse; -} - -div#cgit table#header { - width: 100%; - margin-bottom: 1em; -} - -div#cgit table#header td.logo { - width: 96px; - vertical-align: top; -} - -div#cgit table#header td.main { - font-size: 250%; - padding-left: 10px; - white-space: nowrap; -} - -div#cgit table#header td.main a { - color: #000; -} - -div#cgit table#header td.form { - text-align: right; - vertical-align: bottom; - padding-right: 1em; - padding-bottom: 2px; - white-space: nowrap; -} - -div#cgit table#header td.form form, -div#cgit table#header td.form input, -div#cgit table#header td.form select { - font-size: 90%; -} - -div#cgit table#header td.sub { - color: #777; - border-top: solid 1px #ccc; - padding-left: 10px; -} - -div#cgit table.tabs { - border-bottom: solid 3px #ccc; - border-collapse: collapse; - margin-top: 2em; - margin-bottom: 0px; - width: 100%; -} - -div#cgit table.tabs td { - padding: 0px 1em; - vertical-align: bottom; -} - -div#cgit table.tabs td a { - padding: 2px 0.75em; - color: #777; - font-size: 110%; -} - -div#cgit table.tabs td a.active { - color: #000; - background-color: #ccc; -} - -div#cgit table.tabs td.form { - text-align: right; -} - -div#cgit table.tabs td.form form { - padding-bottom: 2px; - font-size: 90%; - white-space: nowrap; -} - -div#cgit table.tabs td.form input, -div#cgit table.tabs td.form select { - font-size: 90%; -} - -div#cgit div.path { - margin: 0px; - padding: 5px 2em 2px 2em; - color: #000; - background-color: #eee; -} - -div#cgit div.content { - margin: 0px; - padding: 2em; - border-bottom: solid 3px #ccc; -} - - -div#cgit table.list { - width: 100%; - border: none; - border-collapse: collapse; -} - -div#cgit table.list tr { - background: white; -} - -div#cgit table.list tr.logheader { - background: #eee; -} - -div#cgit table.list tr:hover { - background: #eee; -} - -div#cgit table.list tr.nohover:hover { - background: white; -} - -div#cgit table.list th { - font-weight: bold; - /* color: #888; - border-top: dashed 1px #888; - border-bottom: dashed 1px #888; - */ - padding: 0.1em 0.5em 0.05em 0.5em; - vertical-align: baseline; -} - -div#cgit table.list td { - border: none; - padding: 0.1em 0.5em 0.1em 0.5em; -} - -div#cgit table.list td.commitgraph { - font-family: monospace; - white-space: pre; -} - -div#cgit table.list td.commitgraph .column1 { - color: #a00; -} - -div#cgit table.list td.commitgraph .column2 { - color: #0a0; -} - -div#cgit table.list td.commitgraph .column3 { - color: #aa0; -} - -div#cgit table.list td.commitgraph .column4 { - color: #00a; -} - -div#cgit table.list td.commitgraph .column5 { - color: #a0a; -} - -div#cgit table.list td.commitgraph .column6 { - color: #0aa; -} - -div#cgit table.list td.logsubject { - font-family: monospace; - font-weight: bold; -} - -div#cgit table.list td.logmsg { - font-family: monospace; - white-space: pre; - padding: 0 0.5em; -} - -div#cgit table.list td a { - color: black; -} - -div#cgit table.list td a.ls-dir { - font-weight: bold; - color: #00f; -} - -div#cgit table.list td a:hover { - color: #00f; -} - -div#cgit img { - border: none; -} - -div#cgit input#switch-btn { - margin: 2px 0px 0px 0px; -} - -div#cgit td#sidebar input.txt { - width: 100%; - margin: 2px 0px 0px 0px; -} - -div#cgit table#grid { - margin: 0px; -} - -div#cgit td#content { - vertical-align: top; - padding: 1em 2em 1em 1em; - border: none; -} - -div#cgit div#summary { - vertical-align: top; - margin-bottom: 1em; -} - -div#cgit table#downloads { - float: right; - border-collapse: collapse; - border: solid 1px #777; - margin-left: 0.5em; - margin-bottom: 0.5em; -} - -div#cgit table#downloads th { - background-color: #ccc; -} - -div#cgit div#blob { - border: solid 1px black; -} - -div#cgit div.error { - color: red; - font-weight: bold; - margin: 1em 2em; -} - -div#cgit a.ls-blob, div#cgit a.ls-dir, div#cgit a.ls-mod { - font-family: monospace; -} - -div#cgit td.ls-size { - text-align: right; - font-family: monospace; - width: 10em; -} - -div#cgit td.ls-mode { - font-family: monospace; - width: 10em; -} - -div#cgit table.blob { - margin-top: 0.5em; - border-top: solid 1px black; -} - -div#cgit table.blob td.lines { - margin: 0; padding: 0 0 0 0.5em; - vertical-align: top; - color: black; -} - -div#cgit table.blob td.linenumbers { - margin: 0; padding: 0 0.5em 0 0.5em; - vertical-align: top; - text-align: right; - border-right: 1px solid gray; -} - -div#cgit table.blob pre { - padding: 0; margin: 0; -} - -div#cgit table.blob a.no, div#cgit table.ssdiff a.no { - color: gray; - text-align: right; - text-decoration: none; -} - -div#cgit table.blob a.no a:hover { - color: black; -} - -div#cgit table.bin-blob { - margin-top: 0.5em; - border: solid 1px black; -} - -div#cgit table.bin-blob th { - font-family: monospace; - white-space: pre; - border: solid 1px #777; - padding: 0.5em 1em; -} - -div#cgit table.bin-blob td { - font-family: monospace; - white-space: pre; - border-left: solid 1px #777; - padding: 0em 1em; -} - -div#cgit table.nowrap td { - white-space: nowrap; -} - -div#cgit table.commit-info { - border-collapse: collapse; - margin-top: 1.5em; -} - -div#cgit div.cgit-panel { - float: right; - margin-top: 1.5em; -} - -div#cgit div.cgit-panel table { - border-collapse: collapse; - border: solid 1px #aaa; - background-color: #eee; -} - -div#cgit div.cgit-panel th { - text-align: center; -} - -div#cgit div.cgit-panel td { - padding: 0.25em 0.5em; -} - -div#cgit div.cgit-panel td.label { - padding-right: 0.5em; -} - -div#cgit div.cgit-panel td.ctrl { - padding-left: 0.5em; -} - -div#cgit table.commit-info th { - text-align: left; - font-weight: normal; - padding: 0.1em 1em 0.1em 0.1em; - vertical-align: top; -} - -div#cgit table.commit-info td { - font-weight: normal; - padding: 0.1em 1em 0.1em 0.1em; -} - -div#cgit div.commit-subject { - font-weight: bold; - font-size: 125%; - margin: 1.5em 0em 0.5em 0em; - padding: 0em; -} - -div#cgit div.commit-msg { - white-space: pre; - font-family: monospace; -} - -div#cgit div.notes-header { - font-weight: bold; - padding-top: 1.5em; -} - -div#cgit div.notes { - white-space: pre; - font-family: monospace; - border: solid 1px #ee9; - background-color: #ffd; - padding: 0.3em 2em 0.3em 1em; - float: left; -} - -div#cgit div.notes-footer { - clear: left; -} - -div#cgit div.diffstat-header { - font-weight: bold; - padding-top: 1.5em; -} - -div#cgit table.diffstat { - border-collapse: collapse; - border: solid 1px #aaa; - background-color: #eee; -} - -div#cgit table.diffstat th { - font-weight: normal; - text-align: left; - text-decoration: underline; - padding: 0.1em 1em 0.1em 0.1em; - font-size: 100%; -} - -div#cgit table.diffstat td { - padding: 0.2em 0.2em 0.1em 0.1em; - font-size: 100%; - border: none; -} - -div#cgit table.diffstat td.mode { - white-space: nowrap; -} - -div#cgit table.diffstat td span.modechange { - padding-left: 1em; - color: red; -} - -div#cgit table.diffstat td.add a { - color: green; -} - -div#cgit table.diffstat td.del a { - color: red; -} - -div#cgit table.diffstat td.upd a { - color: blue; -} - -div#cgit table.diffstat td.graph { - width: 500px; - vertical-align: middle; -} - -div#cgit table.diffstat td.graph table { - border: none; -} - -div#cgit table.diffstat td.graph td { - padding: 0px; - border: 0px; - height: 7pt; -} - -div#cgit table.diffstat td.graph td.add { - background-color: #5c5; -} - -div#cgit table.diffstat td.graph td.rem { - background-color: #c55; -} - -div#cgit div.diffstat-summary { - color: #888; - padding-top: 0.5em; -} - -div#cgit table.diff { - width: 100%; -} - -div#cgit table.diff td { - font-family: monospace; - white-space: pre; -} - -div#cgit table.diff td div.head { - font-weight: bold; - margin-top: 1em; - color: black; -} - -div#cgit table.diff td div.hunk { - color: #009; -} - -div#cgit table.diff td div.add { - color: green; -} - -div#cgit table.diff td div.del { - color: red; -} - -div#cgit .sha1 { - font-family: monospace; - font-size: 90%; -} - -div#cgit .left { - text-align: left; -} - -div#cgit .right { - text-align: right; - float: none !important; - width: auto !important; - padding: 0 !important; -} - -div#cgit table.list td.reposection { - font-style: italic; - color: #888; -} - -div#cgit a.button { - font-size: 80%; - padding: 0em 0.5em; -} - -div#cgit a.primary { - font-size: 100%; -} - -div#cgit a.secondary { - font-size: 90%; -} - -div#cgit td.toplevel-repo { - -} - -div#cgit table.list td.sublevel-repo { - padding-left: 1.5em; -} - -div#cgit ul.pager { - list-style-type: none; - text-align: center; - margin: 1em 0em 0em 0em; - padding: 0; -} - -div#cgit ul.pager li { - display: inline-block; - margin: 0.25em 0.5em; -} - -div#cgit ul.pager a { - color: #777; -} - -div#cgit ul.pager .current { - font-weight: bold; -} - -div#cgit span.age-mins { - font-weight: bold; - color: #080; -} - -div#cgit span.age-hours { - color: #080; -} - -div#cgit span.age-days { - color: #040; -} - -div#cgit span.age-weeks { - color: #444; -} - -div#cgit span.age-months { - color: #888; -} - -div#cgit span.age-years { - color: #bbb; -} -div#cgit div.footer { - margin-top: 0.5em; - text-align: center; - font-size: 80%; - color: #ccc; -} -div#cgit a.branch-deco { - color: #000; - margin: 0px 0.5em; - padding: 0px 0.25em; - background-color: #88ff88; - border: solid 1px #007700; -} -div#cgit a.tag-deco { - color: #000; - margin: 0px 0.5em; - padding: 0px 0.25em; - background-color: #ffff88; - border: solid 1px #777700; -} -div#cgit a.remote-deco { - color: #000; - margin: 0px 0.5em; - padding: 0px 0.25em; - background-color: #ccccff; - border: solid 1px #000077; -} -div#cgit a.deco { - color: #000; - margin: 0px 0.5em; - padding: 0px 0.25em; - background-color: #ff8888; - border: solid 1px #770000; -} - -div#cgit div.commit-subject a.branch-deco, -div#cgit div.commit-subject a.tag-deco, -div#cgit div.commit-subject a.remote-deco, -div#cgit div.commit-subject a.deco { - margin-left: 1em; - font-size: 75%; -} - -div#cgit table.stats { - border: solid 1px black; - border-collapse: collapse; -} - -div#cgit table.stats th { - text-align: left; - padding: 1px 0.5em; - background-color: #eee; - border: solid 1px black; -} - -div#cgit table.stats td { - text-align: right; - padding: 1px 0.5em; - border: solid 1px black; -} - -div#cgit table.stats td.total { - font-weight: bold; - text-align: left; -} - -div#cgit table.stats td.sum { - color: #c00; - font-weight: bold; -/* background-color: #eee; */ -} - -div#cgit table.stats td.left { - text-align: left; -} - -div#cgit table.vgraph { - border-collapse: separate; - border: solid 1px black; - height: 200px; -} - -div#cgit table.vgraph th { - background-color: #eee; - font-weight: bold; - border: solid 1px white; - padding: 1px 0.5em; -} - -div#cgit table.vgraph td { - vertical-align: bottom; - padding: 0px 10px; -} - -div#cgit table.vgraph div.bar { - background-color: #eee; -} - -div#cgit table.hgraph { - border: solid 1px black; - width: 800px; -} - -div#cgit table.hgraph th { - background-color: #eee; - font-weight: bold; - border: solid 1px black; - padding: 1px 0.5em; -} - -div#cgit table.hgraph td { - vertical-align: middle; - padding: 2px 2px; -} - -div#cgit table.hgraph div.bar { - background-color: #eee; - height: 1em; -} - -div#cgit table.ssdiff { - width: 100%; -} - -div#cgit table.ssdiff td { - font-size: 75%; - font-family: monospace; - white-space: pre; - padding: 1px 4px 1px 4px; - border-left: solid 1px #aaa; - border-right: solid 1px #aaa; -} - -div#cgit table.ssdiff td.add { - color: black; - background: #cfc; - min-width: 50%; -} - -div#cgit table.ssdiff td.add_dark { - color: black; - background: #aca; - min-width: 50%; -} - -div#cgit table.ssdiff span.add { - background: #cfc; - font-weight: bold; -} - -div#cgit table.ssdiff td.del { - color: black; - background: #fcc; - min-width: 50%; -} - -div#cgit table.ssdiff td.del_dark { - color: black; - background: #caa; - min-width: 50%; -} - -div#cgit table.ssdiff span.del { - background: #fcc; - font-weight: bold; -} - -div#cgit table.ssdiff td.changed { - color: black; - background: #ffc; - min-width: 50%; -} - -div#cgit table.ssdiff td.changed_dark { - color: black; - background: #cca; - min-width: 50%; -} - -div#cgit table.ssdiff td.lineno { - color: black; - background: #eee; - text-align: right; - width: 3em; - min-width: 3em; -} - -div#cgit table.ssdiff td.hunk { - color: black; - background: #ccf; - border-top: solid 1px #aaa; - border-bottom: solid 1px #aaa; -} - -div#cgit table.ssdiff td.head { - border-top: solid 1px #aaa; - border-bottom: solid 1px #aaa; -} - -div#cgit table.ssdiff td.head div.head { - font-weight: bold; - color: black; -} - -div#cgit table.ssdiff td.foot { - border-top: solid 1px #aaa; - border-left: none; - border-right: none; - border-bottom: none; -} - -div#cgit table.ssdiff td.space { - border: none; -} - -div#cgit table.ssdiff td.space div { - min-height: 3em; -} - -/* - * Style definitions generated by highlight 3.14, http://www.andre-simon.de/ - * Highlighting theme: Kwrite Editor - */ -div#cgit table.blob .num { color:#b07e00; } -div#cgit table.blob .esc { color:#ff00ff; } -div#cgit table.blob .str { color:#bf0303; } -div#cgit table.blob .pps { color:#818100; } -div#cgit table.blob .slc { color:#838183; font-style:italic; } -div#cgit table.blob .com { color:#838183; font-style:italic; } -div#cgit table.blob .ppc { color:#008200; } -div#cgit table.blob .opt { color:#000000; } -div#cgit table.blob .ipl { color:#0057ae; } -div#cgit table.blob .lin { color:#555555; } -div#cgit table.blob .kwa { color:#000000; font-weight:bold; } -div#cgit table.blob .kwb { color:#0057ae; } -div#cgit table.blob .kwc { color:#000000; font-weight:bold; } -div#cgit table.blob .kwd { color:#010181; } diff --git a/web/html/home.php b/web/html/home.php deleted file mode 100644 index 5ea79ee9..00000000 --- a/web/html/home.php +++ /dev/null @@ -1,215 +0,0 @@ - - -
-
- -
-

-

- 50, - 'SeB' => 'M', - 'K' => username_from_sid($_COOKIE["AURSID"]), - 'outdated' => 'on', - 'SB' => 'l', - 'SO' => 'a' - ); - pkg_search_page($params, false, $_COOKIE["AURSID"]); - ?> -

- -
-
-

-

">

- 50, - 'SeB' => 'm', - 'K' => username_from_sid($_COOKIE["AURSID"]), - 'SB' => 'l', - 'SO' => 'd' - ); - pkg_search_page($params, false, $_COOKIE["AURSID"]); - ?> -
-
-

-

">

- 50, - 'SeB' => 'c', - 'K' => username_from_sid($_COOKIE["AURSID"]), - 'SB' => 'l', - 'SO' => 'd' - ); - pkg_search_page($params, false, $_COOKIE["AURSID"]); - ?> -
- -
-

AUR

-

- ', - '', - '', - '' - ); - ?> - ', '', - '', - '' - ); - ?> - - -

-

- : - -

-

-
-
-

-

-
-

- ', - '' - ); - ?> -

-
    -
  • :
  • -
  • :
  • -
  • :
  • -
-

- ', - '' - ); - ?> -

-
-

-
-

- ', - '' - ); - ?> -

- -

- -

-
    - $fingerprint): ?> -
  • :
  • - -
- -
-

-
-

- ', - '', - '', - '' - ); - ?> -

-
-

-
-

- ', - '', - '', - '' - ); - ?> -

-
-
- -
-
-
-
-
-
- - - " maxlength="35" autocomplete="off"/> -
-
-
-
- -
-
- -
- -
- -
- - -
- - - - - diff --git a/web/html/images/action-undo.svg b/web/html/images/action-undo.svg deleted file mode 100644 index b93ebb78..00000000 --- a/web/html/images/action-undo.svg +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/web/html/images/ajax-loader.gif b/web/html/images/ajax-loader.gif deleted file mode 100644 index df07e7ec2076177c99b53d4d29a45f0db6b06a9a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 723 zcmZ?wbhEHb6kyWo5uik&V|NP^(AHU+;_dI&}>C3lYM=m|vboAbp zdv88|`N04KivPL&TtkAL9RpmA^bD98f#Qn)q@0UV6H8K46v{J8G87WC5-W1@6I1ju z^V0Ge6o0aCasyTAfJ^{6l7UrML7^`tbKa5#T#rsMt#c4)wm4&2aJl;4?H%*^*q;ct zZ+YZ!f=91--8C-PwbPuinV^!8D8ZUAZ$+j|`^0?*ZXH_r=F;-s=Wq7D-W{Q@F^9F$ zTCh`s37bYUpw-=pI*&V4IF+P$l9wbc(l{x7eoOCbBdG(^nGZDWjsAGTTd?u$#mhT{ z{bn8t<<=6J=66T{n^C4fqn2>E3WhNCJ~l~G@x1uTreFAcY2|b4S-i`cPqf%2ZE*i3 z+J9zZu_cRCJ%=P)K~y-6jgvo!6G0Tle=|GDx_9PaSMatt8xuJ=jueWZ*0zF( zjc8@z38oPY2!}RWYjKN}g`kaCi1-H-uCNkOgxf0BeA-5$w9LxMMtXHz@2@3 zyz+UJPuh|vi*mtJavK=cNwf1dpEbZ!a<``>o|1IZ?Bv;J>;8WS9J=%2sOyMVt`f_h zlJvCko4lXZH(|7*(w!f`Tnu;_ptK?Jqw7?)K+hZAu%R^ukDjFp75q4Pbjddz93wNAlTi;8fmk1LdSvP5vdgJg^M# zaG-vgp9c5>)Q7GRMsXQ9!>~RL)NlL5fD7Ck3IMJGg}hz^t^pqh0-C^eU>&Fc%V89s z01(qlD|><0z!Ts~QmejXjKU~B2rL4Jfq5~#v~m%6p46(=A2%lGz#nlao8kSq3cLUS N002ovPDHLkV1na%{Dc4i diff --git a/web/html/images/pencil.min.svg b/web/html/images/pencil.min.svg deleted file mode 100644 index 06125ae0..00000000 --- a/web/html/images/pencil.min.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web/html/images/pencil.svg b/web/html/images/pencil.svg deleted file mode 100644 index 91f08991..00000000 --- a/web/html/images/pencil.svg +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - diff --git a/web/html/images/pin.min.svg b/web/html/images/pin.min.svg deleted file mode 100644 index ac08903d..00000000 --- a/web/html/images/pin.min.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/web/html/images/pin.svg b/web/html/images/pin.svg deleted file mode 100644 index b4ee9eb7..00000000 --- a/web/html/images/pin.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web/html/images/rss.svg b/web/html/images/rss.svg deleted file mode 100644 index 3c7f6ba1..00000000 --- a/web/html/images/rss.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web/html/images/unpin.min.svg b/web/html/images/unpin.min.svg deleted file mode 100644 index 3cf2413c..00000000 --- a/web/html/images/unpin.min.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/web/html/images/unpin.svg b/web/html/images/unpin.svg deleted file mode 100644 index de897152..00000000 --- a/web/html/images/unpin.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/web/html/images/x.min.svg b/web/html/images/x.min.svg deleted file mode 100644 index 833d4f22..00000000 --- a/web/html/images/x.min.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web/html/images/x.svg b/web/html/images/x.svg deleted file mode 100644 index e323fe19..00000000 --- a/web/html/images/x.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/web/html/index.php b/web/html/index.php deleted file mode 100644 index dc435162..00000000 --- a/web/html/index.php +++ /dev/null @@ -1,205 +0,0 @@ - '1'); - } - } - - include get_route('/' . $tokens[1]); -} elseif (!empty($tokens[1]) && '/' . $tokens[1] == get_pkgreq_route()) { - if (!empty($tokens[2])) { - /* TODO: Create a proper data structure to pass variables from - * the routing framework to the individual pages instead of - * initializing arbitrary variables here. */ - if (!empty($tokens[3]) && $tokens[3] == 'close') { - $pkgreq_id = $tokens[2]; - } else { - $pkgreq_id = null; - } - - if (!$pkgreq_id) { - header("HTTP/1.0 404 Not Found"); - include "./404.php"; - return; - } - } - - include get_route('/' . $tokens[1]); -} elseif (!empty($tokens[1]) && '/' . $tokens[1] == get_user_route()) { - if (!empty($tokens[2])) { - $_REQUEST['ID'] = uid_from_username($tokens[2]); - - if (!$_REQUEST['ID']) { - header("HTTP/1.0 404 Not Found"); - include "./404.php"; - return; - } - - if (!empty($tokens[3])) { - if ($tokens[3] == 'edit') { - $_REQUEST['Action'] = "DisplayAccount"; - } elseif ($tokens[3] == 'update') { - $_REQUEST['Action'] = "UpdateAccount"; - } elseif ($tokens[3] == 'delete') { - $_REQUEST['Action'] = "DeleteAccount"; - } elseif ($tokens[3] == 'comments') { - $_REQUEST['Action'] = "ListComments"; - } else { - header("HTTP/1.0 404 Not Found"); - include "./404.php"; - return; - } - } else { - $_REQUEST['Action'] = "AccountInfo"; - } - } - include get_route('/' . $tokens[1]); -} elseif (get_route($path) !== NULL) { - include get_route($path); -} else { - switch ($path) { - case "/css/archweb.css": - case "/css/aurweb.css": - case "/css/cgit.css": - case "/css/archnavbar/archnavbar.css": - header("Content-Type: text/css"); - readfile("./$path"); - break; - case "/images/ajax-loader.gif": - header("Content-Type: image/gif"); - readfile("./$path"); - break; - case "/css/archnavbar/archlogo.png": - case "/css/archnavbar/aurlogo.png": - case "/images/favicon.ico": - header("Content-Type: image/png"); - readfile("./$path"); - break; - case "/images/x.min.svg": - case "/images/action-undo.min.svg": - case "/images/pencil.min.svg": - case "/images/pin.min.svg": - case "/images/unpin.min.svg": - case "/images/rss.svg": - header("Content-Type: image/svg+xml"); - readfile("./$path"); - break; - case "/js/typeahead.js": - header("Content-Type: application/javascript"); - readfile("./$path"); - break; - case "/packages.gz": - case "/packages-meta-v1.json.gz": - case "/packages-meta-ext-v1.json.gz": - case "/pkgbase.gz": - case "/users.gz": - header("Content-Type: text/plain"); - header("Content-Encoding: gzip"); - readfile("./$path"); - break; - default: - header("HTTP/1.0 404 Not Found"); - include "./404.php"; - break; - } -} diff --git a/web/html/js/comment-edit.js b/web/html/js/comment-edit.js deleted file mode 100644 index 23ffdd34..00000000 --- a/web/html/js/comment-edit.js +++ /dev/null @@ -1,61 +0,0 @@ -function add_busy_indicator(sibling) { - const img = document.createElement('img'); - img.src = "/static/images/ajax-loader.gif"; - img.classList.add('ajax-loader'); - img.style.height = 11; - img.style.width = 16; - img.alt = "Busy…"; - - sibling.insertAdjacentElement('afterend', img); -} - -function remove_busy_indicator(sibling) { - const elem = sibling.nextElementSibling; - elem.parentNode.removeChild(elem); -} - -function getParentsUntil(elem, className) { - // Limit to 10 depth - for ( ; elem && elem !== document; elem = elem.parentNode) { - if (elem.matches(className)) { - break; - } - } - - return elem; -} - -function handleEditCommentClick(event, pkgbasename) { - event.preventDefault(); - const parent_element = getParentsUntil(event.target, '.comment-header'); - const parent_id = parent_element.id; - const comment_id = parent_id.substr(parent_id.indexOf('-') + 1); - // The div class="article-content" which contains the comment - const edit_form = parent_element.nextElementSibling; - - const url = "/pkgbase/" + pkgbasename + "/comments/" + comment_id + "/form?"; - - add_busy_indicator(event.target); - - fetch(url + new URLSearchParams({ next: window.location.pathname }), { - method: 'GET', - credentials: 'same-origin' - }) - .then(function(response) { - if (!response.ok) { - throw Error(response.statusText); - } - return response.json(); - }) - .then(function(data) { - remove_busy_indicator(event.target); - edit_form.innerHTML = data.form; - edit_form.querySelector('textarea').focus(); - }) - .catch(function(error) { - remove_busy_indicator(event.target); - console.error(error); - }); - - return false; -} diff --git a/web/html/js/copy.js b/web/html/js/copy.js deleted file mode 100644 index 3b659270..00000000 --- a/web/html/js/copy.js +++ /dev/null @@ -1,9 +0,0 @@ -document.addEventListener('DOMContentLoaded', function() { - let elements = document.querySelectorAll('.copy'); - elements.forEach(function(el) { - el.addEventListener('click', function(e) { - e.preventDefault(); - navigator.clipboard.writeText(e.target.text); - }); - }); -}); diff --git a/web/html/js/typeahead-home.js b/web/html/js/typeahead-home.js deleted file mode 100644 index 5af51c53..00000000 --- a/web/html/js/typeahead-home.js +++ /dev/null @@ -1,6 +0,0 @@ -document.addEventListener('DOMContentLoaded', function() { - const input = document.getElementById('pkgsearch-field'); - const form = document.getElementById('pkgsearch-form'); - const type = 'suggest'; - typeahead.init(type, input, form); -}); diff --git a/web/html/js/typeahead-pkgbase-merge.js b/web/html/js/typeahead-pkgbase-merge.js deleted file mode 100644 index a8c87e4f..00000000 --- a/web/html/js/typeahead-pkgbase-merge.js +++ /dev/null @@ -1,6 +0,0 @@ -document.addEventListener('DOMContentLoaded', function() { - const input = document.getElementById('merge_into'); - const form = document.getElementById('merge-form'); - const type = "suggest-pkgbase"; - typeahead.init(type, input, form, false); -}); diff --git a/web/html/js/typeahead-pkgbase-request.js b/web/html/js/typeahead-pkgbase-request.js deleted file mode 100644 index e012d55f..00000000 --- a/web/html/js/typeahead-pkgbase-request.js +++ /dev/null @@ -1,36 +0,0 @@ -function showHideMergeSection() { - const elem = document.getElementById('id_type'); - const merge_section = document.getElementById('merge_section'); - if (elem.value == 'merge') { - merge_section.style.display = ''; - } else { - merge_section.style.display = 'none'; - } -} - -function showHideRequestHints() { - document.getElementById('deletion_hint').style.display = 'none'; - document.getElementById('merge_hint').style.display = 'none'; - document.getElementById('orphan_hint').style.display = 'none'; - - const elem = document.getElementById('id_type'); - document.getElementById(elem.value + '_hint').style.display = ''; -} - -document.addEventListener('DOMContentLoaded', function() { - showHideMergeSection(); - showHideRequestHints(); - - const input = document.getElementById('id_merge_into'); - const form = document.getElementById('request-form'); - const type = "suggest-pkgbase"; - - typeahead.init(type, input, form, false); -}); - -// Bind the change event here, otherwise we have to inline javascript, -// which angers CSP (Content Security Policy). -document.getElementById("id_type").addEventListener("change", function() { - showHideMergeSection(); - showHideRequestHints(); -}); diff --git a/web/html/js/typeahead.js b/web/html/js/typeahead.js deleted file mode 100644 index bfd3d156..00000000 --- a/web/html/js/typeahead.js +++ /dev/null @@ -1,151 +0,0 @@ -"use strict"; - -const typeahead = (function() { - var input; - var form; - var suggest_type; - var list; - var submit = true; - - function resetResults() { - if (!list) return; - list.style.display = "none"; - list.innerHTML = ""; - } - - function getCompleteList() { - if (!list) { - list = document.createElement("UL"); - list.setAttribute("class", "pkgsearch-typeahead"); - form.appendChild(list); - setListLocation(); - } - return list; - } - - function onListClick(e) { - let target = e.target; - while (!target.getAttribute('data-value')) { - target = target.parentNode; - } - input.value = target.getAttribute('data-value'); - if (submit) { - form.submit(); - } - } - - function setListLocation() { - if (!list) return; - const rects = input.getClientRects()[0]; - list.style.top = (rects.top + rects.height) + "px"; - list.style.left = rects.left + "px"; - } - - function loadData(letter, data) { - const pkgs = data.slice(0, 10); // Show maximum of 10 results - - resetResults(); - - if (pkgs.length === 0) { - return; - } - - const ul = getCompleteList(); - ul.style.display = "block"; - const fragment = document.createDocumentFragment(); - - for (let i = 0; i < pkgs.length; i++) { - const item = document.createElement("li"); - const text = pkgs[i].replace(letter, '' + letter + ''); - item.innerHTML = '' + text + ''; - item.setAttribute('data-value', pkgs[i]); - fragment.appendChild(item); - } - - ul.appendChild(fragment); - ul.addEventListener('click', onListClick); - } - - function fetchData(letter) { - const url = '/rpc?v=5&type=' + suggest_type + '&arg=' + letter; - fetch(url).then(function(response) { - return response.json(); - }).then(function(data) { - loadData(letter, data); - }); - } - - function onInputClick() { - if (input.value === "") { - resetResults(); - return; - } - fetchData(input.value); - } - - function onKeyDown(e) { - if (!list) return; - - const elem = document.querySelector(".pkgsearch-typeahead li.active"); - switch(e.keyCode) { - case 13: // enter - if (!submit) { - return; - } - if (elem) { - input.value = elem.getAttribute('data-value'); - form.submit(); - } else { - form.submit(); - } - e.preventDefault(); - break; - case 38: // up - if (elem && elem.previousElementSibling) { - elem.className = ""; - elem.previousElementSibling.className = "active"; - } - e.preventDefault(); - break; - case 40: // down - if (elem && elem.nextElementSibling) { - elem.className = ""; - elem.nextElementSibling.className = "active"; - } else if (!elem && list.childElementCount !== 0) { - list.children[0].className = "active"; - } - e.preventDefault(); - break; - } - } - - // debounce https://davidwalsh.name/javascript-debounce-function - function debounce(func, wait, immediate) { - var timeout; - return function() { - var context = this, args = arguments; - var later = function() { - timeout = null; - if (!immediate) func.apply(context, args); - }; - var callNow = immediate && !timeout; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - if (callNow) func.apply(context, args); - }; - } - - return { - init: function(type, inputfield, formfield, submitdata = true) { - suggest_type = type; - input = inputfield; - form = formfield; - submit = submitdata; - - input.addEventListener("input", onInputClick); - input.addEventListener("keydown", onKeyDown); - window.addEventListener('resize', debounce(setListLocation, 150)); - document.addEventListener("click", resetResults); - } - } -}()); diff --git a/web/html/login.php b/web/html/login.php deleted file mode 100644 index 3f3d66cc..00000000 --- a/web/html/login.php +++ /dev/null @@ -1,68 +0,0 @@ - -
-

AUR

- -

- ' . username_from_sid($_COOKIE["AURSID"]) . ''); ?> - [] -

- -
-
- - -
- -

- - -

-

- - -

-

- - -

-

- " /> - [] - - [] - - - - -

-
-
- -

- ', ''); ?> -

- -
-query("SELECT SSOAccountID FROM Users WHERE ID = " . $dbh->quote($uid)) - ->fetchColumn(); - if ($sso_account_id) - $redirect_uri = '/sso/logout'; - } -} - -header("Location: $redirect_uri"); diff --git a/web/html/modified-rss.php b/web/html/modified-rss.php deleted file mode 100644 index 4c5c47e0..00000000 --- a/web/html/modified-rss.php +++ /dev/null @@ -1,62 +0,0 @@ -cssStyleSheet = false; -$rss->xslStyleSheet = false; - -# Use UTF-8 (fixes FS#10706). -$rss->encoding = "UTF-8"; - -#All the general RSS setup -$rss->title = "AUR Latest Modified Packages"; -$rss->description = "The latest modified packages in the AUR"; -$rss->link = "${protocol}://{$host}"; -$rss->syndicationURL = "{$protocol}://{$host}" . get_uri('/rss/'); -$image = new FeedImage(); -$image->title = "AUR Latest Modified Packages"; -$image->url = "{$protocol}://{$host}/css/archnavbar/aurlogo.png"; -$image->link = $rss->link; -$image->description = "AUR Latest Modified Packages Feed"; -$rss->image = $image; - -#Get the latest packages and add items for them -$packages = latest_modified_pkgs(100); - -foreach ($packages as $indx => $row) { - $item = new FeedItem(); - $item->title = $row["Name"]; - $item->link = "{$protocol}://{$host}" . get_pkg_uri($row["Name"]); - $item->description = $row["Description"]; - $item->date = intval($row["ModifiedTS"]); - $item->source = "{$protocol}://{$host}"; - $item->author = username_from_id($row["MaintainerUID"]); - $item->guidIsPermaLink = true; - $item->guid = $row["Name"] . "-" . $row["ModifiedTS"]; - $rss->addItem($item); -} - -#save it so that useCached() can find it -$feedContent = $rss->createFeed(); -set_cache_value($feed_key, $feedContent, 600); -echo $feedContent; -?> diff --git a/web/html/packages.php b/web/html/packages.php deleted file mode 100644 index 24d1f82e..00000000 --- a/web/html/packages.php +++ /dev/null @@ -1,173 +0,0 @@ - - - - -\n"; - } -} else { - if (!isset($_GET['K']) && !isset($_GET['SB'])) { - $_GET['SB'] = 'p'; - $_GET['SO'] = 'd'; - } - echo '
'; - if (isset($_COOKIE["AURSID"])) { - pkg_search_page($_GET, true, $_COOKIE["AURSID"]); - } else { - pkg_search_page($_GET, true); - } - echo '
'; -} - -html_footer(AURWEB_VERSION); diff --git a/web/html/passreset.php b/web/html/passreset.php deleted file mode 100644 index 26b9bbbb..00000000 --- a/web/html/passreset.php +++ /dev/null @@ -1,100 +0,0 @@ - - -
-

- - -

- -

- - -
- -
- - - - - - - - - - - - - -
-
- -
- -

', - ''); ?>

- -
- -
-

-

- -
- -
- - $i) { - $id = intval($id); - if ($id > 0) { - $ids[] = $id; - } - } -} - -/* Perform package base actions. */ -$via = isset($_POST['via']) ? $_POST['via'] : NULL; -$return_to = isset($_POST['return_to']) ? $_POST['return_to'] : NULL; -$ret = false; -$output = ""; -$fragment = ""; -if (check_token()) { - if (current_action("do_Flag")) { - list($ret, $output) = pkgbase_flag($ids, $_POST['comments']); - } elseif (current_action("do_UnFlag")) { - list($ret, $output) = pkgbase_unflag($ids); - } elseif (current_action("do_Adopt")) { - list($ret, $output) = pkgbase_adopt($ids, true, NULL); - } elseif (current_action("do_Disown")) { - if (isset($_POST['confirm'])) { - list($ret, $output) = pkgbase_adopt($ids, false, $via); - } else { - $output = __("The selected packages have not been disowned, check the confirmation checkbox."); - $ret = false; - } - } elseif (current_action("do_DisownComaintainer")) { - $uid = uid_from_sid($_COOKIE["AURSID"]); - list($ret, $output) = pkgbase_remove_comaintainer($base_id, $uid); - } elseif (current_action("do_Vote")) { - list($ret, $output) = pkgbase_vote($ids, true); - } elseif (current_action("do_UnVote")) { - list($ret, $output) = pkgbase_vote($ids, false); - } elseif (current_action("do_Delete")) { - if (isset($_POST['confirm'])) { - if (!isset($_POST['merge_Into']) || empty($_POST['merge_Into'])) { - list($ret, $output) = pkgbase_delete($ids, NULL, $via); - unset($_GET['ID']); - unset($base_id); - } - else { - $merge_base_id = pkgbase_from_name($_POST['merge_Into']); - if (!$merge_base_id) { - $output = __("Cannot find package to merge votes and comments into."); - $ret = false; - } elseif (in_array($merge_base_id, $ids)) { - $output = __("Cannot merge a package base with itself."); - $ret = false; - } else { - list($ret, $output) = pkgbase_delete($ids, $merge_base_id, $via); - unset($_GET['ID']); - unset($base_id); - } - } - } - else { - $output = __("The selected packages have not been deleted, check the confirmation checkbox."); - $ret = false; - } - } elseif (current_action("do_Notify")) { - list($ret, $output) = pkgbase_notify($ids); - } elseif (current_action("do_UnNotify")) { - list($ret, $output) = pkgbase_notify($ids, false); - } elseif (current_action("do_DeleteComment")) { - list($ret, $output) = pkgbase_delete_comment(); - } elseif (current_action("do_UndeleteComment")) { - list($ret, $output) = pkgbase_delete_comment(true); - if ($ret && isset($_POST["comment_id"])) { - $fragment = '#comment-' . intval($_POST["comment_id"]); - } - } elseif (current_action("do_PinComment")) { - list($ret, $output) = pkgbase_pin_comment(); - } elseif (current_action("do_UnpinComment")) { - list($ret, $output) = pkgbase_pin_comment(true); - } elseif (current_action("do_SetKeywords")) { - list($ret, $output) = pkgbase_set_keywords($base_id, preg_split("/[\s,;]+/", $_POST['keywords'], -1, PREG_SPLIT_NO_EMPTY)); - } elseif (current_action("do_FileRequest")) { - list($ret, $output) = pkgreq_file($ids, $_POST['type'], $_POST['merge_into'], $_POST['comments']); - } elseif (current_action("do_CloseRequest")) { - list($ret, $output) = pkgreq_close($_POST['reqid'], $_POST['reason'], $_POST['comments']); - } elseif (current_action("do_EditComaintainers")) { - list($ret, $output) = pkgbase_set_comaintainers($base_id, explode("\n", $_POST['users'])); - } elseif (current_action("do_AddComment")) { - $uid = uid_from_sid($_COOKIE["AURSID"]); - list($ret, $output) = pkgbase_add_comment($base_id, $uid, $_REQUEST['comment']); - if ($ret && isset($_REQUEST['enable_notifications'])) { - list($ret, $output) = pkgbase_notify(array($base_id)); - } - $fragment = '#news'; - } elseif (current_action("do_EditComment")) { - list($ret, $output) = pkgbase_edit_comment($_REQUEST['comment']); - if ($ret && isset($_POST["comment_id"])) { - $fragment = '#comment-' . intval($_POST["comment_id"]); - } - } - - if ($ret) { - if (current_action("do_CloseRequest") || - (current_action("do_Delete") && $via)) { - /* Redirect back to package request page on success. */ - header('Location: ' . get_pkgreq_route()); - exit(); - } elseif ((current_action("do_DeleteComment") || - current_action("do_UndeleteComment")) && $return_to) { - header('Location: ' . $return_to); - exit(); - } elseif (current_action("do_PinComment") && $return_to) { - header('Location: ' . $return_to); - exit(); - } elseif (isset($base_id)) { - /* Redirect back to package base page on success. */ - header('Location: ' . get_pkgbase_uri($pkgbase_name) . $fragment); - exit(); - } else { - /* Redirect back to package search page. */ - header('Location: ' . get_pkg_route()); - exit(); - } - } -} - -if (isset($base_id)) { - $pkgs = pkgbase_get_pkgnames($base_id); - if (!$output && count($pkgs) == 1) { - /* Not a split package. Redirect to the package page. */ - if (empty($_SERVER['QUERY_STRING'])) { - header('Location: ' . get_pkg_uri($pkgs[0]) . $fragment); - } else { - header('Location: ' . get_pkg_uri($pkgs[0]) . '?' . $_SERVER['QUERY_STRING'] . $fragment); - } - } - - $details = pkgbase_get_details($base_id); -} else { - $details = array(); -} -html_header($title, $details); -?> - - - -

- -
- - - - -
-

:

-

- ', htmlspecialchars($pkgbase_name), ''); ?> -

-
    - -
  • - -
-

- - -

-
-
- - - - - - -

-

" />

-
-
-
- - -
-

:

-

- ', htmlspecialchars($pkgbase_name), ''); ?> -

-
    - -
  • - -
-

- - - - 0 && !has_credential(CRED_PKGBASE_DISOWN)): ?> - ', $comaintainers[0], ''); ?> - - - -

-
-
- - - - - - -

" />

-
-
-
- - $i) { - $id = intval($id); - if ($id > 0) { - $ids[] = $id; - } - } -} - -/* Perform package base actions. */ -$ret = false; -$output = ""; -if (check_token()) { - if (current_action("do_Flag")) { - list($ret, $output) = pkgbase_flag($ids, $_POST['comments']); - } - - if ($ret) { - header('Location: ' . get_pkgbase_uri($pkgbase_name)); - exit(); - } -} - -/* Get default comment. */ -$comment = ''; -if (isset($_POST['comments'])) { - $comment = $_POST['comments']; -} - -html_header(__("Flag Package Out-Of-Date")); - -if (has_credential(CRED_PKGBASE_FLAG)): ?> -
-

:

-

- ', htmlspecialchars($pkgbase_name), ''); ?> -

-
    - -
  • - -
- -

- 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. -

- -

- ', ''); ?> - -

- - -
- - -
-
- - - -

- - -

-

" />

-
-
-
- - -
-

:

-

- ', htmlspecialchars($pkgbase_name), ''); ?> - -

-
    - -
  • - -
-

- - - -

-
-
- - - - - - - - -

-

-

-

" />

-
-
-
- - 0) ? $_GET['PP'] : 50; - $current = ceil($first / $per_page); - $pages = ceil($total / $per_page); - $templ_pages = array(); - - if ($current > 1) { - $templ_pages['« ' . __('First')] = 0; - $templ_pages['‹ ' . __('Previous')] = ($current - 2) * $per_page; - } - - if ($current - 5 > 1) - $templ_pages["..."] = false; - - for ($i = max($current - 5, 1); $i <= min($pages, $current + 5); $i++) { - $templ_pages[$i] = ($i - 1) * $per_page; - } - - if ($current + 5 < $pages) - $templ_pages["... "] = false; - - if ($current < $pages) { - $templ_pages[__('Next') . ' ›'] = $current * $per_page; - $templ_pages[__('Last') . ' »'] = ($pages - 1) * $per_page; - } - - $SID = $_COOKIE['AURSID']; - - html_header(__("Requests")); - echo '
'; - $show_headers = true; - include('pkgreq_results.php'); - echo '
'; -} - -html_footer(AURWEB_VERSION); diff --git a/web/html/register.php b/web/html/register.php deleted file mode 100644 index fee0a68f..00000000 --- a/web/html/register.php +++ /dev/null @@ -1,87 +0,0 @@ -'; -echo '

' . __('Register') . '

'; - -if (in_request("Action") == "NewAccount") { - list($success, $message) = process_account_form( - "new", - "NewAccount", - in_request("U"), - 1, - 0, - in_request("E"), - in_request("BE"), - in_request("H"), - '', - '', - in_request("R"), - in_request("L"), - in_request("TZ"), - in_request("HP"), - in_request("I"), - in_request("K"), - in_request("PK"), - 0, - in_request("CN"), - in_request("UN"), - in_request("ON"), - 0, - "", - '', - in_request("captcha_salt"), - in_request("captcha"), - ); - - print $message; - - if (!$success) { - display_account_form("NewAccount", - in_request("U"), - 1, - 0, - in_request("E"), - in_request("BE"), - in_request("H"), - '', - '', - in_request("R"), - in_request("L"), - in_request("TZ"), - in_request("HP"), - in_request("I"), - in_request("K"), - in_request("PK"), - 0, - in_request("CN"), - in_request("UN"), - in_request("ON"), - 0, - "", - '', - in_request("captcha_salt"), - in_request("captcha") - ); - } -} else { - print '

' . __("Use this form to create an account.") . '

'; - display_account_form("NewAccount", "", "", "", "", "", "", "", "", "", $LANG); -} - -echo ''; - -html_footer(AURWEB_VERSION); - -?> diff --git a/web/html/rpc.php b/web/html/rpc.php deleted file mode 100644 index 64c95622..00000000 --- a/web/html/rpc.php +++ /dev/null @@ -1,17 +0,0 @@ -handle($_GET); -} -else { - echo file_get_contents('../../doc/rpc.html'); -} -?> diff --git a/web/html/rss.php b/web/html/rss.php deleted file mode 100644 index 1e6335cf..00000000 --- a/web/html/rss.php +++ /dev/null @@ -1,61 +0,0 @@ -cssStyleSheet = false; -$rss->xslStyleSheet = false; - -# Use UTF-8 (fixes FS#10706). -$rss->encoding = "UTF-8"; - -#All the general RSS setup -$rss->title = "AUR Newest Packages"; -$rss->description = "The latest and greatest packages in the AUR"; -$rss->link = "${protocol}://{$host}"; -$rss->syndicationURL = "{$protocol}://{$host}" . get_uri('/rss/'); -$image = new FeedImage(); -$image->title = "AUR Newest Packages"; -$image->url = "{$protocol}://{$host}/css/archnavbar/aurlogo.png"; -$image->link = $rss->link; -$image->description = "AUR Newest Packages Feed"; -$rss->image = $image; - -#Get the latest packages and add items for them -$packages = latest_pkgs(100); - -foreach ($packages as $indx => $row) { - $item = new FeedItem(); - $item->title = $row["Name"]; - $item->link = "{$protocol}://{$host}" . get_pkg_uri($row["Name"]); - $item->description = $row["Description"]; - $item->date = intval($row["SubmittedTS"]); - $item->source = "{$protocol}://{$host}"; - $item->author = username_from_id($row["MaintainerUID"]); - $item->guid = $item->link; - $rss->addItem($item); -} - -#save it so that useCached() can find it -$feedContent = $rss->createFeed(); -set_cache_value($feed_key, $feedContent, 600); -echo $feedContent; -?> diff --git a/web/html/tos.php b/web/html/tos.php deleted file mode 100644 index fc5d8765..00000000 --- a/web/html/tos.php +++ /dev/null @@ -1,50 +0,0 @@ - -
-

AUR

- -
-
-

- ' . username_from_sid($_COOKIE["AURSID"]) . ''); ?> -

-

- -

-
    - -
  • "> ()
  • - -
-

- - ]" value="" /> - - -

-

- " /> -

-
-
- -
- time() ? 1 : 0; - - # List voters of a proposal. - $whovoted = voter_list($row['ID']); - - $canvote = 1; - $hasvoted = 0; - $errorvote = ""; - if ($isrunning == 0) { - $canvote = 0; - $errorvote = __("Voting is closed for this proposal."); - } else if (!has_credential(CRED_TU_VOTE)) { - $canvote = 0; - $errorvote = __("Only Trusted Users are allowed to vote."); - } else if ($row['User'] == username_from_sid($_COOKIE["AURSID"])) { - $canvote = 0; - $errorvote = __("You cannot vote in an proposal about you."); - } - if (tu_voted($row['ID'], uid_from_sid($_COOKIE["AURSID"]))) { - $canvote = 0; - $hasvoted = 1; - if ($isrunning) { - $errorvote = __("You've already voted for this proposal."); - } - } - - if ($canvote == 1) { - if (isset($_POST['doVote']) && check_token()) { - if (isset($_POST['voteYes'])) { - $myvote = "Yes"; - } else if (isset($_POST['voteNo'])) { - $myvote = "No"; - } else if (isset($_POST['voteAbstain'])) { - $myvote = "Abstain"; - } - - cast_proposal_vote($row['ID'], uid_from_sid($_COOKIE["AURSID"]), $myvote, $row[$myvote] + 1); - - # Can't vote anymore - # - $canvote = 0; - $errorvote = __("You've already voted for this proposal."); - - # Update if they voted - if (tu_voted($row['ID'], uid_from_sid($_COOKIE["AURSID"]))) { - $hasvoted = 1; - } - $row = vote_details($_GET['id']); - } - } - include("tu_details.php"); - } - } else { - print __("Vote ID not valid."); - } - - } else { - $limit = $pp; - if (isset($_GET['off'])) - $offset = $_GET['off']; - - if (isset($_GET['by'])) - $by = $_GET['by']; - else - $by = 'desc'; - - if (!empty($offset) && is_numeric($offset)) { - if ($offset >= 1) { - $off = $offset; - } else { - $off = 0; - } - } else { - $off = 0; - } - - $order = ($by == 'asc') ? 'ASC' : 'DESC'; - $lim = ($limit > 0) ? " LIMIT $limit OFFSET $off" : ""; - $by_next = ($by == 'desc') ? 'asc' : 'desc'; - - $result = current_proposal_list($order); - $type = __("Current Votes"); - $nextresult = 0; - include("tu_list.php"); - - $result = past_proposal_list($order, $lim); - $type = __("Past Votes"); - $nextresult = proposal_count(); - include("tu_list.php"); - - $result = last_votes_list(); - include("tu_last_votes_list.php"); - } -} -else { - header('Location: /'); -} - -html_footer(AURWEB_VERSION); diff --git a/web/html/voters.php b/web/html/voters.php deleted file mode 100644 index bacbcfc8..00000000 --- a/web/html/voters.php +++ /dev/null @@ -1,34 +0,0 @@ - - -
-

Votes for

-
-
    - $row): ?> -
  • - - 0): ?> - () - -
  • - -
-
-
- -exec("SET NAMES 'utf8' COLLATE 'utf8_general_ci';"); - } else if ($backend == "sqlite") { - $dsn = $backend . - ":" . $name; - - self::$dbh = new PDO($dsn, null, null); - } else { - die("Error - " . $backend . " is not supported by aurweb"); - } - - } catch (PDOException $e) { - die('Error - Could not connect to AUR database'); - } - } - - return self::$dbh; - } -} diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php deleted file mode 100644 index 0d021f99..00000000 --- a/web/lib/acctfuncs.inc.php +++ /dev/null @@ -1,1522 +0,0 @@ -\n" - . "
  • " . __("It must be between %s and %s characters long", $length_min, $length_max) - . "
  • " - . "
  • " . __("Start and end with a letter or number") . "
  • " - . "
  • " . __("Can contain only one period, underscore or hyphen.") - . "
  • \n"; - } - - if (!$error && $P && !$C) { - $error = __("Please confirm your new password."); - } - if (!$error && $P && $P != $C) { - $error = __("Password fields do not match."); - } - if (!$error && $P != '' && !good_passwd($P)) { - $length_min = config_get_int('options', 'passwd_min_len'); - $error = __("Your password must be at least %s characters.", - $length_min); - } - - if (!$error && !valid_email($E)) { - $error = __("The email address is invalid."); - } - if (!$error && $BE && !valid_email($BE)) { - $error = __("The backup email address is invalid."); - } - - if (!$error && !empty($HP) && !valid_homepage($HP)) { - $error = __("The home page is invalid, please specify the full HTTP(s) URL."); - } - - if (!$error && $K != '' && !valid_pgp_fingerprint($K)) { - $error = __("The PGP key fingerprint is invalid."); - } - - if (!$error && !empty($PK)) { - $ssh_keys = array_filter(array_map('trim', explode("\n", $PK))); - $ssh_fingerprints = array(); - - foreach ($ssh_keys as &$ssh_key) { - if (!valid_ssh_pubkey($ssh_key)) { - $error = __("The SSH public key is invalid."); - break; - } - - $ssh_fingerprint = ssh_key_fingerprint($ssh_key); - if (!$ssh_fingerprint) { - $error = __("The SSH public key is invalid."); - break; - } - - $tokens = explode(" ", $ssh_key); - $ssh_key = $tokens[0] . " " . $tokens[1]; - - $ssh_fingerprints[] = $ssh_fingerprint; - } - - /* - * Destroy last reference to prevent accidentally overwriting - * an array element. - */ - unset($ssh_key); - } - - if (isset($_COOKIE['AURSID'])) { - $atype = account_from_sid($_COOKIE['AURSID']); - if (($atype == "User" && $T > 1) || ($atype == "Trusted User" && $T > 2)) { - $error = __("Cannot increase account permissions."); - } - } - - if (!$error && !array_key_exists($L, $SUPPORTED_LANGS)) { - $error = __("Language is not currently supported."); - } - if (!$error && !array_key_exists($TZ, generate_timezone_list())) { - $error = __("Timezone is not currently supported."); - } - if (!$error) { - /* - * Check whether the user name is available. - * TODO: Fix race condition. - */ - $q = "SELECT COUNT(*) AS CNT FROM Users "; - $q.= "WHERE Username = " . $dbh->quote($U); - if ($TYPE == "edit") { - $q.= " AND ID != ".intval($UID); - } - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - - if ($row[0]) { - $error = __("The username, %s%s%s, is already in use.", - "", htmlspecialchars($U,ENT_QUOTES), ""); - } - } - if (!$error) { - /* - * Check whether the e-mail address is available. - * TODO: Fix race condition. - */ - $q = "SELECT COUNT(*) AS CNT FROM Users "; - $q.= "WHERE Email = " . $dbh->quote($E); - if ($TYPE == "edit") { - $q.= " AND ID != ".intval($UID); - } - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - - if ($row[0]) { - $error = __("The address, %s%s%s, is already in use.", - "", htmlspecialchars($E,ENT_QUOTES), ""); - } - } - if (!$error && isset($ssh_keys) && count($ssh_keys) > 0) { - /* - * Check whether any of the SSH public keys is already in use. - * TODO: Fix race condition. - */ - $q = "SELECT Fingerprint FROM SSHPubKeys "; - $q.= "WHERE Fingerprint IN ("; - $q.= implode(',', array_map(array($dbh, 'quote'), $ssh_fingerprints)); - $q.= ")"; - if ($TYPE == "edit") { - $q.= " AND UserID != " . intval($UID); - } - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - - if ($row) { - $error = __("The SSH public key, %s%s%s, is already in use.", - "", htmlspecialchars($row[0], ENT_QUOTES), ""); - } - } - - if (!$error && $TYPE == "new" && empty($captcha)) { - $error = __("The CAPTCHA is missing."); - } - - if (!$error && $TYPE == "new" && !in_array($captcha_salt, get_captcha_salts())) { - $error = __("This CAPTCHA has expired. Please try again."); - } - - if (!$error && $TYPE == "new" && $captcha != get_captcha_answer($captcha_salt)) { - $error = __("The entered CAPTCHA answer is invalid."); - } - - if ($error) { - $message = "
    • ".$error."
    \n"; - return array(false, $message); - } - - if ($TYPE == "new") { - /* Create an unprivileged user. */ - if (empty($P)) { - $send_resetkey = true; - $email = $E; - } else { - $send_resetkey = false; - $P = password_hash($P, PASSWORD_DEFAULT); - } - $U = $dbh->quote($U); - $E = $dbh->quote($E); - $BE = $dbh->quote($BE); - $P = $dbh->quote($P); - $R = $dbh->quote($R); - $L = $dbh->quote($L); - $TZ = $dbh->quote($TZ); - $HP = $dbh->quote($HP); - $I = $dbh->quote($I); - $K = $dbh->quote(str_replace(" ", "", $K)); - $q = "INSERT INTO Users (AccountTypeID, Suspended, "; - $q.= "InactivityTS, Username, Email, BackupEmail, Passwd , "; - $q.= "RealName, LangPreference, Timezone, Homepage, IRCNick, PGPKey) "; - $q.= "VALUES (1, 0, 0, $U, $E, $BE, $P, $R, $L, $TZ, "; - $q.= "$HP, $I, $K)"; - $result = $dbh->exec($q); - if (!$result) { - $message = __("Error trying to create account, %s%s%s.", - "", htmlspecialchars($U,ENT_QUOTES), ""); - return array(false, $message); - } - - $uid = $dbh->lastInsertId(); - if (isset($ssh_keys) && count($ssh_keys) > 0) { - account_set_ssh_keys($uid, $ssh_keys, $ssh_fingerprints); - } - - $message = __("The account, %s%s%s, has been successfully created.", - "", htmlspecialchars($U,ENT_QUOTES), ""); - $message .= "

    \n"; - - if ($send_resetkey) { - send_resetkey($email, true); - $message .= __("A password reset key has been sent to your e-mail address."); - $message .= "

    \n"; - } else { - $message .= __("Click on the Login link above to use your account."); - $message .= "

    \n"; - } - } else { - /* Modify an existing account. */ - $q = "SELECT InactivityTS FROM Users WHERE "; - $q.= "ID = " . intval($UID); - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - if ($row[0] && $J) { - $inactivity_ts = $row[0]; - } elseif ($J) { - $inactivity_ts = time(); - } else { - $inactivity_ts = 0; - } - - $q = "UPDATE Users SET "; - $q.= "Username = " . $dbh->quote($U); - if ($T) { - $q.= ", AccountTypeID = ".intval($T); - } - if ($S) { - /* Ensure suspended users can't keep an active session */ - delete_user_sessions($UID); - $q.= ", Suspended = 1"; - } else { - $q.= ", Suspended = 0"; - } - $q.= ", Email = " . $dbh->quote($E); - $q.= ", BackupEmail = " . $dbh->quote($BE); - if ($H) { - $q.= ", HideEmail = 1"; - } else { - $q.= ", HideEmail = 0"; - } - if ($P) { - $hash = password_hash($P, PASSWORD_DEFAULT); - $q .= ", Passwd = " . $dbh->quote($hash); - } - $q.= ", RealName = " . $dbh->quote($R); - $q.= ", LangPreference = " . $dbh->quote($L); - $q.= ", Timezone = " . $dbh->quote($TZ); - $q.= ", Homepage = " . $dbh->quote($HP); - $q.= ", IRCNick = " . $dbh->quote($I); - $q.= ", PGPKey = " . $dbh->quote(str_replace(" ", "", $K)); - $q.= ", InactivityTS = " . $inactivity_ts; - $q.= ", CommentNotify = " . ($CN ? "1" : "0"); - $q.= ", UpdateNotify = " . ($UN ? "1" : "0"); - $q.= ", OwnershipNotify = " . ($ON ? "1" : "0"); - $q.= " WHERE ID = ".intval($UID); - $result = $dbh->exec($q); - - if (isset($ssh_keys) && count($ssh_keys) > 0) { - $ssh_key_result = account_set_ssh_keys($UID, $ssh_keys, $ssh_fingerprints); - } else { - $ssh_key_result = true; - } - - if (isset($_COOKIE["AURTZ"]) && ($_COOKIE["AURTZ"] != $TZ)) { - /* set new cookie for timezone */ - $timeout = intval(config_get("options", "persistent_cookie_timeout")); - $cookie_time = time() + $timeout; - setcookie("AURTZ", $TZ, $cookie_time, "/"); - } - - if (isset($_COOKIE["AURLANG"]) && ($_COOKIE["AURLANG"] != $L)) { - /* set new cookie for language */ - $timeout = intval(config_get("options", "persistent_cookie_timeout")); - $cookie_time = time() + $timeout; - setcookie("AURLANG", $L, $cookie_time, "/"); - } - - if ($result === false || $ssh_key_result === false) { - $message = __("No changes were made to the account, %s%s%s.", - "", htmlspecialchars($U,ENT_QUOTES), ""); - } else { - $message = __("The account, %s%s%s, has been successfully modified.", - "", htmlspecialchars($U,ENT_QUOTES), ""); - } - } - - return array(true, $message); -} - -/** - * Display the search results page - * - * @param string $O The offset for the results page - * @param string $SB The column to sort the results page by - * @param string $U The username search criteria - * @param string $T The account type search criteria - * @param string $S Whether the account is suspended search criteria - * @param string $E The e-mail address search criteria - * @param string $R The real name search criteria - * @param string $I The IRC nickname search criteria - * @param string $K The PGP key fingerprint search criteria - * - * @return void - */ -function search_results_page($O=0,$SB="",$U="",$T="", - $S="",$E="",$R="",$I="",$K="") { - - $HITS_PER_PAGE = 50; - if ($O) { - $OFFSET = intval($O); - } else { - $OFFSET = 0; - } - if ($OFFSET < 0) { - $OFFSET = 0; - } - $search_vars = array(); - - $dbh = DB::connect(); - - $q = "SELECT Users.*, AccountTypes.AccountType "; - $q.= "FROM Users, AccountTypes "; - $q.= "WHERE AccountTypes.ID = Users.AccountTypeID "; - if ($T == "u") { - $q.= "AND AccountTypes.ID = 1 "; - $search_vars[] = "T"; - } elseif ($T == "t") { - $q.= "AND AccountTypes.ID = 2 "; - $search_vars[] = "T"; - } elseif ($T == "d") { - $q.= "AND AccountTypes.ID = 3 "; - $search_vars[] = "T"; - } elseif ($T == "td") { - $q.= "AND AccountTypes.ID = 4 "; - $search_vars[] = "T"; - } - if ($S) { - $q.= "AND Users.Suspended = 1 "; - $search_vars[] = "S"; - } - if ($U) { - $U = "%" . addcslashes($U, '%_') . "%"; - $q.= "AND Username LIKE " . $dbh->quote($U) . " "; - $search_vars[] = "U"; - } - if ($E) { - $E = "%" . addcslashes($E, '%_') . "%"; - $q.= "AND Email LIKE " . $dbh->quote($E) . " "; - $search_vars[] = "E"; - } - if ($R) { - $R = "%" . addcslashes($R, '%_') . "%"; - $q.= "AND RealName LIKE " . $dbh->quote($R) . " "; - $search_vars[] = "R"; - } - if ($I) { - $I = "%" . addcslashes($I, '%_') . "%"; - $q.= "AND IRCNick LIKE " . $dbh->quote($I) . " "; - $search_vars[] = "I"; - } - if ($K) { - $K = "%" . addcslashes(str_replace(" ", "", $K), '%_') . "%"; - $q.= "AND PGPKey LIKE " . $dbh->quote($K) . " "; - $search_vars[] = "K"; - } - switch ($SB) { - case 't': - $q.= "ORDER BY AccountTypeID, Username "; - break; - case 'r': - $q.= "ORDER BY RealName, AccountTypeID "; - break; - case 'i': - $q.= "ORDER BY IRCNick, AccountTypeID "; - break; - default: - $q.= "ORDER BY Username, AccountTypeID "; - break; - } - $search_vars[] = "SB"; - $q.= "LIMIT " . $HITS_PER_PAGE . " OFFSET " . $OFFSET; - - $dbh = DB::connect(); - - $result = $dbh->query($q); - - $userinfo = array(); - if ($result) { - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $userinfo[] = $row; - } - } - - include("account_search_results.php"); - return; -} - -/** - * Attempt to login and generate a session - * - * @return array Session ID for user, error message if applicable - */ -function try_login() { - $login_error = ""; - $new_sid = ""; - $userID = null; - - if (!isset($_REQUEST['user']) && !isset($_REQUEST['passwd'])) { - return array('SID' => '', 'error' => null); - } - - if (is_ipbanned()) { - $login_error = __('The login form is currently disabled ' . - 'for your IP address, probably due ' . - 'to sustained spam attacks. Sorry for the ' . - 'inconvenience.'); - return array('SID' => '', 'error' => $login_error); - } - - $dbh = DB::connect(); - $userID = uid_from_loginname($_REQUEST['user']); - - if (user_suspended($userID)) { - $login_error = __('Account suspended'); - return array('SID' => '', 'error' => $login_error); - } - - switch (check_passwd($userID, $_REQUEST['passwd'])) { - case -1: - $login_error = __('Your password has been reset. ' . - 'If you just created a new account, please ' . - 'use the link from the confirmation email ' . - 'to set an initial password. Otherwise, ' . - 'please request a reset key on the %s' . - 'Password Reset%s page.', '', - ''); - return array('SID' => '', 'error' => $login_error); - case 0: - $login_error = __("Bad username or password."); - return array('SID' => '', 'error' => $login_error); - case 1: - break; - } - - $logged_in = 0; - $num_tries = 0; - - /* Generate a session ID and store it. */ - while (!$logged_in && $num_tries < 5) { - $new_sid = new_sid(); - $q = "INSERT INTO Sessions (UsersID, SessionID, LastUpdateTS)" - ." VALUES (" . $userID . ", '" . $new_sid . "', " . strval(time()) . ")"; - $result = $dbh->exec($q); - - /* Query will fail if $new_sid is not unique. */ - if ($result) { - $logged_in = 1; - break; - } - - $num_tries++; - } - - if (!$logged_in) { - $login_error = __('An error occurred trying to generate a user session.'); - return array('SID' => $new_sid, 'error' => $login_error); - } - - $q = "UPDATE Users SET LastLogin = " . strval(time()) . ", "; - $q.= "LastLoginIPAddress = " . $dbh->quote($_SERVER['REMOTE_ADDR']) . " "; - $q.= "WHERE ID = $userID"; - $dbh->exec($q); - - /* Set the SID cookie. */ - if (isset($_POST['remember_me']) && $_POST['remember_me'] == "on") { - /* Set cookies for 30 days. */ - $timeout = config_get_int('options', 'persistent_cookie_timeout'); - $cookie_time = time() + $timeout; - - /* Set session for 30 days. */ - $q = "UPDATE Sessions SET LastUpdateTS = $cookie_time "; - $q.= "WHERE SessionID = '$new_sid'"; - $dbh->exec($q); - } else { - $cookie_time = 0; - } - - setcookie("AURSID", $new_sid, $cookie_time, "/", null, !empty($_SERVER['HTTPS']), true); - - $referer = in_request('referer'); - if (strpos($referer, aur_location()) !== 0) { - $referer = '/'; - } - header("Location: " . get_uri($referer)); - $login_error = ""; - return array('SID' => $new_sid, 'error' => null); -} - -/** - * Determine if the user is using a banned IP address - * - * @return bool True if IP address is banned, otherwise false - */ -function is_ipbanned() { - $dbh = DB::connect(); - - $q = "SELECT * FROM Bans WHERE IPAddress = " . $dbh->quote($_SERVER['REMOTE_ADDR']); - $result = $dbh->query($q); - - return ($result->fetchColumn() ? true : false); -} - -/** - * Validate a username against a collection of rules - * - * The username must be longer or equal to the configured minimum length. It - * must be shorter or equal to the configured maximum length. It must start and - * end with either a letter or a number. It can contain one period, hypen, or - * underscore. Returns boolean of whether name is valid. - * - * @param string $user Username to validate - * - * @return bool True if username meets criteria, otherwise false - */ -function valid_username($user) { - $length_min = config_get_int('options', 'username_min_len'); - $length_max = config_get_int('options', 'username_max_len'); - - if (strlen($user) < $length_min || strlen($user) > $length_max) { - return false; - } else if (!preg_match("/^[a-z0-9]+[.\-_]?[a-z0-9]+$/Di", $user)) { - return false; - } - - return true; -} - -/** - * Determine if a user already has a proposal open about themselves - * - * @param string $user Username to checkout for open proposal - * - * @return bool True if there is an open proposal about the user, otherwise false - */ -function open_user_proposals($user) { - $dbh = DB::connect(); - $q = "SELECT * FROM TU_VoteInfo WHERE User = " . $dbh->quote($user) . " "; - $q.= "AND End > " . strval(time()); - $result = $dbh->query($q); - - return ($result->fetchColumn() ? true : false); -} - -/** - * Add a new Trusted User proposal to the database - * - * @param string $agenda The agenda of the vote - * @param string $user The use the vote is about - * @param int $votelength The length of time for the vote to last - * @param string $submitteruid The user ID of the individual who submitted the proposal - * - * @return void - */ -function add_tu_proposal($agenda, $user, $votelength, $quorum, $submitteruid) { - $dbh = DB::connect(); - - $q = "SELECT COUNT(*) FROM Users WHERE (AccountTypeID = 2 OR AccountTypeID = 4)"; - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - $active_tus = $row[0]; - - $q = "INSERT INTO TU_VoteInfo (Agenda, User, Submitted, End, Quorum, "; - $q.= "SubmitterID, ActiveTUs) VALUES "; - $q.= "(" . $dbh->quote($agenda) . ", " . $dbh->quote($user) . ", "; - $q.= strval(time()) . ", " . strval(time()) . " + " . $dbh->quote($votelength); - $q.= ", " . $dbh->quote($quorum) . ", " . $submitteruid . ", "; - $q.= $active_tus . ")"; - $result = $dbh->exec($q); -} - -/** - * Add a reset key to the database for a specified user - * - * @param string $resetkey A password reset key to be stored in database - * @param string $uid The user ID to store the reset key for - * - * @return void - */ -function create_resetkey($resetkey, $uid) { - $dbh = DB::connect(); - $q = "UPDATE Users "; - $q.= "SET ResetKey = '" . $resetkey . "' "; - $q.= "WHERE ID = " . $uid; - $dbh->exec($q); -} - -/** - * Send a reset key to a specific e-mail address - * - * @param string $user User name or email address of the user - * @param bool $welcome Whether to use the welcome message - * - * @return void - */ -function send_resetkey($user, $welcome=false) { - $uid = uid_from_loginname($user); - if ($uid == null) { - return; - } - - /* We (ab)use new_sid() to get a random 32 characters long string. */ - $resetkey = new_sid(); - create_resetkey($resetkey, $uid); - - /* Send e-mail with confirmation link. */ - notify(array($welcome ? 'welcome' : 'send-resetkey', $uid)); -} - -/** - * Change a user's password in the database if reset key and e-mail are correct - * - * @param string $password The new password - * @param string $resetkey Code e-mailed to a user to reset a password - * @param string $user User name or email address of the user - * - * @return string|void Redirect page if successful, otherwise return error message - */ -function password_reset($password, $resetkey, $user) { - $hash = password_hash($password, PASSWORD_DEFAULT); - - $dbh = DB::connect(); - $q = "UPDATE Users SET "; - $q.= "Passwd = " . $dbh->quote($hash) . ", "; - $q.= "ResetKey = '' "; - $q.= "WHERE ResetKey != '' "; - $q.= "AND ResetKey = " . $dbh->quote($resetkey) . " "; - $q.= "AND (Email = " . $dbh->quote($user) . " OR "; - $q.= "UserName = " . $dbh->quote($user) . ")"; - $result = $dbh->exec($q); - - if (!$result) { - $error = __('Invalid e-mail and reset key combination.'); - return $error; - } else { - header('Location: ' . get_uri('/passreset/') . '?step=complete'); - exit(); - } -} - -/** - * Determine if the password is longer than the minimum length - * - * @param string $passwd The password to check - * - * @return bool True if longer than minimum length, otherwise false - */ -function good_passwd($passwd) { - $length_min = config_get_int('options', 'passwd_min_len'); - return (strlen($passwd) >= $length_min); -} - -/** - * Determine if the password is correct and salt it if it hasn't been already - * - * @param int $user_id The user ID to check the password against - * @param string $passwd The password the visitor sent - * - * @return int Positive if password is correct, negative if password is unset - */ -function check_passwd($user_id, $passwd) { - $dbh = DB::connect(); - - /* Get password hash and salt. */ - $q = "SELECT Passwd, Salt FROM Users WHERE ID = " . intval($user_id); - $result = $dbh->query($q); - if (!$result) { - return 0; - } - $row = $result->fetch(PDO::FETCH_ASSOC); - if (!$row) { - return 0; - } - $hash = $row['Passwd']; - $salt = $row['Salt']; - if (!$hash) { - return -1; - } - - /* Verify the password hash. */ - if (!password_verify($passwd, $hash)) { - /* Invalid password, fall back to MD5. */ - if (md5($salt . $passwd) != $hash) { - return 0; - } - } - - /* Password correct, migrate the hash if necessary. */ - if (password_needs_rehash($hash, PASSWORD_DEFAULT)) { - $hash = password_hash($passwd, PASSWORD_DEFAULT); - - $q = "UPDATE Users SET Passwd = " . $dbh->quote($hash) . " "; - $q.= "WHERE ID = " . intval($user_id); - $dbh->query($q); - } - - return 1; -} - -/** - * Determine if the PGP key fingerprint is valid (must be 40 hexadecimal digits) - * - * @param string $fingerprint PGP fingerprint to check if valid - * - * @return bool True if the fingerprint is 40 hexadecimal digits, otherwise false - */ -function valid_pgp_fingerprint($fingerprint) { - $fingerprint = str_replace(" ", "", $fingerprint); - return (strlen($fingerprint) == 40 && ctype_xdigit($fingerprint)); -} - -/** - * Determine if the SSH public key is valid - * - * @param string $pubkey SSH public key to check - * - * @return bool True if the SSH public key is valid, otherwise false - */ -function valid_ssh_pubkey($pubkey) { - $valid_prefixes = explode(' ', config_get('auth', 'valid-keytypes')); - - $has_valid_prefix = false; - foreach ($valid_prefixes as $prefix) { - if (strpos($pubkey, $prefix . " ") === 0) { - $has_valid_prefix = true; - break; - } - } - if (!$has_valid_prefix) { - return false; - } - - $tokens = explode(" ", $pubkey); - if (empty($tokens[1])) { - return false; - } - - return (base64_encode(base64_decode($tokens[1], true)) == $tokens[1]); -} - -/** - * Determine if the user account has been suspended - * - * @param string $id The ID of user to check if suspended - * - * @return bool True if the user is suspended, otherwise false - */ -function user_suspended($id) { - $dbh = DB::connect(); - if (!$id) { - return false; - } - $q = "SELECT Suspended FROM Users WHERE ID = " . $id; - $result = $dbh->query($q); - if ($result) { - $row = $result->fetch(PDO::FETCH_NUM); - if ($row[0]) { - return true; - } - } - return false; -} - -/** - * Delete a specified user account from the database - * - * @param int $id The user ID of the account to be deleted - * - * @return void - */ -function user_delete($id) { - $dbh = DB::connect(); - $id = intval($id); - - /* - * These are normally already taken care of by propagation constraints - * but it is better to be explicit here. - */ - $fields_delete = array( - array("Sessions", "UsersID"), - array("PackageVotes", "UsersID"), - array("PackageNotifications", "UserID") - ); - - $fields_set_null = array( - array("PackageBases", "SubmitterUID"), - array("PackageBases", "MaintainerUID"), - array("PackageBases", "PackagerUID"), - array("PackageComments", "UsersID"), - array("PackageComments", "DelUsersID"), - array("PackageRequests", "UsersID"), - array("TU_VoteInfo", "SubmitterID"), - array("TU_Votes", "UserID") - ); - - foreach($fields_delete as list($table, $field)) { - $q = "DELETE FROM " . $table . " "; - $q.= "WHERE " . $field . " = " . $id; - $dbh->query($q); - } - - foreach($fields_set_null as list($table, $field)) { - $q = "UPDATE " . $table . " SET " . $field . " = NULL "; - $q.= "WHERE " . $field . " = " . $id; - $dbh->query($q); - } - - $q = "DELETE FROM Users WHERE ID = " . $id; - $dbh->query($q); - return; -} - -/** - * Remove the session from the database on logout - * - * @param string $sid User's session ID - * - * @return void - */ -function delete_session_id($sid) { - $dbh = DB::connect(); - - $q = "DELETE FROM Sessions WHERE SessionID = " . $dbh->quote($sid); - $dbh->query($q); -} - -/** - * Remove all sessions belonging to a particular user - * - * @param int $uid ID of user to remove all sessions for - * - * @return void - */ -function delete_user_sessions($uid) { - $dbh = DB::connect(); - - $q = "DELETE FROM Sessions WHERE UsersID = " . intval($uid); - $dbh->exec($q); -} - -/** - * Remove sessions from the database that have exceed the timeout - * - * @return void - */ -function clear_expired_sessions() { - $dbh = DB::connect(); - - $timeout = config_get_int('options', 'login_timeout'); - $q = "DELETE FROM Sessions WHERE LastUpdateTS < (" . strval(time()) . " - " . $timeout . ")"; - $dbh->query($q); - - return; -} - -/** - * Get account details for a specific user - * - * @param string $uid The User ID of account to get information for - * @param string $username The username of the account to get for - * - * @return array Account details for the specified user - */ -function account_details($uid, $username) { - $dbh = DB::connect(); - $q = "SELECT Users.*, AccountTypes.AccountType "; - $q.= "FROM Users, AccountTypes "; - $q.= "WHERE AccountTypes.ID = Users.AccountTypeID "; - if (!empty($uid)) { - $q.= "AND Users.ID = ".intval($uid); - } else { - $q.= "AND Users.Username = " . $dbh->quote($username); - } - $result = $dbh->query($q); - - if ($result) { - $row = $result->fetch(PDO::FETCH_ASSOC); - } - - return $row; -} - -/** - * Determine if a user has already voted on a specific proposal - * - * @param string $voteid The ID of the Trusted User proposal - * @param string $uid The ID to check if the user already voted - * - * @return bool True if the user has already voted, otherwise false - */ -function tu_voted($voteid, $uid) { - $dbh = DB::connect(); - - $q = "SELECT COUNT(*) FROM TU_Votes "; - $q.= "WHERE VoteID = " . intval($voteid) . " AND UserID = " . intval($uid); - $result = $dbh->query($q); - if ($result->fetchColumn() > 0) { - return true; - } - else { - return false; - } -} - -/** - * Get all current Trusted User proposals from the database - * - * @param string $order Ascending or descending order for the proposal listing - * - * @return array The details for all current Trusted User proposals - */ -function current_proposal_list($order) { - $dbh = DB::connect(); - - $q = "SELECT * FROM TU_VoteInfo WHERE End > " . time() . " ORDER BY Submitted " . $order; - $result = $dbh->query($q); - - $details = array(); - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $details[] = $row; - } - - return $details; -} - -/** - * Get a subset of all past Trusted User proposals from the database - * - * @param string $order Ascending or descending order for the proposal listing - * @param string $lim The number of proposals to list with the offset - * - * @return array The details for the subset of past Trusted User proposals - */ -function past_proposal_list($order, $lim) { - $dbh = DB::connect(); - - $q = "SELECT * FROM TU_VoteInfo WHERE End < " . time() . " ORDER BY Submitted " . $order . $lim; - $result = $dbh->query($q); - - $details = array(); - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $details[] = $row; - } - - return $details; -} - -/** - * Get the vote ID of the last vote of all Trusted Users - * - * @return array The vote ID of the last vote of each Trusted User - */ -function last_votes_list() { - $dbh = DB::connect(); - - $q = "SELECT UserID, MAX(VoteID) AS LastVote FROM TU_Votes, "; - $q .= "TU_VoteInfo, Users WHERE TU_VoteInfo.ID = TU_Votes.VoteID AND "; - $q .= "TU_VoteInfo.End < " . strval(time()) . " AND "; - $q .= "Users.ID = TU_Votes.UserID AND (Users.AccountTypeID = 2 OR Users.AccountTypeID = 4) "; - $q .= "GROUP BY UserID ORDER BY LastVote DESC, UserName ASC"; - $result = $dbh->query($q); - - $details = array(); - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $details[] = $row; - } - - return $details; -} - -/** - * Determine the total number of Trusted User proposals - * - * @return string The total number of Trusted User proposals - */ -function proposal_count() { - $dbh = DB::connect(); - $q = "SELECT COUNT(*) FROM TU_VoteInfo"; - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - - return $row[0]; -} - -/** - * Get all details related to a specific vote from the database - * - * @param string $voteid The ID of the Trusted User proposal - * - * @return array All stored details for a specific vote - */ -function vote_details($voteid) { - $dbh = DB::connect(); - - $q = "SELECT * FROM TU_VoteInfo "; - $q.= "WHERE ID = " . intval($voteid); - - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_ASSOC); - - return $row; -} - -/** - * Get an alphabetical list of users who voted for a proposal with HTML links - * - * @param string $voteid The ID of the Trusted User proposal - * - * @return array All users who voted for a specific proposal - */ -function voter_list($voteid) { - $dbh = DB::connect(); - - $whovoted = array(); - - $q = "SELECT tv.UserID,U.Username "; - $q.= "FROM TU_Votes tv, Users U "; - $q.= "WHERE tv.VoteID = " . intval($voteid); - $q.= " AND tv.UserID = U.ID "; - $q.= "ORDER BY Username"; - - $result = $dbh->query($q); - if ($result) { - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $whovoted[] = $row['Username']; - } - } - return $whovoted; -} - -/** - * Cast a vote for a specific user proposal - * - * @param string $voteid The ID of the proposal being voted on - * @param string $uid The user ID of the individual voting - * @param string $vote Vote position, either "Yes", "No", or "Abstain" - * @param int $newtotal The total number of votes after the user has voted - * - * @return void - */ -function cast_proposal_vote($voteid, $uid, $vote, $newtotal) { - $dbh = DB::connect(); - - $q = "UPDATE TU_VoteInfo SET " . $vote . " = (" . $newtotal . ") WHERE ID = " . $voteid; - $result = $dbh->exec($q); - - $q = "INSERT INTO TU_Votes (VoteID, UserID) VALUES (" . intval($voteid) . ", " . intval($uid) . ")"; - $result = $dbh->exec($q); -} - -/** - * Verify a user has the proper permissions to edit an account - * - * @param array $acctinfo User account information for edited account - * - * @return bool True if permission to edit the account, otherwise false - */ -function can_edit_account($acctinfo) { - if ($acctinfo['AccountType'] == 'Developer' || - $acctinfo['AccountType'] == 'Trusted User & Developer') { - return has_credential(CRED_ACCOUNT_EDIT_DEV); - } - - $uid = $acctinfo['ID']; - return has_credential(CRED_ACCOUNT_EDIT, array($uid)); -} - -/* - * Compute the fingerprint of an SSH key. - * - * @param string $ssh_key The SSH public key to retrieve the fingerprint for - * - * @return string The SSH key fingerprint - */ -function ssh_key_fingerprint($ssh_key) { - $tmpfile = tempnam(sys_get_temp_dir(), "aurweb"); - file_put_contents($tmpfile, $ssh_key); - - /* - * The -l option of ssh-keygen can be used to show the fingerprint of - * the specified public key file. Expected output format: - * - * 2048 SHA256:uBBTXmCNjI2CnLfkuz9sG8F+e9/T4C+qQQwLZWIODBY user@host (RSA) - * - * ... where 2048 is the key length, the second token is the actual - * fingerprint, followed by the key comment and the key type. - */ - - $cmd = "/usr/bin/ssh-keygen -l -f " . escapeshellarg($tmpfile); - exec($cmd, $out, $ret); - if ($ret !== 0 || count($out) !== 1) { - return false; - } - - unlink($tmpfile); - - $tokens = explode(' ', $out[0]); - if (count($tokens) < 4) { - return false; - } - - $tokens = explode(':', $tokens[1]); - if (count($tokens) != 2 || $tokens[0] != 'SHA256') { - return false; - } - - return $tokens[1]; -} - -/* - * Get the SSH public keys associated with an account. - * - * @param int $uid The user ID of the account to retrieve the keys for. - * - * @return array An array representing the keys - */ -function account_get_ssh_keys($uid) { - $dbh = DB::connect(); - $q = "SELECT PubKey FROM SSHPubKeys WHERE UserID = " . intval($uid); - $result = $dbh->query($q); - - if ($result) { - return $result->fetchAll(PDO::FETCH_COLUMN, 0); - } else { - return array(); - } -} - -/* - * Set the SSH public keys associated with an account. - * - * @param int $uid The user ID of the account to assign the keys to. - * @param array $ssh_keys The SSH public keys. - * @param array $ssh_fingerprints The corresponding SSH key fingerprints. - * - * @return bool Boolean flag indicating success or failure. - */ -function account_set_ssh_keys($uid, $ssh_keys, $ssh_fingerprints) { - $dbh = DB::connect(); - - $q = sprintf("DELETE FROM SSHPubKeys WHERE UserID = %d", $uid); - $dbh->exec($q); - - $ssh_fingerprint = reset($ssh_fingerprints); - foreach ($ssh_keys as $ssh_key) { - $q = sprintf( - "INSERT INTO SSHPubKeys (UserID, Fingerprint, PubKey) " . - "VALUES (%d, %s, %s)", $uid, - $dbh->quote($ssh_fingerprint), $dbh->quote($ssh_key) - ); - $dbh->exec($q); - $ssh_fingerprint = next($ssh_fingerprints); - } - - return true; -} - -/* - * Invoke the email notification script. - * - * @param string $params Command line parameters for the script. - * - * @return void - */ -function notify($params) { - $cmd = config_get('notifications', 'notify-cmd'); - foreach ($params as $param) { - $cmd .= ' ' . escapeshellarg($param); - } - - $descspec = array( - 0 => array('pipe', 'r'), - 1 => array('pipe', 'w'), - ); - - $p = proc_open($cmd, $descspec, $pipes); - - if (!is_resource($p)) { - return false; - } - - fclose($pipes[0]); - fclose($pipes[1]); - - return proc_close($p); -} - -/* - * Obtain a list of terms a given user has not yet accepted. - * - * @param int $uid The ID of the user to obtain terms for. - * - * @return array A list of terms the user has not yet accepted. - */ -function fetch_updated_terms($uid) { - $dbh = DB::connect(); - - $q = "SELECT ID, Terms.Revision, Description, URL "; - $q .= "FROM Terms LEFT JOIN AcceptedTerms "; - $q .= "ON AcceptedTerms.TermsID = Terms.ID "; - $q .= "AND AcceptedTerms.UsersID = " . intval($uid) . " "; - $q .= "WHERE AcceptedTerms.Revision IS NULL OR "; - $q .= "AcceptedTerms.Revision < Terms.Revision"; - - $result = $dbh->query($q); - - if ($result) { - return $result->fetchAll(); - } else { - return array(); - } -} - -/* - * Accept a list of given terms. - * - * @param int $uid The ID of the user to accept the terms. - * @param array $termrev An array mapping each term to the accepted revision. - * - * @return void - */ -function accept_terms($uid, $termrev) { - $dbh = DB::connect(); - - $q = "SELECT TermsID, Revision FROM AcceptedTerms "; - $q .= "WHERE UsersID = " . intval($uid); - - $result = $dbh->query($q); - - if (!$result) { - return; - } - - $termrev_update = array(); - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $id = $row['TermsID']; - if (!array_key_exists($id, $termrev)) { - continue; - } - if ($row['Revision'] < $termrev[$id]) { - $termrev_update[$id] = $termrev[$id]; - } - } - $termrev_add = array_diff_key($termrev, $termrev_update); - - foreach ($termrev_add as $id => $rev) { - $q = "INSERT INTO AcceptedTerms (TermsID, UsersID, Revision) "; - $q .= "VALUES (" . intval($id) . ", " . intval($uid) . ", "; - $q .= intval($rev) . ")"; - $dbh->exec($q); - } - - foreach ($termrev_update as $id => $rev) { - $q = "UPDATE AcceptedTerms "; - $q .= "SET Revision = " . intval($rev) . " "; - $q .= "WHERE TermsID = " . intval($id) . " AND "; - $q .= "UsersID = " . intval($uid); - $dbh->exec($q); - } -} - -function account_comments($uid, $limit, $offset=0) { - $dbh = DB::connect(); - $q = "SELECT PackageComments.ID, Comments, UsersID, "; - $q.= "PackageBaseId, CommentTS, DelTS, EditedTS, B.UserName AS EditUserName, "; - $q.= "PinnedTS, "; - $q.= "C.UserName as DelUserName, RenderedComment, "; - $q.= "PB.ID as PackageBaseID, PB.Name as PackageBaseName "; - $q.= "FROM PackageComments "; - $q.= "LEFT JOIN PackageBases PB ON PackageComments.PackageBaseID = PB.ID "; - $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID "; - $q.= "LEFT JOIN Users B ON PackageComments.EditedUsersID = B.ID "; - $q.= "LEFT JOIN Users C ON PackageComments.DelUsersID = C.ID "; - $q.= "WHERE A.ID = " . $dbh->quote($uid) . " "; - $q.= "ORDER BY CommentTS DESC"; - - if ($limit > 0) { - $q.=" LIMIT " . intval($limit); - } - - if ($offset > 0) { - $q.=" OFFSET " . intval($offset); - } - - $result = $dbh->query($q); - if (!$result) { - return null; - } - - return $result->fetchAll(); -} - -function account_comments_count($uid) { - $dbh = DB::connect(); - $q = "SELECT COUNT(*) "; - $q.= "FROM PackageComments "; - $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID "; - $q.= "WHERE A.ID = " . $dbh->quote($uid); - - $result = $dbh->query($q); - return $result->fetchColumn(); -} - -/* - * Compute the list of active CAPTCHA salts. The salt changes based on the - * number of registered users. This ensures that new users always use a - * different salt and protects against hardcoding the CAPTCHA response. - * - * The first CAPTCHA in the list is the most recent one and should be used for - * new CAPTCHA challenges. The other ones are slightly outdated but may still - * be valid for recent challenges that were created before the number of users - * increased. The current implementation ensures that we can still use our - * CAPTCHA salt, even if five new users registered since the CAPTCHA challenge - * was created. - * - * @return string The list of active salts, the first being the most recent - * one. - */ -function get_captcha_salts() { - $dbh = DB::connect(); - $q = "SELECT count(*) FROM Users"; - $result = $dbh->query($q); - $user_count = $result->fetchColumn(); - - $ret = array(); - for ($i = 0; $i <= 5; $i++) { - array_push($ret, 'aurweb-' . ($user_count - $i)); - } - return $ret; -} - -/* - * Return the CAPTCHA challenge for a given salt. - * - * @param string $salt The salt to be used for the CAPTCHA computation. - * - * @return string The challenge as a string. - */ -function get_captcha_challenge($salt) { - $token = substr(md5($salt), 0, 3); - return "LC_ALL=C pacman -V|sed -r 's#[0-9]+#" . $token . "#g'|md5sum|cut -c1-6"; -} - -/* - * Compute CAPTCHA answer for a given salt. - * - * @param string $salt The salt to be used for the CAPTCHA computation. - * - * @return string The correct answer as a string. - */ -function get_captcha_answer($salt) { - $token = substr(md5($salt), 0, 3); - $text = <<quote($_COOKIE["AURSID"]); - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - - if (!$row) { - # Invalid SessionID - hacker alert! - # - $failed = 1; - } else { - $last_update = $row[0]; - if ($last_update + $timeout <= $row[1]) { - $failed = 2; - } - } - - if ($failed == 1) { - # clear out the hacker's cookie, and send them to a naughty page - # why do you have to be so harsh on these people!? - # - setcookie("AURSID", "", 1, "/", null, !empty($_SERVER['HTTPS']), true); - unset($_COOKIE['AURSID']); - } elseif ($failed == 2) { - # session id timeout was reached and they must login again. - # - delete_session_id($_COOKIE["AURSID"]); - - setcookie("AURSID", "", 1, "/", null, !empty($_SERVER['HTTPS']), true); - unset($_COOKIE['AURSID']); - } else { - # still logged in and haven't reached the timeout, go ahead - # and update the idle timestamp - - # Only update the timestamp if it is less than the - # current time plus $timeout. - # - # This keeps 'remembered' sessions from being - # overwritten. - if ($last_update < time() + $timeout) { - $q = "UPDATE Sessions SET LastUpdateTS = " . strval(time()) . " "; - $q.= "WHERE SessionID = " . $dbh->quote($_COOKIE["AURSID"]); - $dbh->exec($q); - } - } - } - return; -} - -/** - * Redirect user to the Terms of Service agreement if there are updated terms. - * - * @return void - */ -function check_tos() { - if (!isset($_COOKIE["AURSID"])) { - return; - } - - $path = $_SERVER['PATH_INFO']; - $route = get_route($path); - if (!$route || $route == "tos.php") { - return; - } - - if (count(fetch_updated_terms(uid_from_sid($_COOKIE["AURSID"]))) > 0) { - header('Location: ' . get_uri('/tos')); - exit(); - } -} - -/** - * Verify the supplied CSRF token matches expected token - * - * @return bool True if the CSRF token is the same as the cookie SID, otherwise false - */ -function check_token() { - if (isset($_POST['token']) && isset($_COOKIE['AURSID'])) { - return ($_POST['token'] == $_COOKIE['AURSID']); - } else { - return false; - } -} - -/** - * Verify a user supplied e-mail against RFC 3696 and DNS records - * - * @param string $addy E-mail address being validated in foo@example.com format - * - * @return bool True if e-mail passes validity checks, otherwise false - */ -function valid_email($addy) { - // check against RFC 3696 - if (filter_var($addy, FILTER_VALIDATE_EMAIL) === false) { - return false; - } - - // check dns for mx, a, aaaa records - list($local, $domain) = explode('@', $addy); - if (!(checkdnsrr($domain, 'MX') || checkdnsrr($domain, 'A') || checkdnsrr($domain, 'AAAA'))) { - return false; - } - - return true; -} - -/** - * Verify that a given URL is valid and uses the HTTP(s) protocol - * - * @param string $url URL of the home page to be validated - * - * @return bool True if URL passes validity checks, false otherwise - */ -function valid_homepage($url) { - if (filter_var($url, FILTER_VALIDATE_URL) === false) { - return false; - } - - $url_components = parse_url($url); - if (!in_array($url_components['scheme'], array('http', 'https'))) { - return false; - } - - return true; -} - -/** - * Generate a unique session ID - * - * @return string MD5 hash of the concatenated user IP, random number, and current time - */ -function new_sid() { - return md5($_SERVER['REMOTE_ADDR'] . uniqid(mt_rand(), true)); -} - -/** - * Determine the user's username in the database using a user ID - * - * @param string $id User's ID - * - * @return string Username if it exists, otherwise null - */ -function username_from_id($id) { - $id = intval($id); - - $dbh = DB::connect(); - $q = "SELECT Username FROM Users WHERE ID = " . $dbh->quote($id); - $result = $dbh->query($q); - if (!$result) { - return null; - } - - $row = $result->fetch(PDO::FETCH_NUM); - if ($row) { - return $row[0]; - } -} - -/** - * Determine the user's username in the database using a session ID - * - * @param string $sid User's session ID - * - * @return string Username of the visitor - */ -function username_from_sid($sid="") { - if (!$sid) { - return ""; - } - $dbh = DB::connect(); - $q = "SELECT Username "; - $q.= "FROM Users, Sessions "; - $q.= "WHERE Users.ID = Sessions.UsersID "; - $q.= "AND Sessions.SessionID = " . $dbh->quote($sid); - $result = $dbh->query($q); - if (!$result) { - return ""; - } - $row = $result->fetch(PDO::FETCH_NUM); - - if ($row) { - return $row[0]; - } -} - -/** - * Format a user name for inclusion in HTML data - * - * @param string $username The user name to format - * - * @return string The generated HTML code for the account link - */ -function html_format_username($username) { - $username_fmt = $username ? htmlspecialchars($username, ENT_QUOTES) : __("None"); - - if ($username && isset($_COOKIE["AURSID"])) { - $link = '' . $username_fmt . ''; - return $link; - } else { - return $username_fmt; - } -} - -/** - * Format the maintainer and co-maintainers for inclusion in HTML data - * - * @param string $maintainer The user name of the maintainer - * @param array $comaintainers The list of co-maintainer user names - * - * @return string The generated HTML code for the account links - */ -function html_format_maintainers($maintainer, $comaintainers) { - $code = html_format_username($maintainer); - - if (count($comaintainers) > 0) { - $code .= ' ('; - foreach ($comaintainers as $comaintainer) { - $code .= html_format_username($comaintainer); - if ($comaintainer !== end($comaintainers)) { - $code .= ', '; - } - } - $code .= ')'; - } - - return $code; -} - -/** - * Format a link in the package actions box - * - * @param string $uri The link target - * @param string $inner The HTML code to use for the link label - * - * @return string The generated HTML code for the action link - */ -function html_action_link($uri, $inner) { - if (isset($_COOKIE["AURSID"])) { - $code = ''; - } else { - $code = ''; - } - $code .= $inner . ''; - - return $code; -} - -/** - * Format a form in the package actions box - * - * @param string $uri The link target - * @param string $action The action name (passed as HTTP POST parameter) - * @param string $inner The HTML code to use for the link label - * - * @return string The generated HTML code for the action link - */ -function html_action_form($uri, $action, $inner) { - if (isset($_COOKIE["AURSID"])) { - $code = '
    '; - $code .= ''; - $code .= '
    '; - } else { - $code = ''; - $code .= $inner . ''; - } - - return $code; -} - -/** - * Determine the user's e-mail address in the database using a session ID - * - * @param string $sid User's session ID - * - * @return string User's e-mail address as given during registration - */ -function email_from_sid($sid="") { - if (!$sid) { - return ""; - } - $dbh = DB::connect(); - $q = "SELECT Email "; - $q.= "FROM Users, Sessions "; - $q.= "WHERE Users.ID = Sessions.UsersID "; - $q.= "AND Sessions.SessionID = " . $dbh->quote($sid); - $result = $dbh->query($q); - if (!$result) { - return ""; - } - $row = $result->fetch(PDO::FETCH_NUM); - - if ($row) { - return $row[0]; - } -} - -/** - * Determine the user's account type in the database using a session ID - * - * @param string $sid User's session ID - * - * @return string Account type of user ("User", "Trusted User", or "Developer") - */ -function account_from_sid($sid="") { - if (!$sid) { - return ""; - } - $dbh = DB::connect(); - $q = "SELECT AccountType "; - $q.= "FROM Users, AccountTypes, Sessions "; - $q.= "WHERE Users.ID = Sessions.UsersID "; - $q.= "AND AccountTypes.ID = Users.AccountTypeID "; - $q.= "AND Sessions.SessionID = " . $dbh->quote($sid); - $result = $dbh->query($q); - if (!$result) { - return ""; - } - $row = $result->fetch(PDO::FETCH_NUM); - - if ($row) { - return $row[0]; - } -} - -/** - * Determine the user's ID in the database using a session ID - * - * @param string $sid User's session ID - * - * @return string|int The user's name, 0 on query failure - */ -function uid_from_sid($sid="") { - if (!$sid) { - return ""; - } - $dbh = DB::connect(); - $q = "SELECT Users.ID "; - $q.= "FROM Users, Sessions "; - $q.= "WHERE Users.ID = Sessions.UsersID "; - $q.= "AND Sessions.SessionID = " . $dbh->quote($sid); - $result = $dbh->query($q); - if (!$result) { - return 0; - } - $row = $result->fetch(PDO::FETCH_NUM); - - if ($row) { - return $row[0]; - } -} - -/** - * Common AUR header displayed on all pages - * - * @global string $LANG Language selected by the visitor - * @global array $SUPPORTED_LANGS Languages that are supported by the AUR - * @param string $title Name of the AUR page to be displayed on browser - * - * @return void - */ -function html_header($title="", $details=array()) { - global $LANG; - global $SUPPORTED_LANGS; - - include('header.php'); - return; -} - -/** - * Common AUR footer displayed on all pages - * - * @param string $ver The AUR version - * - * @return void - */ -function html_footer($ver="") { - include('footer.php'); - return; -} - -/** - * Determine if a user has permission to submit a package - * - * @param string $name Name of the package to be submitted - * @param string $sid User's session ID - * - * @return int 0 if the user can't submit, 1 if the user can submit - */ -function can_submit_pkgbase($name="", $sid="") { - if (!$name || !$sid) {return 0;} - $dbh = DB::connect(); - $q = "SELECT MaintainerUID "; - $q.= "FROM PackageBases WHERE Name = " . $dbh->quote($name); - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - - if (!$row[0]) { - return 1; - } - $my_uid = uid_from_sid($sid); - - if ($row[0] === NULL || $row[0] == $my_uid) { - return 1; - } - - return 0; -} - -/** - * Determine if a package can be overwritten by some package base - * - * @param string $name Name of the package to be submitted - * @param int $base_id The ID of the package base - * - * @return bool True if the package can be overwritten, false if not - */ -function can_submit_pkg($name, $base_id) { - $dbh = DB::connect(); - $q = "SELECT COUNT(*) FROM Packages WHERE "; - $q.= "Name = " . $dbh->quote($name) . " AND "; - $q.= "PackageBaseID <> " . intval($base_id); - $result = $dbh->query($q); - - if (!$result) return false; - return ($result->fetchColumn() == 0); -} - -/** - * Recursively delete a directory - * - * @param string $dirname Name of the directory to be removed - * - * @return void - */ -function rm_tree($dirname) { - if (empty($dirname) || !is_dir($dirname)) return; - - foreach (scandir($dirname) as $item) { - if ($item != '.' && $item != '..') { - $path = $dirname . '/' . $item; - if (is_file($path) || is_link($path)) { - unlink($path); - } - else { - rm_tree($path); - } - } - } - - rmdir($dirname); - - return; -} - - /** - * Determine the user's ID in the database using a username - * - * @param string $username The username of an account - * - * @return string Return user ID if exists for username, otherwise null - */ -function uid_from_username($username) { - $dbh = DB::connect(); - $q = "SELECT ID FROM Users WHERE Username = " . $dbh->quote($username); - $result = $dbh->query($q); - if (!$result) { - return null; - } - - $row = $result->fetch(PDO::FETCH_NUM); - if ($row) { - return $row[0]; - } -} - -/** - * Determine the user's ID in the database using a username or email address - * - * @param string $username The username or email address of an account - * - * @return string Return user ID if exists, otherwise null - */ -function uid_from_loginname($loginname) { - $uid = uid_from_username($loginname); - if (!$uid) { - $uid = uid_from_email($loginname); - } - return $uid; -} - -/** - * Determine the user's ID in the database using an e-mail address - * - * @param string $email An e-mail address in foo@example.com format - * - * @return string The user's ID - */ -function uid_from_email($email) { - $dbh = DB::connect(); - $q = "SELECT ID FROM Users WHERE Email = " . $dbh->quote($email); - $result = $dbh->query($q); - if (!$result) { - return null; - } - - $row = $result->fetch(PDO::FETCH_NUM); - if ($row) { - return $row[0]; - } -} - -/** - * Generate clean url with edited/added user values - * - * Makes a clean string of variables for use in URLs based on current $_GET and - * list of values to edit/add to that. Any empty variables are discarded. - * - * @example print "http://example.com/test.php?" . mkurl("foo=bar&bar=baz") - * - * @param string $append string of variables and values formatted as in URLs - * - * @return string clean string of variables to append to URL, urlencoded - */ -function mkurl($append) { - $get = $_GET; - $append = explode('&', $append); - $uservars = array(); - $out = ''; - - foreach ($append as $i) { - $ex = explode('=', $i); - $uservars[$ex[0]] = $ex[1]; - } - - foreach ($uservars as $k => $v) { $get[$k] = $v; } - - foreach ($get as $k => $v) { - if ($v !== '') { - $out .= '&' . urlencode($k) . '=' . urlencode($v); - } - } - - return substr($out, 5); -} - -/** - * Get a package comment - * - * @param int $comment_id The ID of the comment - * - * @return array The user ID and comment OR null, null in case of an error - */ -function comment_by_id($comment_id) { - $dbh = DB::connect(); - $q = "SELECT UsersID, Comments FROM PackageComments "; - $q.= "WHERE ID = " . intval($comment_id); - $result = $dbh->query($q); - if (!$result) { - return array(null, null); - } - - return $result->fetch(PDO::FETCH_NUM); -} - -/** - * Process submitted comments so any links can be followed - * - * @param string $comment Raw user submitted package comment - * - * @return string User comment with links printed in HTML - */ -function parse_comment($comment) { - $url_pattern = '/(\b(?:https?|ftp):\/\/[\w\/\#~:.?+=&%@!\-;,]+?' . - '(?=[.:?\-;,]*(?:[^\w\/\#~:.?+=&%@!\-;,]|$)))/iS'; - - $matches = preg_split($url_pattern, $comment, -1, - PREG_SPLIT_DELIM_CAPTURE); - - $html = ''; - for ($i = 0; $i < count($matches); $i++) { - if ($i % 2) { - # convert links - $html .= '' . htmlspecialchars($matches[$i]) . ''; - } - else { - # convert everything else - $html .= nl2br(htmlspecialchars($matches[$i])); - } - } - - return $html; -} - -/** - * Wrapper for beginning a database transaction - */ -function begin_atomic_commit() { - $dbh = DB::connect(); - $dbh->beginTransaction(); -} - -/** - * Wrapper for committing a database transaction - */ -function end_atomic_commit() { - $dbh = DB::connect(); - $dbh->commit(); -} - -/** - * Merge pkgbase and package options - * - * Merges entries of the first and the second array. If any key appears in both - * arrays and the corresponding value in the second array is either a non-array - * type or a non-empty array, the value from the second array replaces the - * value from the first array. If the value from the second array is an array - * containing a single empty string, the value in the resulting array becomes - * an empty array instead. If the value in the second array is empty, the - * resulting array contains the value from the first array. - * - * @param array $pkgbase_info Options from the pkgbase section - * @param array $section_info Options from the package section - * - * @return array Merged information from both sections - */ -function array_pkgbuild_merge($pkgbase_info, $section_info) { - $pi = $pkgbase_info; - foreach ($section_info as $opt_key => $opt_val) { - if (is_array($opt_val)) { - if ($opt_val == array('')) { - $pi[$opt_key] = array(); - } elseif (count($opt_val) > 0) { - $pi[$opt_key] = $opt_val; - } - } else { - $pi[$opt_key] = $opt_val; - } - } - return $pi; -} - -/** - * Bound an integer value between two values - * - * @param int $n Integer value to bound - * @param int $min Lower bound - * @param int $max Upper bound - * - * @return int Bounded integer value - */ -function bound($n, $min, $max) { - return min(max($n, $min), $max); -} - -/** - * Return the URL of the AUR root - * - * @return string The URL of the AUR root - */ -function aur_location() { - $location = config_get('options', 'aur_location'); - if (substr($location, -1) != '/') { - $location .= '/'; - } - return $location; -} - -/** - * Calculate pagination templates - * - * @return array The array of pagination templates, per page, and offset values - */ -function calculate_pagination($total_comment_count) { - /* Sanitize paging variables. */ - if (isset($_GET["O"])) { - $_GET["O"] = max(intval($_GET["O"]), 0); - } else { - $_GET["O"] = 0; - } - $offset = $_GET["O"]; - - if (isset($_GET["PP"])) { - $_GET["PP"] = bound(intval($_GET["PP"]), 1, 250); - } else { - $_GET["PP"] = 10; - } - $per_page = $_GET["PP"]; - - // Page offsets start at zero, so page 2 has offset 1, which means that we - // need to add 1 to the offset to get the current page. - $current_page = ceil($offset / $per_page) + 1; - $num_pages = ceil($total_comment_count / $per_page); - $pagination_templs = array(); - - if ($current_page > 1) { - $previous_page = $current_page - 1; - $previous_offset = ($previous_page - 1) * $per_page; - $pagination_templs['« ' . __('First')] = 0; - $pagination_templs['‹ ' . __('Previous')] = $previous_offset; - } - - if ($current_page - 5 > 1) { - $pagination_templs["..."] = false; - } - - for ($i = max($current_page - 5, 1); $i <= min($num_pages, $current_page + 5); $i++) { - $pagination_templs[$i] = ($i - 1) * $per_page; - } - - if ($current_page + 5 < $num_pages) - $pagination_templs["... "] = false; - - if ($current_page < $num_pages) { - $pagination_templs[__('Next') . ' ›'] = $current_page * $per_page; - $pagination_templs[__('Last') . ' »'] = ($num_pages - 1) * $per_page; - } - - return array($pagination_templs, $per_page, $offset); -} diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php deleted file mode 100644 index 81c27bd9..00000000 --- a/web/lib/aurjson.class.php +++ /dev/null @@ -1,710 +0,0 @@ -version = intval($http_data['v']); - } - if ($this->version < 1 || $this->version > 6) { - return $this->json_error('Invalid version specified.'); - } - - if (!isset($http_data['type']) || !isset($http_data['arg'])) { - return $this->json_error('No request type/data specified.'); - } - if (!in_array($http_data['type'], self::$exposed_methods)) { - return $this->json_error('Incorrect request type specified.'); - } - - if (isset($http_data['search_by']) && !isset($http_data['by'])) { - $http_data['by'] = $http_data['search_by']; - } - if (isset($http_data['by']) && !in_array($http_data['by'], self::$exposed_fields)) { - return $this->json_error('Incorrect by field specified.'); - } - - $this->dbh = DB::connect(); - - if ($this->check_ratelimit($_SERVER['REMOTE_ADDR'])) { - header("HTTP/1.1 429 Too Many Requests"); - return $this->json_error('Rate limit reached'); - } - - $type = str_replace('-', '_', $http_data['type']); - if ($type == 'info' && $this->version >= 5) { - $type = 'multiinfo'; - } - $json = call_user_func(array(&$this, $type), $http_data); - - $etag = md5($json); - header("Etag: \"$etag\""); - /* - * Make sure to strip a few things off the - * if-none-match header. Stripping whitespace may not - * be required, but removing the quote on the incoming - * header is required to make the equality test. - */ - $if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? - trim($_SERVER['HTTP_IF_NONE_MATCH'], "\t\n\r\" ") : false; - if ($if_none_match && $if_none_match == $etag) { - header('HTTP/1.1 304 Not Modified'); - return; - } - - if (isset($http_data['callback'])) { - $callback = $http_data['callback']; - if (!preg_match('/^[a-zA-Z0-9()_.]{1,128}$/D', $callback)) { - return $this->json_error('Invalid callback name.'); - } - header('content-type: text/javascript'); - return '/**/' . $callback . '(' . $json . ')'; - } else { - header('content-type: application/json'); - return $json; - } - } - - /* - * Check if an IP needs to be rate limited. - * - * @param $ip IP of the current request - * - * @return true if IP needs to be rate limited, false otherwise. - */ - private function check_ratelimit($ip) { - $limit = config_get("ratelimit", "request_limit"); - if ($limit == 0) { - return false; - } - - $this->update_ratelimit($ip); - - $status = false; - $value = get_cache_value('ratelimit:' . $ip, $status); - if (!$status) { - $stmt = $this->dbh->prepare(" - SELECT Requests FROM ApiRateLimit - WHERE IP = :ip"); - $stmt->bindParam(":ip", $ip); - $result = $stmt->execute(); - - if (!$result) { - return false; - } - - $row = $stmt->fetch(PDO::FETCH_ASSOC); - $value = $row['Requests']; - } - - return $value > $limit; - } - - /* - * Update a rate limit for an IP by increasing it's requests value by one. - * - * @param $ip IP of the current request - * - * @return void - */ - private function update_ratelimit($ip) { - $window_length = config_get("ratelimit", "window_length"); - $db_backend = config_get("database", "backend"); - $time = time(); - $deletion_time = $time - $window_length; - - /* Try to use the cache. */ - $status = false; - $value = get_cache_value('ratelimit-ws:' . $ip, $status); - if (!$status || ($status && $value < $deletion_time)) { - if (set_cache_value('ratelimit-ws:' . $ip, $time, $window_length) && - set_cache_value('ratelimit:' . $ip, 1, $window_length)) { - return; - } - } else { - $value = get_cache_value('ratelimit:' . $ip, $status); - if ($status && set_cache_value('ratelimit:' . $ip, $value + 1, $window_length)) - return; - } - - /* Clean up old windows. */ - $stmt = $this->dbh->prepare(" - DELETE FROM ApiRateLimit - WHERE WindowStart < :time"); - $stmt->bindParam(":time", $deletion_time); - $stmt->execute(); - - if ($db_backend == "mysql") { - $stmt = $this->dbh->prepare(" - INSERT INTO ApiRateLimit - (IP, Requests, WindowStart) - VALUES (:ip, 1, :window_start) - ON DUPLICATE KEY UPDATE Requests=Requests+1"); - $stmt->bindParam(":ip", $ip); - $stmt->bindParam(":window_start", $time); - $stmt->execute(); - } elseif ($db_backend == "sqlite") { - $stmt = $this->dbh->prepare(" - INSERT OR IGNORE INTO ApiRateLimit - (IP, Requests, WindowStart) - VALUES (:ip, 0, :window_start);"); - $stmt->bindParam(":ip", $ip); - $stmt->bindParam(":window_start", $time); - $stmt->execute(); - - $stmt = $this->dbh->prepare(" - UPDATE ApiRateLimit - SET Requests = Requests + 1 - WHERE IP = :ip"); - $stmt->bindParam(":ip", $ip); - $stmt->execute(); - } else { - throw new RuntimeException("Unknown database backend"); - } - } - - /* - * Returns a JSON formatted error string. - * - * @param $msg The error string to return - * - * @return mixed A json formatted error response. - */ - private function json_error($msg) { - header('content-type: application/json'); - if ($this->version < 3) { - return $this->json_results('error', 0, $msg, NULL); - } elseif ($this->version >= 3) { - return $this->json_results('error', 0, array(), $msg); - } - } - - /* - * Returns a JSON formatted result data. - * - * @param $type The response method type. - * @param $count The number of results to return - * @param $data The result data to return - * @param $error An error message to include in the response - * - * @return mixed A json formatted result response. - */ - private function json_results($type, $count, $data, $error) { - $json_array = array( - 'version' => $this->version, - 'type' => $type, - 'resultcount' => $count, - 'results' => $data - ); - - if ($this->version != 5) { - $json_array['warning'] = 'The use of versions lower than 5 is ' - . 'now deprecated and will soon be unsupported. To ensure ' - . 'your API client supports the change without issue, it ' - . 'should use version 5 and adjust for any changes in the ' - . 'API interface. See https://aur.archlinux.org/rpc for ' - . 'documentation related to v5.'; - } - - if ($error) { - $json_array['error'] = $error; - } - - return json_encode($json_array); - } - - /* - * Get extended package details (for info and multiinfo queries). - * - * @param $pkgid The ID of the package to retrieve details for. - * @param $base_id The ID of the package base to retrieve details for. - * - * @return array An array containing package details. - */ - private function get_extended_fields($pkgid, $base_id) { - $query = "SELECT DependencyTypes.Name AS Type, " . - "PackageDepends.DepName AS Name, " . - "PackageDepends.DepCondition AS Cond " . - "FROM PackageDepends " . - "LEFT JOIN DependencyTypes " . - "ON DependencyTypes.ID = PackageDepends.DepTypeID " . - "WHERE PackageDepends.PackageID = " . $pkgid . " " . - "UNION SELECT RelationTypes.Name AS Type, " . - "PackageRelations.RelName AS Name, " . - "PackageRelations.RelCondition AS Cond " . - "FROM PackageRelations " . - "LEFT JOIN RelationTypes " . - "ON RelationTypes.ID = PackageRelations.RelTypeID " . - "WHERE PackageRelations.PackageID = " . $pkgid . " " . - "UNION SELECT 'groups' AS Type, `Groups`.`Name`, '' AS Cond " . - "FROM `Groups` INNER JOIN PackageGroups " . - "ON PackageGroups.PackageID = " . $pkgid . " " . - "AND PackageGroups.GroupID = `Groups`.ID " . - "UNION SELECT 'license' AS Type, Licenses.Name, '' AS Cond " . - "FROM Licenses INNER JOIN PackageLicenses " . - "ON PackageLicenses.PackageID = " . $pkgid . " " . - "AND PackageLicenses.LicenseID = Licenses.ID"; - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - $rows = db_cache_result($query, 'extended-fields:' . $pkgid, PDO::FETCH_ASSOC, $ttl); - - $type_map = array( - 'depends' => 'Depends', - 'makedepends' => 'MakeDepends', - 'checkdepends' => 'CheckDepends', - 'optdepends' => 'OptDepends', - 'conflicts' => 'Conflicts', - 'provides' => 'Provides', - 'replaces' => 'Replaces', - 'groups' => 'Groups', - 'license' => 'License', - ); - $data = array(); - foreach ($rows as $row) { - $type = $type_map[$row['Type']]; - $data[$type][] = $row['Name'] . $row['Cond']; - } - - if ($this->version >= 5) { - $query = "SELECT Keyword FROM PackageKeywords " . - "WHERE PackageBaseID = " . intval($base_id) . " " . - "ORDER BY Keyword ASC"; - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - $rows = db_cache_result($query, 'keywords:' . intval($base_id), PDO::FETCH_NUM, $ttl); - $data['Keywords'] = array_map(function ($x) { return $x[0]; }, $rows); - } - - return $data; - } - - /* - * Retrieve package information (used in info, multiinfo, search and - * depends requests). - * - * @param $type The request type. - * @param $where_condition An SQL WHERE-condition to filter packages. - * - * @return mixed Returns an array of package matches. - */ - private function process_query($type, $where_condition) { - $max_results = config_get_int('options', 'max_rpc_results'); - - if ($this->version == 1) { - $fields = implode(',', self::$fields_v1); - $query = "SELECT {$fields} " . - "FROM Packages LEFT JOIN PackageBases " . - "ON PackageBases.ID = Packages.PackageBaseID " . - "LEFT JOIN Users " . - "ON PackageBases.MaintainerUID = Users.ID " . - "LEFT JOIN PackageLicenses " . - "ON PackageLicenses.PackageID = Packages.ID " . - "LEFT JOIN Licenses " . - "ON Licenses.ID = PackageLicenses.LicenseID " . - "WHERE ${where_condition} " . - "AND PackageBases.PackagerUID IS NOT NULL " . - "LIMIT $max_results"; - } elseif ($this->version >= 2) { - if ($this->version == 2 || $this->version == 3) { - $fields = implode(',', self::$fields_v2); - } else if ($this->version >= 4 && $this->version <= 6) { - $fields = implode(',', self::$fields_v4); - } - $query = "SELECT {$fields} " . - "FROM Packages LEFT JOIN PackageBases " . - "ON PackageBases.ID = Packages.PackageBaseID " . - "LEFT JOIN Users " . - "ON PackageBases.MaintainerUID = Users.ID " . - "WHERE ${where_condition} " . - "AND PackageBases.PackagerUID IS NOT NULL " . - "LIMIT $max_results"; - } - $result = $this->dbh->query($query); - - if ($result) { - $resultcount = 0; - $search_data = array(); - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $resultcount++; - $row['URLPath'] = sprintf(config_get('options', 'snapshot_uri'), urlencode($row['PackageBase'])); - if ($this->version < 4) { - $row['CategoryID'] = 1; - } - - /* - * Unfortunately, mysql_fetch_assoc() returns - * all fields as strings. We need to coerce - * numeric values into integers to provide - * proper data types in the JSON response. - */ - foreach (self::$numeric_fields as $field) { - if (isset($row[$field])) { - $row[$field] = intval($row[$field]); - } - } - - foreach (self::$decimal_fields as $field) { - if (isset($row[$field])) { - $row[$field] = floatval($row[$field]); - } - } - - if ($this->version >= 2 && ($type == 'info' || $type == 'multiinfo')) { - $extfields = $this->get_extended_fields($row['ID'], $row['PackageBaseID']); - if ($extfields) { - $row = array_merge($row, $extfields); - } - } - - if ($this->version < 3) { - if ($type == 'info') { - $search_data = $row; - break; - } else { - array_push($search_data, $row); - } - } elseif ($this->version >= 3) { - array_push($search_data, $row); - } - } - - if ($resultcount === $max_results) { - return $this->json_error('Too many package results.'); - } - - return $this->json_results($type, $resultcount, $search_data, NULL); - } else { - return $this->json_results($type, 0, array(), NULL); - } - } - - /* - * Parse the args to the multiinfo function. We may have a string or an - * array, so do the appropriate thing. Within the elements, both * package - * IDs and package names are valid; sort them into the relevant arrays and - * escape/quote the names. - * - * @param array $args Query parameters. - * - * @return mixed An array containing 'ids' and 'names'. - */ - private function parse_multiinfo_args($args) { - if (!is_array($args)) { - $args = array($args); - } - - $id_args = array(); - $name_args = array(); - foreach ($args as $arg) { - if (!$arg) { - continue; - } - if ($this->version < 5 && is_numeric($arg)) { - $id_args[] = intval($arg); - } else { - $name_args[] = $this->dbh->quote($arg); - } - } - - return array('ids' => $id_args, 'names' => $name_args); - } - - /* - * Performs a fulltext mysql search of the package database. - * - * @param array $http_data Query parameters. - * - * @return mixed Returns an array of package matches. - */ - private function search($http_data) { - $keyword_string = $http_data['arg']; - - if (isset($http_data['by'])) { - $search_by = $http_data['by']; - } else { - $search_by = 'name-desc'; - } - - if ($search_by === 'name' || $search_by === 'name-desc') { - if (strlen($keyword_string) < 2) { - return $this->json_error('Query arg too small.'); - } - - if ($this->version >= 6 && $search_by === 'name-desc') { - $where_condition = construct_keyword_search($this->dbh, - $keyword_string, true, false); - } else { - $keyword_string = $this->dbh->quote( - "%" . addcslashes($keyword_string, '%_') . "%"); - - if ($search_by === 'name') { - $where_condition = "(Packages.Name LIKE $keyword_string)"; - } else if ($search_by === 'name-desc') { - $where_condition = "(Packages.Name LIKE $keyword_string "; - $where_condition .= "OR Description LIKE $keyword_string)"; - } - - } - } else if ($search_by === 'maintainer') { - if (empty($keyword_string)) { - $where_condition = "Users.ID is NULL"; - } else { - $keyword_string = $this->dbh->quote($keyword_string); - $where_condition = "Users.Username = $keyword_string "; - } - } else if (in_array($search_by, self::$exposed_depfields)) { - if (empty($keyword_string)) { - return $this->json_error('Query arg is empty.'); - } else { - $keyword_string = $this->dbh->quote($keyword_string); - $search_by = $this->dbh->quote($search_by); - $subquery = "SELECT PackageDepends.DepName FROM PackageDepends "; - $subquery .= "LEFT JOIN DependencyTypes "; - $subquery .= "ON PackageDepends.DepTypeID = DependencyTypes.ID "; - $subquery .= "WHERE PackageDepends.PackageID = Packages.ID "; - $subquery .= "AND DependencyTypes.Name = $search_by"; - $where_condition = "$keyword_string IN ($subquery)"; - } - } - - return $this->process_query('search', $where_condition); - } - - /* - * Returns the info on a specific package. - * - * @param array $http_data Query parameters. - * - * @return mixed Returns an array of value data containing the package data - */ - private function info($http_data) { - $pqdata = $http_data['arg']; - if ($this->version < 5 && is_numeric($pqdata)) { - $where_condition = "Packages.ID = $pqdata"; - } else { - $where_condition = "Packages.Name = " . $this->dbh->quote($pqdata); - } - - return $this->process_query('info', $where_condition); - } - - /* - * Returns the info on multiple packages. - * - * @param array $http_data Query parameters. - * - * @return mixed Returns an array of results containing the package data - */ - private function multiinfo($http_data) { - $pqdata = $http_data['arg']; - $args = $this->parse_multiinfo_args($pqdata); - $ids = $args['ids']; - $names = $args['names']; - - if (!$ids && !$names) { - return $this->json_error('Invalid query arguments.'); - } - - $where_condition = ""; - if ($ids) { - $ids_value = implode(',', $args['ids']); - $where_condition .= "Packages.ID IN ($ids_value) "; - } - if ($ids && $names) { - $where_condition .= "OR "; - } - if ($names) { - /* - * Individual names were quoted in - * parse_multiinfo_args(). - */ - $names_value = implode(',', $args['names']); - $where_condition .= "Packages.Name IN ($names_value) "; - } - - return $this->process_query('multiinfo', $where_condition); - } - - /* - * Returns all the packages for a specific maintainer. - * - * @param array $http_data Query parameters. - * - * @return mixed Returns an array of value data containing the package data - */ - private function msearch($http_data) { - $http_data['by'] = 'maintainer'; - return $this->search($http_data); - } - - /* - * Get all package names that start with $search. - * - * @param array $http_data Query parameters. - * - * @return string The JSON formatted response data. - */ - private function suggest($http_data) { - $search = $http_data['arg']; - $query = "SELECT Packages.Name FROM Packages "; - $query.= "LEFT JOIN PackageBases "; - $query.= "ON PackageBases.ID = Packages.PackageBaseID "; - $query.= "WHERE Packages.Name LIKE "; - $query.= $this->dbh->quote(addcslashes($search, '%_') . '%'); - $query.= " AND PackageBases.PackagerUID IS NOT NULL "; - $query.= "ORDER BY Name ASC LIMIT 20"; - - $result = $this->dbh->query($query); - $result_array = array(); - - if ($result) { - $result_array = $result->fetchAll(PDO::FETCH_COLUMN, 0); - } - - return json_encode($result_array); - } - - /* - * Get all package base names that start with $search. - * - * @param array $http_data Query parameters. - * - * @return string The JSON formatted response data. - */ - private function suggest_pkgbase($http_data) { - $search = $http_data['arg']; - $query = "SELECT Name FROM PackageBases WHERE Name LIKE "; - $query.= $this->dbh->quote(addcslashes($search, '%_') . '%'); - $query.= " AND PackageBases.PackagerUID IS NOT NULL "; - $query.= "ORDER BY Name ASC LIMIT 20"; - - $result = $this->dbh->query($query); - $result_array = array(); - - if ($result) { - $result_array = $result->fetchAll(PDO::FETCH_COLUMN, 0); - } - - return json_encode($result_array); - } - - /** - * Get the HTML markup of the comment form. - * - * @param array $http_data Query parameters. - * - * @return string The JSON formatted response data. - */ - private function get_comment_form($http_data) { - if (!isset($http_data['base_id']) || !isset($http_data['pkgbase_name'])) { - $output = array( - 'success' => 0, - 'error' => __('Package base ID or package base name missing.') - ); - return json_encode($output); - } - - $comment_id = intval($http_data['arg']); - $base_id = intval($http_data['base_id']); - $pkgbase_name = $http_data['pkgbase_name']; - - list($user_id, $comment) = comment_by_id($comment_id); - - if (!has_credential(CRED_COMMENT_EDIT, array($user_id))) { - $output = array( - 'success' => 0, - 'error' => __('You are not allowed to edit this comment.') - ); - return json_encode($output); - } elseif (is_null($comment)) { - $output = array( - 'success' => 0, - 'error' => __('Comment does not exist.') - ); - return json_encode($output); - } - - ob_start(); - include('pkg_comment_form.php'); - $html = ob_get_clean(); - $output = array( - 'success' => 1, - 'form' => $html - ); - - return json_encode($output); - } -} diff --git a/web/lib/cachefuncs.inc.php b/web/lib/cachefuncs.inc.php deleted file mode 100644 index b2b96c24..00000000 --- a/web/lib/cachefuncs.inc.php +++ /dev/null @@ -1,99 +0,0 @@ -addServer($mcserver[0], intval($mcserver[1])); - } -} - -# Set a value in the cache (currently APC) if cache is available for use. If -# not available, this becomes effectively a no-op (return value is -# false). Accepts an optional TTL (defaults to 600 seconds). -function set_cache_value($key, $value, $ttl=600) { - $status = false; - if (defined('EXTENSION_LOADED_APC')) { - $status = apc_store(CACHE_PREFIX.$key, $value, $ttl); - } - if (defined('EXTENSION_LOADED_MEMCACHE')) { - global $memcache; - $status = $memcache->set(CACHE_PREFIX.$key, $value, $ttl); - } - return $status; -} - -# Get a value from the cache (currently APC) if cache is available for use. If -# not available, this returns false (optionally sets passed in variable $status -# to false, much like apc_fetch() behaves). This allows for testing the fetch -# result appropriately even in the event that a 'false' value was the value in -# the cache. -function get_cache_value($key, &$status=false) { - if(defined('EXTENSION_LOADED_APC')) { - $ret = apc_fetch(CACHE_PREFIX.$key, $status); - if ($status) { - return $ret; - } - } - if (defined('EXTENSION_LOADED_MEMCACHE')) { - global $memcache; - $ret = $memcache->get(CACHE_PREFIX.$key); - if (!$ret) { - $status = false; - } - else { - $status = true; - } - return $ret; - } - return $status; -} - -# Run a simple db query, retrieving and/or caching the value if APC is -# available for use. Accepts an optional TTL value (defaults to 600 seconds). -function db_cache_value($dbq, $key, $ttl=600) { - $dbh = DB::connect(); - $status = false; - $value = get_cache_value($key, $status); - if (!$status) { - $result = $dbh->query($dbq); - if (!$result) { - return false; - } - $row = $result->fetch(PDO::FETCH_NUM); - $value = $row[0]; - set_cache_value($key, $value, $ttl); - } - return $value; -} - -# Run a simple db query, retrieving and/or caching the result set if APC is -# available for use. Accepts an optional TTL value (defaults to 600 seconds). -function db_cache_result($dbq, $key, $fetch_style=PDO::FETCH_NUM, $ttl=600) { - $dbh = DB::connect(); - $status = false; - $value = get_cache_value($key, $status); - if (!$status) { - $result = $dbh->query($dbq); - if (!$result) { - return false; - } - $value = $result->fetchAll($fetch_style); - set_cache_value($key, $value, $ttl); - } - return $value; -} - -?> diff --git a/web/lib/confparser.inc.php b/web/lib/confparser.inc.php deleted file mode 100644 index fdd2b78e..00000000 --- a/web/lib/confparser.inc.php +++ /dev/null @@ -1,59 +0,0 @@ -useCached(); // use cached version if age<1 hour -$rss->title = "PHP news"; -$rss->description = "daily news from the PHP scripting world"; - -//optional -$rss->descriptionTruncSize = 500; -$rss->descriptionHtmlSyndicated = true; - -$rss->link = "http://www.dailyphp.net/news"; -$rss->syndicationURL = "http://www.dailyphp.net/".$_SERVER["PHP_SELF"]; - -$image = new FeedImage(); -$image->title = "dailyphp.net logo"; -$image->url = "http://www.dailyphp.net/images/logo.gif"; -$image->link = "http://www.dailyphp.net"; -$image->description = "Feed provided by dailyphp.net. Click to visit."; - -//optional -$image->descriptionTruncSize = 500; -$image->descriptionHtmlSyndicated = true; - -$rss->image = $image; - -// get your news items from somewhere, e.g. your database: -mysql_select_db($dbHost, $dbUser, $dbPass); -$res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC"); -while ($data = mysql_fetch_object($res)) { - $item = new FeedItem(); - $item->title = $data->title; - $item->link = $data->url; - $item->description = $data->short; - - //optional - item->descriptionTruncSize = 500; - item->descriptionHtmlSyndicated = true; - - $item->date = $data->newsdate; - $item->source = "http://www.dailyphp.net"; - $item->author = "John Doe"; - - $rss->addItem($item); -} - -// valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1 (deprecated), -// MBOX, OPML, ATOM, ATOM0.3, HTML, JS -echo $rss->saveFeed("RSS1.0", "news/feed.xml"); - - -*************************************************************************** -* A little setup * -**************************************************************************/ - -// your local timezone, set to "" to disable or for GMT -define("TIME_ZONE","+01:00"); - - - - -/** - * Version string. - **/ -define("FEEDCREATOR_VERSION", "FeedCreator 1.7.2"); - - - -/** - * A FeedItem is a part of a FeedCreator feed. - * - * @author Kai Blankenhorn - * @since 1.3 - */ -class FeedItem extends HtmlDescribable { - /** - * Mandatory attributes of an item. - */ - var $title, $description, $link; - - /** - * Optional attributes of an item. - */ - var $author, $authorEmail, $image, $category, $comments, $guid, $guidIsPermaLink, $source, $creator; - - /** - * Publishing date of an item. May be in one of the following formats: - * - * RFC 822: - * "Mon, 20 Jan 03 18:05:41 +0400" - * "20 Jan 03 18:05:41 +0000" - * - * ISO 8601: - * "2003-01-20T18:05:41+04:00" - * - * Unix: - * 1043082341 - */ - var $date; - - /** - * Any additional elements to include as an assiciated array. All $key => $value pairs - * will be included unencoded in the feed item in the form - * <$key>$value - * Again: No encoding will be used! This means you can invalidate or enhance the feed - * if $value contains markup. This may be abused to embed tags not implemented by - * the FeedCreator class used. - */ - var $additionalElements = Array(); - - // on hold - // var $source; -} - - - -/** - * An FeedImage may be added to a FeedCreator feed. - * @author Kai Blankenhorn - * @since 1.3 - */ -class FeedImage extends HtmlDescribable { - /** - * Mandatory attributes of an image. - */ - var $title, $url, $link; - - /** - * Optional attributes of an image. - */ - var $width, $height, $description; -} - - - -/** - * An HtmlDescribable is an item within a feed that can have a description that may - * include HTML markup. - */ -class HtmlDescribable { - /** - * Indicates whether the description field should be rendered in HTML. - */ - var $descriptionHtmlSyndicated; - - /** - * Indicates whether and to how many characters a description should be truncated. - */ - var $descriptionTruncSize; - - /** - * Returns a formatted description field, depending on descriptionHtmlSyndicated and - * $descriptionTruncSize properties - * @return string the formatted description - */ - function getDescription() { - $descriptionField = new FeedHtmlField($this->description); - $descriptionField->syndicateHtml = $this->descriptionHtmlSyndicated; - $descriptionField->truncSize = $this->descriptionTruncSize; - return $descriptionField->output(); - } - -} - - -/** - * An FeedHtmlField describes and generates - * a feed, item or image html field (probably a description). Output is - * generated based on $truncSize, $syndicateHtml properties. - * @author Pascal Van Hecke - * @version 1.6 - */ -class FeedHtmlField { - /** - * Mandatory attributes of a FeedHtmlField. - */ - var $rawFieldContent; - - /** - * Optional attributes of a FeedHtmlField. - * - */ - var $truncSize, $syndicateHtml; - - /** - * Creates a new instance of FeedHtmlField. - * @param $string: if given, sets the rawFieldContent property - */ - function FeedHtmlField($parFieldContent) { - if ($parFieldContent) { - $this->rawFieldContent = $parFieldContent; - } - } - - - /** - * Creates the right output, depending on $truncSize, $syndicateHtml properties. - * @return string the formatted field - */ - function output() { - // when field available and syndicated in html we assume - // - valid html in $rawFieldContent and we enclose in CDATA tags - // - no truncation (truncating risks producing invalid html) - if (!$this->rawFieldContent) { - $result = ""; - } elseif ($this->syndicateHtml) { - $result = "rawFieldContent."]]>"; - } else { - if ($this->truncSize and is_int($this->truncSize)) { - $result = FeedCreator::iTrunc(htmlspecialchars($this->rawFieldContent),$this->truncSize); - } else { - $result = htmlspecialchars($this->rawFieldContent); - } - } - return $result; - } - -} - - - -/** - * UniversalFeedCreator lets you choose during runtime which - * format to build. - * For general usage of a feed class, see the FeedCreator class - * below or the example above. - * - * @since 1.3 - * @author Kai Blankenhorn - */ -class UniversalFeedCreator extends FeedCreator { - var $_feed; - - function _setFormat($format) { - switch (strtoupper($format)) { - - case "2.0": - // fall through - case "RSS2.0": - $this->_feed = new RSSCreator20(); - break; - - case "1.0": - // fall through - case "RSS1.0": - $this->_feed = new RSSCreator10(); - break; - - case "0.91": - // fall through - case "RSS0.91": - $this->_feed = new RSSCreator091(); - break; - - case "PIE0.1": - $this->_feed = new PIECreator01(); - break; - - case "MBOX": - $this->_feed = new MBOXCreator(); - break; - - case "OPML": - $this->_feed = new OPMLCreator(); - break; - - case "ATOM": - // fall through: always the latest ATOM version - - case "ATOM0.3": - $this->_feed = new AtomCreator03(); - break; - - case "HTML": - $this->_feed = new HTMLCreator(); - break; - - case "JS": - // fall through - case "JAVASCRIPT": - $this->_feed = new JSCreator(); - break; - - default: - $this->_feed = new RSSCreator091(); - break; - } - - $vars = get_object_vars($this); - foreach ($vars as $key => $value) { - // prevent overwriting of properties "contentType", "encoding"; do not copy "_feed" itself - if (!in_array($key, array("_feed", "contentType", "encoding"))) { - $this->_feed->{$key} = $this->{$key}; - } - } - } - - /** - * Creates a syndication feed based on the items previously added. - * - * @see FeedCreator::addItem() - * @param string format format the feed should comply to. Valid values are: - * "PIE0.1", "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3", "HTML", "JS" - * @return string the contents of the feed. - */ - function createFeed($format = "RSS0.91") { - $this->_setFormat($format); - return $this->_feed->createFeed(); - } - - - - /** - * Saves this feed as a file on the local disk. After the file is saved, an HTTP redirect - * header may be sent to redirect the use to the newly created file. - * @since 1.4 - * - * @param string format format the feed should comply to. Valid values are: - * "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM", "ATOM0.3", "HTML", "JS" - * @param string filename optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()). - * @param boolean displayContents optional send the content of the file or not. If true, the file will be sent in the body of the response. - */ - function saveFeed($format="RSS0.91", $filename="", $displayContents=true) { - $this->_setFormat($format); - $this->_feed->saveFeed($filename, $displayContents); - } - - - /** - * Turns on caching and checks if there is a recent version of this feed in the cache. - * If there is, an HTTP redirect header is sent. - * To effectively use caching, you should create the FeedCreator object and call this method - * before anything else, especially before you do the time consuming task to build the feed - * (web fetching, for example). - * - * @param string format format the feed should comply to. Valid values are: - * "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3". - * @param filename string optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()). - * @param timeout int optional the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour) - */ - function useCached($format="RSS0.91", $filename="", $timeout=3600) { - $this->_setFormat($format); - $this->_feed->useCached($filename, $timeout); - } - -} - - -/** - * FeedCreator is the abstract base implementation for concrete - * implementations that implement a specific format of syndication. - * - * @abstract - * @author Kai Blankenhorn - * @since 1.4 - */ -class FeedCreator extends HtmlDescribable { - - /** - * Mandatory attributes of a feed. - */ - var $title, $description, $link; - - - /** - * Optional attributes of a feed. - */ - var $syndicationURL, $image, $language, $copyright, $pubDate, $lastBuildDate, $editor, $editorEmail, $webmaster, $category, $docs, $ttl, $rating, $skipHours, $skipDays; - - /** - * The url of the external xsl stylesheet used to format the naked rss feed. - * Ignored in the output when empty. - */ - var $xslStyleSheet = ""; - - - /** - * @access private - */ - var $items = Array(); - - - /** - * This feed's MIME content type. - * @since 1.4 - * @access private - */ - var $contentType = "application/xml"; - - - /** - * This feed's character encoding. - * @since 1.6.1 - **/ - var $encoding = "ISO-8859-1"; - - - /** - * Any additional elements to include as an assiciated array. All $key => $value pairs - * will be included unencoded in the feed in the form - * <$key>$value - * Again: No encoding will be used! This means you can invalidate or enhance the feed - * if $value contains markup. This may be abused to embed tags not implemented by - * the FeedCreator class used. - */ - var $additionalElements = Array(); - - - /** - * Adds an FeedItem to the feed. - * - * @param object FeedItem $item The FeedItem to add to the feed. - * @access public - */ - function addItem($item) { - $this->items[] = $item; - } - - - /** - * Truncates a string to a certain length at the most sensible point. - * First, if there's a '.' character near the end of the string, the string is truncated after this character. - * If there is no '.', the string is truncated after the last ' ' character. - * If the string is truncated, " ..." is appended. - * If the string is already shorter than $length, it is returned unchanged. - * - * @static - * @param string string A string to be truncated. - * @param int length the maximum length the string should be truncated to - * @return string the truncated string - */ - function iTrunc($string, $length) { - if (strlen($string)<=$length) { - return $string; - } - - $pos = strrpos($string,"."); - if ($pos>=$length-4) { - $string = substr($string,0,$length-4); - $pos = strrpos($string,"."); - } - if ($pos>=$length*0.4) { - return substr($string,0,$pos+1)." ..."; - } - - $pos = strrpos($string," "); - if ($pos>=$length-4) { - $string = substr($string,0,$length-4); - $pos = strrpos($string," "); - } - if ($pos>=$length*0.4) { - return substr($string,0,$pos)." ..."; - } - - return substr($string,0,$length-4)." ..."; - - } - - - /** - * Creates a comment indicating the generator of this feed. - * The format of this comment seems to be recognized by - * Syndic8.com. - */ - function _createGeneratorComment() { - return "\n"; - } - - - /** - * Creates a string containing all additional elements specified in - * $additionalElements. - * @param elements array an associative array containing key => value pairs - * @param indentString string a string that will be inserted before every generated line - * @return string the XML tags corresponding to $additionalElements - */ - function _createAdditionalElements($elements, $indentString="") { - $ae = ""; - if (is_array($elements)) { - foreach($elements AS $key => $value) { - $ae.= $indentString."<$key>$value\n"; - } - } - return $ae; - } - - function _createStylesheetReferences() { - $xml = ""; - if ($this->cssStyleSheet) $xml .= "cssStyleSheet."\" type=\"text/css\"?>\n"; - if ($this->xslStyleSheet) $xml .= "xslStyleSheet."\" type=\"text/xsl\"?>\n"; - return $xml; - } - - - /** - * Builds the feed's text. - * @abstract - * @return string the feed's complete text - */ - function createFeed() { - } - - /** - * Generate a filename for the feed cache file. The result will be $_SERVER["PHP_SELF"] with the extension changed to .xml. - * For example: - * - * echo $_SERVER["PHP_SELF"]."\n"; - * echo FeedCreator::_generateFilename(); - * - * would produce: - * - * /rss/latestnews.php - * latestnews.xml - * - * @return string the feed cache filename - * @since 1.4 - * @access private - */ - function _generateFilename() { - $fileInfo = pathinfo($_SERVER["PHP_SELF"]); - return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".xml"; - } - - - /** - * @since 1.4 - * @access private - */ - function _redirect($filename) { - // attention, heavily-commented-out-area - - // maybe use this in addition to file time checking - //Header("Expires: ".date("r",time()+$this->_timeout)); - - /* no caching at all, doesn't seem to work as good: - Header("Cache-Control: no-cache"); - Header("Pragma: no-cache"); - */ - - // HTTP redirect, some feed readers' simple HTTP implementations don't follow it - //Header("Location: ".$filename); - - Header("Content-Type: ".$this->contentType."; charset=".$this->encoding."; filename=".basename($filename)); - Header("Content-Disposition: inline; filename=".basename($filename)); - readfile($filename, "r"); - die(); - } - - /** - * Turns on caching and checks if there is a recent version of this feed in the cache. - * If there is, an HTTP redirect header is sent. - * To effectively use caching, you should create the FeedCreator object and call this method - * before anything else, especially before you do the time consuming task to build the feed - * (web fetching, for example). - * @since 1.4 - * @param filename string optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()). - * @param timeout int optional the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour) - */ - function useCached($filename="", $timeout=3600) { - $this->_timeout = $timeout; - if ($filename=="") { - $filename = $this->_generateFilename(); - } - if (file_exists($filename) AND (time()-filemtime($filename) < $timeout)) { - $this->_redirect($filename); - } - } - - - /** - * Saves this feed as a file on the local disk. After the file is saved, a redirect - * header may be sent to redirect the user to the newly created file. - * @since 1.4 - * - * @param filename string optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()). - * @param redirect boolean optional send an HTTP redirect header or not. If true, the user will be automatically redirected to the created file. - */ - function saveFeed($filename="", $displayContents=true) { - if ($filename=="") { - $filename = $this->_generateFilename(); - } - $feedFile = fopen($filename, "w+"); - if ($feedFile) { - fputs($feedFile,$this->createFeed()); - fclose($feedFile); - if ($displayContents) { - $this->_redirect($filename); - } - } else { - echo "
    Error creating feed file, please check write permissions.
    "; - } - } - -} - - -/** - * FeedDate is an internal class that stores a date for a feed or feed item. - * Usually, you won't need to use this. - */ -class FeedDate { - var $unix; - - /** - * Creates a new instance of FeedDate representing a given date. - * Accepts RFC 822, ISO 8601 date formats as well as unix time stamps. - * @param mixed $dateString optional the date this FeedDate will represent. If not specified, the current date and time is used. - */ - function FeedDate($dateString="") { - if ($dateString=="") $dateString = date("r"); - - if (is_integer($dateString)) { - $this->unix = $dateString; - return; - } - if (preg_match("~(?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),\\s+)?(\\d{1,2})\\s+([a-zA-Z]{3})\\s+(\\d{4})\\s+(\\d{2}):(\\d{2}):(\\d{2})\\s+(.*)~",$dateString,$matches)) { - $months = Array("Jan"=>1,"Feb"=>2,"Mar"=>3,"Apr"=>4,"May"=>5,"Jun"=>6,"Jul"=>7,"Aug"=>8,"Sep"=>9,"Oct"=>10,"Nov"=>11,"Dec"=>12); - $this->unix = mktime($matches[4],$matches[5],$matches[6],$months[$matches[2]],$matches[1],$matches[3]); - if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') { - $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60; - } else { - if (strlen($matches[7])==1) { - $oneHour = 3600; - $ord = ord($matches[7]); - if ($ord < ord("M")) { - $tzOffset = (ord("A") - $ord - 1) * $oneHour; - } elseif ($ord >= ord("M") AND $matches[7]!="Z") { - $tzOffset = ($ord - ord("M")) * $oneHour; - } elseif ($matches[7]=="Z") { - $tzOffset = 0; - } - } - switch ($matches[7]) { - case "UT": - case "GMT": $tzOffset = 0; - } - } - $this->unix += $tzOffset; - return; - } - if (preg_match("~(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(.*)~",$dateString,$matches)) { - $this->unix = mktime($matches[4],$matches[5],$matches[6],$matches[2],$matches[3],$matches[1]); - if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') { - $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60; - } else { - if ($matches[7]=="Z") { - $tzOffset = 0; - } - } - $this->unix += $tzOffset; - return; - } - $this->unix = 0; - } - - /** - * Gets the date stored in this FeedDate as an RFC 822 date. - * - * @return a date in RFC 822 format - */ - function rfc822() { - //return gmdate("r",$this->unix); - $date = gmdate("D, d M Y H:i:s", $this->unix); - if (TIME_ZONE!="") $date .= " ".str_replace(":","",TIME_ZONE); - return $date; - } - - /** - * Gets the date stored in this FeedDate as an ISO 8601 date. - * - * @return a date in ISO 8601 format - */ - function iso8601() { - $date = gmdate("Y-m-d\TH:i:sO",$this->unix); - $date = substr($date,0,22) . ':' . substr($date,-2); - if (TIME_ZONE!="") $date = str_replace("+00:00",TIME_ZONE,$date); - return $date; - } - - /** - * Gets the date stored in this FeedDate as unix time stamp. - * - * @return a date as a unix time stamp - */ - function unix() { - return $this->unix; - } -} - - -/** - * RSSCreator10 is a FeedCreator that implements RDF Site Summary (RSS) 1.0. - * - * @see http://www.purl.org/rss/1.0/ - * @since 1.3 - * @author Kai Blankenhorn - */ -class RSSCreator10 extends FeedCreator { - - /** - * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0. - * The feed will contain all items previously added in the same order. - * @return string the feed's complete text - */ - function createFeed() { - $feed = "encoding."\"?>\n"; - $feed.= $this->_createGeneratorComment(); - if ($this->cssStyleSheet=="") { - $cssStyleSheet = "http://www.w3.org/2000/08/w3c-synd/style.css"; - } - $feed.= $this->_createStylesheetReferences(); - $feed.= "\n"; - $feed.= " syndicationURL."\">\n"; - $feed.= " ".htmlspecialchars($this->title)."\n"; - $feed.= " ".htmlspecialchars($this->description)."\n"; - $feed.= " ".$this->link."\n"; - if ($this->image!=null) { - $feed.= " image->url."\" />\n"; - } - $now = new FeedDate(); - $feed.= " ".htmlspecialchars($now->iso8601())."\n"; - $feed.= " \n"; - $feed.= " \n"; - for ($i=0;$iitems);$i++) { - $feed.= " items[$i]->link)."\"/>\n"; - } - $feed.= " \n"; - $feed.= " \n"; - $feed.= " \n"; - if ($this->image!=null) { - $feed.= " image->url."\">\n"; - $feed.= " ".$this->image->title."\n"; - $feed.= " ".$this->image->link."\n"; - $feed.= " ".$this->image->url."\n"; - $feed.= " \n"; - } - $feed.= $this->_createAdditionalElements($this->additionalElements, " "); - - for ($i=0;$iitems);$i++) { - $feed.= " items[$i]->link)."\">\n"; - //$feed.= " Posting\n"; - $feed.= " text/html\n"; - if ($this->items[$i]->date!=null) { - $itemDate = new FeedDate($this->items[$i]->date); - $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; - } - if ($this->items[$i]->source!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->source)."\n"; - } - if ($this->items[$i]->author!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->author)."\n"; - } - $feed.= " ".htmlspecialchars(strip_tags(strtr($this->items[$i]->title,"\n\r"," ")))."\n"; - $feed.= " ".htmlspecialchars($this->items[$i]->link)."\n"; - $feed.= " ".htmlspecialchars($this->items[$i]->description)."\n"; - $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); - $feed.= " \n"; - } - $feed.= "\n"; - return $feed; - } -} - - - -/** - * RSSCreator091 is a FeedCreator that implements RSS 0.91 Spec, revision 3. - * - * @see http://my.netscape.com/publish/formats/rss-spec-0.91.html - * @since 1.3 - * @author Kai Blankenhorn - */ -class RSSCreator091 extends FeedCreator { - - /** - * Stores this RSS feed's version number. - * @access private - */ - var $RSSVersion; - - function RSSCreator091() { - $this->_setRSSVersion("0.91"); - $this->contentType = "application/rss+xml"; - } - - /** - * Sets this RSS feed's version number. - * @access private - */ - function _setRSSVersion($version) { - $this->RSSVersion = $version; - } - - /** - * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0. - * The feed will contain all items previously added in the same order. - * @return string the feed's complete text - */ - function createFeed() { - $feed = "encoding."\"?>\n"; - $feed.= $this->_createGeneratorComment(); - $feed.= $this->_createStylesheetReferences(); - $feed.= "RSSVersion."\" xmlns:atom=\"http://www.w3.org/2005/Atom\">\n"; - $feed.= " \n"; - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."\n"; - $this->descriptionTruncSize = 500; - $feed.= " ".$this->getDescription()."\n"; - $feed.= " ".$this->link."\n"; - $feed.= " syndicationURL."\" rel=\"self\" type=\"application/rss+xml\" />\n"; - $now = new FeedDate(); - $feed.= " ".htmlspecialchars($now->rfc822())."\n"; - $feed.= " ".FEEDCREATOR_VERSION."\n"; - - if ($this->image!=null) { - $feed.= " \n"; - $feed.= " ".$this->image->url."\n"; - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->image->title),100)."\n"; - $feed.= " ".$this->image->link."\n"; - if ($this->image->width!="") { - $feed.= " ".$this->image->width."\n"; - } - if ($this->image->height!="") { - $feed.= " ".$this->image->height."\n"; - } - if ($this->image->description!="") { - $feed.= " ".$this->image->getDescription()."\n"; - } - $feed.= " \n"; - } - if ($this->language!="") { - $feed.= " ".$this->language."\n"; - } - if ($this->copyright!="") { - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->copyright),100)."\n"; - } - if ($this->editor!="") { - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->editor),100)."\n"; - } - if ($this->webmaster!="") { - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->webmaster),100)."\n"; - } - if ($this->pubDate!="") { - $pubDate = new FeedDate($this->pubDate); - $feed.= " ".htmlspecialchars($pubDate->rfc822())."\n"; - } - if ($this->category!="") { - $feed.= " ".htmlspecialchars($this->category)."\n"; - } - if ($this->docs!="") { - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->docs),500)."\n"; - } - if ($this->ttl!="") { - $feed.= " ".htmlspecialchars($this->ttl)."\n"; - } - if ($this->rating!="") { - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->rating),500)."\n"; - } - if ($this->skipHours!="") { - $feed.= " ".htmlspecialchars($this->skipHours)."\n"; - } - if ($this->skipDays!="") { - $feed.= " ".htmlspecialchars($this->skipDays)."\n"; - } - $feed.= $this->_createAdditionalElements($this->additionalElements, " "); - - for ($i=0;$iitems);$i++) { - $feed.= " \n"; - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."\n"; - $feed.= " ".htmlspecialchars($this->items[$i]->link)."\n"; - $feed.= " ".$this->items[$i]->getDescription()."\n"; - - if ($this->items[$i]->author!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->author)."\n"; - } - /* - // on hold - if ($this->items[$i]->source!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->source)."\n"; - } - */ - if ($this->items[$i]->category!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->category)."\n"; - } - if ($this->items[$i]->comments!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->comments)."\n"; - } - if ($this->items[$i]->date!="") { - $itemDate = new FeedDate($this->items[$i]->date); - $feed.= " ".htmlspecialchars($itemDate->rfc822())."\n"; - } - if ($this->items[$i]->guid!="") { - $feed.= " items[$i]->guidIsPermaLink == false) { - $feed.= " isPermaLink=\"false\""; - } - $feed.= ">".htmlspecialchars($this->items[$i]->guid)."\n"; - } - $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); - $feed.= " \n"; - } - $feed.= " \n"; - $feed.= "\n"; - return $feed; - } -} - - - -/** - * RSSCreator20 is a FeedCreator that implements RDF Site Summary (RSS) 2.0. - * - * @see http://backend.userland.com/rss - * @since 1.3 - * @author Kai Blankenhorn - */ -class RSSCreator20 extends RSSCreator091 { - - function RSSCreator20() { - parent::_setRSSVersion("2.0"); - } - -} - - -/** - * PIECreator01 is a FeedCreator that implements the emerging PIE specification, - * as in http://intertwingly.net/wiki/pie/Syntax. - * - * @deprecated - * @since 1.3 - * @author Scott Reynen and Kai Blankenhorn - */ -class PIECreator01 extends FeedCreator { - - function PIECreator01() { - $this->encoding = "utf-8"; - } - - function createFeed() { - $feed = "encoding."\"?>\n"; - $feed.= $this->_createStylesheetReferences(); - $feed.= "\n"; - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."\n"; - $this->truncSize = 500; - $feed.= " ".$this->getDescription()."\n"; - $feed.= " ".$this->link."\n"; - for ($i=0;$iitems);$i++) { - $feed.= " \n"; - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."\n"; - $feed.= " ".htmlspecialchars($this->items[$i]->link)."\n"; - $itemDate = new FeedDate($this->items[$i]->date); - $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; - $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; - $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; - $feed.= " ".htmlspecialchars($this->items[$i]->guid)."\n"; - if ($this->items[$i]->author!="") { - $feed.= " \n"; - $feed.= " ".htmlspecialchars($this->items[$i]->author)."\n"; - if ($this->items[$i]->authorEmail!="") { - $feed.= " ".$this->items[$i]->authorEmail."\n"; - } - $feed.=" \n"; - } - $feed.= " \n"; - $feed.= "
    ".$this->items[$i]->getDescription()."
    \n"; - $feed.= "
    \n"; - $feed.= "
    \n"; - } - $feed.= "
    \n"; - return $feed; - } -} - - -/** - * AtomCreator03 is a FeedCreator that implements the atom specification, - * as in http://www.intertwingly.net/wiki/pie/FrontPage. - * Please note that just by using AtomCreator03 you won't automatically - * produce valid atom files. For example, you have to specify either an editor - * for the feed or an author for every single feed item. - * - * Some elements have not been implemented yet. These are (incomplete list): - * author URL, item author's email and URL, item contents, alternate links, - * other link content types than text/html. Some of them may be created with - * AtomCreator03::additionalElements. - * - * @see FeedCreator#additionalElements - * @since 1.6 - * @author Kai Blankenhorn , Scott Reynen - */ -class AtomCreator03 extends FeedCreator { - - function AtomCreator03() { - $this->contentType = "application/atom+xml"; - $this->encoding = "utf-8"; - } - - function createFeed() { - $feed = "encoding."\"?>\n"; - $feed.= $this->_createGeneratorComment(); - $feed.= $this->_createStylesheetReferences(); - $feed.= "language!="") { - $feed.= " xml:lang=\"".$this->language."\""; - } - $feed.= ">\n"; - $feed.= " ".htmlspecialchars($this->title)."\n"; - $feed.= " ".htmlspecialchars($this->description)."\n"; - $feed.= " link)."\"/>\n"; - $feed.= " ".htmlspecialchars($this->link)."\n"; - $now = new FeedDate(); - $feed.= " ".htmlspecialchars($now->iso8601())."\n"; - if ($this->editor!="") { - $feed.= " \n"; - $feed.= " ".$this->editor."\n"; - if ($this->editorEmail!="") { - $feed.= " ".$this->editorEmail."\n"; - } - $feed.= " \n"; - } - $feed.= " ".FEEDCREATOR_VERSION."\n"; - $feed.= $this->_createAdditionalElements($this->additionalElements, " "); - for ($i=0;$iitems);$i++) { - $feed.= " \n"; - $feed.= " ".htmlspecialchars(strip_tags($this->items[$i]->title))."\n"; - $feed.= " items[$i]->link)."\"/>\n"; - if ($this->items[$i]->date=="") { - $this->items[$i]->date = time(); - } - $itemDate = new FeedDate($this->items[$i]->date); - $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; - $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; - $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; - $feed.= " ".htmlspecialchars($this->items[$i]->link)."\n"; - $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); - if ($this->items[$i]->author!="") { - $feed.= " \n"; - $feed.= " ".htmlspecialchars($this->items[$i]->author)."\n"; - $feed.= " \n"; - } - if ($this->items[$i]->description!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->description)."\n"; - } - $feed.= " \n"; - } - $feed.= "\n"; - return $feed; - } -} - - -/** - * MBOXCreator is a FeedCreator that implements the mbox format - * as described in http://www.qmail.org/man/man5/mbox.html - * - * @since 1.3 - * @author Kai Blankenhorn - */ -class MBOXCreator extends FeedCreator { - - function MBOXCreator() { - $this->contentType = "text/plain"; - $this->encoding = "ISO-8859-15"; - } - - function qp_enc($input = "", $line_max = 76) { - $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); - $lines = preg_split("/(?:\r\n|\r|\n)/", $input); - $eol = "\r\n"; - $escape = "="; - $output = ""; - while( list(, $line) = each($lines) ) { - //$line = rtrim($line); // remove trailing white space -> no =20\r\n necessary - $linlen = strlen($line); - $newline = ""; - for($i = 0; $i < $linlen; $i++) { - $c = substr($line, $i, 1); - $dec = ord($c); - if ( ($dec == 32) && ($i == ($linlen - 1)) ) { // convert space at eol only - $c = "=20"; - } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required - $h2 = floor($dec/16); $h1 = floor($dec%16); - $c = $escape.$hex["$h2"].$hex["$h1"]; - } - if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted - $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay - $newline = ""; - } - $newline .= $c; - } // end of for - $output .= $newline.$eol; - } - return trim($output); - } - - - /** - * Builds the MBOX contents. - * @return string the feed's complete text - */ - function createFeed() { - for ($i=0;$iitems);$i++) { - if ($this->items[$i]->author!="") { - $from = $this->items[$i]->author; - } else { - $from = $this->title; - } - $itemDate = new FeedDate($this->items[$i]->date); - $feed.= "From ".strtr(MBOXCreator::qp_enc($from)," ","_")." ".date("D M d H:i:s Y",$itemDate->unix())."\n"; - $feed.= "Content-Type: text/plain;\n"; - $feed.= " charset=\"".$this->encoding."\"\n"; - $feed.= "Content-Transfer-Encoding: quoted-printable\n"; - $feed.= "Content-Type: text/plain\n"; - $feed.= "From: \"".MBOXCreator::qp_enc($from)."\"\n"; - $feed.= "Date: ".$itemDate->rfc822()."\n"; - $feed.= "Subject: ".MBOXCreator::qp_enc(FeedCreator::iTrunc($this->items[$i]->title,100))."\n"; - $feed.= "\n"; - $body = chunk_split(MBOXCreator::qp_enc($this->items[$i]->description)); - $feed.= preg_replace("~\nFrom ([^\n]*)(\n?)~","\n>From $1$2\n",$body); - $feed.= "\n"; - $feed.= "\n"; - } - return $feed; - } - - /** - * Generate a filename for the feed cache file. Overridden from FeedCreator to prevent XML data types. - * @return string the feed cache filename - * @since 1.4 - * @access private - */ - function _generateFilename() { - $fileInfo = pathinfo($_SERVER["PHP_SELF"]); - return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".mbox"; - } -} - - -/** - * OPMLCreator is a FeedCreator that implements OPML 1.0. - * - * @see http://opml.scripting.com/spec - * @author Dirk Clemens, Kai Blankenhorn - * @since 1.5 - */ -class OPMLCreator extends FeedCreator { - - function OPMLCreator() { - $this->encoding = "utf-8"; - } - - function createFeed() { - $feed = "encoding."\"?>\n"; - $feed.= $this->_createGeneratorComment(); - $feed.= $this->_createStylesheetReferences(); - $feed.= "\n"; - $feed.= " \n"; - $feed.= " ".htmlspecialchars($this->title)."\n"; - if ($this->pubDate!="") { - $date = new FeedDate($this->pubDate); - $feed.= " ".$date->rfc822()."\n"; - } - if ($this->lastBuildDate!="") { - $date = new FeedDate($this->lastBuildDate); - $feed.= " ".$date->rfc822()."\n"; - } - if ($this->editor!="") { - $feed.= " ".$this->editor."\n"; - } - if ($this->editorEmail!="") { - $feed.= " ".$this->editorEmail."\n"; - } - $feed.= " \n"; - $feed.= " \n"; - for ($i=0;$iitems);$i++) { - $feed.= " items[$i]->title,"\n\r"," "))); - $feed.= " title=\"".$title."\""; - $feed.= " text=\"".$title."\""; - //$feed.= " description=\"".htmlspecialchars($this->items[$i]->description)."\""; - $feed.= " url=\"".htmlspecialchars($this->items[$i]->link)."\""; - $feed.= "/>\n"; - } - $feed.= " \n"; - $feed.= "\n"; - return $feed; - } -} - - - -/** - * HTMLCreator is a FeedCreator that writes an HTML feed file to a specific - * location, overriding the createFeed method of the parent FeedCreator. - * The HTML produced can be included over http by scripting languages, or serve - * as the source for an IFrame. - * All output by this class is embedded in
    tags to enable formatting - * using CSS. - * - * @author Pascal Van Hecke - * @since 1.7 - */ -class HTMLCreator extends FeedCreator { - - var $contentType = "text/html"; - - /** - * Contains HTML to be output at the start of the feed's html representation. - */ - var $header; - - /** - * Contains HTML to be output at the end of the feed's html representation. - */ - var $footer ; - - /** - * Contains HTML to be output between entries. A separator is only used in - * case of multiple entries. - */ - var $separator; - - /** - * Used to prefix the stylenames to make sure they are unique - * and do not clash with stylenames on the users' page. - */ - var $stylePrefix; - - /** - * Determines whether the links open in a new window or not. - */ - var $openInNewWindow = true; - - var $imageAlign ="right"; - - /** - * In case of very simple output you may want to get rid of the style tags, - * hence this variable. There's no equivalent on item level, but of course you can - * add strings to it while iterating over the items ($this->stylelessOutput .= ...) - * and when it is non-empty, ONLY the styleless output is printed, the rest is ignored - * in the function createFeed(). - */ - var $stylelessOutput =""; - - /** - * Writes the HTML. - * @return string the scripts's complete text - */ - function createFeed() { - // if there is styleless output, use the content of this variable and ignore the rest - if ($this->stylelessOutput!="") { - return $this->stylelessOutput; - } - - //if no stylePrefix is set, generate it yourself depending on the script name - if ($this->stylePrefix=="") { - $this->stylePrefix = str_replace(".", "_", $this->_generateFilename())."_"; - } - - //set an openInNewWindow_token_to be inserted or not - if ($this->openInNewWindow) { - $targetInsert = " target='_blank'"; - } - - // use this array to put the lines in and implode later with "document.write" javascript - $feedArray = array(); - if ($this->image!=null) { - $imageStr = "". - "".
-							FeedCreator::iTrunc(htmlspecialchars($this->image->title),100).
-							"image->width) { - $imageStr .=" width='".$this->image->width. "' "; - } - if ($this->image->height) { - $imageStr .=" height='".$this->image->height."' "; - } - $imageStr .="/>"; - $feedArray[] = $imageStr; - } - - if ($this->title) { - $feedArray[] = ""; - } - if ($this->getDescription()) { - $feedArray[] = "
    ". - str_replace("]]>", "", str_replace("getDescription())). - "
    "; - } - - if ($this->header) { - $feedArray[] = "
    ".$this->header."
    "; - } - - for ($i=0;$iitems);$i++) { - if ($this->separator and $i > 0) { - $feedArray[] = "
    ".$this->separator."
    "; - } - - if ($this->items[$i]->title) { - if ($this->items[$i]->link) { - $feedArray[] = - ""; - } else { - $feedArray[] = - "
    ". - FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100). - "
    "; - } - } - if ($this->items[$i]->getDescription()) { - $feedArray[] = - "
    ". - str_replace("]]>", "", str_replace("items[$i]->getDescription())). - "
    "; - } - } - if ($this->footer) { - $feedArray[] = "
    ".$this->footer."
    "; - } - - $feed= "".join($feedArray, "\r\n"); - return $feed; - } - - /** - * Overrrides parent to produce .html extensions - * - * @return string the feed cache filename - * @since 1.4 - * @access private - */ - function _generateFilename() { - $fileInfo = pathinfo($_SERVER["PHP_SELF"]); - return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".html"; - } -} - - -/** - * JSCreator is a class that writes a js file to a specific - * location, overriding the createFeed method of the parent HTMLCreator. - * - * @author Pascal Van Hecke - */ -class JSCreator extends HTMLCreator { - var $contentType = "text/javascript"; - - /** - * writes the javascript - * @return string the scripts's complete text - */ - function createFeed() - { - $feed = parent::createFeed(); - $feedArray = explode("\n",$feed); - - $jsFeed = ""; - foreach ($feedArray as $value) { - $jsFeed .= "document.write('".trim(addslashes($value))."');\n"; - } - return $jsFeed; - } - - /** - * Overrrides parent to produce .js extensions - * - * @return string the feed cache filename - * @since 1.4 - * @access private - */ - function _generateFilename() { - $fileInfo = pathinfo($_SERVER["PHP_SELF"]); - return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".js"; - } - -} - - - -/*** TEST SCRIPT ********************************************************* - -//include("feedcreator.class.php"); - -$rss = new UniversalFeedCreator(); -$rss->useCached(); -$rss->title = "PHP news"; -$rss->description = "daily news from the PHP scripting world"; - -//optional -//$rss->descriptionTruncSize = 500; -//$rss->descriptionHtmlSyndicated = true; -//$rss->xslStyleSheet = "http://feedster.com/rss20.xsl"; - -$rss->link = "http://www.dailyphp.net/news"; -$rss->feedURL = "http://www.dailyphp.net/".$PHP_SELF; - -$image = new FeedImage(); -$image->title = "dailyphp.net logo"; -$image->url = "http://www.dailyphp.net/images/logo.gif"; -$image->link = "http://www.dailyphp.net"; -$image->description = "Feed provided by dailyphp.net. Click to visit."; - -//optional -$image->descriptionTruncSize = 500; -$image->descriptionHtmlSyndicated = true; - -$rss->image = $image; - -// get your news items from somewhere, e.g. your database: -//mysql_select_db($dbHost, $dbUser, $dbPass); -//$res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC"); -//while ($data = mysql_fetch_object($res)) { - $item = new FeedItem(); - $item->title = "This is an the test title of an item"; - $item->link = "http://localhost/item/"; - $item->description = "description in
    HTML"; - - //optional - //item->descriptionTruncSize = 500; - $item->descriptionHtmlSyndicated = true; - - $item->date = time(); - $item->source = "http://www.dailyphp.net"; - $item->author = "John Doe"; - - $rss->addItem($item); -//} - -// valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1, MBOX, OPML, ATOM0.3, HTML, JS -echo $rss->saveFeed("RSS0.91", "feed.xml"); - - - -***************************************************************************/ - -?> diff --git a/web/lib/gettext.php b/web/lib/gettext.php deleted file mode 100644 index 098f0e5e..00000000 --- a/web/lib/gettext.php +++ /dev/null @@ -1,432 +0,0 @@ -. - Copyright (c) 2005 Nico Kaiser - - This file is part of PHP-gettext. - - PHP-gettext is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - PHP-gettext is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with PHP-gettext; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -/** - * Provides a simple gettext replacement that works independently from - * the system's gettext abilities. - * It can read MO files and use them for translating strings. - * The files are passed to gettext_reader as a Stream (see streams.php) - * - * This version has the ability to cache all strings and translations to - * speed up the string lookup. - * While the cache is enabled by default, it can be switched off with the - * second parameter in the constructor (e.g. whenusing very large MO files - * that you don't want to keep in memory) - */ -class gettext_reader { - //public: - var $error = 0; // public variable that holds error code (0 if no error) - - //private: - var $BYTEORDER = 0; // 0: low endian, 1: big endian - var $STREAM = NULL; - var $short_circuit = false; - var $enable_cache = false; - var $originals = NULL; // offset of original table - var $translations = NULL; // offset of translation table - var $pluralheader = NULL; // cache header field for plural forms - var $total = 0; // total string count - var $table_originals = NULL; // table for original strings (offsets) - var $table_translations = NULL; // table for translated strings (offsets) - var $cache_translations = NULL; // original -> translation mapping - - - /* Methods */ - - - /** - * Reads a 32bit Integer from the Stream - * - * @access private - * @return Integer from the Stream - */ - function readint() { - if ($this->BYTEORDER == 0) { - // low endian - $input=unpack('V', $this->STREAM->read(4)); - return array_shift($input); - } else { - // big endian - $input=unpack('N', $this->STREAM->read(4)); - return array_shift($input); - } - } - - function read($bytes) { - return $this->STREAM->read($bytes); - } - - /** - * Reads an array of Integers from the Stream - * - * @param int count How many elements should be read - * @return Array of Integers - */ - function readintarray($count) { - if ($this->BYTEORDER == 0) { - // low endian - return unpack('V'.$count, $this->STREAM->read(4 * $count)); - } else { - // big endian - return unpack('N'.$count, $this->STREAM->read(4 * $count)); - } - } - - /** - * Constructor - * - * @param object Reader the StreamReader object - * @param boolean enable_cache Enable or disable caching of strings (default on) - */ - function __construct($Reader, $enable_cache = true) { - // If there isn't a StreamReader, turn on short circuit mode. - if (! $Reader || isset($Reader->error) ) { - $this->short_circuit = true; - return; - } - - // Caching can be turned off - $this->enable_cache = $enable_cache; - - $MAGIC1 = "\x95\x04\x12\xde"; - $MAGIC2 = "\xde\x12\x04\x95"; - - $this->STREAM = $Reader; - $magic = $this->read(4); - if ($magic == $MAGIC1) { - $this->BYTEORDER = 1; - } elseif ($magic == $MAGIC2) { - $this->BYTEORDER = 0; - } else { - $this->error = 1; // not MO file - return false; - } - - // FIXME: Do we care about revision? We should. - $revision = $this->readint(); - - $this->total = $this->readint(); - $this->originals = $this->readint(); - $this->translations = $this->readint(); - } - - /** - * Loads the translation tables from the MO file into the cache - * If caching is enabled, also loads all strings into a cache - * to speed up translation lookups - * - * @access private - */ - function load_tables() { - if (is_array($this->cache_translations) && - is_array($this->table_originals) && - is_array($this->table_translations)) - return; - - /* get original and translations tables */ - if (!is_array($this->table_originals)) { - $this->STREAM->seekto($this->originals); - $this->table_originals = $this->readintarray($this->total * 2); - } - if (!is_array($this->table_translations)) { - $this->STREAM->seekto($this->translations); - $this->table_translations = $this->readintarray($this->total * 2); - } - - if ($this->enable_cache) { - $this->cache_translations = array (); - /* read all strings in the cache */ - for ($i = 0; $i < $this->total; $i++) { - $this->STREAM->seekto($this->table_originals[$i * 2 + 2]); - $original = $this->STREAM->read($this->table_originals[$i * 2 + 1]); - $this->STREAM->seekto($this->table_translations[$i * 2 + 2]); - $translation = $this->STREAM->read($this->table_translations[$i * 2 + 1]); - $this->cache_translations[$original] = $translation; - } - } - } - - /** - * Returns a string from the "originals" table - * - * @access private - * @param int num Offset number of original string - * @return string Requested string if found, otherwise '' - */ - function get_original_string($num) { - $length = $this->table_originals[$num * 2 + 1]; - $offset = $this->table_originals[$num * 2 + 2]; - if (! $length) - return ''; - $this->STREAM->seekto($offset); - $data = $this->STREAM->read($length); - return (string)$data; - } - - /** - * Returns a string from the "translations" table - * - * @access private - * @param int num Offset number of original string - * @return string Requested string if found, otherwise '' - */ - function get_translation_string($num) { - $length = $this->table_translations[$num * 2 + 1]; - $offset = $this->table_translations[$num * 2 + 2]; - if (! $length) - return ''; - $this->STREAM->seekto($offset); - $data = $this->STREAM->read($length); - return (string)$data; - } - - /** - * Binary search for string - * - * @access private - * @param string string - * @param int start (internally used in recursive function) - * @param int end (internally used in recursive function) - * @return int string number (offset in originals table) - */ - function find_string($string, $start = -1, $end = -1) { - if (($start == -1) or ($end == -1)) { - // find_string is called with only one parameter, set start end end - $start = 0; - $end = $this->total; - } - if (abs($start - $end) <= 1) { - // We're done, now we either found the string, or it doesn't exist - $txt = $this->get_original_string($start); - if ($string == $txt) - return $start; - else - return -1; - } else if ($start > $end) { - // start > end -> turn around and start over - return $this->find_string($string, $end, $start); - } else { - // Divide table in two parts - $half = (int)(($start + $end) / 2); - $cmp = strcmp($string, $this->get_original_string($half)); - if ($cmp == 0) - // string is exactly in the middle => return it - return $half; - else if ($cmp < 0) - // The string is in the upper half - return $this->find_string($string, $start, $half); - else - // The string is in the lower half - return $this->find_string($string, $half, $end); - } - } - - /** - * Translates a string - * - * @access public - * @param string string to be translated - * @return string translated string (or original, if not found) - */ - function translate($string) { - if ($this->short_circuit) - return $string; - $this->load_tables(); - - if ($this->enable_cache) { - // Caching enabled, get translated string from cache - if (array_key_exists($string, $this->cache_translations)) - return $this->cache_translations[$string]; - else - return $string; - } else { - // Caching not enabled, try to find string - $num = $this->find_string($string); - if ($num == -1) - return $string; - else - return $this->get_translation_string($num); - } - } - - /** - * Sanitize plural form expression for use in PHP eval call. - * - * @access private - * @return string sanitized plural form expression - */ - function sanitize_plural_expression($expr) { - // Get rid of disallowed characters. - $expr = preg_replace('@[^a-zA-Z0-9_:;\(\)\?\|\&=!<>+*/\%-]@', '', $expr); - - // Add parenthesis for tertiary '?' operator. - $expr .= ';'; - $res = ''; - $p = 0; - for ($i = 0; $i < strlen($expr); $i++) { - $ch = $expr[$i]; - switch ($ch) { - case '?': - $res .= ' ? ('; - $p++; - break; - case ':': - $res .= ') : ('; - break; - case ';': - $res .= str_repeat( ')', $p) . ';'; - $p = 0; - break; - default: - $res .= $ch; - } - } - return $res; - } - - /** - * Parse full PO header and extract only plural forms line. - * - * @access private - * @return string verbatim plural form header field - */ - function extract_plural_forms_header_from_po_header($header) { - if (preg_match("/(^|\n)plural-forms: ([^\n]*)\n/i", $header, $regs)) - $expr = $regs[2]; - else - $expr = "nplurals=2; plural=n == 1 ? 0 : 1;"; - return $expr; - } - - /** - * Get possible plural forms from MO header - * - * @access private - * @return string plural form header - */ - function get_plural_forms() { - // lets assume message number 0 is header - // this is true, right? - $this->load_tables(); - - // cache header field for plural forms - if (! is_string($this->pluralheader)) { - if ($this->enable_cache) { - $header = $this->cache_translations[""]; - } else { - $header = $this->get_translation_string(0); - } - $expr = $this->extract_plural_forms_header_from_po_header($header); - $this->pluralheader = $this->sanitize_plural_expression($expr); - } - return $this->pluralheader; - } - - /** - * Detects which plural form to take - * - * @access private - * @param n count - * @return int array index of the right plural form - */ - function select_string($n) { - $string = $this->get_plural_forms(); - $string = str_replace('nplurals',"\$total",$string); - $string = str_replace("n",$n,$string); - $string = str_replace('plural',"\$plural",$string); - - $total = 0; - $plural = 0; - - eval("$string"); - if ($plural >= $total) $plural = $total - 1; - return $plural; - } - - /** - * Plural version of gettext - * - * @access public - * @param string single - * @param string plural - * @param string number - * @return translated plural form - */ - function ngettext($single, $plural, $number) { - if ($this->short_circuit) { - if ($number != 1) - return $plural; - else - return $single; - } - - // find out the appropriate form - $select = $this->select_string($number); - - // this should contains all strings separated by NULLs - $key = $single . chr(0) . $plural; - - - if ($this->enable_cache) { - if (! array_key_exists($key, $this->cache_translations)) { - return ($number != 1) ? $plural : $single; - } else { - $result = $this->cache_translations[$key]; - $list = explode(chr(0), $result); - return $list[$select]; - } - } else { - $num = $this->find_string($key); - if ($num == -1) { - return ($number != 1) ? $plural : $single; - } else { - $result = $this->get_translation_string($num); - $list = explode(chr(0), $result); - return $list[$select]; - } - } - } - - function pgettext($context, $msgid) { - $key = $context . chr(4) . $msgid; - $ret = $this->translate($key); - if (strpos($ret, "\004") !== false) { - return $msgid; - } else { - return $ret; - } - } - - function npgettext($context, $singular, $plural, $number) { - $key = $context . chr(4) . $singular; - $ret = $this->ngettext($key, $plural, $number); - if (strpos($ret, "\004") !== false) { - return $singular; - } else { - return $ret; - } - - } -} - -?> diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php deleted file mode 100644 index a053962e..00000000 --- a/web/lib/pkgbasefuncs.inc.php +++ /dev/null @@ -1,1253 +0,0 @@ -query($q); - if (!$result) { - return null; - } - - return $result->fetchColumn(0); -} - -/** - * Get all package comment information for a specific package base - * - * @param int $base_id The package base ID to get comments for - * @param int $limit Maximum number of comments to return (0 means unlimited) - * @param bool $include_deleted True if deleted comments should be included - * @param bool $only_pinned True when only pinned comments are to be included - * - * @return array All package comment information for a specific package base - */ -function pkgbase_comments($base_id, $limit, $include_deleted, $only_pinned=false, $offset=0) { - $base_id = intval($base_id); - $limit = intval($limit); - if (!$base_id) { - return null; - } - - $dbh = DB::connect(); - $q = "SELECT PackageComments.ID, A.UserName AS UserName, UsersID, Comments, "; - $q.= "PackageBaseID, CommentTS, DelTS, EditedTS, B.UserName AS EditUserName, "; - $q.= "DelUsersID, C.UserName AS DelUserName, RenderedComment, "; - $q.= "PinnedTS FROM PackageComments "; - $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID "; - $q.= "LEFT JOIN Users B ON PackageComments.EditedUsersID = B.ID "; - $q.= "LEFT JOIN Users C ON PackageComments.DelUsersID = C.ID "; - $q.= "WHERE PackageBaseID = " . $base_id . " "; - - if (!$include_deleted) { - $q.= "AND DelTS IS NULL "; - } - if ($only_pinned) { - $q.= "AND NOT PinnedTS = 0 "; - } - $q.= "ORDER BY CommentTS DESC"; - if ($limit > 0) { - $q.=" LIMIT " . $limit; - } - if ($offset > 0) { - $q.=" OFFSET " . $offset; - } - $result = $dbh->query($q); - if (!$result) { - return null; - } - - return $result->fetchAll(); -} - -/* - * Invoke the comment rendering script. - * - * @param int $id ID of the comment to render - * - * @return void - */ -function render_comment($id) { - $cmd = config_get('options', 'render-comment-cmd'); - $cmd .= ' ' . intval($id); - - $descspec = array( - 0 => array('pipe', 'r'), - 1 => array('pipe', 'w'), - ); - - $p = proc_open($cmd, $descspec, $pipes); - - if (!is_resource($p)) { - return false; - } - - fclose($pipes[0]); - fclose($pipes[1]); - - return proc_close($p); -} - -/** - * Add a comment to a package page and send out appropriate notifications - * - * @param string $base_id The package base ID to add the comment on - * @param string $uid The user ID of the individual who left the comment - * @param string $comment The comment left on a package page - * - * @return void - */ -function pkgbase_add_comment($base_id, $uid, $comment) { - $dbh = DB::connect(); - - if (trim($comment) == '') { - return array(false, __('Comment cannot be empty.')); - } - - $q = "INSERT INTO PackageComments "; - $q.= "(PackageBaseID, UsersID, Comments, RenderedComment, CommentTS) "; - $q.= "VALUES (" . intval($base_id) . ", " . $uid . ", "; - $q.= $dbh->quote($comment) . ", '', " . strval(time()) . ")"; - $dbh->exec($q); - $comment_id = $dbh->lastInsertId(); - - render_comment($comment_id); - - notify(array('comment', $uid, $base_id, $comment_id)); - - return array(true, __('Comment has been added.')); -} - -/** - * Pin/unpin a package comment - * - * @param bool $unpin True if unpinning rather than pinning - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_pin_comment($unpin=false) { - $uid = uid_from_sid($_COOKIE["AURSID"]); - - if (!$uid) { - return array(false, __("You must be logged in before you can edit package information.")); - } - - if (isset($_POST["comment_id"])) { - $comment_id = $_POST["comment_id"]; - } else { - return array(false, __("Missing comment ID.")); - } - - if (!$unpin) { - if (pkgbase_comments_count($_POST['package_base'], false, true) >= 5){ - return array(false, __("No more than 5 comments can be pinned.")); - } - } - - if (!can_pin_comment($comment_id)) { - if (!$unpin) { - return array(false, __("You are not allowed to pin this comment.")); - } else { - return array(false, __("You are not allowed to unpin this comment.")); - } - } - - $dbh = DB::connect(); - $q = "UPDATE PackageComments "; - if (!$unpin) { - $q.= "SET PinnedTS = " . strval(time()) . " "; - } else { - $q.= "SET PinnedTS = 0 "; - } - $q.= "WHERE ID = " . intval($comment_id); - $dbh->exec($q); - - if (!$unpin) { - return array(true, __("Comment has been pinned.")); - } else { - return array(true, __("Comment has been unpinned.")); - } -} - -/** - - * Get a list of all packages a logged-in user has voted for - * - * @param string $sid The session ID of the visitor - * - * @return array All packages the visitor has voted for - */ -function pkgbase_votes_from_sid($sid="") { - $pkgs = array(); - if (!$sid) {return $pkgs;} - $dbh = DB::connect(); - $q = "SELECT PackageBaseID "; - $q.= "FROM PackageVotes, Users, Sessions "; - $q.= "WHERE Users.ID = Sessions.UsersID "; - $q.= "AND Users.ID = PackageVotes.UsersID "; - $q.= "AND Sessions.SessionID = " . $dbh->quote($sid); - $result = $dbh->query($q); - if ($result) { - while ($row = $result->fetch(PDO::FETCH_NUM)) { - $pkgs[$row[0]] = 1; - } - } - return $pkgs; -} - -/** - * Get the package base details - * - * @param string $id The package base ID to get description for - * - * @return array The package base's details OR error message - **/ -function pkgbase_get_details($base_id) { - $dbh = DB::connect(); - - $q = "SELECT PackageBases.ID, PackageBases.Name, "; - $q.= "PackageBases.NumVotes, PackageBases.Popularity, "; - $q.= "PackageBases.OutOfDateTS, PackageBases.SubmittedTS, "; - $q.= "PackageBases.ModifiedTS, PackageBases.SubmitterUID, "; - $q.= "PackageBases.MaintainerUID, PackageBases.PackagerUID, "; - $q.= "PackageBases.FlaggerUID, "; - $q.= "(SELECT COUNT(*) FROM PackageRequests "; - $q.= " WHERE PackageRequests.PackageBaseID = PackageBases.ID "; - $q.= " AND PackageRequests.Status = 0) AS RequestCount "; - $q.= "FROM PackageBases "; - $q.= "WHERE PackageBases.ID = " . intval($base_id); - $result = $dbh->query($q); - - $row = array(); - - if (!$result) { - $row['error'] = __("Error retrieving package details."); - } - else { - $row = $result->fetch(PDO::FETCH_ASSOC); - if (empty($row)) { - $row['error'] = __("Package details could not be found."); - } - } - - return $row; -} - -/** - * Display the package base details page - * - * @param string $id The package base ID to get details page for - * @param array $row Package base details retrieved by pkgbase_get_details() - * @param string $SID The session ID of the visitor - * - * @return void - */ -function pkgbase_display_details($base_id, $row, $SID="") { - if (isset($row['error'])) { - print "

    " . $row['error'] . "

    \n"; - } - else { - $pkgbase_name = pkgbase_name_from_id($base_id); - - include('pkgbase_details.php'); - - if ($SID) { - $comment_section = "package"; - include('pkg_comment_box.php'); - } - - $include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED); - - $limit_pinned = isset($_GET['pinned']) ? 0 : 5; - $pinned = pkgbase_comments($base_id, $limit_pinned, false, true); - if (!empty($pinned)) { - $comment_section = "package"; - include('pkg_comments.php'); - } - unset($pinned); - - - $total_comment_count = pkgbase_comments_count($base_id, $include_deleted); - list($pagination_templs, $per_page, $offset) = calculate_pagination($total_comment_count); - - $comments = pkgbase_comments($base_id, $per_page, $include_deleted, false, $offset); - if (!empty($comments)) { - $comment_section = "package"; - include('pkg_comments.php'); - } - } -} - -/** - * Convert a list of package IDs into a list of corresponding package bases. - * - * @param array|int $ids Array of package IDs to convert - * - * @return array|int List of package base IDs - */ -function pkgbase_from_pkgid($ids) { - $dbh = DB::connect(); - - if (is_array($ids)) { - $q = "SELECT PackageBaseID FROM Packages "; - $q.= "WHERE ID IN (" . implode(",", $ids) . ")"; - $result = $dbh->query($q); - return $result->fetchAll(PDO::FETCH_COLUMN, 0); - } else { - $q = "SELECT PackageBaseID FROM Packages "; - $q.= "WHERE ID = " . $ids; - $result = $dbh->query($q); - return $result->fetch(PDO::FETCH_COLUMN, 0); - } -} - -/** - * Retrieve ID of a package base by name - * - * @param string $name The package base name to retrieve the ID for - * - * @return int The ID of the package base - */ -function pkgbase_from_name($name) { - $dbh = DB::connect(); - $q = "SELECT ID FROM PackageBases WHERE Name = " . $dbh->quote($name); - $result = $dbh->query($q); - return $result->fetch(PDO::FETCH_COLUMN, 0); -} - -/** - * Retrieve the name of a package base given its ID - * - * @param int $base_id The ID of the package base to query - * - * @return string The name of the package base - */ -function pkgbase_name_from_id($base_id) { - $dbh = DB::connect(); - $q = "SELECT Name FROM PackageBases WHERE ID = " . intval($base_id); - $result = $dbh->query($q); - return $result->fetch(PDO::FETCH_COLUMN, 0); -} - -/** - * Get the names of all packages belonging to a package base - * - * @param int $base_id The ID of the package base - * - * @return array The names of all packages belonging to the package base - */ -function pkgbase_get_pkgnames($base_id) { - $dbh = DB::connect(); - $q = "SELECT Name FROM Packages WHERE PackageBaseID = " . intval($base_id); - $result = $dbh->query($q); - return $result->fetchAll(PDO::FETCH_COLUMN, 0); -} - -/** - * Determine whether a package base is (or contains a) VCS package - * - * @param int $base_id The ID of the package base - * - * @return bool True if the package base is/contains a VCS package - */ -function pkgbase_is_vcs($base_id) { - $suffixes = array("-cvs", "-svn", "-git", "-hg", "-bzr", "-darcs"); - $haystack = pkgbase_get_pkgnames($base_id); - array_push($haystack, pkgbase_name_from_id($base_id)); - foreach ($haystack as $pkgname) { - foreach ($suffixes as $suffix) { - if (substr_compare($pkgname, $suffix, -strlen($suffix)) === 0) { - return true; - } - } - } - return false; -} - -/** - * Delete all packages belonging to a package base - * - * @param int $base_id The ID of the package base - * - * @return void - */ -function pkgbase_delete_packages($base_id) { - $dbh = DB::connect(); - $q = "DELETE FROM Packages WHERE PackageBaseID = " . intval($base_id); - $dbh->exec($q); -} - -/** - * Retrieve the maintainer of a package base given its ID - * - * @param int $base_id The ID of the package base to query - * - * @return int The user ID of the current package maintainer - */ -function pkgbase_maintainer_uid($base_id) { - $dbh = DB::connect(); - $q = "SELECT MaintainerUID FROM PackageBases WHERE ID = " . intval($base_id); - $result = $dbh->query($q); - return $result->fetch(PDO::FETCH_COLUMN, 0); -} - -/** - * Retrieve the maintainers of an array of package bases given by their ID - * - * @param int $base_ids The array of IDs of the package bases to query - * - * @return int The user ID of the current package maintainer - */ -function pkgbase_maintainer_uids($base_ids) { - $dbh = DB::connect(); - $q = "SELECT MaintainerUID FROM PackageBases WHERE ID IN (" . implode(",", $base_ids) . ")"; - $result = $dbh->query($q); - return $result->fetchAll(PDO::FETCH_COLUMN, 0); -} - -/** - * Flag package(s) as out-of-date - * - * @param array $base_ids Array of package base IDs to flag/unflag - * @param string $comment The comment to add - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_flag($base_ids, $comment) { - if (!has_credential(CRED_PKGBASE_FLAG)) { - return array(false, __("You must be logged in before you can flag packages.")); - } - - $base_ids = sanitize_ids($base_ids); - if (empty($base_ids)) { - return array(false, __("You did not select any packages to flag.")); - } - - if (strlen($comment) < 3) { - return array(false, __("The selected packages have not been flagged, please enter a comment.")); - } - - $uid = uid_from_sid($_COOKIE['AURSID']); - $dbh = DB::connect(); - - $q = "UPDATE PackageBases SET "; - $q.= "OutOfDateTS = " . strval(time()) . ", FlaggerUID = " . $uid . ", "; - $q.= "FlaggerComment = " . $dbh->quote($comment) . " "; - $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") "; - $q.= "AND OutOfDateTS IS NULL"; - $dbh->exec($q); - - foreach ($base_ids as $base_id) { - notify(array('flag', $uid, $base_id)); - } - - return array(true, __("The selected packages have been flagged out-of-date.")); -} - -/** - * Unflag package(s) as out-of-date - * - * @param array $base_ids Array of package base IDs to flag/unflag - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_unflag($base_ids) { - $uid = uid_from_sid($_COOKIE["AURSID"]); - if (!$uid) { - return array(false, __("You must be logged in before you can unflag packages.")); - } - - $base_ids = sanitize_ids($base_ids); - if (empty($base_ids)) { - return array(false, __("You did not select any packages to unflag.")); - } - - $dbh = DB::connect(); - - $q = "UPDATE PackageBases SET "; - $q.= "OutOfDateTS = NULL "; - $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") "; - - $maintainers = array_merge(pkgbase_maintainer_uids($base_ids), pkgbase_get_comaintainer_uids($base_ids)); - if (!has_credential(CRED_PKGBASE_UNFLAG, $maintainers)) { - $q.= "AND (MaintainerUID = " . $uid . " OR FlaggerUID = " . $uid. ")"; - } - - $result = $dbh->exec($q); - - if ($result) { - return array(true, __("The selected packages have been unflagged.")); - } -} - -/** - * Get package flag OOD comment - * - * @param int $base_id - * - * @return array Tuple of pkgbase ID, reason for OOD, and user who flagged - */ -function pkgbase_get_flag_comment($base_id) { - $base_id = intval($base_id); - $dbh = DB::connect(); - - $q = "SELECT FlaggerComment,OutOfDateTS,Username FROM PackageBases "; - $q.= "LEFT JOIN Users ON FlaggerUID = Users.ID "; - $q.= "WHERE PackageBases.ID = " . $base_id . " "; - $q.= "AND PackageBases.OutOfDateTS IS NOT NULL"; - $result = $dbh->query($q); - - $row = array(); - - if (!$result) { - $row['error'] = __("Error retrieving package details."); - } - else { - $row = $result->fetch(PDO::FETCH_ASSOC); - if (empty($row)) { - $row['error'] = __("Package details could not be found."); - } - } - - return $row; -} - -/** - * Delete package bases - * - * @param array $base_ids Array of package base IDs to delete - * @param int $merge_base_id Package base to merge the deleted ones into - * @param int $via Package request to close upon deletion - * @param bool $grant Allow anyone to delete the package base - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_delete ($base_ids, $merge_base_id, $via, $grant=false) { - if (!$grant && !has_credential(CRED_PKGBASE_DELETE)) { - return array(false, __("You do not have permission to delete packages.")); - } - - $base_ids = sanitize_ids($base_ids); - if (empty($base_ids)) { - return array(false, __("You did not select any packages to delete.")); - } - - $dbh = DB::connect(); - - if ($merge_base_id) { - $merge_base_name = pkgbase_name_from_id($merge_base_id); - } - - $uid = uid_from_sid($_COOKIE['AURSID']); - foreach ($base_ids as $base_id) { - if ($merge_base_id) { - notify(array('delete', $uid, $base_id, $merge_base_id)); - } else { - notify(array('delete', $uid, $base_id)); - } - } - - /* - * Close package request if the deletion was initiated through the - * request interface. NOTE: This needs to happen *before* the actual - * deletion. Otherwise, the former maintainer will not be included in - * the Cc list of the request notification email. - */ - if ($via) { - pkgreq_close(intval($via), 'accepted', ''); - } - - /* Scan through pending deletion requests and close them. */ - $username = username_from_sid($_COOKIE['AURSID']); - foreach ($base_ids as $base_id) { - $pkgreq_ids = array_merge(pkgreq_by_pkgbase($base_id)); - foreach ($pkgreq_ids as $pkgreq_id) { - pkgreq_close(intval($pkgreq_id), 'accepted', - 'The user ' . $username . - ' deleted the package.', true); - } - } - - if ($merge_base_id) { - /* Merge comments */ - $q = "UPDATE PackageComments "; - $q.= "SET PackageBaseID = " . intval($merge_base_id) . " "; - $q.= "WHERE PackageBaseID IN (" . implode(",", $base_ids) . ")"; - $dbh->exec($q); - - /* Merge notifications */ - $q = "SELECT DISTINCT UserID FROM PackageNotifications cn "; - $q.= "WHERE PackageBaseID IN (" . implode(",", $base_ids) . ") "; - $q.= "AND NOT EXISTS (SELECT * FROM PackageNotifications cn2 "; - $q.= "WHERE cn2.PackageBaseID = " . intval($merge_base_id) . " "; - $q.= "AND cn2.UserID = cn.UserID)"; - $result = $dbh->query($q); - - while ($notify_uid = $result->fetch(PDO::FETCH_COLUMN, 0)) { - $q = "INSERT INTO PackageNotifications (UserID, PackageBaseID) "; - $q.= "VALUES (" . intval($notify_uid) . ", " . intval($merge_base_id) . ")"; - $dbh->exec($q); - } - - /* Merge votes */ - foreach ($base_ids as $base_id) { - $q = "UPDATE PackageVotes "; - $q.= "SET PackageBaseID = " . intval($merge_base_id) . " "; - $q.= "WHERE PackageBaseID = " . $base_id . " "; - $q.= "AND UsersID NOT IN ("; - $q.= "SELECT * FROM (SELECT UsersID "; - $q.= "FROM PackageVotes "; - $q.= "WHERE PackageBaseID = " . intval($merge_base_id); - $q.= ") temp)"; - $dbh->exec($q); - } - - $q = "UPDATE PackageBases "; - $q.= "SET NumVotes = (SELECT COUNT(*) FROM PackageVotes "; - $q.= "WHERE PackageBaseID = " . intval($merge_base_id) . ") "; - $q.= "WHERE ID = " . intval($merge_base_id); - $dbh->exec($q); - } - - $q = "DELETE FROM Packages WHERE PackageBaseID IN (" . implode(",", $base_ids) . ")"; - $dbh->exec($q); - - $q = "DELETE FROM PackageBases WHERE ID IN (" . implode(",", $base_ids) . ")"; - $dbh->exec($q); - - return array(true, __("The selected packages have been deleted.")); -} - -/** - * Adopt or disown packages - * - * @param array $base_ids Array of package base IDs to adopt/disown - * @param bool $action Adopts if true, disowns if false. Adopts by default - * @param int $via Package request to close upon adoption - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_adopt ($base_ids, $action=true, $via) { - $dbh = DB::connect(); - - $uid = uid_from_sid($_COOKIE["AURSID"]); - if (!$uid) { - if ($action) { - return array(false, __("You must be logged in before you can adopt packages.")); - } else { - return array(false, __("You must be logged in before you can disown packages.")); - } - } - - /* Verify package ownership. */ - $base_ids = sanitize_ids($base_ids); - - $q = "SELECT ID FROM PackageBases "; - $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") "; - - if ($action && !has_credential(CRED_PKGBASE_ADOPT)) { - /* Regular users may only adopt orphan packages. */ - $q.= "AND MaintainerUID IS NULL"; - } - if (!$action && !has_credential(CRED_PKGBASE_DISOWN)) { - /* Regular users may only disown their own packages. */ - $q.= "AND MaintainerUID = " . $uid; - } - - $result = $dbh->query($q); - $base_ids = $result->fetchAll(PDO::FETCH_COLUMN, 0); - - /* Error out if the list of remaining packages is empty. */ - if (empty($base_ids)) { - if ($action) { - return array(false, __("You did not select any packages to adopt.")); - } else { - return array(false, __("You did not select any packages to disown.")); - } - } - - /* - * Close package request if the disownment was initiated through the - * request interface. NOTE: This needs to happen *before* the actual - * disown operation. Otherwise, the former maintainer will not be - * included in the Cc list of the request notification email. - */ - if ($via) { - pkgreq_close(intval($via), 'accepted', ''); - } - - /* Scan through pending orphan requests and close them. */ - if (!$action) { - $username = username_from_sid($_COOKIE['AURSID']); - foreach ($base_ids as $base_id) { - $pkgreq_ids = pkgreq_by_pkgbase($base_id, 'orphan'); - foreach ($pkgreq_ids as $pkgreq_id) { - pkgreq_close(intval($pkgreq_id), 'accepted', - 'The user ' . $username . - ' disowned the package.', true); - } - } - } - - /* Adopt or disown the package. */ - if ($action) { - $q = "UPDATE PackageBases "; - $q.= "SET MaintainerUID = $uid "; - $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") "; - $dbh->exec($q); - - /* Add the new maintainer to the notification list. */ - pkgbase_notify($base_ids); - } else { - /* Update the co-maintainer list when disowning a package. */ - if (has_credential(CRED_PKGBASE_DISOWN)) { - foreach ($base_ids as $base_id) { - pkgbase_set_comaintainers($base_id, array()); - } - - $q = "UPDATE PackageBases "; - $q.= "SET MaintainerUID = NULL "; - $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") "; - $dbh->exec($q); - } else { - foreach ($base_ids as $base_id) { - $comaintainers = pkgbase_get_comaintainers($base_id); - - if (count($comaintainers) > 0) { - $comaintainer_uid = uid_from_username($comaintainers[0]); - $comaintainers = array_diff($comaintainers, array($comaintainers[0])); - pkgbase_set_comaintainers($base_id, $comaintainers); - } else { - $comaintainer_uid = "NULL"; - } - - $q = "UPDATE PackageBases "; - $q.= "SET MaintainerUID = " . $comaintainer_uid . " "; - $q.= "WHERE ID = " . $base_id; - $dbh->exec($q); - } - } - } - - foreach ($base_ids as $base_id) { - notify(array($action ? 'adopt' : 'disown', $uid, $base_id)); - } - - if ($action) { - return array(true, __("The selected packages have been adopted.")); - } else { - return array(true, __("The selected packages have been disowned.")); - } -} - -/** - * Vote and un-vote for packages - * - * @param array $base_ids Array of package base IDs to vote/un-vote - * @param bool $action Votes if true, un-votes if false. Votes by default - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_vote ($base_ids, $action=true) { - if (!has_credential(CRED_PKGBASE_VOTE)) { - if ($action) { - return array(false, __("You must be logged in before you can vote for packages.")); - } else { - return array(false, __("You must be logged in before you can un-vote for packages.")); - } - } - - $base_ids = sanitize_ids($base_ids); - if (empty($base_ids)) { - if ($action) { - return array(false, __("You did not select any packages to vote for.")); - } else { - return array(false, __("Your votes have been removed from the selected packages.")); - } - } - - $dbh = DB::connect(); - $my_votes = pkgbase_votes_from_sid($_COOKIE["AURSID"]); - $uid = uid_from_sid($_COOKIE["AURSID"]); - - $first = 1; - $vote_ids = ""; - $vote_clauses = ""; - foreach ($base_ids as $pid) { - if ($action) { - $check = !isset($my_votes[$pid]); - } else { - $check = isset($my_votes[$pid]); - } - - if ($check) { - if ($first) { - $first = 0; - $vote_ids = $pid; - if ($action) { - $vote_clauses = "($uid, $pid, " . strval(time()) . ")"; - } - } else { - $vote_ids .= ", $pid"; - if ($action) { - $vote_clauses .= ", ($uid, $pid, " . strval(time()) . ")"; - } - } - } - } - - if (!empty($vote_ids)) { - /* Only add votes for packages the user hasn't already voted for. */ - $op = $action ? "+" : "-"; - $q = "UPDATE PackageBases SET NumVotes = NumVotes $op 1 "; - $q.= "WHERE ID IN ($vote_ids)"; - - $dbh->exec($q); - - if ($action) { - $q = "INSERT INTO PackageVotes (UsersID, PackageBaseID, VoteTS) VALUES "; - $q.= $vote_clauses; - } else { - $q = "DELETE FROM PackageVotes WHERE UsersID = $uid "; - $q.= "AND PackageBaseID IN ($vote_ids)"; - } - - $dbh->exec($q); - } - - if ($action) { - return array(true, __("Your votes have been cast for the selected packages.")); - } else { - return array(true, __("Your votes have been removed from the selected packages.")); - } -} - -/** - * Get all usernames and IDs that voted for a specific package base - * - * @param string $pkgbase_name The package base to retrieve votes for - * - * @return array User IDs and usernames that voted for a specific package base - */ -function pkgbase_votes_from_name($pkgbase_name) { - $dbh = DB::connect(); - - $q = "SELECT UsersID, Username, Name, VoteTS FROM PackageVotes "; - $q.= "LEFT JOIN Users ON UsersID = Users.ID "; - $q.= "LEFT JOIN PackageBases "; - $q.= "ON PackageVotes.PackageBaseID = PackageBases.ID "; - $q.= "WHERE PackageBases.Name = ". $dbh->quote($pkgbase_name) . " "; - $q.= "ORDER BY Username"; - $result = $dbh->query($q); - - if (!$result) { - return; - } - - $votes = array(); - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $votes[] = $row; - } - - return $votes; -} - -/** - * Determine if a user has already voted for a specific package base - * - * @param string $uid The user ID to check for an existing vote - * @param string $base_id The package base ID to check for an existing vote - * - * @return bool True if the user has already voted, otherwise false - */ -function pkgbase_user_voted($uid, $base_id) { - $dbh = DB::connect(); - $q = "SELECT COUNT(*) FROM PackageVotes WHERE "; - $q.= "UsersID = ". $dbh->quote($uid) . " AND "; - $q.= "PackageBaseID = " . $dbh->quote($base_id); - $result = $dbh->query($q); - if (!$result) { - return null; - } - - return ($result->fetch(PDO::FETCH_COLUMN, 0) > 0); -} - -/** - * Determine if a user wants notifications for a specific package base - * - * @param string $uid User ID to check in the database - * @param string $base_id Package base ID to check notifications for - * - * @return bool True if the user wants notifications, otherwise false - */ -function pkgbase_user_notify($uid, $base_id) { - $dbh = DB::connect(); - - $q = "SELECT * FROM PackageNotifications WHERE UserID = " . $dbh->quote($uid); - $q.= " AND PackageBaseID = " . $dbh->quote($base_id); - $result = $dbh->query($q); - - if (!$result) { - return false; - } - - return ($result->fetch(PDO::FETCH_NUM) > 0); -} - -/** - * Toggle notification of packages - * - * @param array $base_ids Array of package base IDs to toggle - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_notify ($base_ids, $action=true) { - if (!has_credential(CRED_PKGBASE_NOTIFY)) { - return; - } - - $base_ids = sanitize_ids($base_ids); - if (empty($base_ids)) { - return array(false, __("Couldn't add to notification list.")); - } - - $dbh = DB::connect(); - $uid = uid_from_sid($_COOKIE["AURSID"]); - - $output = ""; - - $first = true; - - /* - * There currently shouldn't be multiple requests here, but the format - * in which it's sent requires this. - */ - foreach ($base_ids as $bid) { - $q = "SELECT Name FROM PackageBases WHERE ID = $bid"; - $result = $dbh->query($q); - if ($result) { - $row = $result->fetch(PDO::FETCH_NUM); - $basename = $row[0]; - } - else { - $basename = ''; - } - - if ($first) - $first = false; - else - $output .= ", "; - - - if ($action) { - $q = "SELECT COUNT(*) FROM PackageNotifications WHERE "; - $q .= "UserID = $uid AND PackageBaseID = $bid"; - - /* Notification already added. Don't add again. */ - $result = $dbh->query($q); - if ($result->fetchColumn() == 0) { - $q = "INSERT INTO PackageNotifications (PackageBaseID, UserID) VALUES ($bid, $uid)"; - $dbh->exec($q); - } - - $output .= $basename; - } - else { - $q = "DELETE FROM PackageNotifications WHERE PackageBaseID = $bid "; - $q .= "AND UserID = $uid"; - $dbh->exec($q); - - $output .= $basename; - } - } - - if ($action) { - $output = __("You have been added to the comment notification list for %s.", $output); - } - else { - $output = __("You have been removed from the comment notification list for %s.", $output); - } - - return array(true, $output); -} - -/** - * Delete a package comment - * - * @param boolean $undelete True if undeleting rather than deleting - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_delete_comment($undelete=false) { - $uid = uid_from_sid($_COOKIE["AURSID"]); - if (!$uid) { - return array(false, __("You must be logged in before you can edit package information.")); - } - - if (isset($_POST["comment_id"])) { - $comment_id = $_POST["comment_id"]; - } else { - return array(false, __("Missing comment ID.")); - } - - $dbh = DB::connect(); - if ($undelete) { - if (!has_credential(CRED_COMMENT_UNDELETE)) { - return array(false, __("You are not allowed to undelete this comment.")); - } - - $q = "UPDATE PackageComments "; - $q.= "SET DelUsersID = NULL, "; - $q.= "DelTS = NULL "; - $q.= "WHERE ID = ".intval($comment_id); - $dbh->exec($q); - return array(true, __("Comment has been undeleted.")); - } else { - if (!can_delete_comment($comment_id)) { - return array(false, __("You are not allowed to delete this comment.")); - } - - $q = "UPDATE PackageComments "; - $q.= "SET DelUsersID = ".$uid.", "; - $q.= "DelTS = " . strval(time()) . " "; - $q.= "WHERE ID = ".intval($comment_id); - $dbh->exec($q); - return array(true, __("Comment has been deleted.")); - } -} - -/** - * Edit a package comment - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_edit_comment($comment) { - $uid = uid_from_sid($_COOKIE["AURSID"]); - if (!$uid) { - return array(false, __("You must be logged in before you can edit package information.")); - } - - if (isset($_POST["comment_id"])) { - $comment_id = $_POST["comment_id"]; - } else { - return array(false, __("Missing comment ID.")); - } - - if (trim($comment) == '') { - return array(false, __('Comment cannot be empty.')); - } - - $dbh = DB::connect(); - if (can_edit_comment($comment_id)) { - $q = "UPDATE PackageComments "; - $q.= "SET EditedUsersID = ".$uid.", "; - $q.= "Comments = ".$dbh->quote($comment).", "; - $q.= "EditedTS = " . strval(time()) . " "; - $q.= "WHERE ID = ".intval($comment_id); - $dbh->exec($q); - - render_comment($comment_id); - - return array(true, __("Comment has been edited.")); - } else { - return array(false, __("You are not allowed to edit this comment.")); - } -} - -/** - * Get a list of package base keywords - * - * @param int $base_id The package base ID to retrieve the keywords for - * - * @return array An array of keywords - */ -function pkgbase_get_keywords($base_id) { - $dbh = DB::connect(); - $q = "SELECT Keyword FROM PackageKeywords "; - $q .= "WHERE PackageBaseID = " . intval($base_id) . " "; - $q .= "ORDER BY Keyword ASC"; - $result = $dbh->query($q); - - if ($result) { - return $result->fetchAll(PDO::FETCH_COLUMN, 0); - } else { - return array(); - } -} - -/** - * Update the list of keywords of a package base - * - * @param int $base_id The package base ID to update the keywords of - * @param array $users Array of keywords - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_set_keywords($base_id, $keywords) { - $base_id = intval($base_id); - - $maintainers = array_merge(array(pkgbase_maintainer_uid($base_id)), pkgbase_get_comaintainer_uids(array($base_id))); - if (!has_credential(CRED_PKGBASE_SET_KEYWORDS, $maintainers)) { - return array(false, __("You are not allowed to edit the keywords of this package base.")); - } - - /* Remove empty and duplicate user names. */ - $keywords = array_unique(array_filter(array_map('trim', $keywords))); - - $dbh = DB::connect(); - - $q = sprintf("DELETE FROM PackageKeywords WHERE PackageBaseID = %d", $base_id); - $dbh->exec($q); - - $i = 0; - foreach ($keywords as $keyword) { - $q = sprintf("INSERT INTO PackageKeywords (PackageBaseID, Keyword) VALUES (%d, %s)", $base_id, $dbh->quote($keyword)); - $dbh->exec($q); - - $i++; - if ($i >= 20) { - break; - } - } - - return array(true, __("The package base keywords have been updated.")); -} - -/** - * Get a list of package base co-maintainers - * - * @param int $base_id The package base ID to retrieve the co-maintainers for - * - * @return array An array of co-maintainer user names - */ -function pkgbase_get_comaintainers($base_id) { - $dbh = DB::connect(); - $q = "SELECT UserName FROM PackageComaintainers "; - $q .= "INNER JOIN Users ON Users.ID = PackageComaintainers.UsersID "; - $q .= "WHERE PackageComaintainers.PackageBaseID = " . intval($base_id) . " "; - $q .= "ORDER BY Priority ASC"; - $result = $dbh->query($q); - - if ($result) { - return $result->fetchAll(PDO::FETCH_COLUMN, 0); - } else { - return array(); - } -} - -/** - * Get a list of package base co-maintainer IDs - * - * @param int $base_id The package base ID to retrieve the co-maintainers for - * - * @return array An array of co-maintainer user UDs - */ -function pkgbase_get_comaintainer_uids($base_ids) { - $dbh = DB::connect(); - $q = "SELECT UsersID FROM PackageComaintainers "; - $q .= "INNER JOIN Users ON Users.ID = PackageComaintainers.UsersID "; - $q .= "WHERE PackageComaintainers.PackageBaseID IN (" . implode(",", $base_ids) . ") "; - $q .= "ORDER BY Priority ASC"; - $result = $dbh->query($q); - - if ($result) { - return $result->fetchAll(PDO::FETCH_COLUMN, 0); - } else { - return array(); - } -} - -/** - * Update the list of co-maintainers of a package base - * - * @param int $base_id The package base ID to update the co-maintainers of - * @param array $users Array of co-maintainer user names - * @param boolean $override Override credential check if true - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_set_comaintainers($base_id, $users, $override=false) { - $maintainer_uid = pkgbase_maintainer_uid($base_id); - if (!$override && !has_credential(CRED_PKGBASE_EDIT_COMAINTAINERS, array($maintainer_uid))) { - return array(false, __("You are not allowed to manage co-maintainers of this package base.")); - } - - /* Remove empty and duplicate user names. */ - $users = array_unique(array_filter(array_map('trim', $users))); - - $dbh = DB::connect(); - - $uids_new = array(); - foreach($users as $user) { - $q = "SELECT ID FROM Users "; - $q .= "WHERE UserName = " . $dbh->quote($user); - $result = $dbh->query($q); - $uid = $result->fetchColumn(0); - - if (!$uid) { - return array(false, __("Invalid user name: %s", $user)); - } elseif ($uid == $maintainer_uid) { - // silently ignore when maintainer == co-maintainer - continue; - } else { - $uids_new[] = $uid; - } - } - - $q = sprintf("SELECT UsersID FROM PackageComaintainers WHERE PackageBaseID = %d", $base_id); - $result = $dbh->query($q); - $uids_old = $result->fetchAll(PDO::FETCH_COLUMN, 0); - - $uids_add = array_diff($uids_new, $uids_old); - $uids_rem = array_diff($uids_old, $uids_new); - - $i = 1; - foreach ($uids_new as $uid) { - if (in_array($uid, $uids_add)) { - $q = sprintf("INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (%d, %d, %d)", $base_id, $uid, $i); - notify(array('comaintainer-add', $uid, $base_id)); - } else { - $q = sprintf("UPDATE PackageComaintainers SET Priority = %d WHERE PackageBaseID = %d AND UsersID = %d", $i, $base_id, $uid); - } - - $dbh->exec($q); - $i++; - } - - foreach ($uids_rem as $uid) { - $q = sprintf("DELETE FROM PackageComaintainers WHERE PackageBaseID = %d AND UsersID = %d", $base_id, $uid); - $dbh->exec($q); - notify(array('comaintainer-remove', $uid, $base_id)); - } - - return array(true, __("The package base co-maintainers have been updated.")); -} - -function pkgbase_remove_comaintainer($base_id, $uid) { - $uname = username_from_id($uid); - $names = pkgbase_get_comaintainers($base_id); - $names = array_diff($names, array($uname)); - return pkgbase_set_comaintainers($base_id, $names, true); -} diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php deleted file mode 100644 index 140c7ec1..00000000 --- a/web/lib/pkgfuncs.inc.php +++ /dev/null @@ -1,957 +0,0 @@ -query($q); - - if (!$result) { - return false; - } - - $uid = $result->fetch(PDO::FETCH_COLUMN, 0); - - return has_credential(CRED_COMMENT_DELETE, array($uid)); -} - -/** - * Determine if the user can delete a specific package comment using an array - * - * Only the comment submitter, Trusted Users, and Developers can delete - * comments. This function is used for the frontend side of comment deletion. - * - * @param array $comment All database information relating a specific comment - * - * @return bool True if the user can delete the comment, otherwise false - */ -function can_delete_comment_array($comment) { - return has_credential(CRED_COMMENT_DELETE, array($comment['UsersID'])); -} - -/** - * Determine if the user can edit a specific package comment - * - * Only the comment submitter, Trusted Users, and Developers can edit - * comments. This function is used for the backend side of comment editing. - * - * @param string $comment_id The comment ID in the database - * - * @return bool True if the user can edit the comment, otherwise false - */ -function can_edit_comment($comment_id=0) { - $dbh = DB::connect(); - - $q = "SELECT UsersID FROM PackageComments "; - $q.= "WHERE ID = " . intval($comment_id); - $result = $dbh->query($q); - - if (!$result) { - return false; - } - - $uid = $result->fetch(PDO::FETCH_COLUMN, 0); - - return has_credential(CRED_COMMENT_EDIT, array($uid)); -} - -/** - * Determine if the user can edit a specific package comment using an array - * - * Only the comment submitter, Trusted Users, and Developers can edit - * comments. This function is used for the frontend side of comment editing. - * - * @param array $comment All database information relating a specific comment - * - * @return bool True if the user can edit the comment, otherwise false - */ -function can_edit_comment_array($comment) { - return has_credential(CRED_COMMENT_EDIT, array($comment['UsersID'])); -} - -/** - * Determine if the user can pin a specific package comment - * - * Only the Package Maintainer, Package Co-maintainers, Trusted Users, and - * Developers can pin comments. This function is used for the backend side of - * comment pinning. - * - * @param string $comment_id The comment ID in the database - * - * @return bool True if the user can pin the comment, otherwise false - */ -function can_pin_comment($comment_id=0) { - $dbh = DB::connect(); - - $q = "SELECT MaintainerUID FROM PackageBases AS pb "; - $q.= "LEFT JOIN PackageComments AS pc ON pb.ID = pc.PackageBaseID "; - $q.= "WHERE pc.ID = " . intval($comment_id) . " "; - $q.= "UNION "; - $q.= "SELECT pcm.UsersID FROM PackageComaintainers AS pcm "; - $q.= "LEFT JOIN PackageComments AS pc "; - $q.= "ON pcm.PackageBaseID = pc.PackageBaseID "; - $q.= "WHERE pc.ID = " . intval($comment_id); - $result = $dbh->query($q); - - if (!$result) { - return false; - } - - $uids = $result->fetchAll(PDO::FETCH_COLUMN, 0); - - return has_credential(CRED_COMMENT_PIN, $uids); -} - -/** - * Determine if the user can edit a specific package comment using an array - * - * Only the Package Maintainer, Package Co-maintainers, Trusted Users, and - * Developers can pin comments. This function is used for the frontend side of - * comment pinning. - * - * @param array $comment All database information relating a specific comment - * - * @return bool True if the user can edit the comment, otherwise false - */ -function can_pin_comment_array($comment) { - return can_pin_comment($comment['ID']); -} - -/** - * Check to see if the package name already exists in the database - * - * @param string $name The package name to check - * - * @return string|void Package name if it already exists - */ -function pkg_from_name($name="") { - if (!$name) {return NULL;} - $dbh = DB::connect(); - $q = "SELECT ID FROM Packages "; - $q.= "WHERE Name = " . $dbh->quote($name); - $result = $dbh->query($q); - if (!$result) { - return; - } - $row = $result->fetch(PDO::FETCH_NUM); - if ($row) { - return $row[0]; - } -} - -/** - * Get licenses for a specific package - * - * @param int $pkgid The package to get licenses for - * - * @return array All licenses for the package - */ -function pkg_licenses($pkgid) { - $pkgid = intval($pkgid); - if (!$pkgid) { - return array(); - } - $q = "SELECT l.Name FROM Licenses l "; - $q.= "INNER JOIN PackageLicenses pl ON pl.LicenseID = l.ID "; - $q.= "WHERE pl.PackageID = ". $pkgid; - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - $rows = db_cache_result($q, 'licenses:' . $pkgid, PDO::FETCH_NUM, $ttl); - return array_map(function ($x) { return $x[0]; }, $rows); -} - -/** - * Get package groups for a specific package - * - * @param int $pkgid The package to get groups for - * - * @return array All package groups for the package - */ -function pkg_groups($pkgid) { - $pkgid = intval($pkgid); - if (!$pkgid) { - return array(); - } - $q = "SELECT g.Name FROM `Groups` g "; - $q.= "INNER JOIN PackageGroups pg ON pg.GroupID = g.ID "; - $q.= "WHERE pg.PackageID = ". $pkgid; - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - $rows = db_cache_result($q, 'groups:' . $pkgid, PDO::FETCH_NUM, $ttl); - return array_map(function ($x) { return $x[0]; }, $rows); -} - -/** - * Get providers for a specific package - * - * @param string $name The name of the "package" to get providers for - * - * @return array The IDs and names of all providers of the package - */ -function pkg_providers($name) { - $dbh = DB::connect(); - $q = "SELECT p.ID, p.Name FROM Packages p "; - $q.= "WHERE p.Name = " . $dbh->quote($name) . " "; - $q.= "UNION "; - $q.= "SELECT p.ID, p.Name FROM Packages p "; - $q.= "LEFT JOIN PackageRelations pr ON pr.PackageID = p.ID "; - $q.= "LEFT JOIN RelationTypes rt ON rt.ID = pr.RelTypeID "; - $q.= "WHERE (rt.Name = 'provides' "; - $q.= "AND pr.RelName = " . $dbh->quote($name) . ")"; - $q.= "UNION "; - $q.= "SELECT 0, Name FROM OfficialProviders "; - $q.= "WHERE Provides = " . $dbh->quote($name); - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - return db_cache_result($q, 'providers:' . $name, PDO::FETCH_NUM, $ttl); -} - -/** - * Get package dependencies for a specific package - * - * @param int $pkgid The package to get dependencies for - * @param int $limit An upper bound for the number of packages to retrieve - * - * @return array All package dependencies for the package - */ -function pkg_dependencies($pkgid, $limit) { - $pkgid = intval($pkgid); - if (!$pkgid) { - return array(); - } - $q = "SELECT pd.DepName, dt.Name, pd.DepDesc, "; - $q.= "pd.DepCondition, pd.DepArch, p.ID "; - $q.= "FROM PackageDepends pd "; - $q.= "LEFT JOIN Packages p ON pd.DepName = p.Name "; - $q.= "LEFT JOIN DependencyTypes dt ON dt.ID = pd.DepTypeID "; - $q.= "WHERE pd.PackageID = ". $pkgid . " "; - $q.= "ORDER BY pd.DepName LIMIT " . intval($limit); - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - return db_cache_result($q, 'dependencies:' . $pkgid, PDO::FETCH_NUM, $ttl); -} - -/** - * Get package relations for a specific package - * - * @param int $pkgid The package to get relations for - * - * @return array All package relations for the package - */ -function pkg_relations($pkgid) { - $pkgid = intval($pkgid); - if (!$pkgid) { - return array(); - } - $q = "SELECT pr.RelName, rt.Name, pr.RelCondition, pr.RelArch, p.ID FROM PackageRelations pr "; - $q.= "LEFT JOIN Packages p ON pr.RelName = p.Name "; - $q.= "LEFT JOIN RelationTypes rt ON rt.ID = pr.RelTypeID "; - $q.= "WHERE pr.PackageID = ". $pkgid . " "; - $q.= "ORDER BY pr.RelName"; - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - return db_cache_result($q, 'relations:' . $pkgid, PDO::FETCH_NUM, $ttl); -} - -/** - * Get the HTML code to display a package dependency link annotation - * (dependency type, architecture, ...) - * - * @param string $type The name of the dependency type - * @param string $arch The package dependency architecture - * @param string $desc An optdepends description - * - * @return string The HTML code of the label to display - */ -function pkg_deplink_annotation($type, $arch, $desc=false) { - if ($type == 'depends' && !$arch) { - return ''; - } - - $link = ' ('; - - if ($type == 'makedepends') { - $link .= 'make'; - } elseif ($type == 'checkdepends') { - $link .= 'check'; - } elseif ($type == 'optdepends') { - $link .= 'optional'; - } - - if ($type != 'depends' && $arch) { - $link .= ', '; - } - - if ($arch) { - $link .= htmlspecialchars($arch); - } - - $link .= ')'; - if ($type == 'optdepends' && $desc) { - $link .= ' – ' . htmlspecialchars($desc) . ' '; - } - $link .= ''; - - return $link; -} - -/** - * Get the HTML code to display a package provider link - * - * @param string $name The name of the provider - * @param bool $official True if the package is in the official repositories - * - * @return string The HTML code of the link to display - */ -function pkg_provider_link($name, $official) { - $link = ''; - $link .= htmlspecialchars($name) . ''; - - return $link; -} - -/** - * Get the HTML code to display a package dependency link - * - * @param string $name The name of the dependency - * @param string $type The name of the dependency type - * @param string $desc The (optional) description of the dependency - * @param string $cond The package dependency condition string - * @param string $arch The package dependency architecture - * @param int $pkg_id The package of the package to display the dependency for - * - * @return string The HTML code of the label to display - */ -function pkg_depend_link($name, $type, $desc, $cond, $arch, $pkg_id) { - /* - * TODO: We currently perform one SQL query per nonexistent package - * dependency. It would be much better if we could annotate dependency - * data with providers so that we already know whether a dependency is - * a "provision name" or a package from the official repositories at - * this point. - */ - $providers = pkg_providers($name); - - if (count($providers) == 0) { - $link = ''; - $link .= htmlspecialchars($name); - $link .= ''; - $link .= htmlspecialchars($cond) . ' '; - $link .= pkg_deplink_annotation($type, $arch, $desc); - return $link; - } - - $link = htmlspecialchars($name); - foreach ($providers as $provider) { - if ($provider[1] == $name) { - $is_official = ($provider[0] == 0); - $name = $provider[1]; - $link = pkg_provider_link($name, $is_official); - break; - } - } - $link .= htmlspecialchars($cond) . ' '; - - foreach ($providers as $key => $provider) { - if ($provider[1] == $name) { - unset($providers[$key]); - } - } - - if (count($providers) > 0) { - $link .= '('; - foreach ($providers as $provider) { - $is_official = ($provider[0] == 0); - $name = $provider[1]; - $link .= pkg_provider_link($name, $is_official) . ', '; - } - $link = substr($link, 0, -2); - $link .= ')'; - } - - $link .= pkg_deplink_annotation($type, $arch, $desc); - - return $link; -} - -/** - * Get the HTML code to display a package requirement link - * - * @param string $name The name of the requirement - * @param string $depends The (literal) name of the dependency of $name - * @param string $type The name of the dependency type - * @param string $arch The package dependency architecture - * @param string $pkgname The name of dependant package - * - * @return string The HTML code of the link to display - */ -function pkg_requiredby_link($name, $depends, $type, $arch, $pkgname) { - $link = ''; - $link .= htmlspecialchars($name) . ''; - - if ($depends != $pkgname) { - $link .= ' ('; - $link .= __('requires %s', htmlspecialchars($depends)); - $link .= ')'; - } - - return $link . pkg_deplink_annotation($type, $arch); -} - -/** - * Get the HTML code to display a package relation - * - * @param string $name The name of the relation - * @param string $cond The package relation condition string - * @param string $arch The package relation architecture - * - * @return string The HTML code of the label to display - */ -function pkg_rel_html($name, $cond, $arch) { - $html = htmlspecialchars($name) . htmlspecialchars($cond); - - if ($arch) { - $html .= ' (' . htmlspecialchars($arch) . ')'; - } - - return $html; -} - -/** - * Get the HTML code to display a source link - * - * @param string $url The URL of the source - * @param string $arch The source architecture - * @param string $package The name of the package - * - * @return string The HTML code of the label to display - */ -function pkg_source_link($url, $arch, $package) { - $url = explode('::', $url); - $parsed_url = parse_url($url[0]); - - if (isset($parsed_url['scheme']) || isset($url[1])) { - $link = '' . htmlspecialchars($url[0]) . ''; - } else { - $file_url = sprintf(config_get('options', 'source_file_uri'), htmlspecialchars($url[0]), $package); - $link = '' . htmlspecialchars($url[0]) . ''; - } - - if ($arch) { - $link .= ' (' . htmlspecialchars($arch) . ')'; - } - - return $link; -} - -/** - * Determine packages that depend on a package - * - * @param string $name The package name for the dependency search - * @param array $provides A list of virtual provisions of the package - * @param int $limit An upper bound for the number of packages to retrieve - * - * @return array All packages that depend on the specified package name - */ -function pkg_required($name="", $provides, $limit) { - $deps = array(); - if ($name != "") { - $dbh = DB::connect(); - - $name_list = $dbh->quote($name); - foreach ($provides as $p) { - $name_list .= ',' . $dbh->quote($p[0]); - } - - $q = "SELECT p.Name, pd.DepName, dt.Name, pd.DepArch "; - $q.= "FROM PackageDepends pd "; - $q.= "LEFT JOIN Packages p ON p.ID = pd.PackageID "; - $q.= "LEFT JOIN DependencyTypes dt ON dt.ID = pd.DepTypeID "; - $q.= "WHERE pd.DepName IN (" . $name_list . ") "; - $q.= "ORDER BY p.Name LIMIT " . intval($limit); - /* Not invalidated by package updates. */ - return db_cache_result($q, 'required:' . $name, PDO::FETCH_NUM); - } - return $deps; -} - -/** - * Get all package sources for a specific package - * - * @param string $pkgid The package ID to get the sources for - * - * @return array All sources associated with a specific package - */ -function pkg_sources($pkgid) { - $pkgid = intval($pkgid); - if (!$pkgid) { - return array(); - } - $q = "SELECT Source, SourceArch FROM PackageSources "; - $q.= "WHERE PackageID = " . $pkgid; - $q.= " ORDER BY Source"; - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - return db_cache_result($q, 'required:' . $pkgid, PDO::FETCH_NUM, $ttl); -} - -/** - * Get the package details - * - * @param string $id The package ID to get description for - * - * @return array The package's details OR error message - **/ -function pkg_get_details($id=0) { - $dbh = DB::connect(); - - $q = "SELECT Packages.*, PackageBases.ID AS BaseID, "; - $q.= "PackageBases.Name AS BaseName, PackageBases.NumVotes, "; - $q.= "PackageBases.Popularity, PackageBases.OutOfDateTS, "; - $q.= "PackageBases.SubmittedTS, PackageBases.ModifiedTS, "; - $q.= "PackageBases.SubmitterUID, PackageBases.MaintainerUID, "; - $q.= "PackageBases.PackagerUID, PackageBases.FlaggerUID, "; - $q.= "(SELECT COUNT(*) FROM PackageRequests "; - $q.= " WHERE PackageRequests.PackageBaseID = Packages.PackageBaseID "; - $q.= " AND PackageRequests.Status = 0) AS RequestCount "; - $q.= "FROM Packages, PackageBases "; - $q.= "WHERE PackageBases.ID = Packages.PackageBaseID "; - $q.= "AND Packages.ID = " . intval($id); - $result = $dbh->query($q); - - $row = array(); - - if (!$result) { - $row['error'] = __("Error retrieving package details."); - } - else { - $row = $result->fetch(PDO::FETCH_ASSOC); - if (empty($row)) { - $row['error'] = __("Package details could not be found."); - } - } - - return $row; -} - -/** - * Display the package details page - * - * @param string $id The package ID to get details page for - * @param array $row Package details retrieved by pkg_get_details() - * @param string $SID The session ID of the visitor - * - * @return void - */ -function pkg_display_details($id=0, $row, $SID="") { - $dbh = DB::connect(); - - if (isset($row['error'])) { - print "

    " . $row['error'] . "

    \n"; - } - else { - $base_id = pkgbase_from_pkgid($id); - $pkgbase_name = pkgbase_name_from_id($base_id); - - include('pkg_details.php'); - - if ($SID) { - include('pkg_comment_box.php'); - } - - $include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED); - - $limit_pinned = isset($_GET['pinned']) ? 0 : 5; - $pinned = pkgbase_comments($base_id, $limit_pinned, false, true); - if (!empty($pinned)) { - $comment_section = "package"; - include('pkg_comments.php'); - } - unset($pinned); - - - $total_comment_count = pkgbase_comments_count($base_id, $include_deleted); - list($pagination_templs, $per_page, $offset) = calculate_pagination($total_comment_count); - - $comments = pkgbase_comments($base_id, $per_page, $include_deleted, false, $offset); - if (!empty($comments)) { - $comment_section = "package"; - include('pkg_comments.php'); - } - } -} - -/** - * Output the body of the search results page - * - * @param array $params Search parameters - * @param bool $show_headers True if statistics should be included - * @param string $SID The session ID of the visitor - * - * @return int The total number of packages matching the query - */ -function pkg_search_page($params, $show_headers=true, $SID="") { - $dbh = DB::connect(); - - /* - * Get commonly used variables. - * TODO: Reduce the number of database queries! - */ - if ($SID) - $myuid = uid_from_sid($SID); - - /* Sanitize paging variables. */ - if (isset($params['O'])) { - $params['O'] = bound(intval($params['O']), 0, 2500); - } else { - $params['O'] = 0; - } - - if (isset($params["PP"])) { - $params["PP"] = bound(intval($params["PP"]), 50, 250); - } else { - $params["PP"] = 50; - } - - /* - * FIXME: Pull out DB-related code. All of it! This one's worth a - * choco-chip cookie, one of those nice big soft ones. - */ - - /* Build the package search query. */ - $q_select = "SELECT "; - if ($SID) { - $q_select .= "PackageNotifications.UserID AS Notify, - PackageVotes.UsersID AS Voted, "; - } - $q_select .= "Users.Username AS Maintainer, - Packages.Name, Packages.Version, Packages.Description, - PackageBases.NumVotes, PackageBases.Popularity, Packages.ID, - Packages.PackageBaseID, PackageBases.OutOfDateTS "; - - $q_from = "FROM Packages - LEFT JOIN PackageBases ON (PackageBases.ID = Packages.PackageBaseID) - LEFT JOIN Users ON (PackageBases.MaintainerUID = Users.ID) "; - if ($SID) { - /* This is not needed for the total row count query. */ - $q_from_extra = "LEFT JOIN PackageVotes - ON (PackageBases.ID = PackageVotes.PackageBaseID AND PackageVotes.UsersID = $myuid) - LEFT JOIN PackageNotifications - ON (PackageBases.ID = PackageNotifications.PackageBaseID AND PackageNotifications.UserID = $myuid) "; - } else { - $q_from_extra = ""; - } - - $q_where = 'WHERE PackageBases.PackagerUID IS NOT NULL '; - - if (isset($params['K'])) { - if (isset($params["SeB"]) && $params["SeB"] == "m") { - /* Search by maintainer. */ - $q_where .= "AND Users.Username = " . $dbh->quote($params['K']) . " "; - } - elseif (isset($params["SeB"]) && $params["SeB"] == "c") { - /* Search by co-maintainer. */ - $q_where .= "AND EXISTS (SELECT * FROM PackageComaintainers "; - $q_where .= "INNER JOIN Users ON Users.ID = PackageComaintainers.UsersID "; - $q_where .= "WHERE PackageComaintainers.PackageBaseID = PackageBases.ID "; - $q_where .= "AND Users.Username = " . $dbh->quote($params['K']) . ")"; - } - elseif (isset($params["SeB"]) && $params["SeB"] == "M") { - /* Search by maintainer and co-maintainer. */ - $q_where .= "AND (Users.Username = " . $dbh->quote($params['K']) . " "; - $q_where .= "OR EXISTS (SELECT * FROM PackageComaintainers "; - $q_where .= "INNER JOIN Users ON Users.ID = PackageComaintainers.UsersID "; - $q_where .= "WHERE PackageComaintainers.PackageBaseID = PackageBases.ID "; - $q_where .= "AND Users.Username = " . $dbh->quote($params['K']) . "))"; - } - elseif (isset($params["SeB"]) && $params["SeB"] == "s") { - /* Search by submitter. */ - $q_where .= "AND SubmitterUID = " . intval(uid_from_username($params['K'])) . " "; - } - elseif (isset($params["SeB"]) && $params["SeB"] == "n") { - /* Search by name. */ - $K = "%" . addcslashes($params['K'], '%_') . "%"; - $q_where .= "AND (Packages.Name LIKE " . $dbh->quote($K) . ") "; - } - elseif (isset($params["SeB"]) && $params["SeB"] == "b") { - /* Search by package base name. */ - $K = "%" . addcslashes($params['K'], '%_') . "%"; - $q_where .= "AND (PackageBases.Name LIKE " . $dbh->quote($K) . ") "; - } - elseif (isset($params["SeB"]) && $params["SeB"] == "k") { - /* Search by name. */ - $q_where .= construct_keyword_search($dbh, $params['K'], false, true); - } - elseif (isset($params["SeB"]) && $params["SeB"] == "N") { - /* Search by name (exact match). */ - $q_where .= "AND (Packages.Name = " . $dbh->quote($params['K']) . ") "; - } - elseif (isset($params["SeB"]) && $params["SeB"] == "B") { - /* Search by package base name (exact match). */ - $q_where .= "AND (PackageBases.Name = " . $dbh->quote($params['K']) . ") "; - } - else { - /* Keyword search (default). */ - $q_where .= construct_keyword_search($dbh, $params['K'], true, true); - } - } - - if (isset($params["do_Orphans"])) { - $q_where .= "AND MaintainerUID IS NULL "; - } - - if (isset($params['outdated'])) { - if ($params['outdated'] == 'on') { - $q_where .= "AND OutOfDateTS IS NOT NULL "; - } - elseif ($params['outdated'] == 'off') { - $q_where .= "AND OutOfDateTS IS NULL "; - } - } - - $order = (isset($params["SO"]) && $params["SO"] == 'd') ? 'DESC' : 'ASC'; - - $q_sort = "ORDER BY "; - $sort_by = isset($params["SB"]) ? $params["SB"] : ''; - switch ($sort_by) { - case 'v': - $q_sort .= "NumVotes " . $order . ", "; - break; - case 'p': - $q_sort .= "Popularity " . $order . ", "; - break; - case 'w': - if ($SID) { - $q_sort .= "Voted " . $order . ", "; - } - break; - case 'o': - if ($SID) { - $q_sort .= "Notify " . $order . ", "; - } - break; - case 'm': - $q_sort .= "Maintainer " . $order . ", "; - break; - case 'l': - $q_sort .= "ModifiedTS " . $order . ", "; - break; - case 'a': - /* For compatibility with old search links. */ - $q_sort .= "-ModifiedTS " . $order . ", "; - break; - default: - break; - } - $q_sort .= " Packages.Name " . $order . " "; - - $q_limit = "LIMIT ".$params["PP"]." OFFSET ".$params["O"]; - - $q = $q_select . $q_from . $q_from_extra . $q_where . $q_sort . $q_limit; - $q_total = "SELECT COUNT(*) " . $q_from . $q_where; - - $result = $dbh->query($q); - $result_t = $dbh->query($q_total); - if ($result_t) { - $row = $result_t->fetch(PDO::FETCH_NUM); - $total = min($row[0], 2500); - } else { - $total = 0; - } - - if ($result && $total > 0) { - if (isset($params["SO"]) && $params["SO"] == "d"){ - $SO_next = "a"; - } - else { - $SO_next = "d"; - } - } - - /* Calculate the results to use. */ - $first = $params['O'] + 1; - - /* Calculation of pagination links. */ - $per_page = ($params['PP'] > 0) ? $params['PP'] : 50; - $current = ceil($first / $per_page); - $pages = ceil($total / $per_page); - $templ_pages = array(); - - if ($current > 1) { - $templ_pages['« ' . __('First')] = 0; - $templ_pages['‹ ' . __('Previous')] = ($current - 2) * $per_page; - } - - if ($current - 5 > 1) - $templ_pages["..."] = false; - - for ($i = max($current - 5, 1); $i <= min($pages, $current + 5); $i++) { - $templ_pages[$i] = ($i - 1) * $per_page; - } - - if ($current + 5 < $pages) - $templ_pages["... "] = false; - - if ($current < $pages) { - $templ_pages[__('Next') . ' ›'] = $current * $per_page; - $templ_pages[__('Last') . ' »'] = ($pages - 1) * $per_page; - } - - $searchresults = array(); - if ($result) { - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $searchresults[] = $row; - } - } - - include('pkg_search_results.php'); - - return $total; -} - -/** - * Construct the WHERE part of the sophisticated keyword search - * - * @param handle $dbh Database handle - * @param string $keywords The search term - * @param bool $namedesc Search name and description fields - * @param bool $keyword Search packages with a matching PackageBases.Keyword - * - * @return string WHERE part of the SQL clause - */ -function construct_keyword_search($dbh, $keywords, $namedesc, $keyword=false) { - $count = 0; - $where_part = ""; - $q_keywords = ""; - $op = ""; - - foreach (str_getcsv($keywords, ' ') as $term) { - if ($term == "") { - continue; - } - if ($count > 0 && strtolower($term) == "and") { - $op = "AND "; - continue; - } - if ($count > 0 && strtolower($term) == "or") { - $op = "OR "; - continue; - } - if ($count > 0 && strtolower($term) == "not") { - $op .= "NOT "; - continue; - } - - $term = "%" . addcslashes($term, '%_') . "%"; - $q_keywords .= $op . " ("; - $q_keywords .= "Packages.Name LIKE " . $dbh->quote($term) . " "; - if ($namedesc) { - $q_keywords .= "OR Description LIKE " . $dbh->quote($term) . " "; - } - - if ($keyword) { - $q_keywords .= "OR EXISTS (SELECT * FROM PackageKeywords WHERE "; - $q_keywords .= "PackageKeywords.PackageBaseID = Packages.PackageBaseID AND "; - $q_keywords .= "PackageKeywords.Keyword LIKE " . $dbh->quote($term) . ")) "; - } else { - $q_keywords .= ") "; - } - - $count++; - if ($count >= 20) { - break; - } - $op = "AND "; - } - - if (!empty($q_keywords)) { - $where_part = "AND (" . $q_keywords . ") "; - } - - return $where_part; -} - -/** - * Determine if a POST string has been sent by a visitor - * - * @param string $action String to check has been sent via POST - * - * @return bool True if the POST string was used, otherwise false - */ -function current_action($action) { - return (isset($_POST['action']) && $_POST['action'] == $action) || - isset($_POST[$action]); -} - -/** - * Determine if sent IDs are valid integers - * - * @param array $ids IDs to validate - * - * @return array All sent IDs that are valid integers - */ -function sanitize_ids($ids) { - $new_ids = array(); - foreach ($ids as $id) { - $id = intval($id); - if ($id > 0) { - $new_ids[] = $id; - } - } - return $new_ids; -} - -/** - * Determine package information for latest package - * - * @param int $numpkgs Number of packages to get information on - * - * @return array $packages Package info for the specified number of recent packages - */ -function latest_pkgs($numpkgs, $orderBy='SubmittedTS') { - $dbh = DB::connect(); - - $q = "SELECT Packages.*, MaintainerUID, SubmittedTS, ModifiedTS "; - $q.= "FROM Packages LEFT JOIN PackageBases ON "; - $q.= "PackageBases.ID = Packages.PackageBaseID "; - $q.= "ORDER BY " . $orderBy . " DESC "; - $q.= "LIMIT " . intval($numpkgs); - $result = $dbh->query($q); - - $packages = array(); - if ($result) { - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $packages[] = $row; - } - } - - return $packages; -} - -/** - * Determine package information for latest modified packages - * - * @param int $numpkgs Number of packages to get information on - * - * @return array $packages Package info for the specified number of recently modified packages - */ -function latest_modified_pkgs($numpkgs) { - return latest_pkgs($numpkgs, 'ModifiedTS'); -} diff --git a/web/lib/pkgreqfuncs.inc.php b/web/lib/pkgreqfuncs.inc.php deleted file mode 100644 index 7fce307c..00000000 --- a/web/lib/pkgreqfuncs.inc.php +++ /dev/null @@ -1,260 +0,0 @@ -query($q)->fetchColumn(); -} - -/** - * Get a list of all package requests - * - * @param int $offset The index of the first request to return - * @param int $limit The maximum number of requests to return - * @param int $uid Only return packages affecting the given user - * @param int $from Do not return packages older than the given date - * - * @return array List of package requests with details - */ -function pkgreq_list($offset, $limit, $uid=false, $from=false) { - $dbh = DB::connect(); - - $q = "SELECT PackageRequests.ID, "; - $q.= "PackageRequests.PackageBaseID AS BaseID, "; - $q.= "PackageRequests.PackageBaseName AS Name, "; - $q.= "PackageRequests.MergeBaseName AS MergeInto, "; - $q.= "RequestTypes.Name AS Type, PackageRequests.Comments, "; - $q.= "Users.Username AS User, PackageRequests.RequestTS, "; - $q.= "PackageRequests.Status, PackageRequests.Status = 0 AS Open "; - $q.= "FROM PackageRequests INNER JOIN RequestTypes ON "; - $q.= "RequestTypes.ID = PackageRequests.ReqTypeID "; - $q.= "INNER JOIN Users ON Users.ID = PackageRequests.UsersID "; - - if ($uid || $from) { - $q.= "WHERE "; - if ($uid) { - $q.= "(PackageRequests.UsersID = " . intval($uid). " "; - $q.= "OR Users.ID = " . intval($uid) . ") AND "; - } - if ($from) { - $q.= "RequestTS >= " . intval($from). " "; - } - } - - $q.= "ORDER BY Open DESC, RequestTS DESC "; - $q.= "LIMIT " . $limit . " OFFSET " . $offset; - - return $dbh->query($q)->fetchAll(); -} - -/** - * Get a list of all open package requests belonging to a certain package base - * - * @param int $baseid The package base ID to retrieve requests for - * @param int $type The type of requests to obtain - * - * @return array List of package request IDs - */ -function pkgreq_by_pkgbase($baseid, $type=false) { - $dbh = DB::connect(); - - $q = "SELECT PackageRequests.ID "; - $q.= "FROM PackageRequests INNER JOIN RequestTypes ON "; - $q.= "RequestTypes.ID = PackageRequests.ReqTypeID "; - $q.= "WHERE PackageRequests.Status = 0 "; - $q.= "AND PackageRequests.PackageBaseID = " . intval($baseid); - - if ($type) { - $q .= " AND RequestTypes.Name = " . $dbh->quote($type); - } - - return $dbh->query($q)->fetchAll(PDO::FETCH_COLUMN, 0); -} - -/** - * Obtain the package base that belongs to a package request. - * - * @param int $id Package request ID to retrieve the package base for - * - * @return int The name of the corresponding package base - */ -function pkgreq_get_pkgbase_name($id) { - $dbh = DB::connect(); - - $q = "SELECT PackageBaseName FROM PackageRequests "; - $q.= "WHERE ID = " . intval($id); - $result = $dbh->query($q); - return $result->fetch(PDO::FETCH_COLUMN, 0); -} - -/** - * Obtain the email address of the creator of a package request - * - * @param int $id Package request ID to retrieve the creator for - * - * @return int The email address of the creator - */ -function pkgreq_get_creator_email($id) { - $dbh = DB::connect(); - - $q = "SELECT Email FROM Users INNER JOIN PackageRequests "; - $q.= "ON Users.ID = PackageRequests.UsersID "; - $q.= "WHERE PackageRequests.ID = " . intval($id); - $result = $dbh->query($q); - return $result->fetch(PDO::FETCH_COLUMN, 0); -} - -/** - * File a deletion/orphan request against a package base - * - * @param string $ids The package base IDs to file the request against - * @param string $type The type of the request - * @param string $merge_into The target of a merge operation - * @param string $comments The comments to be added to the request - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgreq_file($ids, $type, $merge_into, $comments) { - if (!has_credential(CRED_PKGREQ_FILE)) { - return array(false, __("You must be logged in to file package requests.")); - } - - /* Ignore merge target for non-merge requests. */ - if ($type !== 'merge') { - $merge_into = ''; - } - - if (!empty($merge_into) && !preg_match("/^[a-z0-9][a-z0-9\.+_-]*$/D", $merge_into)) { - return array(false, __("Invalid name: only lowercase letters are allowed.")); - } - - if (!empty($merge_into) && !pkgbase_from_name($merge_into)) { - return array(false, __("Cannot find package to merge votes and comments into.")); - } - - if (empty($comments)) { - return array(false, __("The comment field must not be empty.")); - } - - $dbh = DB::connect(); - $uid = uid_from_sid($_COOKIE["AURSID"]); - - /* TODO: Allow for filing multiple requests at once. */ - $base_id = intval($ids[0]); - $pkgbase_name = pkgbase_name_from_id($base_id); - - if ($merge_into == $pkgbase_name) { - return array(false, __("Cannot merge a package base with itself.")); - } - - $q = "SELECT ID FROM RequestTypes WHERE Name = " . $dbh->quote($type); - $result = $dbh->query($q); - if ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $type_id = $row['ID']; - } else { - return array(false, __("Invalid request type.")); - } - - $q = "INSERT INTO PackageRequests "; - $q.= "(ReqTypeID, PackageBaseID, PackageBaseName, MergeBaseName, "; - $q.= "UsersID, Comments, ClosureComment, RequestTS) VALUES (" . $type_id . ", "; - $q.= $base_id . ", " . $dbh->quote($pkgbase_name) . ", "; - $q.= $dbh->quote($merge_into) . ", " . $uid . ", "; - $q.= $dbh->quote($comments) . ", '', " . strval(time()) . ")"; - $dbh->exec($q); - $request_id = $dbh->lastInsertId(); - - /* Send e-mail notifications. */ - $params = array('request-open', $uid, $request_id, $type, $base_id); - if ($type === 'merge') { - $params[] = $merge_into; - } - notify($params); - - $auto_orphan_age = config_get('options', 'auto_orphan_age'); - $auto_delete_age = config_get('options', 'auto_delete_age'); - $details = pkgbase_get_details($base_id); - if ($type == 'orphan' && $details['OutOfDateTS'] > 0 && - time() - $details['OutOfDateTS'] >= $auto_orphan_age && - $auto_orphan_age > 0) { - /* - * Close package request. NOTE: This needs to happen *before* - * the actual disown operation. Otherwise, the former - * maintainer will not be included in the Cc list of the - * request notification email. - */ - $out_of_date_time = date("Y-m-d", intval($details["OutOfDateTS"])); - pkgreq_close($request_id, "accepted", - "The package base has been flagged out-of-date " . - "since " . $out_of_date_time . ".", true); - $q = "UPDATE PackageBases SET MaintainerUID = NULL "; - $q.= "WHERE ID = " . $base_id; - $dbh->exec($q); - } else if ($type == 'deletion' && $details['MaintainerUID'] == $uid && - $details['SubmittedTS'] > 0 && $auto_delete_age > 0 && - time() - $details['SubmittedTS'] <= $auto_delete_age) { - /* - * Close package request. NOTE: This needs to happen *before* - * the actual deletion operation. Otherwise, the former - * maintainer will not be included in the Cc list of the - * request notification email. - */ - pkgreq_close($request_id, "accepted", - "Deletion of a fresh package requested by its " . - "current maintainer.", true); - pkgbase_delete(array($base_id), NULL, NULL, true); - } - - return array(true, __("Added request successfully.")); -} - -/** - * Close a deletion/orphan request - * - * @param int $id The package request to close - * @param string $reason Whether the request was accepted or rejected - * @param string $comments Comments to be added to the notification email - * @param boolean $auto_close (optional) Whether the request is auto-closed - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgreq_close($id, $reason, $comments, $auto_close=false) { - switch ($reason) { - case 'accepted': - $status = 2; - break; - case 'rejected': - $status = 3; - break; - default: - return array(false, __("Invalid reason.")); - } - - $dbh = DB::connect(); - $id = intval($id); - $uid = $auto_close ? 0 : uid_from_sid($_COOKIE["AURSID"]); - - if (!$auto_close && !has_credential(CRED_PKGREQ_CLOSE)) { - return array(false, __("Only TUs and developers can close requests.")); - } - - $q = "UPDATE PackageRequests SET Status = " . intval($status) . ", "; - $q.= "ClosedTS = " . strval(time()) . ", "; - $q.= "ClosedUID = " . ($uid == 0 ? "NULL" : intval($uid)) . ", "; - $q.= "ClosureComment = " . $dbh->quote($comments) . " "; - $q.= "WHERE ID = " . intval($id); - $dbh->exec($q); - - /* Send e-mail notifications. */ - notify(array('request-close', $uid, $id, $reason)); - - return array(true, __("Request closed successfully.")); -} diff --git a/web/lib/routing.inc.php b/web/lib/routing.inc.php deleted file mode 100644 index 73c667d2..00000000 --- a/web/lib/routing.inc.php +++ /dev/null @@ -1,85 +0,0 @@ - 'home.php', - '/index.php' => 'home.php', - '/packages' => 'packages.php', - '/pkgbase' => 'pkgbase.php', - '/requests' => 'pkgreq.php', - '/register' => 'register.php', - '/account' => 'account.php', - '/accounts' => 'account.php', - '/login' => 'login.php', - '/logout' => 'logout.php', - '/passreset' => 'passreset.php', - '/rpc' => 'rpc.php', - '/rss/modified' => 'modified-rss.php', - '/rss' => 'rss.php', - '/tos' => 'tos.php', - '/tu' => 'tu.php', - '/addvote' => 'addvote.php', -); - -$PKG_PATH = '/packages'; -$PKGBASE_PATH = '/pkgbase'; -$PKGREQ_PATH = '/requests'; -$USER_PATH = '/account'; - -function get_route($path) { - global $ROUTES; - - $path = rtrim($path, '/'); - if (isset($ROUTES[$path])) { - return $ROUTES[$path]; - } else { - return NULL; - } -} - -function get_uri($path, $absolute=false) { - if ($absolute) { - return rtrim(aur_location(), '/') . $path; - } else { - return $path; - } -} - -function get_pkg_route() { - global $PKG_PATH; - return $PKG_PATH; -} - -function get_pkgbase_route() { - global $PKGBASE_PATH; - return $PKGBASE_PATH; -} - -function get_pkgreq_route() { - global $PKGREQ_PATH; - return $PKGREQ_PATH; -} - -function get_pkg_uri($pkgname, $absolute=false) { - global $PKG_PATH; - $path = $PKG_PATH . '/' . urlencode($pkgname) . '/'; - return get_uri($path, $absolute); -} - -function get_pkgbase_uri($pkgbase_name, $absolute=false) { - global $PKGBASE_PATH; - $path = $PKGBASE_PATH . '/' . urlencode($pkgbase_name) . '/'; - return get_uri($path, $absolute); -} - -function get_user_route() { - global $USER_PATH; - return $USER_PATH; -} - -function get_user_uri($username, $absolute=false) { - global $USER_PATH; - $path = $USER_PATH . '/' . urlencode($username) . '/'; - return get_uri($path, $absolute); -} diff --git a/web/lib/stats.inc.php b/web/lib/stats.inc.php deleted file mode 100644 index f5692f96..00000000 --- a/web/lib/stats.inc.php +++ /dev/null @@ -1,108 +0,0 @@ -query($q); - - $newest_packages = new ArrayObject(); - if ($result) { - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $newest_packages->append($row); - } - set_cache_value($key, $newest_packages); - } - } - include('stats/updates_table.php'); -} - -/** - * Display a user's statistics table - * - * @param string $userid The user ID of the person to get package statistics for - * - * @return void - */ -function user_table($userid) { - $base_q = "SELECT COUNT(*) FROM PackageBases "; - $base_q.= "WHERE MaintainerUID = " . $userid . " "; - $base_q.= "AND PackagerUID IS NOT NULL"; - - $user_pkg_count = db_cache_value($base_q, 'user_pkg_count:' . $userid); - - $q = "SELECT COUNT(*) FROM PackageBases "; - $q.= "WHERE OutOfDateTS IS NOT NULL "; - $q.= "AND MaintainerUID = " . $userid . " "; - $q.= "AND PackagerUID IS NOT NULL"; - - $flagged_outdated = db_cache_value($q, 'user_flagged_outdated:' . $userid); - - include('stats/user_table.php'); -} - -/** - * Display the general package statistics table - * - * @return void - */ -function general_stats_table() { - # AUR statistics - $q = "SELECT COUNT(*) FROM PackageBases WHERE PackagerUID IS NOT NULL"; - $pkg_count = db_cache_value($q, 'pkg_count'); - - $q = "SELECT COUNT(*) FROM PackageBases "; - $q.= "WHERE MaintainerUID IS NULL "; - $q.= "AND PackagerUID IS NOT NULL"; - $orphan_count = db_cache_value($q, 'orphan_count'); - - $q = "SELECT count(*) FROM Users"; - $user_count = db_cache_value($q, 'user_count'); - - $q = "SELECT count(*) FROM Users,AccountTypes WHERE Users.AccountTypeID = AccountTypes.ID AND (AccountTypes.AccountType = 'Trusted User' OR AccountTypes.AccountType = 'Trusted User & Developer')"; - $tu_count = db_cache_value($q, 'tu_count'); - - $targstamp = intval(strtotime("-7 days")); - $yearstamp = intval(strtotime("-1 year")); - - $q = "SELECT COUNT(*) FROM PackageBases "; - $q.= "WHERE SubmittedTS >= $targstamp "; - $q.= "AND PackagerUID IS NOT NULL"; - $add_count = db_cache_value($q, 'add_count'); - - /* - * A package whose last modification time differs less than an hour - * from the initial submission time is considered new. - */ - - $q = "SELECT COUNT(*) FROM PackageBases "; - $q.= "WHERE ModifiedTS >= $targstamp "; - $q.= "AND ModifiedTS - SubmittedTS >= 3600 "; - $q.= "AND PackagerUID IS NOT NULL"; - $update_count = db_cache_value($q, 'update_count'); - - $q = "SELECT COUNT(*) FROM PackageBases "; - $q.= "WHERE ModifiedTS >= $yearstamp "; - $q.= "AND ModifiedTS - SubmittedTS >= 3600 "; - $q.= "AND PackagerUID IS NOT NULL"; - $update_year_count = db_cache_value($q, 'update_year_count'); - - $q = "SELECT COUNT(*) FROM PackageBases "; - $q.= "WHERE ModifiedTS - SubmittedTS < 3600 "; - $q.= "AND PackagerUID IS NOT NULL"; - $never_update_count = db_cache_value($q, 'never_update_count'); - - include('stats/general_stats_table.php'); -} diff --git a/web/lib/streams.php b/web/lib/streams.php deleted file mode 100644 index 00cf6cc5..00000000 --- a/web/lib/streams.php +++ /dev/null @@ -1,167 +0,0 @@ -. - - This file is part of PHP-gettext. - - PHP-gettext is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - PHP-gettext is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with PHP-gettext; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - - - // Simple class to wrap file streams, string streams, etc. - // seek is essential, and it should be byte stream -class StreamReader { - // should return a string [FIXME: perhaps return array of bytes?] - function read($bytes) { - return false; - } - - // should return new position - function seekto($position) { - return false; - } - - // returns current position - function currentpos() { - return false; - } - - // returns length of entire stream (limit for seekto()s) - function length() { - return false; - } -}; - -class StringReader { - var $_pos; - var $_str; - - function __construct($str='') { - $this->_str = $str; - $this->_pos = 0; - } - - function read($bytes) { - $data = substr($this->_str, $this->_pos, $bytes); - $this->_pos += $bytes; - if (strlen($this->_str)<$this->_pos) - $this->_pos = strlen($this->_str); - - return $data; - } - - function seekto($pos) { - $this->_pos = $pos; - if (strlen($this->_str)<$this->_pos) - $this->_pos = strlen($this->_str); - return $this->_pos; - } - - function currentpos() { - return $this->_pos; - } - - function length() { - return strlen($this->_str); - } - -}; - - -class FileReader { - var $_pos; - var $_fd; - var $_length; - - function __construct($filename) { - if (file_exists($filename)) { - - $this->_length=filesize($filename); - $this->_pos = 0; - $this->_fd = fopen($filename,'rb'); - if (!$this->_fd) { - $this->error = 3; // Cannot read file, probably permissions - return false; - } - } else { - $this->error = 2; // File doesn't exist - return false; - } - } - - function read($bytes) { - if ($bytes) { - fseek($this->_fd, $this->_pos); - - // PHP 5.1.1 does not read more than 8192 bytes in one fread() - // the discussions at PHP Bugs suggest it's the intended behaviour - $data = ''; - while ($bytes > 0) { - $chunk = fread($this->_fd, $bytes); - $data .= $chunk; - $bytes -= strlen($chunk); - } - $this->_pos = ftell($this->_fd); - - return $data; - } else return ''; - } - - function seekto($pos) { - fseek($this->_fd, $pos); - $this->_pos = ftell($this->_fd); - return $this->_pos; - } - - function currentpos() { - return $this->_pos; - } - - function length() { - return $this->_length; - } - - function close() { - fclose($this->_fd); - } - -}; - -// Preloads entire file in memory first, then creates a StringReader -// over it (it assumes knowledge of StringReader internals) -class CachedFileReader extends StringReader { - function __construct($filename) { - if (file_exists($filename)) { - - $length=filesize($filename); - $fd = fopen($filename,'rb'); - - if (!$fd) { - $this->error = 3; // Cannot read file, probably permissions - return false; - } - $this->_str = fread($fd, $length); - fclose($fd); - - } else { - $this->error = 2; // File doesn't exist - return false; - } - } -}; - - -?> diff --git a/web/lib/timezone.inc.php b/web/lib/timezone.inc.php deleted file mode 100644 index 949f846d..00000000 --- a/web/lib/timezone.inc.php +++ /dev/null @@ -1,63 +0,0 @@ - Displayed Description - */ -function generate_timezone_list() { - $php_timezones = DateTimeZone::listIdentifiers(DateTimeZone::ALL); - - $offsets = array(); - foreach ($php_timezones as $timezone) { - $tz = new DateTimeZone($timezone); - $offset = $tz->getOffset(new DateTime()); - $offsets[$timezone] = "(UTC" . ($offset < 0 ? "-" : "+") . gmdate("H:i", abs($offset)) . - ") " . $timezone; - } - - asort($offsets); - return $offsets; -} - -/** - * Set the timezone for the user. - * - * @return null - */ -function set_tz() { - $timezones = generate_timezone_list(); - $update_cookie = false; - - if (isset($_COOKIE["AURTZ"])) { - $timezone = $_COOKIE["AURTZ"]; - } elseif (isset($_COOKIE["AURSID"])) { - $dbh = DB::connect(); - $q = "SELECT Timezone FROM Users, Sessions "; - $q .= "WHERE Users.ID = Sessions.UsersID "; - $q .= "AND Sessions.SessionID = "; - $q .= $dbh->quote($_COOKIE["AURSID"]); - $result = $dbh->query($q); - - if ($result) { - $timezone = $result->fetchColumn(0); - if (!$timezone) { - unset($timezone); - } - } - - $update_cookie = true; - } - - if (!isset($timezone) || !array_key_exists($timezone, $timezones)) { - $timezone = config_get("options", "default_timezone"); - } - date_default_timezone_set($timezone); - - if ($update_cookie) { - $timeout = intval(config_get("options", "persistent_cookie_timeout")); - $cookie_time = time() + $timeout; - setcookie("AURTZ", $timezone, $cookie_time, "/"); - } -} diff --git a/web/lib/translator.inc.php b/web/lib/translator.inc.php deleted file mode 100644 index cbed1274..00000000 --- a/web/lib/translator.inc.php +++ /dev/null @@ -1,139 +0,0 @@ -", ""); - -include_once("confparser.inc.php"); -include_once('DB.class.php'); -include_once('gettext.php'); -include_once('streams.php'); - -global $streamer, $l10n; - -# Languages we have translations for -$SUPPORTED_LANGS = array( - "ar" => "العربية", - "ast" => "Asturianu", - "ca" => "Català", - "cs" => "ÄŒeský", - "da" => "Dansk", - "de" => "Deutsch", - "en" => "English", - "el" => "Ελληνικά", - "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" => "正體中文" -); - -function __() { - global $LANG; - global $l10n; - - # Create the translation. - $args = func_get_args(); - - # First argument is always string to be translated - $tag = array_shift($args); - - # Translate using gettext_reader initialized before. - $translated = $l10n->translate($tag); - $translated = htmlspecialchars($translated, ENT_QUOTES); - - # Subsequent arguments are strings to be formatted - if (count($args) > 0) { - $translated = vsprintf($translated, $args); - } - - return $translated; -} - -function _n($msgid1, $msgid2, $n) { - global $l10n; - - $translated = sprintf($l10n->ngettext($msgid1, $msgid2, $n), $n); - return htmlspecialchars($translated, ENT_QUOTES); -} - -# set up the visitor's language -# -function set_lang() { - global $LANG; - global $SUPPORTED_LANGS; - global $streamer, $l10n; - - $update_cookie = 0; - if (isset($_POST['setlang'])) { - # visitor is requesting a language change - # - $LANG = $_POST['setlang']; - $update_cookie = 1; - - } elseif (isset($_COOKIE['AURLANG'])) { - # If a cookie is set, use that - # - $LANG = $_COOKIE['AURLANG']; - - } elseif (isset($_COOKIE["AURSID"])) { - # No language but a session; use default lang preference - # - $dbh = DB::connect(); - $q = "SELECT LangPreference FROM Users, Sessions "; - $q.= "WHERE Users.ID = Sessions.UsersID "; - $q.= "AND Sessions.SessionID = "; - $q.= $dbh->quote($_COOKIE["AURSID"]); - $result = $dbh->query($q); - - if ($result) { - $LANG = $result->fetchColumn(0); - if (!$LANG) { - unset($LANG); - } - } - $update_cookie = 1; - } - - # Set $LANG to default if nothing is valid. - if (!isset($LANG) || !array_key_exists($LANG, $SUPPORTED_LANGS)) { - $LANG = config_get('options', 'default_lang'); - } - - if ($update_cookie) { - $timeout = intval(config_get('options', 'persistent_cookie_timeout')); - $cookie_time = time() + $timeout; - setcookie("AURLANG", $LANG, $cookie_time, "/"); - } - - $localedir = config_get('options', 'localedir'); - $streamer = new FileReader($localedir . '/' . $LANG . - '/LC_MESSAGES/aurweb.mo'); - $l10n = new gettext_reader($streamer, true); - - return; -} diff --git a/web/lib/version.inc.php b/web/lib/version.inc.php deleted file mode 100644 index 81d960bc..00000000 --- a/web/lib/version.inc.php +++ /dev/null @@ -1,2 +0,0 @@ - - ' . htmlspecialchars($username) . '') ?> -

    -

    - ', '') ?> -

    - -
    -
    - - - -
    -
    -

    - - -

    - -

    - -

    - -

    - " /> -

    -
    -
    diff --git a/web/template/account_details.php b/web/template/account_details.php deleted file mode 100644 index 84f8b9c5..00000000 --- a/web/template/account_details.php +++ /dev/null @@ -1,93 +0,0 @@ - - - - -
    -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - -
    - " . __("hidden") . ""; - else: - ?> - "> - -
    " rel="nofollow">
    - -
    format('Y-m-d') ?>
    - -
    Links:
      -
    • - -
    • - - -
    • - -
    -
    diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php deleted file mode 100644 index 4ce6b875..00000000 --- a/web/template/account_edit_form.php +++ /dev/null @@ -1,222 +0,0 @@ - -

    - ', '') ?> - ', '') ?> - ', '') ?> -

    - -
    - - - -
    - - - - - -
    -
    -

    - - () -

    -

    - -

    - -

    - - -

    - -

    - - - - - - -

    - - - -

    - - /> -

    - - -

    - - () -

    -

    - -

    - -

    - - /> -

    -

    - -

    - -

    - - -

    -

    - - - - " . __("Hide Email Address") . "") ?> - -

    - -

    - - -

    - -

    - - -

    - -

    - - -

    - -

    - - -

    - -

    - - -

    -

    - - -

    -
    - - -
    - -

    - - -

    - -

    - - -

    -
    - - -
    - -

    - - -

    -
    - -
    - : -

    - - /> -

    -

    - - /> -

    -

    - - /> -

    -
    - -
    - - -

    - - -

    - - -

    - - () - -

    - -
    - -
    -

    - - - " />   - - " />   - - " /> -

    -
    -
    diff --git a/web/template/account_search_results.php b/web/template/account_search_results.php deleted file mode 100644 index 0f7eb7a4..00000000 --- a/web/template/account_search_results.php +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - $row): ?> - - - - - - - - - - - -
    "> - - - - "> - -   - -
    - - - - - - -
    -
    -
    - - - $ind): - ?> - - - " /> -
    -
    -
    -
    -
    - - - $ind): - ?> - - - -->" /> -
    -
    -
    - -

    - -

    - - diff --git a/web/template/cgit/footer.html b/web/template/cgit/footer.html deleted file mode 100644 index 14c358f1..00000000 --- a/web/template/cgit/footer.html +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/web/template/cgit/header.html b/web/template/cgit/header.html deleted file mode 100644 index 2d418702..00000000 --- a/web/template/cgit/header.html +++ /dev/null @@ -1,15 +0,0 @@ - diff --git a/web/template/comaintainers_form.php b/web/template/comaintainers_form.php deleted file mode 100644 index f61d494c..00000000 --- a/web/template/comaintainers_form.php +++ /dev/null @@ -1,19 +0,0 @@ -
    -

    :

    -

    - ', htmlspecialchars($pkgbase_name), ''); ?> -

    -
    -
    - -

    - - -

    -

    - " /> -

    -
    -
    -
    diff --git a/web/template/flag_comment.php b/web/template/flag_comment.php deleted file mode 100644 index dc285a97..00000000 --- a/web/template/flag_comment.php +++ /dev/null @@ -1,26 +0,0 @@ -
    -

    -

    - - ', html_format_username($message['Username']), '', - '', htmlspecialchars($pkgbase_name), '', - '', date('Y-m-d', $message['OutOfDateTS']), ''); ?> - - ', htmlspecialchars($pkgbase_name), ''); ?> - -

    - -

    -

    -

    -
    -

    - -

    -

    - " /> -
    -

    -
    diff --git a/web/template/footer.php b/web/template/footer.php deleted file mode 100644 index 7f97aae0..00000000 --- a/web/template/footer.php +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - diff --git a/web/template/header.php b/web/template/header.php deleted file mode 100644 index 9631be91..00000000 --- a/web/template/header.php +++ /dev/null @@ -1,82 +0,0 @@ -'; ?> - - - - AUR (<?= htmlspecialchars($LANG); ?>)<?php if ($title != "") { print " - " . htmlspecialchars($title); } ?> - - - - ' /> - ' /> - - - - - - - - -
    -
    -
    "> -
    -
    - - -
    -
    -
    -
    -
    -
      - -
    • -
    • - -
    • - - -
    • - -
    • -
    • -
    • - -
    • AUR
    • -
    • -
    • - -
    • - -
    • - - -
    -
    - diff --git a/web/template/pkg_comment_box.php b/web/template/pkg_comment_box.php deleted file mode 100644 index 22f90d4a..00000000 --- a/web/template/pkg_comment_box.php +++ /dev/null @@ -1,4 +0,0 @@ -
    -

    - -
    diff --git a/web/template/pkg_comment_form.php b/web/template/pkg_comment_form.php deleted file mode 100644 index e8a516e3..00000000 --- a/web/template/pkg_comment_form.php +++ /dev/null @@ -1,28 +0,0 @@ -
    -
    -
    - " /> - - - - - -
    -

    - - ', "") ?> -

    -

    - -

    -

    - " /> - - - - - - -

    -
    -
    diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php deleted file mode 100644 index ffa9e137..00000000 --- a/web/template/pkg_comments.php +++ /dev/null @@ -1,239 +0,0 @@ - - - - -
    - -
    - -
    -

    - - - - - - - - - - - - -

    - - 1): ?> -

    - $pagestart): ?> - - - - - - - - - - - - -

    - -
    - - $row): ?> - ' . $date_fmtd . ''; - if ($comment_section == "package") { - if ($row['UserName']) { - $user_fmtd = html_format_username($row['UserName']); - $heading = __('%s commented on %s', $user_fmtd, $date_link); - } else { - $heading = __('Anonymous comment on %s', $date_link); - } - } elseif ($comment_section == "account") { - $pkg_uri = '' . htmlspecialchars($row['PackageBaseName']) . ''; - $heading = __('Commented on package %s on %s', $pkg_uri, $date_link); - } - - $is_deleted = $row['DelTS']; - $is_edited = $row['EditedTS']; - $is_pinned = $row['PinnedTS']; - - if ($uid && $is_deleted) { - $date_fmtd = date('Y-m-d H:i', $row['DelTS']); - $heading .= ' ('; - if ($row['DelUserName']) { - $user_fmtd = html_format_username($row['DelUserName']); - $heading .= __('deleted on %s by %s', $date_fmtd, $user_fmtd); - } else { - $heading .= __('deleted on %s', $date_fmtd); - } - $heading .= ')'; - } elseif ($uid && $is_edited) { - $date_fmtd = date('Y-m-d H:i', $row['EditedTS']); - $heading .= ' ('; - if ($row['EditUserName']) { - $user_fmtd = html_format_username($row['EditUserName']); - $heading .= __('edited on %s by %s', $date_fmtd, $user_fmtd); - } else { - $heading .= __('edited on %s', $date_fmtd); - } - $heading .= ')'; - } - - $comment_classes = "comment-header"; - if ($is_deleted) { - $comment_classes .= " comment-deleted"; - } - ?> -

    - - -
    -
    - - - - " /> - -
    -
    - - - -
    -
    - - - - " /> - -
    -
    - - - - <?= __('Edit comment') ?> - - - = 5)): ?> -
    -
    - - - " /> - - " /> - -
    -
    - - - -
    -
    - - - - " /> - -
    -
    - -

    -
    -
    - - - -

    - -

    - -
    -
    - -
    - - diff --git a/web/template/pkg_details.php b/web/template/pkg_details.php deleted file mode 100644 index 25d85b78..00000000 --- a/web/template/pkg_details.php +++ /dev/null @@ -1,317 +0,0 @@ - -
    -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0): -?> - - - - - - 0): ?> - - - - - - 0): ?> - - - - - - 0): ?> - - - - - - 0): ?> - - - - - - 0): ?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - (, ) - -
    () - -
    - -
    -
    - - - - - "/> - -
    -
    -' . htmlspecialchars($kw) . "\n"; - } -endif; -?> -
    - - - - , - - - - - -
    - - - - , - - - - - -
    - - - - , - - - - - -
    - - - - , - - - - - -
    - - - - , - - - - - -
    = .2 ? 2 : 6) ?>
    - -
    -
    -

    - 0): ?> -
      - $darr): ?> -
    • - -
    - -
    -
    -

    - 0): ?> -
      - $darr): ?> -
    • - -
    - -
    -
    -

    -
    - 0): ?> -
    -
      - $src): ?> -
    • - -
    -
    - -
    -
    - - diff --git a/web/template/pkg_search_form.php b/web/template/pkg_search_form.php deleted file mode 100644 index 3d0cde6c..00000000 --- a/web/template/pkg_search_form.php +++ /dev/null @@ -1,120 +0,0 @@ - __('Name, Description'), - 'n' => __('Name Only'), - 'b' => __('Package Base'), - 'N' => __('Exact Name'), - 'B' => __('Exact Package Base'), - 'k' => __('Keywords'), - 'm' => __('Maintainer'), - 'c' => __('Co-maintainer'), - 'M' => __('Maintainer, Co-maintainer'), - 's' => __('Submitter') -); - -$outdated_flags = array( - '' => __('All'), - 'on' => __('Flagged'), - 'off' => __('Not Flagged') -); - -$sortby = array( - 'n' => __('Name'), - 'v' => __('Votes'), - 'p' => __('Popularity'), - 'w' => __('Voted'), - 'o' => __('Notify'), - 'm' => __('Maintainer'), - 'l' => __('Last modified') -); - -$orderby = array( - 'a' => __('Ascending'), - 'd' => __('Descending') -); - -$per_page = array(50, 100, 250); -?> - - diff --git a/web/template/pkg_search_results.php b/web/template/pkg_search_results.php deleted file mode 100644 index 61335560..00000000 --- a/web/template/pkg_search_results.php +++ /dev/null @@ -1,153 +0,0 @@ -'; - if ($sb) { - echo '' . $title . ''; - } else { - echo $title; - } - if ($hint) { - echo '?'; - } - echo ''; - }; -} else { - $fmtth = function($title, $sb=false, $so=false, $hint=false) { - echo '' . $title . ''; - }; -} - -if (!$result): ?> -

    - -

    - - -
    -

    - - -

    - 1): ?> -

    - $pagestart): ?> - - - - - - - - -

    - -
    - - -
    - - - - - - - - - - - - - - - - - - - - - $row): ?> - - - - - - class="flagged"> - - - - - - - - - - - - -
     
    ]" value="1" />"> - - - - - - - - - - - - - - - - - -
    - - -
    -

    - - -

    - 1): ?> -

    - $pagestart): ?> - - - - - - - - -

    - -
    - - -

    - - - - - - - - " /> -

    - - -
    - diff --git a/web/template/pkgbase_actions.php b/web/template/pkgbase_actions.php deleted file mode 100644 index 3d208328..00000000 --- a/web/template/pkgbase_actions.php +++ /dev/null @@ -1,49 +0,0 @@ - diff --git a/web/template/pkgbase_details.php b/web/template/pkgbase_details.php deleted file mode 100644 index bde29c1c..00000000 --- a/web/template/pkgbase_details.php +++ /dev/null @@ -1,146 +0,0 @@ - -
    -

    - - - - - - - - - 0): -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - (, ) - -
    () - -
    - -
    -
    - - - - - "/> - -
    -
    -' . htmlspecialchars($kw) . "\n"; - } -endif; -?> -
    = .2 ? 2 : 6) ?>
    - -
    -
    -

    - 0): ?> -
      - $pkg): -?> -
    • - -
    - -
    -
    -
    - - diff --git a/web/template/pkgreq_close_form.php b/web/template/pkgreq_close_form.php deleted file mode 100644 index 6228f6ab..00000000 --- a/web/template/pkgreq_close_form.php +++ /dev/null @@ -1,31 +0,0 @@ -
    -

    :

    -

    - ', htmlspecialchars($pkgbase_name), ''); ?> -

    -

    - : - -

    -
    -
    - - -

    - - -

    -

    - - -

    -

    - " /> -

    -
    -
    -
    diff --git a/web/template/pkgreq_form.php b/web/template/pkgreq_form.php deleted file mode 100644 index 9d74093e..00000000 --- a/web/template/pkgreq_form.php +++ /dev/null @@ -1,81 +0,0 @@ -
    -

    :

    -

    - ', htmlspecialchars($pkgbase_name), ''); ?> -

    -
      - -
    • - -
    -
    -
    - - - -

    - - -

    - - -

    - - -

    -

    - - -

    -

    - -

    -

    - -

    -

    - -

    -

    - " /> -

    -
    -
    -
    diff --git a/web/template/pkgreq_results.php b/web/template/pkgreq_results.php deleted file mode 100644 index 1a565c3e..00000000 --- a/web/template/pkgreq_results.php +++ /dev/null @@ -1,129 +0,0 @@ - -

    - - -
    -

    - - -

    - 1): ?> -

    - $pagestart): ?> - - - - - - - - -

    - -
    - - - - - - - - - - - - - - - - $row): ?> - $idle_time); - if (!$due) { - $time_left = $idle_time - (time() - intval($row['RequestTS'])); - if ($time_left > 48 * 3600) { - $time_left_fmt = _n("~%d day left", "~%d days left", round($time_left / (24 * 3600))); - } elseif ($time_left > 3600) { - $time_left_fmt = _n("~%d hour left", "~%d hours left", round($time_left / 3600)); - } else { - $time_left_fmt = __("<1 hour left"); - } - } - ?> - - - - - - - - - - - - - - class="flagged"> - - - - - - - - - - - - - - - - - -
    "> - - - () - - - - - - - - - - - - - () - -
    - - -
    - - -
    -

    - - -

    - 1): ?> -

    - $pagestart): ?> - - - - - - - - -

    - -
    - - diff --git a/web/template/search_accounts_form.php b/web/template/search_accounts_form.php deleted file mode 100644 index f7824a94..00000000 --- a/web/template/search_accounts_form.php +++ /dev/null @@ -1,52 +0,0 @@ -
    -
    -
    - -
    -
    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - " />   - " /> -

    -
    -
    diff --git a/web/template/stats/general_stats_table.php b/web/template/stats/general_stats_table.php deleted file mode 100644 index 9dcc3aaf..00000000 --- a/web/template/stats/general_stats_table.php +++ /dev/null @@ -1,36 +0,0 @@ -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    diff --git a/web/template/stats/updates_table.php b/web/template/stats/updates_table.php deleted file mode 100644 index 23a86288..00000000 --- a/web/template/stats/updates_table.php +++ /dev/null @@ -1,19 +0,0 @@ -

    ()

    - -RSS Feed -RSS Feed - - - - getIterator() as $row): ?> - - - - - - -
    - " title=""> - - -
    diff --git a/web/template/stats/user_table.php b/web/template/stats/user_table.php deleted file mode 100644 index e7b00834..00000000 --- a/web/template/stats/user_table.php +++ /dev/null @@ -1,21 +0,0 @@ - - -

    - - - - - - - - - - -
    - - -
    - -
    diff --git a/web/template/template.phps b/web/template/template.phps deleted file mode 100644 index f1a0bb0d..00000000 --- a/web/template/template.phps +++ /dev/null @@ -1,19 +0,0 @@ -\n"; - - -html_footer(AURWEB_VERSION); diff --git a/web/template/tu_details.php b/web/template/tu_details.php deleted file mode 100644 index d739060d..00000000 --- a/web/template/tu_details.php +++ /dev/null @@ -1,123 +0,0 @@ - 0) { - $participation = $total / $active_tus; -} else { - $participation = 0; -} - -if ($yes > $active_tus / 2) { - $vote_accepted = true; -} elseif ($participation > $quorum && $yes > $no) { - $vote_accepted = true; -} else { - $vote_accepted = false; -} -?> -
    -

    - - -

    - -

    - - -

    - : - - - - - N/A - - -
    - -
    - : - - -
    - : - - - - - - - - -

    - -

    - \n", htmlspecialchars($row['Agenda'])) ?> -

    - - - - - - - - - - - - - - - - - - - - - 0): ?> - - - - - -
    - - - - - - %
    -
    - - -
    -

    -
      - -
    • - -
    -
    - - -
    - - -
    -
    - " /> - " /> - " /> - - -
    -
    - - -
    diff --git a/web/template/tu_last_votes_list.php b/web/template/tu_last_votes_list.php deleted file mode 100644 index 6e852581..00000000 --- a/web/template/tu_last_votes_list.php +++ /dev/null @@ -1,36 +0,0 @@ -
    -

    - - - - - - - - - - - - $row): - if ($indx % 2): - $c = "even"; - else: - $c = "odd"; - endif; - $username = username_from_id($row["UserID"]); - ?> - - - - - - -
    - - - -
    -
    diff --git a/web/template/tu_list.php b/web/template/tu_list.php deleted file mode 100644 index 204c89ea..00000000 --- a/web/template/tu_list.php +++ /dev/null @@ -1,82 +0,0 @@ -
    -

    - - -
      -
    • -
    - - - -

    - - - - - - - - - - - - - - - - - - $row): ?> - - - - - - - - - - - - - - -
    - - - - - - - - - - - -
    - -
    -

    - - 0 && $off != 0): - $back = (($off - $limit) <= 0) ? 0 : $off - $limit; ?> - ?off=&by='>‹ - - - - - -

    - -
    From ad61c443f47686f41315735341cf53b4464cf0e0 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sat, 29 Apr 2023 09:55:54 +0200 Subject: [PATCH 022/178] fix: restore & move cgit html files restore files accidentally deleted with PHP cleanup. https://gitlab.archlinux.org/archlinux/aurweb/-/tree/1325c71712a12c529d7a3defa9cbabfad296922e/web/template/cgit Signed-off-by: moson-mo --- conf/cgitrc.proto | 4 ++-- docker/cgit-entrypoint.sh | 4 ++-- static/html/cgit/footer.html | 6 ++++++ static/html/cgit/header.html | 15 +++++++++++++++ 4 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 static/html/cgit/footer.html create mode 100644 static/html/cgit/header.html diff --git a/conf/cgitrc.proto b/conf/cgitrc.proto index 1b3eacbd..ed53c51c 100644 --- a/conf/cgitrc.proto +++ b/conf/cgitrc.proto @@ -20,8 +20,8 @@ cache-static-ttl=60 root-title=AUR Package Repositories root-desc=Web interface to the AUR Package Repositories -header=/srv/http/aurweb/web/template/cgit/header.html -footer=/srv/http/aurweb/web/template/cgit/footer.html +header=/srv/http/aurweb/static/html/cgit/header.html +footer=/srv/http/aurweb/static/html/cgit/footer.html max-repodesc-length=50 max-blob-size=2048 max-stats=year diff --git a/docker/cgit-entrypoint.sh b/docker/cgit-entrypoint.sh index a44675e2..282430e2 100755 --- a/docker/cgit-entrypoint.sh +++ b/docker/cgit-entrypoint.sh @@ -5,8 +5,8 @@ mkdir -p /var/data/cgit cp -vf conf/cgitrc.proto /etc/cgitrc sed -ri "s|clone-prefix=.*|clone-prefix=${CGIT_CLONE_PREFIX}|" /etc/cgitrc -sed -ri 's|header=.*|header=/aurweb/web/template/cgit/header.html|' /etc/cgitrc -sed -ri 's|footer=.*|footer=/aurweb/web/template/cgit/footer.html|' /etc/cgitrc +sed -ri 's|header=.*|header=/aurweb/static/html/cgit/header.html|' /etc/cgitrc +sed -ri 's|footer=.*|footer=/aurweb/static/html/cgit/footer.html|' /etc/cgitrc sed -ri 's|repo\.path=.*|repo.path=/aurweb/aur.git|' /etc/cgitrc sed -ri "s|^(css)=.*$|\1=${CGIT_CSS}|" /etc/cgitrc diff --git a/static/html/cgit/footer.html b/static/html/cgit/footer.html new file mode 100644 index 00000000..b3e79568 --- /dev/null +++ b/static/html/cgit/footer.html @@ -0,0 +1,6 @@ + diff --git a/static/html/cgit/header.html b/static/html/cgit/header.html new file mode 100644 index 00000000..2d418702 --- /dev/null +++ b/static/html/cgit/header.html @@ -0,0 +1,15 @@ + From bab17a9d262e1f184deece9003e67df8baae01c4 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sat, 29 Apr 2023 09:59:34 +0200 Subject: [PATCH 023/178] doc: amend INSTALL instructions change path for metadata archive files Signed-off-by: moson-mo --- INSTALL | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/INSTALL b/INSTALL index 107fab4b..c6c71ca7 100644 --- a/INSTALL +++ b/INSTALL @@ -30,9 +30,6 @@ read the instructions below. ssl_certificate /etc/ssl/certs/aur.cert.pem; ssl_certificate_key /etc/ssl/private/aur.key.pem; - # Asset root. This is used to match against gzip archives. - root /srv/http/aurweb/web/html; - # TU Bylaws redirect. location = /trusted-user/TUbylaws.html { return 301 https://tu-bylaws.aur.archlinux.org; @@ -62,6 +59,9 @@ read the instructions below. # Static archive assets. location ~ \.gz$ { + # Asset root. This is used to match against gzip archives. + root /srv/http/aurweb/archives; + types { application/gzip text/plain } default_type text/plain; add_header Content-Encoding gzip; From e896edaccc3ef5666298d3c1a42816d35c8d2950 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Sun, 30 Apr 2023 10:12:09 +0100 Subject: [PATCH 024/178] chore: support for python 3.11 and poetry.lock update Signed-off-by: Leonidas Spyropoulos --- poetry.lock | 259 ++++++++++++++++++++++++------------------------- pyproject.toml | 2 +- 2 files changed, 128 insertions(+), 133 deletions(-) diff --git a/poetry.lock b/poetry.lock index 1b98a5b8..5e933e70 100644 --- a/poetry.lock +++ b/poetry.lock @@ -14,14 +14,14 @@ files = [ [[package]] name = "alembic" -version = "1.10.3" +version = "1.10.4" description = "A database migration tool for SQLAlchemy." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "alembic-1.10.3-py3-none-any.whl", hash = "sha256:b2e0a6cfd3a8ce936a1168320bcbe94aefa3f4463cd773a968a55071beb3cd37"}, - {file = "alembic-1.10.3.tar.gz", hash = "sha256:32a69b13a613aeb7e8093f242da60eff9daed13c0df02fff279c1b06c32965d2"}, + {file = "alembic-1.10.4-py3-none-any.whl", hash = "sha256:43942c3d4bf2620c466b91c0f4fca136fe51ae972394a0cc8b90810d664e4f5c"}, + {file = "alembic-1.10.4.tar.gz", hash = "sha256:295b54bbb92c4008ab6a7dcd1e227e668416d6f84b98b3c4446a2bc6214a556b"}, ] [package.dependencies] @@ -352,63 +352,63 @@ files = [ [[package]] name = "coverage" -version = "7.2.3" +version = "7.2.4" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "coverage-7.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e58c0d41d336569d63d1b113bd573db8363bc4146f39444125b7f8060e4e04f5"}, - {file = "coverage-7.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:344e714bd0fe921fc72d97404ebbdbf9127bac0ca1ff66d7b79efc143cf7c0c4"}, - {file = "coverage-7.2.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:974bc90d6f6c1e59ceb1516ab00cf1cdfbb2e555795d49fa9571d611f449bcb2"}, - {file = "coverage-7.2.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0743b0035d4b0e32bc1df5de70fba3059662ace5b9a2a86a9f894cfe66569013"}, - {file = "coverage-7.2.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d0391fb4cfc171ce40437f67eb050a340fdbd0f9f49d6353a387f1b7f9dd4fa"}, - {file = "coverage-7.2.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4a42e1eff0ca9a7cb7dc9ecda41dfc7cbc17cb1d02117214be0561bd1134772b"}, - {file = "coverage-7.2.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:be19931a8dcbe6ab464f3339966856996b12a00f9fe53f346ab3be872d03e257"}, - {file = "coverage-7.2.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:72fcae5bcac3333a4cf3b8f34eec99cea1187acd55af723bcbd559adfdcb5535"}, - {file = "coverage-7.2.3-cp310-cp310-win32.whl", hash = "sha256:aeae2aa38395b18106e552833f2a50c27ea0000122bde421c31d11ed7e6f9c91"}, - {file = "coverage-7.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:83957d349838a636e768251c7e9979e899a569794b44c3728eaebd11d848e58e"}, - {file = "coverage-7.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dfd393094cd82ceb9b40df4c77976015a314b267d498268a076e940fe7be6b79"}, - {file = "coverage-7.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:182eb9ac3f2b4874a1f41b78b87db20b66da6b9cdc32737fbbf4fea0c35b23fc"}, - {file = "coverage-7.2.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bb1e77a9a311346294621be905ea8a2c30d3ad371fc15bb72e98bfcfae532df"}, - {file = "coverage-7.2.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca0f34363e2634deffd390a0fef1aa99168ae9ed2af01af4a1f5865e362f8623"}, - {file = "coverage-7.2.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55416d7385774285b6e2a5feca0af9652f7f444a4fa3d29d8ab052fafef9d00d"}, - {file = "coverage-7.2.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:06ddd9c0249a0546997fdda5a30fbcb40f23926df0a874a60a8a185bc3a87d93"}, - {file = "coverage-7.2.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fff5aaa6becf2c6a1699ae6a39e2e6fb0672c2d42eca8eb0cafa91cf2e9bd312"}, - {file = "coverage-7.2.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ea53151d87c52e98133eb8ac78f1206498c015849662ca8dc246255265d9c3c4"}, - {file = "coverage-7.2.3-cp311-cp311-win32.whl", hash = "sha256:8f6c930fd70d91ddee53194e93029e3ef2aabe26725aa3c2753df057e296b925"}, - {file = "coverage-7.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:fa546d66639d69aa967bf08156eb8c9d0cd6f6de84be9e8c9819f52ad499c910"}, - {file = "coverage-7.2.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2317d5ed777bf5a033e83d4f1389fd4ef045763141d8f10eb09a7035cee774c"}, - {file = "coverage-7.2.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be9824c1c874b73b96288c6d3de793bf7f3a597770205068c6163ea1f326e8b9"}, - {file = "coverage-7.2.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c3b2803e730dc2797a017335827e9da6da0e84c745ce0f552e66400abdfb9a1"}, - {file = "coverage-7.2.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f69770f5ca1994cb32c38965e95f57504d3aea96b6c024624fdd5bb1aa494a1"}, - {file = "coverage-7.2.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1127b16220f7bfb3f1049ed4a62d26d81970a723544e8252db0efde853268e21"}, - {file = "coverage-7.2.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:aa784405f0c640940595fa0f14064d8e84aff0b0f762fa18393e2760a2cf5841"}, - {file = "coverage-7.2.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3146b8e16fa60427e03884301bf8209221f5761ac754ee6b267642a2fd354c48"}, - {file = "coverage-7.2.3-cp37-cp37m-win32.whl", hash = "sha256:1fd78b911aea9cec3b7e1e2622c8018d51c0d2bbcf8faaf53c2497eb114911c1"}, - {file = "coverage-7.2.3-cp37-cp37m-win_amd64.whl", hash = "sha256:0f3736a5d34e091b0a611964c6262fd68ca4363df56185902528f0b75dbb9c1f"}, - {file = "coverage-7.2.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:981b4df72c93e3bc04478153df516d385317628bd9c10be699c93c26ddcca8ab"}, - {file = "coverage-7.2.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0045f8f23a5fb30b2eb3b8a83664d8dc4fb58faddf8155d7109166adb9f2040"}, - {file = "coverage-7.2.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f760073fcf8f3d6933178d67754f4f2d4e924e321f4bb0dcef0424ca0215eba1"}, - {file = "coverage-7.2.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c86bd45d1659b1ae3d0ba1909326b03598affbc9ed71520e0ff8c31a993ad911"}, - {file = "coverage-7.2.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:172db976ae6327ed4728e2507daf8a4de73c7cc89796483e0a9198fd2e47b462"}, - {file = "coverage-7.2.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d2a3a6146fe9319926e1d477842ca2a63fe99af5ae690b1f5c11e6af074a6b5c"}, - {file = "coverage-7.2.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f649dd53833b495c3ebd04d6eec58479454a1784987af8afb77540d6c1767abd"}, - {file = "coverage-7.2.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7c4ed4e9f3b123aa403ab424430b426a1992e6f4c8fd3cb56ea520446e04d152"}, - {file = "coverage-7.2.3-cp38-cp38-win32.whl", hash = "sha256:eb0edc3ce9760d2f21637766c3aa04822030e7451981ce569a1b3456b7053f22"}, - {file = "coverage-7.2.3-cp38-cp38-win_amd64.whl", hash = "sha256:63cdeaac4ae85a179a8d6bc09b77b564c096250d759eed343a89d91bce8b6367"}, - {file = "coverage-7.2.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:20d1a2a76bb4eb00e4d36b9699f9b7aba93271c9c29220ad4c6a9581a0320235"}, - {file = "coverage-7.2.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ea748802cc0de4de92ef8244dd84ffd793bd2e7be784cd8394d557a3c751e21"}, - {file = "coverage-7.2.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21b154aba06df42e4b96fc915512ab39595105f6c483991287021ed95776d934"}, - {file = "coverage-7.2.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd214917cabdd6f673a29d708574e9fbdb892cb77eb426d0eae3490d95ca7859"}, - {file = "coverage-7.2.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c2e58e45fe53fab81f85474e5d4d226eeab0f27b45aa062856c89389da2f0d9"}, - {file = "coverage-7.2.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:87ecc7c9a1a9f912e306997ffee020297ccb5ea388421fe62a2a02747e4d5539"}, - {file = "coverage-7.2.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:387065e420aed3c71b61af7e82c7b6bc1c592f7e3c7a66e9f78dd178699da4fe"}, - {file = "coverage-7.2.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ea3f5bc91d7d457da7d48c7a732beaf79d0c8131df3ab278e6bba6297e23c6c4"}, - {file = "coverage-7.2.3-cp39-cp39-win32.whl", hash = "sha256:ae7863a1d8db6a014b6f2ff9c1582ab1aad55a6d25bac19710a8df68921b6e30"}, - {file = "coverage-7.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:3f04becd4fcda03c0160d0da9c8f0c246bc78f2f7af0feea1ec0930e7c93fa4a"}, - {file = "coverage-7.2.3-pp37.pp38.pp39-none-any.whl", hash = "sha256:965ee3e782c7892befc25575fa171b521d33798132692df428a09efacaffe8d0"}, - {file = "coverage-7.2.3.tar.gz", hash = "sha256:d298c2815fa4891edd9abe5ad6e6cb4207104c7dd9fd13aea3fdebf6f9b91259"}, + {file = "coverage-7.2.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9e5eedde6e6e241ec3816f05767cc77e7456bf5ec6b373fb29917f0990e2078f"}, + {file = "coverage-7.2.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5c6c6e3b8fb6411a2035da78d86516bfcfd450571d167304911814407697fb7a"}, + {file = "coverage-7.2.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7668a621afc52db29f6867e0e9c72a1eec9f02c94a7c36599119d557cf6e471"}, + {file = "coverage-7.2.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cdfb53bef4b2739ff747ebbd76d6ac5384371fd3c7a8af08899074eba034d483"}, + {file = "coverage-7.2.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5c4f2e44a2ae15fa6883898e756552db5105ca4bd918634cbd5b7c00e19e8a1"}, + {file = "coverage-7.2.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:700bc9fb1074e0c67c09fe96a803de66663830420781df8dc9fb90d7421d4ccb"}, + {file = "coverage-7.2.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ac4861241e693e21b280f07844ae0e0707665e1dfcbf9466b793584984ae45c4"}, + {file = "coverage-7.2.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3d6f3c5b6738a494f17c73b4aa3aa899865cc33a74aa85e3b5695943b79ad3ce"}, + {file = "coverage-7.2.4-cp310-cp310-win32.whl", hash = "sha256:437da7d2fcc35bf45e04b7e9cfecb7c459ec6f6dc17a8558ed52e8d666c2d9ab"}, + {file = "coverage-7.2.4-cp310-cp310-win_amd64.whl", hash = "sha256:1d3893f285fd76f56651f04d1efd3bdce251c32992a64c51e5d6ec3ba9e3f9c9"}, + {file = "coverage-7.2.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a17bf32e9e3333d78606ac1073dd20655dc0752d5b923fa76afd3bc91674ab4"}, + {file = "coverage-7.2.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f7ffdb3af2a01ce91577f84fc0faa056029fe457f3183007cffe7b11ea78b23c"}, + {file = "coverage-7.2.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89e63b38c7b888e00fd42ce458f838dccb66de06baea2da71801b0fc9070bfa0"}, + {file = "coverage-7.2.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4522dd9aeb9cc2c4c54ce23933beb37a4e106ec2ba94f69138c159024c8a906a"}, + {file = "coverage-7.2.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29c7d88468f01a75231797173b52dc66d20a8d91b8bb75c88fc5861268578f52"}, + {file = "coverage-7.2.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bc47015fc0455753e8aba1f38b81b731aaf7f004a0c390b404e0fcf1d6c1d72f"}, + {file = "coverage-7.2.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5c122d120c11a236558c339a59b4b60947b38ac9e3ad30a0e0e02540b37bf536"}, + {file = "coverage-7.2.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:50fda3d33b705b9c01e3b772cfa7d14de8aec2ec2870e4320992c26d057fde12"}, + {file = "coverage-7.2.4-cp311-cp311-win32.whl", hash = "sha256:ab08af91cf4d847a6e15d7d5eeae5fead1487caf16ff3a2056dbe64d058fd246"}, + {file = "coverage-7.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:876e4ef3eff00b50787867c5bae84857a9af4c369a9d5b266cd9b19f61e48ef7"}, + {file = "coverage-7.2.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3fc9cde48de956bfbacea026936fbd4974ff1dc2f83397c6f1968f0142c9d50b"}, + {file = "coverage-7.2.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12bc9127c8aca2f7c25c9acca53da3db6799b2999b40f28c2546237b7ea28459"}, + {file = "coverage-7.2.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2857894c22833d3da6e113623a9b7440159b2295280b4e0d954cadbfa724b85a"}, + {file = "coverage-7.2.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4db4e6c115d869cd5397d3d21fd99e4c7053205c33a4ae725c90d19dcd178af"}, + {file = "coverage-7.2.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f37ae1804596f13d811e0247ffc8219f5261b3565bdf45fcbb4fc091b8e9ff35"}, + {file = "coverage-7.2.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:cdee9a77fd0ce000781680b6a1f4b721c567f66f2f73a49be1843ff439d634f3"}, + {file = "coverage-7.2.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0b65a6a5484b7f2970393d6250553c05b2ede069e0e18abe907fdc7f3528252e"}, + {file = "coverage-7.2.4-cp37-cp37m-win32.whl", hash = "sha256:1a3e8697cb40f28e5bcfb6f4bda7852d96dbb6f6fd7cc306aba4ae690c9905ab"}, + {file = "coverage-7.2.4-cp37-cp37m-win_amd64.whl", hash = "sha256:4078939c4b7053e14e87c65aa68dbed7867e326e450f94038bfe1a1b22078ff9"}, + {file = "coverage-7.2.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:603a2b172126e3b08c11ca34200143089a088cd0297d4cfc4922d2c1c3a892f9"}, + {file = "coverage-7.2.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:72751d117ceaad3b1ea3bcb9e85f5409bbe9fb8a40086e17333b994dbccc0718"}, + {file = "coverage-7.2.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f19ba9301e6fb0b94ba71fda9a1b02d11f0aab7f8e2455122a4e2921b6703c2f"}, + {file = "coverage-7.2.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d784177a7fb9d0f58d24d3e60638c8b729c3693963bf67fa919120f750db237"}, + {file = "coverage-7.2.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d2a9180beff1922b09bd7389e23454928e108449e646c26da5c62e29b0bf4e3"}, + {file = "coverage-7.2.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:39747afc854a7ee14e5e132da7db179d6281faf97dc51e6d7806651811c47538"}, + {file = "coverage-7.2.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60feb703abc8d78e9427d873bcf924c9e30cf540a21971ef5a17154da763b60f"}, + {file = "coverage-7.2.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c2becddfcbf3d994a8f4f9dd2b6015cae3a3eff50dedc6e4a17c3cccbe8f93d4"}, + {file = "coverage-7.2.4-cp38-cp38-win32.whl", hash = "sha256:56a674ad18d6b04008283ca03c012be913bf89d91c0803c54c24600b300d9e51"}, + {file = "coverage-7.2.4-cp38-cp38-win_amd64.whl", hash = "sha256:ab08e03add2cf5793e66ac1bbbb24acfa90c125476f5724f5d44c56eeec1d635"}, + {file = "coverage-7.2.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:92b565c51732ea2e7e541709ccce76391b39f4254260e5922e08e00971e88e33"}, + {file = "coverage-7.2.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8769a67e8816c7e94d5bf446fc0501641fde78fdff362feb28c2c64d45d0e9b1"}, + {file = "coverage-7.2.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56d74d6fbd5a98a5629e8467b719b0abea9ca01a6b13555d125c84f8bf4ea23d"}, + {file = "coverage-7.2.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d9f770c6052d9b5c9b0e824fd8c003fe33276473b65b4f10ece9565ceb62438e"}, + {file = "coverage-7.2.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3023ce23e41a6f006c09f7e6d62b6c069c36bdc9f7de16a5ef823acc02e6c63"}, + {file = "coverage-7.2.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fabd1f4d12dfd6b4f309208c2f31b116dc5900e0b42dbafe4ee1bc7c998ffbb0"}, + {file = "coverage-7.2.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e41a7f44e73b37c6f0132ecfdc1c8b67722f42a3d9b979e6ebc150c8e80cf13a"}, + {file = "coverage-7.2.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:864e36947289be05abd83267c4bade35e772526d3e9653444a9dc891faf0d698"}, + {file = "coverage-7.2.4-cp39-cp39-win32.whl", hash = "sha256:ea534200efbf600e60130c48552f99f351cae2906898a9cd924c1c7f2fb02853"}, + {file = "coverage-7.2.4-cp39-cp39-win_amd64.whl", hash = "sha256:00f8fd8a5fe1ffc3aef78ea2dbf553e5c0f4664324e878995e38d41f037eb2b3"}, + {file = "coverage-7.2.4-pp37.pp38.pp39-none-any.whl", hash = "sha256:856bcb837e96adede31018a0854ce7711a5d6174db1a84e629134970676c54fa"}, + {file = "coverage-7.2.4.tar.gz", hash = "sha256:7283f78d07a201ac7d9dc2ac2e4faaea99c4d302f243ee5b4e359f3e170dc008"}, ] [package.dependencies] @@ -528,14 +528,14 @@ testing = ["pre-commit"] [[package]] name = "fakeredis" -version = "2.11.0" +version = "2.11.2" description = "Fake implementation of redis API for testing purposes." category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "fakeredis-2.11.0-py3-none-any.whl", hash = "sha256:156ef67713dd53000c28dd341be61a365c20230bc17c8fb8320b0c123e667aff"}, - {file = "fakeredis-2.11.0.tar.gz", hash = "sha256:d25883dc52c31546e586b6ec3c49c5999b3025bfc4812532d71dedcfed56fee1"}, + {file = "fakeredis-2.11.2-py3-none-any.whl", hash = "sha256:69a504328a89e5e5f2d05a4236b570fb45244c96997c5002c8c6a0503b95f289"}, + {file = "fakeredis-2.11.2.tar.gz", hash = "sha256:e0fef512b8ec49679d373456aa4698a4103005ecd7ca0b13170a2c1d3af949c5"}, ] [package.dependencies] @@ -1101,68 +1101,63 @@ files = [ [[package]] name = "orjson" -version = "3.8.10" +version = "3.8.11" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" category = "main" optional = false python-versions = ">= 3.7" files = [ - {file = "orjson-3.8.10-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:4dfe0651e26492d5d929bbf4322de9afbd1c51ac2e3947a7f78492b20359711d"}, - {file = "orjson-3.8.10-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:bc30de5c7b3a402eb59cc0656b8ee53ca36322fc52ab67739c92635174f88336"}, - {file = "orjson-3.8.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c08b426fae7b9577b528f99af0f7e0ff3ce46858dd9a7d1bf86d30f18df89a4c"}, - {file = "orjson-3.8.10-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bce970f293825e008dbf739268dfa41dfe583aa2a1b5ef4efe53a0e92e9671ea"}, - {file = "orjson-3.8.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9b23fb0264bbdd7218aa685cb6fc71f0dcecf34182f0a8596a3a0dff010c06f9"}, - {file = "orjson-3.8.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0826ad2dc1cea1547edff14ce580374f0061d853cbac088c71162dbfe2e52205"}, - {file = "orjson-3.8.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7bce6e61cea6426309259b04c6ee2295b3f823ea51a033749459fe2dd0423b2"}, - {file = "orjson-3.8.10-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:0b470d31244a6f647e5402aac7d2abaf7bb4f52379acf67722a09d35a45c9417"}, - {file = "orjson-3.8.10-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:48824649019a25d3e52f6454435cf19fe1eb3d05ee697e65d257f58ae3aa94d9"}, - {file = "orjson-3.8.10-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:faee89e885796a9cc493c930013fa5cfcec9bfaee431ddf00f0fbfb57166a8b3"}, - {file = "orjson-3.8.10-cp310-none-win_amd64.whl", hash = "sha256:3cfe32b1227fe029a5ad989fbec0b453a34e5e6d9a977723f7c3046d062d3537"}, - {file = "orjson-3.8.10-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:2073b62822738d6740bd2492f6035af5c2fd34aa198322b803dc0e70559a17b7"}, - {file = "orjson-3.8.10-cp311-cp311-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:b2c4faf20b6bb5a2d7ac0c16f58eb1a3800abcef188c011296d1dc2bb2224d48"}, - {file = "orjson-3.8.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c1825997232a324911d11c75d91e1e0338c7b723c149cf53a5fc24496c048a4"}, - {file = "orjson-3.8.10-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f7e85d4682f3ed7321d36846cad0503e944ea9579ef435d4c162e1b73ead8ac9"}, - {file = "orjson-3.8.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8cdaacecb92997916603ab232bb096d0fa9e56b418ca956b9754187d65ca06"}, - {file = "orjson-3.8.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ddabc5e44702d13137949adee3c60b7091e73a664f6e07c7b428eebb2dea7bbf"}, - {file = "orjson-3.8.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27bb26e171e9cfdbec39c7ca4739b6bef8bd06c293d56d92d5e3a3fc017df17d"}, - {file = "orjson-3.8.10-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1810e5446fe68d61732e9743592da0ec807e63972eef076d09e02878c2f5958e"}, - {file = "orjson-3.8.10-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:61e2e51cefe7ef90c4fbbc9fd38ecc091575a3ea7751d56fad95cbebeae2a054"}, - {file = "orjson-3.8.10-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f3e9ac9483c2b4cd794e760316966b7bd1e6afb52b0218f068a4e80c9b2db4f6"}, - {file = "orjson-3.8.10-cp311-none-win_amd64.whl", hash = "sha256:26aee557cf8c93b2a971b5a4a8e3cca19780573531493ce6573aa1002f5c4378"}, - {file = "orjson-3.8.10-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:11ae68f995a50724032af297c92f20bcde31005e0bf3653b12bff9356394615b"}, - {file = "orjson-3.8.10-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:35d879b46b8029e1e01e9f6067928b470a4efa1ca749b6d053232b873c2dcf66"}, - {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:345e41abd1d9e3ecfb554e1e75ff818cf42e268bd06ad25a96c34e00f73a327e"}, - {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:45a5afc9cda6b8aac066dd50d8194432fbc33e71f7164f95402999b725232d78"}, - {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad632dc330a7b39da42530c8d146f76f727d476c01b719dc6743c2b5701aaf6b"}, - {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4bf2556ba99292c4dc550560384dd22e88b5cdbe6d98fb4e202e902b5775cf9f"}, - {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b88afd662190f19c3bb5036a903589f88b1d2c2608fbb97281ce000db6b08897"}, - {file = "orjson-3.8.10-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:abce8d319aae800fd2d774db1106f926dee0e8a5ca85998fd76391fcb58ef94f"}, - {file = "orjson-3.8.10-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:e999abca892accada083f7079612307d94dd14cc105a699588a324f843216509"}, - {file = "orjson-3.8.10-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a3fdee68c4bb3c5d6f89ed4560f1384b5d6260e48fbf868bae1a245a3c693d4d"}, - {file = "orjson-3.8.10-cp37-none-win_amd64.whl", hash = "sha256:e5d7f82506212e047b184c06e4bcd48c1483e101969013623cebcf51cf12cad9"}, - {file = "orjson-3.8.10-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:d953e6c2087dcd990e794f8405011369ee11cf13e9aaae3172ee762ee63947f2"}, - {file = "orjson-3.8.10-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:81aa3f321d201bff0bd0f4014ea44e51d58a9a02d8f2b0eeab2cee22611be8e1"}, - {file = "orjson-3.8.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d27b6182f75896dd8c10ea0f78b9265a3454be72d00632b97f84d7031900dd4"}, - {file = "orjson-3.8.10-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1486600bc1dd1db26c588dd482689edba3d72d301accbe4301db4b2b28bd7aa4"}, - {file = "orjson-3.8.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:344ea91c556a2ce6423dc13401b83ab0392aa697a97fa4142c2c63a6fd0bbfef"}, - {file = "orjson-3.8.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:979f231e3bad1c835627eef1a30db12a8af58bfb475a6758868ea7e81897211f"}, - {file = "orjson-3.8.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fa3a26dcf0f5f2912a8ce8e87273e68b2a9526854d19fd09ea671b154418e88"}, - {file = "orjson-3.8.10-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:b6e79d8864794635974b18821b49a7f27859d17b93413d4603efadf2e92da7a5"}, - {file = "orjson-3.8.10-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ce49999bcbbc14791c61844bc8a69af44f5205d219be540e074660038adae6bf"}, - {file = "orjson-3.8.10-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c2ef690335b24f9272dbf6639353c1ffc3f196623a92b851063e28e9515cf7dd"}, - {file = "orjson-3.8.10-cp38-none-win_amd64.whl", hash = "sha256:5a0b1f4e4fa75e26f814161196e365fc0e1a16e3c07428154505b680a17df02f"}, - {file = "orjson-3.8.10-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:af7601a78b99f0515af2f8ab12c955c0072ffcc1e437fb2556f4465783a4d813"}, - {file = "orjson-3.8.10-cp39-cp39-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:6bbd7b3a3e2030b03c68c4d4b19a2ef5b89081cbb43c05fe2010767ef5e408db"}, - {file = "orjson-3.8.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4355c9aedfefe60904e8bd7901315ebbc8bb828f665e4c9bc94b1432e67cb6f7"}, - {file = "orjson-3.8.10-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b7b0ba074375e25c1594e770e2215941e2017c3cd121889150737fa1123e8bfe"}, - {file = "orjson-3.8.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34b6901c110c06ab9e8d7d0496db4bc9a0c162ca8d77f67539d22cb39e0a1ef4"}, - {file = "orjson-3.8.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cb62ec16a1c26ad9487727b529103cb6a94a1d4969d5b32dd0eab5c3f4f5a6f2"}, - {file = "orjson-3.8.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:595e1e7d04aaaa3d41113e4eb9f765ab642173c4001182684ae9ddc621bb11c8"}, - {file = "orjson-3.8.10-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:64ffd92328473a2f9af059410bd10c703206a4bbc7b70abb1bedcd8761e39eb8"}, - {file = "orjson-3.8.10-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b1f648ec89c6a426098868460c0ef8c86b457ce1378d7569ff4acb6c0c454048"}, - {file = "orjson-3.8.10-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6a286ad379972e4f46579e772f0477e6b505f1823aabcd64ef097dbb4549e1a4"}, - {file = "orjson-3.8.10-cp39-none-win_amd64.whl", hash = "sha256:d2874cee6856d7c386b596e50bc517d1973d73dc40b2bd6abec057b5e7c76b2f"}, - {file = "orjson-3.8.10.tar.gz", hash = "sha256:dcf6adb4471b69875034afab51a14b64f1026bc968175a2bb02c5f6b358bd413"}, + {file = "orjson-3.8.11-cp310-cp310-macosx_11_0_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:9fa900bdd84b4576c8dd6f3e2a00b35797f29283af328c6e3d70addfa4c2d599"}, + {file = "orjson-3.8.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1103e597c16f82c241e1b02beadc9c91cecd93e60433ca73cb6464dcc235f37c"}, + {file = "orjson-3.8.11-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d70b6db9d4e1e6057829cd7fe119c217cebaf989f88d14b2445fa69fc568d03e"}, + {file = "orjson-3.8.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3afccf7f8684dca7f017837a315de0a1ab5c095de22a4eed206d079f9325ed72"}, + {file = "orjson-3.8.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1fedcc428416e23a6c9de62a000c22ae33bbe0108302ad5d5935e29ea739bf37"}, + {file = "orjson-3.8.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf48ed8d4b6ab9f23b7ee642462369d7133412d72824bad89f9bf4311c06c6a1"}, + {file = "orjson-3.8.11-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:3c55065bc2075a5ea6ffb30462d84fd3aa5bbb7ae600855c325ee5753feec715"}, + {file = "orjson-3.8.11-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:08729e339ff3146e6de56c1166f014c3d2ec3e79ffb76d6c55d52cc892e5e477"}, + {file = "orjson-3.8.11-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:358e515b8b19a275b259f5ee1e0efa2859b1d976b5ed5d016ac59f9e6c8788a3"}, + {file = "orjson-3.8.11-cp310-none-win_amd64.whl", hash = "sha256:62eb8bdcf6f4cdbe12743e88ad98696277a75f91a35e8fb93a7ea2b9f4a7000c"}, + {file = "orjson-3.8.11-cp311-cp311-macosx_11_0_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:982ab319b7a5ece4199caf2a2b3a28e62a8e289cb6418548ef98bced7e2a6cfe"}, + {file = "orjson-3.8.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e14903bfeb591a9117b7d40d81e3ebca9700b4e77bd829d6f22ea57941bb0ebf"}, + {file = "orjson-3.8.11-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:58c068f93d701f9466f667bf3b5cb4e4946aee940df2b07ca5101f1cf1b60ce4"}, + {file = "orjson-3.8.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9486963d2e65482c565dacb366adb36d22aa22acf7274b61490244c3d87fa631"}, + {file = "orjson-3.8.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c3b5405edc3a5f9e34516ee1a729f6c46aecf6de960ae07a7b3e95ebdd0e1d9"}, + {file = "orjson-3.8.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b65424ceee82b94e3613233b67ef110dc58f9d83b0076ec47a506289552a861"}, + {file = "orjson-3.8.11-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:173b8f8c750590f432757292cfb197582e5c14347b913b4017561d47af0e759b"}, + {file = "orjson-3.8.11-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:37f38c8194ce086e6a9816b4b8dde5e7f383feeed92feec0385d99baf64f9b6e"}, + {file = "orjson-3.8.11-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:553fdaf9f4b5060a0dcc517ae0c511c289c184a83d6719d03c5602ed0eef0390"}, + {file = "orjson-3.8.11-cp311-none-win_amd64.whl", hash = "sha256:12f647d4da0aab1997e25bed4fa2b76782b5b9d2d1bf3066b5f0a57d34d833c4"}, + {file = "orjson-3.8.11-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:71a656f1c62e84c69060093e20cedff6a92e472d53ff5b8b9026b1b298542a68"}, + {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:176d742f53434541e50a5e659694073aa51dcbd8f29a1708a4fa1a320193c615"}, + {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b369019e597b59c4b97e9f925a3b725321fa1481c129d76c74c6ea3823f5d1e8"}, + {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a53b3c02a38aadc5302661c2ca18645093971488992df77ce14fef16f598b2e"}, + {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6d7b050135669d2335e40120215ad4120e29958c139f8bab68ce06a1cb1a1b2c"}, + {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66f0c9e4e8f6641497a7dc50591af3704b11468e9fc90cfb5874f28b0a61edb5"}, + {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:235926b38ed9b76ab2bca99ff26ece79c1c46bc10079b06e660b087aecffbe69"}, + {file = "orjson-3.8.11-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c2d3e6b65458ed71b6797f321d6e8bfeeadee9d3d31cac47806a608ea745edd7"}, + {file = "orjson-3.8.11-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4118dcd2b5a27a22af5ad92414073f25d93bca1868f1f580056003c84841062f"}, + {file = "orjson-3.8.11-cp37-none-win_amd64.whl", hash = "sha256:b68a07794834b7bd53ae2a8b4fe4bf010734cae3f0917d434c83b97acf8e5bce"}, + {file = "orjson-3.8.11-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:98befa717efaab7ddb847ebe47d473f6bd6f0cb53e98e6c3d487c7c58ba2e174"}, + {file = "orjson-3.8.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f9415b86ef154bf247fa78a6918aac50089c296e26fb6cf15bc9d7e6402a1f8"}, + {file = "orjson-3.8.11-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f7aeefac55848aeb29f20b91fa55f9e488f446201bb1bb31dc17480d113d8955"}, + {file = "orjson-3.8.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d47f97b99beb9bcac6e288a76b559543a61e0187443d8089204b757726b1d000"}, + {file = "orjson-3.8.11-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7d5aecccfaf2052cd07ed5bec8efba9ddfea055682fcd346047b1a3e9da3034"}, + {file = "orjson-3.8.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04b60dfc1251742e79bb075d7a7c4e37078b932a02e6f005c45761bd90c69189"}, + {file = "orjson-3.8.11-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:ef52f1d5a2f89ef9049781c90ea35d5edf74374ed6ed515c286a706d1b290267"}, + {file = "orjson-3.8.11-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7c7b4fae3b8fc69c8e76f1c0694f3decfe8a57f87e7ac7779ebb59cd71135438"}, + {file = "orjson-3.8.11-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f4e4a1001933166fd1c257b920b241b35322bef99ed7329338bf266ac053abe7"}, + {file = "orjson-3.8.11-cp38-none-win_amd64.whl", hash = "sha256:5ff10789cbc08a9fd94507c907ba55b9315e99f20345ff8ef34fac432dacd948"}, + {file = "orjson-3.8.11-cp39-cp39-macosx_11_0_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:c67ac094a4dde914297543af19f22532d7124f3a35245580d8b756c4ff2f5884"}, + {file = "orjson-3.8.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdf201e77d3fac9d8d6f68d872ef45dccfe46f30b268bb88b6c5af5065b433aa"}, + {file = "orjson-3.8.11-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3485c458670c0edb79ca149fe201f199dd9ccfe7ca3acbdef617e3c683e7b97f"}, + {file = "orjson-3.8.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e97fdbb779a3b8f5d9fc7dfddef5325f81ee45897eb7cb4638d5d9734d42514"}, + {file = "orjson-3.8.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2fc050f8e7f2e4061c8c9968ad0be745b11b03913b77ffa8ceca65914696886c"}, + {file = "orjson-3.8.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2ef933da50b31c112b252be03d1ef59e0d0552c1a08e48295bd529ce42aaab8"}, + {file = "orjson-3.8.11-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:714c3e2be6ed7e4ff6e887926d6e171bfd94fdee76d7d3bfa74ee19237a2d49d"}, + {file = "orjson-3.8.11-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7e4ded77ac7432a155d1d27a83bcadf722750aea3b9e6c4d47f2a92054ab71cb"}, + {file = "orjson-3.8.11-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:382f15861a4bf447ab9d07106010e61b217ef6d4245c6cf64af0c12c4c5e2346"}, + {file = "orjson-3.8.11-cp39-none-win_amd64.whl", hash = "sha256:0bc3d1b93a73b46a698c054697eb2d27bdedbc5ea0d11ec5f1a6bfbec36346b5"}, + {file = "orjson-3.8.11.tar.gz", hash = "sha256:882c77126c42dd93bb35288632d69b1e393863a2b752de3e5fe0112833609496"}, ] [[package]] @@ -1566,14 +1561,14 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)" [[package]] name = "requests" -version = "2.28.2" +version = "2.29.0" description = "Python HTTP for Humans." category = "main" optional = false -python-versions = ">=3.7, <4" +python-versions = ">=3.7" files = [ - {file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"}, - {file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"}, + {file = "requests-2.29.0-py3-none-any.whl", hash = "sha256:e8f3c9be120d3333921d213eef078af392fba3933ab7ed2d1cba3b56f2568c3b"}, + {file = "requests-2.29.0.tar.gz", hash = "sha256:f2e34a75f4749019bb0e3effb66683630e4ffeaf75819fb51bebef1bf5aef059"}, ] [package.dependencies] @@ -1606,14 +1601,14 @@ idna2008 = ["idna"] [[package]] name = "setuptools" -version = "67.7.1" +version = "67.7.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-67.7.1-py3-none-any.whl", hash = "sha256:6f0839fbdb7e3cfef1fc38d7954f5c1c26bf4eebb155a55c9bf8faf997b9fb67"}, - {file = "setuptools-67.7.1.tar.gz", hash = "sha256:bb16732e8eb928922eabaa022f881ae2b7cdcfaf9993ef1f5e841a96d32b8e0c"}, + {file = "setuptools-67.7.2-py3-none-any.whl", hash = "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b"}, + {file = "setuptools-67.7.2.tar.gz", hash = "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990"}, ] [package.extras] @@ -1807,14 +1802,14 @@ files = [ [[package]] name = "tomlkit" -version = "0.11.7" +version = "0.11.8" description = "Style preserving TOML library" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "tomlkit-0.11.7-py3-none-any.whl", hash = "sha256:5325463a7da2ef0c6bbfefb62a3dc883aebe679984709aee32a317907d0a8d3c"}, - {file = "tomlkit-0.11.7.tar.gz", hash = "sha256:f392ef70ad87a672f02519f99967d28a4d3047133e2d1df936511465fbb3791d"}, + {file = "tomlkit-0.11.8-py3-none-any.whl", hash = "sha256:8c726c4c202bdb148667835f68d68780b9a003a9ec34167b6c673b38eff2a171"}, + {file = "tomlkit-0.11.8.tar.gz", hash = "sha256:9330fc7faa1db67b541b28e62018c17d20be733177d290a13b24c62d1614e0c3"}, ] [[package]] @@ -1910,21 +1905,21 @@ files = [ [[package]] name = "werkzeug" -version = "2.2.3" +version = "2.3.2" description = "The comprehensive WSGI web application library." category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Werkzeug-2.2.3-py3-none-any.whl", hash = "sha256:56433961bc1f12533306c624f3be5e744389ac61d722175d543e1751285da612"}, - {file = "Werkzeug-2.2.3.tar.gz", hash = "sha256:2e1ccc9417d4da358b9de6f174e3ac094391ea1d4fbef2d667865d819dfd0afe"}, + {file = "Werkzeug-2.3.2-py3-none-any.whl", hash = "sha256:b7b8bc1609f35ae8e45d48a9b58d7a4eb1e41eec148d37e977e5df6ebf3398b2"}, + {file = "Werkzeug-2.3.2.tar.gz", hash = "sha256:2f3278e9ef61511cdf82cc28fc5da0f5b501dd8f01ecf5ef6a5d810048f68702"}, ] [package.dependencies] MarkupSafe = ">=2.1.1" [package.extras] -watchdog = ["watchdog"] +watchdog = ["watchdog (>=2.3)"] [[package]] name = "wsproto" @@ -1959,5 +1954,5 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" -python-versions = ">=3.9,<3.11" -content-hash = "b82180015aa365bf55c890e8a3be5e549fa52f4e62cf4619fb71870939dda170" +python-versions = ">=3.9,<3.12" +content-hash = "7eba1b2d0fd17dacea153cb3f6ebdcb11d7888902cbb3a88a65f3c6c38f65699" diff --git a/pyproject.toml b/pyproject.toml index eaaa7221..d75a1d4c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,7 +51,7 @@ build-backend = "poetry.masonry.api" "Request Mailing List" = "https://lists.archlinux.org/listinfo/aur-requests" [tool.poetry.dependencies] -python = ">=3.9,<3.11" +python = ">=3.9,<3.12" # poetry-dynamic-versioning is used to produce tool.poetry.version # based on git tags. From b3fcfb7679029bb8d72b2ac02c6d294f47224c38 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sun, 30 Apr 2023 20:24:24 +0200 Subject: [PATCH 025/178] doc: improve instructions for setting up a dev/test env Provide more detailed information how to get started with a dev/test env. Signed-off-by: moson-mo --- CONTRIBUTING.md | 2 + TESTING | 207 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 155 insertions(+), 54 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a91e3eec..1957ae22 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -97,6 +97,8 @@ Accessible services (on the host): Docker services, by default, are setup to be hot reloaded when source code is changed. +For detailed setup instructions have a look at [TESTING](TESTING) + #### Using INSTALL The [INSTALL](INSTALL) file describes steps to install the application on diff --git a/TESTING b/TESTING index 078d330b..e9cbf33b 100644 --- a/TESTING +++ b/TESTING @@ -1,59 +1,130 @@ Setup Testing Environment ========================= +The quickest way to get you hacking on aurweb is to utilize docker. +In case you prefer to run it bare-metal see instructions further below. + +Containerized environment +------------------------- + +1) Clone the aurweb project: + + $ git clone https://gitlab.archlinux.org/archlinux/aurweb.git + $ cd aurweb + +2) Install the necessary packages: + + # pacman -S --needed docker docker-compose + +3) Build the aurweb:latest image: + + # systemctl start docker + # docker compose build + +4) Run local Docker development instance: + + # docker compose up -d + +5) Browse to local aurweb development server. + + https://localhost:8444/ + +6) [Optionally] populate the database with dummy data: + + # docker compose exec mariadb /bin/bash + # pacman -S --noconfirm words fortune-mod + # poetry run schema/gendummydata.py dummy_data.sql + # mariadb -uaur -paur aurweb < dummy_data.sql + # exit + + Inspect `dummy_data.sql` for test credentials. + Passwords match usernames. + +We now have fully set up environment which we can start and stop with: + + # docker compose start + # docker compose stop + +Proceed with topic "Setup for running tests" + + +Bare Metal installation +----------------------- + Note that this setup is only to test the web interface. If you need to have a full aurweb instance with cgit, ssh interface, etc, follow the directions in INSTALL. -docker-compose --------------- - -1) Clone the aurweb project: - - $ git clone https://gitlab.archlinux.org/archlinux/aurweb.git - -2) Install the necessary packages: - - # pacman -S docker-compose - -2) Build the aurweb:latest image: - - $ cd /path/to/aurweb/ - $ docker-compose build - -3) Run local Docker development instance: - - $ cd /path/to/aurweb/ - $ docker-compose up -d nginx - -4) Browse to local aurweb development server. - - Python: https://localhost:8444/ - -5) [Optionally] populate the database with dummy data: - - $ docker-compose up mariadb - $ docker-compose exec mariadb /bin/sh - # pacman -S --noconfirm words fortune-mod - # poetry run schema/gendummydata.py dummy_data.sql - # mysql -uaur -paur aurweb < dummy_data.sql - -Inspect `dummy_data.sql` for test credentials. Passwords match usernames. - -Bare Metal ----------- - 1) Clone the aurweb project: $ git clone git://git.archlinux.org/aurweb.git + $ cd aurweb 2) Install the necessary packages: - # pacman -S python-poetry + # pacman -S --needed python-poetry mariadb words fortune-mod nginx -4) Install the package/dependencies via `poetry`: +3) Install the package/dependencies via `poetry`: + + $ poetry install + +4) Copy conf/config.dev to conf/config and replace YOUR_AUR_ROOT by the absolute + path to the root of your aurweb clone. sed can do both tasks for you: + + $ sed -e "s;YOUR_AUR_ROOT;$PWD;g" conf/config.dev > conf/config + + Note that when the upstream config.dev is updated, you should compare it to + your conf/config, or regenerate your configuration with the command above. + +5) Set up mariadb: + + # mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql + # systemctl start mariadb + # mariadb -u root + > CREATE USER 'aur'@'localhost' IDENTIFIED BY 'aur'; + > GRANT ALL ON *.* TO 'aur'@'localhost' WITH GRANT OPTION; + > CREATE DATABASE aurweb; + > exit + +6) Prepare a database and insert dummy data: + + $ AUR_CONFIG=conf/config poetry run python -m aurweb.initdb + $ poetry run schema/gendummydata.py dummy_data.sql + $ mariadb -uaur -paur aurweb < dummy_data.sql + +7) Run the test server: + + ## set AUR_CONFIG to our locally created config + $ export AUR_CONFIG=conf/config + + ## with aurweb.spawn + $ poetry run python -m aurweb.spawn + + ## with systemd service + $ sudo install -m644 examples/aurweb.service /etc/systemd/system/ + # systemctl enable --now aurweb.service + + +Setup for running tests +----------------------- + +If you've set up a docker environment, you can run the full test-suite with: + # docker compose run test + +You can collect code-coverage data with: + $ ./util/fix-coverage data/.coverage + +See information further below on how to visualize the data. + +For running individual tests, we need to perform a couple of additional steps. +In case you did the bare-metal install, steps 2, 3, 4 and 5 should be skipped. + +1) Install the necessary packages: + + # pacman -S --needed python-poetry mariadb-libs asciidoc openssh + +2) Install the package/dependencies via `poetry`: - $ cd /path/to/aurweb/ $ poetry install 3) Copy conf/config.dev to conf/config and replace YOUR_AUR_ROOT by the absolute @@ -64,23 +135,51 @@ Bare Metal Note that when the upstream config.dev is updated, you should compare it to your conf/config, or regenerate your configuration with the command above. -4) Prepare a database: +4) Edit the config file conf/config and change the mysql/mariadb portion - $ cd /path/to/aurweb/ + We can make use of our mariadb docker container instead of having to install + mariadb. Change the config as follows: - $ AUR_CONFIG=conf/config poetry run python -m aurweb.initdb + --------------------------------------------------------------------- + ; MySQL database information. User defaults to root for containerized + ; testing with mysqldb. This should be set to a non-root user. + user = root + password = aur + host = 127.0.0.1 + port = 13306 + ;socket = /var/run/mysqld/mysqld.sock + --------------------------------------------------------------------- - $ poetry run schema/gendummydata.py dummy_data.sql - $ mysql -uaur -paur aurweb < dummy_data.sql +5) Start our mariadb docker container -5) Run the test server: + # docker compose start mariadb - ## set AUR_CONFIG to our locally created config - $ export AUR_CONFIG=conf/config +6) Set environment variables - ## with aurweb.spawn - $ poetry run python -m aurweb.spawn + $ export AUR_CONFIG=conf/config + $ export LOG_CONFIG=logging.test.conf - ## with systemd service - $ sudo install -m644 examples/aurweb.service /etc/systemd/system/ - $ systemctl enable --now aurweb.service +7) Compile translation & doc files + + $ make -C po install + $ make -C doc + +Now we can run our python test-suite or individual tests with: + + $ poetry run pytest test/ + $ poetry run pytest test/test_whatever.py + +To run Sharness tests: + + $ poetry run make -C test sh + +The e-Mails that have been generated can be found at test-emails/ + +After test runs, code-coverage reports can be created with: + ## CLI report + $ coverage report + + ## HTML version stored at htmlcov/ + $ coverage html + +More information about tests can be found at test/README.md From 8c5b85db5c7888a1fca661f098bd12a3ec76756f Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sun, 30 Apr 2023 21:10:42 +0200 Subject: [PATCH 026/178] housekeep: remove fix for poetry installer The problems with the "modern installer" got fixed. We don't need this workaround anymore. https://github.com/python-poetry/poetry/issues/7572 Signed-off-by: moson-mo --- poetry.toml | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 poetry.toml diff --git a/poetry.toml b/poetry.toml deleted file mode 100644 index 8d4747a6..00000000 --- a/poetry.toml +++ /dev/null @@ -1,5 +0,0 @@ -# disable the modern installer until python-installer is fixed -# https://github.com/python-poetry/poetry/issues/7572 - -[installer] -modern-installation = false From a8d14e019457cef9e62cab2da0b4ed67a51ac46d Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Wed, 26 Apr 2023 23:39:10 +0100 Subject: [PATCH 027/178] housekeep: remove unused templates and rework existing ones Signed-off-by: Leonidas Spyropoulos --- .gitlab/issue_templates/Account Request.md | 14 ------ .gitlab/issue_templates/Bug.md | 26 +++++++--- .gitlab/issue_templates/Feature.md | 24 ++++++++- .gitlab/issue_templates/Feedback.md | 58 ---------------------- 4 files changed, 41 insertions(+), 81 deletions(-) delete mode 100644 .gitlab/issue_templates/Account Request.md delete mode 100644 .gitlab/issue_templates/Feedback.md diff --git a/.gitlab/issue_templates/Account Request.md b/.gitlab/issue_templates/Account Request.md deleted file mode 100644 index 6831d3ad..00000000 --- a/.gitlab/issue_templates/Account Request.md +++ /dev/null @@ -1,14 +0,0 @@ -## Checklist - -- [ ] I have set a Username in the Details section -- [ ] I have set an Email in the Details section -- [ ] I have set a valid Account Type in the Details section - -## Details - -- Instance: aur-dev.archlinux.org -- Username: the_username_you_want -- Email: valid@email.org -- Account Type: (User|Trusted User) - -/label account-request diff --git a/.gitlab/issue_templates/Bug.md b/.gitlab/issue_templates/Bug.md index 3e7a04bf..9e20aadb 100644 --- a/.gitlab/issue_templates/Bug.md +++ b/.gitlab/issue_templates/Bug.md @@ -1,12 +1,24 @@ + +/label ~bug ~unconfirmed +/title [BUG] + + ### Checklist -This bug template is meant to provide bug issues for code existing in -the aurweb repository. This bug template is **not meant** to handle -bugs with user-uploaded packages. +**NOTE:** This bug template is meant to provide bug issues for code existing in +the aurweb repository. -To work out a bug you have found in a user-uploaded package, contact -the package's maintainer first. If you receive no response, file the -relevant package request against it so TUs can deal with cleanup. +**This bug template is not meant to handle bugs with user-uploaded packages.** +To report issues you might have found in a user-uploaded package, contact +the package's maintainer in comments. - [ ] I confirm that this is an issue with aurweb's code and not a user-uploaded package. @@ -29,7 +41,7 @@ this bug. ### Logs -If you have any logs relevent to the bug, include them here in +If you have any logs relevant to the bug, include them here in quoted or code blocks. ### Version(s) diff --git a/.gitlab/issue_templates/Feature.md b/.gitlab/issue_templates/Feature.md index c907adcd..630c53c3 100644 --- a/.gitlab/issue_templates/Feature.md +++ b/.gitlab/issue_templates/Feature.md @@ -1,3 +1,25 @@ + +/label ~feature ~unconfirmed +/title [FEATURE] + + +### Checklist + +**NOTE:** This bug template is meant to provide bug issues for code existing in +the aurweb repository. + +**This bug template is not meant to handle bugs with user-uploaded packages.** +To report issues you might have found in a user-uploaded package, contact +the package's maintainer in comments. + - [ ] I have summed up the feature in concise words in the [Summary](#summary) section. - [ ] I have completely described the feature in the [Description](#description) section. - [ ] I have completed the [Blockers](#blockers) section. @@ -28,5 +50,3 @@ Example: - [Feature] Do not allow users to be Tyrants - \<(issue|merge_request)_link\> - -/label feature unconsidered diff --git a/.gitlab/issue_templates/Feedback.md b/.gitlab/issue_templates/Feedback.md deleted file mode 100644 index 950ec0c6..00000000 --- a/.gitlab/issue_templates/Feedback.md +++ /dev/null @@ -1,58 +0,0 @@ -**NOTE:** This issue template is only applicable to FastAPI implementations -in the code-base, which only exists within the `pu` branch. If you wish to -file an issue for the current PHP implementation of aurweb, please file a -standard issue prefixed with `[Bug]` or `[Feature]`. - - -**Checklist** - -- [ ] I have prefixed the issue title with `[Feedback]` along with a message - pointing to the route or feature tested. - - Example: `[Feedback] /packages/{name}` -- [ ] I have completed the [Changes](#changes) section. -- [ ] I have completed the [Bugs](#bugs) section. -- [ ] I have completed the [Improvements](#improvements) section. -- [ ] I have completed the [Summary](#summary) section. - -### Changes - -Please describe changes in user experience when compared to the PHP -implementation. This section can actually hold a lot of info if you -are up for it -- changes in routes, HTML rendering, back-end behavior, -etc. - -If you cannot see any changes from your standpoint, include a short -statement about that fact. - -### Bugs - -Please describe any bugs you've experienced while testing the route -pertaining to this issue. A "perfect" bug report would include your -specific experience, what you expected to occur, and what happened -otherwise. If you can, please include output of `docker-compose logs fastapi` -with your report; especially if any unintended exceptions occurred. - -### Improvements - -If you've experienced improvements in the route when compared to PHP, -please do include those here. We'd like to know if users are noticing -these improvements and how they feel about them. - -There are multiple routes with no improvements. For these, just include -a short sentence about the fact that you've experienced none. - -### Summary - -First: If you've gotten here and completed the [Changes](#changes), -[Bugs](#bugs), and [Improvements](#improvements) sections, we'd like -to thank you very much for your contribution and willingness to test. -We are not a company, and we are not a large team; any bit of assistance -here helps the project astronomically and moves us closer toward a -new release. - -That being said: please include an overall summary of your experience -and how you felt about the current implementation which you're testing -in comparison with PHP (current aur.archlinux.org, or https://localhost:8443 -through docker). - -/label feedback From af4239bcac0fd71ccc4168b70eed77ccf3d567c1 Mon Sep 17 00:00:00 2001 From: Christian Heusel Date: Wed, 22 Mar 2023 08:49:22 +0100 Subject: [PATCH 028/178] replace reference to AUR TU Guidelines with AUR Submission Guidelines Signed-off-by: Christian Heusel --- templates/home.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/home.html b/templates/home.html index e8296239..cb103f18 100644 --- a/templates/home.html +++ b/templates/home.html @@ -1,10 +1,10 @@

    AUR {% trans %}Home{% endtrans %}

    - {{ "Welcome to the AUR! Please read the %sAUR User Guidelines%s and %sAUR TU Guidelines%s for more information." + {{ "Welcome to the AUR! Please read the %sAUR User Guidelines%s for more information and the %sAUR Submission Guidelines%s if you want to contribute a PKGBUILD." | tr | format('', "", - '', "") + '', "") | safe }} {{ "Contributed PKGBUILDs %smust%s conform to the %sArch Packaging Standards%s otherwise they will be deleted!" From b115aedf97bff1d1455d46298738bd8debd931bd Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sat, 6 May 2023 20:29:05 +0200 Subject: [PATCH 029/178] chore(deps): update several dependencies - Removing rfc3986 (1.5.0) - Updating coverage (7.2.4 -> 7.2.5) - Updating fastapi (0.94.1 -> 0.95.1) - Updating httpcore (0.16.3 -> 0.17.0) - Updating sqlalchemy (1.4.47 -> 1.4.48) - Updating httpx (0.23.3 -> 0.24.0) - Updating prometheus-fastapi-instrumentator (5.11.2 -> 6.0.0) - Updating protobuf (4.22.3 -> 4.22.4) - Updating pytest-asyncio (0.20.3 -> 0.21.0) - Updating requests (2.29.0 -> 2.30.0) - Updating uvicorn (0.21.1 -> 0.22.0) - Updating watchfiles (0.18.1 -> 0.19.0) - Updating werkzeug (2.3.2 -> 2.3.3) Signed-off-by: moson-mo --- poetry.lock | 336 ++++++++++++++++++++++++------------------------- pyproject.toml | 41 +++--- 2 files changed, 182 insertions(+), 195 deletions(-) diff --git a/poetry.lock b/poetry.lock index 5e933e70..54a7701d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -352,63 +352,63 @@ files = [ [[package]] name = "coverage" -version = "7.2.4" +version = "7.2.5" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "coverage-7.2.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9e5eedde6e6e241ec3816f05767cc77e7456bf5ec6b373fb29917f0990e2078f"}, - {file = "coverage-7.2.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5c6c6e3b8fb6411a2035da78d86516bfcfd450571d167304911814407697fb7a"}, - {file = "coverage-7.2.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7668a621afc52db29f6867e0e9c72a1eec9f02c94a7c36599119d557cf6e471"}, - {file = "coverage-7.2.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cdfb53bef4b2739ff747ebbd76d6ac5384371fd3c7a8af08899074eba034d483"}, - {file = "coverage-7.2.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5c4f2e44a2ae15fa6883898e756552db5105ca4bd918634cbd5b7c00e19e8a1"}, - {file = "coverage-7.2.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:700bc9fb1074e0c67c09fe96a803de66663830420781df8dc9fb90d7421d4ccb"}, - {file = "coverage-7.2.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ac4861241e693e21b280f07844ae0e0707665e1dfcbf9466b793584984ae45c4"}, - {file = "coverage-7.2.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3d6f3c5b6738a494f17c73b4aa3aa899865cc33a74aa85e3b5695943b79ad3ce"}, - {file = "coverage-7.2.4-cp310-cp310-win32.whl", hash = "sha256:437da7d2fcc35bf45e04b7e9cfecb7c459ec6f6dc17a8558ed52e8d666c2d9ab"}, - {file = "coverage-7.2.4-cp310-cp310-win_amd64.whl", hash = "sha256:1d3893f285fd76f56651f04d1efd3bdce251c32992a64c51e5d6ec3ba9e3f9c9"}, - {file = "coverage-7.2.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a17bf32e9e3333d78606ac1073dd20655dc0752d5b923fa76afd3bc91674ab4"}, - {file = "coverage-7.2.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f7ffdb3af2a01ce91577f84fc0faa056029fe457f3183007cffe7b11ea78b23c"}, - {file = "coverage-7.2.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89e63b38c7b888e00fd42ce458f838dccb66de06baea2da71801b0fc9070bfa0"}, - {file = "coverage-7.2.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4522dd9aeb9cc2c4c54ce23933beb37a4e106ec2ba94f69138c159024c8a906a"}, - {file = "coverage-7.2.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29c7d88468f01a75231797173b52dc66d20a8d91b8bb75c88fc5861268578f52"}, - {file = "coverage-7.2.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bc47015fc0455753e8aba1f38b81b731aaf7f004a0c390b404e0fcf1d6c1d72f"}, - {file = "coverage-7.2.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5c122d120c11a236558c339a59b4b60947b38ac9e3ad30a0e0e02540b37bf536"}, - {file = "coverage-7.2.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:50fda3d33b705b9c01e3b772cfa7d14de8aec2ec2870e4320992c26d057fde12"}, - {file = "coverage-7.2.4-cp311-cp311-win32.whl", hash = "sha256:ab08af91cf4d847a6e15d7d5eeae5fead1487caf16ff3a2056dbe64d058fd246"}, - {file = "coverage-7.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:876e4ef3eff00b50787867c5bae84857a9af4c369a9d5b266cd9b19f61e48ef7"}, - {file = "coverage-7.2.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3fc9cde48de956bfbacea026936fbd4974ff1dc2f83397c6f1968f0142c9d50b"}, - {file = "coverage-7.2.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12bc9127c8aca2f7c25c9acca53da3db6799b2999b40f28c2546237b7ea28459"}, - {file = "coverage-7.2.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2857894c22833d3da6e113623a9b7440159b2295280b4e0d954cadbfa724b85a"}, - {file = "coverage-7.2.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4db4e6c115d869cd5397d3d21fd99e4c7053205c33a4ae725c90d19dcd178af"}, - {file = "coverage-7.2.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f37ae1804596f13d811e0247ffc8219f5261b3565bdf45fcbb4fc091b8e9ff35"}, - {file = "coverage-7.2.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:cdee9a77fd0ce000781680b6a1f4b721c567f66f2f73a49be1843ff439d634f3"}, - {file = "coverage-7.2.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0b65a6a5484b7f2970393d6250553c05b2ede069e0e18abe907fdc7f3528252e"}, - {file = "coverage-7.2.4-cp37-cp37m-win32.whl", hash = "sha256:1a3e8697cb40f28e5bcfb6f4bda7852d96dbb6f6fd7cc306aba4ae690c9905ab"}, - {file = "coverage-7.2.4-cp37-cp37m-win_amd64.whl", hash = "sha256:4078939c4b7053e14e87c65aa68dbed7867e326e450f94038bfe1a1b22078ff9"}, - {file = "coverage-7.2.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:603a2b172126e3b08c11ca34200143089a088cd0297d4cfc4922d2c1c3a892f9"}, - {file = "coverage-7.2.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:72751d117ceaad3b1ea3bcb9e85f5409bbe9fb8a40086e17333b994dbccc0718"}, - {file = "coverage-7.2.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f19ba9301e6fb0b94ba71fda9a1b02d11f0aab7f8e2455122a4e2921b6703c2f"}, - {file = "coverage-7.2.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d784177a7fb9d0f58d24d3e60638c8b729c3693963bf67fa919120f750db237"}, - {file = "coverage-7.2.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d2a9180beff1922b09bd7389e23454928e108449e646c26da5c62e29b0bf4e3"}, - {file = "coverage-7.2.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:39747afc854a7ee14e5e132da7db179d6281faf97dc51e6d7806651811c47538"}, - {file = "coverage-7.2.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60feb703abc8d78e9427d873bcf924c9e30cf540a21971ef5a17154da763b60f"}, - {file = "coverage-7.2.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c2becddfcbf3d994a8f4f9dd2b6015cae3a3eff50dedc6e4a17c3cccbe8f93d4"}, - {file = "coverage-7.2.4-cp38-cp38-win32.whl", hash = "sha256:56a674ad18d6b04008283ca03c012be913bf89d91c0803c54c24600b300d9e51"}, - {file = "coverage-7.2.4-cp38-cp38-win_amd64.whl", hash = "sha256:ab08e03add2cf5793e66ac1bbbb24acfa90c125476f5724f5d44c56eeec1d635"}, - {file = "coverage-7.2.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:92b565c51732ea2e7e541709ccce76391b39f4254260e5922e08e00971e88e33"}, - {file = "coverage-7.2.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8769a67e8816c7e94d5bf446fc0501641fde78fdff362feb28c2c64d45d0e9b1"}, - {file = "coverage-7.2.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56d74d6fbd5a98a5629e8467b719b0abea9ca01a6b13555d125c84f8bf4ea23d"}, - {file = "coverage-7.2.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d9f770c6052d9b5c9b0e824fd8c003fe33276473b65b4f10ece9565ceb62438e"}, - {file = "coverage-7.2.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3023ce23e41a6f006c09f7e6d62b6c069c36bdc9f7de16a5ef823acc02e6c63"}, - {file = "coverage-7.2.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fabd1f4d12dfd6b4f309208c2f31b116dc5900e0b42dbafe4ee1bc7c998ffbb0"}, - {file = "coverage-7.2.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e41a7f44e73b37c6f0132ecfdc1c8b67722f42a3d9b979e6ebc150c8e80cf13a"}, - {file = "coverage-7.2.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:864e36947289be05abd83267c4bade35e772526d3e9653444a9dc891faf0d698"}, - {file = "coverage-7.2.4-cp39-cp39-win32.whl", hash = "sha256:ea534200efbf600e60130c48552f99f351cae2906898a9cd924c1c7f2fb02853"}, - {file = "coverage-7.2.4-cp39-cp39-win_amd64.whl", hash = "sha256:00f8fd8a5fe1ffc3aef78ea2dbf553e5c0f4664324e878995e38d41f037eb2b3"}, - {file = "coverage-7.2.4-pp37.pp38.pp39-none-any.whl", hash = "sha256:856bcb837e96adede31018a0854ce7711a5d6174db1a84e629134970676c54fa"}, - {file = "coverage-7.2.4.tar.gz", hash = "sha256:7283f78d07a201ac7d9dc2ac2e4faaea99c4d302f243ee5b4e359f3e170dc008"}, + {file = "coverage-7.2.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:883123d0bbe1c136f76b56276074b0c79b5817dd4238097ffa64ac67257f4b6c"}, + {file = "coverage-7.2.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d2fbc2a127e857d2f8898aaabcc34c37771bf78a4d5e17d3e1f5c30cd0cbc62a"}, + {file = "coverage-7.2.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f3671662dc4b422b15776cdca89c041a6349b4864a43aa2350b6b0b03bbcc7f"}, + {file = "coverage-7.2.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780551e47d62095e088f251f5db428473c26db7829884323e56d9c0c3118791a"}, + {file = "coverage-7.2.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:066b44897c493e0dcbc9e6a6d9f8bbb6607ef82367cf6810d387c09f0cd4fe9a"}, + {file = "coverage-7.2.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b9a4ee55174b04f6af539218f9f8083140f61a46eabcaa4234f3c2a452c4ed11"}, + {file = "coverage-7.2.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:706ec567267c96717ab9363904d846ec009a48d5f832140b6ad08aad3791b1f5"}, + {file = "coverage-7.2.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ae453f655640157d76209f42c62c64c4d4f2c7f97256d3567e3b439bd5c9b06c"}, + {file = "coverage-7.2.5-cp310-cp310-win32.whl", hash = "sha256:f81c9b4bd8aa747d417407a7f6f0b1469a43b36a85748145e144ac4e8d303cb5"}, + {file = "coverage-7.2.5-cp310-cp310-win_amd64.whl", hash = "sha256:dc945064a8783b86fcce9a0a705abd7db2117d95e340df8a4333f00be5efb64c"}, + {file = "coverage-7.2.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:40cc0f91c6cde033da493227797be2826cbf8f388eaa36a0271a97a332bfd7ce"}, + {file = "coverage-7.2.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a66e055254a26c82aead7ff420d9fa8dc2da10c82679ea850d8feebf11074d88"}, + {file = "coverage-7.2.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c10fbc8a64aa0f3ed136b0b086b6b577bc64d67d5581acd7cc129af52654384e"}, + {file = "coverage-7.2.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a22cbb5ede6fade0482111fa7f01115ff04039795d7092ed0db43522431b4f2"}, + {file = "coverage-7.2.5-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:292300f76440651529b8ceec283a9370532f4ecba9ad67d120617021bb5ef139"}, + {file = "coverage-7.2.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7ff8f3fb38233035028dbc93715551d81eadc110199e14bbbfa01c5c4a43f8d8"}, + {file = "coverage-7.2.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:a08c7401d0b24e8c2982f4e307124b671c6736d40d1c39e09d7a8687bddf83ed"}, + {file = "coverage-7.2.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef9659d1cda9ce9ac9585c045aaa1e59223b143f2407db0eaee0b61a4f266fb6"}, + {file = "coverage-7.2.5-cp311-cp311-win32.whl", hash = "sha256:30dcaf05adfa69c2a7b9f7dfd9f60bc8e36b282d7ed25c308ef9e114de7fc23b"}, + {file = "coverage-7.2.5-cp311-cp311-win_amd64.whl", hash = "sha256:97072cc90f1009386c8a5b7de9d4fc1a9f91ba5ef2146c55c1f005e7b5c5e068"}, + {file = "coverage-7.2.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bebea5f5ed41f618797ce3ffb4606c64a5de92e9c3f26d26c2e0aae292f015c1"}, + {file = "coverage-7.2.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:828189fcdda99aae0d6bf718ea766b2e715eabc1868670a0a07bf8404bf58c33"}, + {file = "coverage-7.2.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e8a95f243d01ba572341c52f89f3acb98a3b6d1d5d830efba86033dd3687ade"}, + {file = "coverage-7.2.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8834e5f17d89e05697c3c043d3e58a8b19682bf365048837383abfe39adaed5"}, + {file = "coverage-7.2.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d1f25ee9de21a39b3a8516f2c5feb8de248f17da7eead089c2e04aa097936b47"}, + {file = "coverage-7.2.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1637253b11a18f453e34013c665d8bf15904c9e3c44fbda34c643fbdc9d452cd"}, + {file = "coverage-7.2.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8e575a59315a91ccd00c7757127f6b2488c2f914096077c745c2f1ba5b8c0969"}, + {file = "coverage-7.2.5-cp37-cp37m-win32.whl", hash = "sha256:509ecd8334c380000d259dc66feb191dd0a93b21f2453faa75f7f9cdcefc0718"}, + {file = "coverage-7.2.5-cp37-cp37m-win_amd64.whl", hash = "sha256:12580845917b1e59f8a1c2ffa6af6d0908cb39220f3019e36c110c943dc875b0"}, + {file = "coverage-7.2.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b5016e331b75310610c2cf955d9f58a9749943ed5f7b8cfc0bb89c6134ab0a84"}, + {file = "coverage-7.2.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:373ea34dca98f2fdb3e5cb33d83b6d801007a8074f992b80311fc589d3e6b790"}, + {file = "coverage-7.2.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a063aad9f7b4c9f9da7b2550eae0a582ffc7623dca1c925e50c3fbde7a579771"}, + {file = "coverage-7.2.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38c0a497a000d50491055805313ed83ddba069353d102ece8aef5d11b5faf045"}, + {file = "coverage-7.2.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2b3b05e22a77bb0ae1a3125126a4e08535961c946b62f30985535ed40e26614"}, + {file = "coverage-7.2.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0342a28617e63ad15d96dca0f7ae9479a37b7d8a295f749c14f3436ea59fdcb3"}, + {file = "coverage-7.2.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf97ed82ca986e5c637ea286ba2793c85325b30f869bf64d3009ccc1a31ae3fd"}, + {file = "coverage-7.2.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c2c41c1b1866b670573657d584de413df701f482574bad7e28214a2362cb1fd1"}, + {file = "coverage-7.2.5-cp38-cp38-win32.whl", hash = "sha256:10b15394c13544fce02382360cab54e51a9e0fd1bd61ae9ce012c0d1e103c813"}, + {file = "coverage-7.2.5-cp38-cp38-win_amd64.whl", hash = "sha256:a0b273fe6dc655b110e8dc89b8ec7f1a778d78c9fd9b4bda7c384c8906072212"}, + {file = "coverage-7.2.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c587f52c81211d4530fa6857884d37f514bcf9453bdeee0ff93eaaf906a5c1b"}, + {file = "coverage-7.2.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4436cc9ba5414c2c998eaedee5343f49c02ca93b21769c5fdfa4f9d799e84200"}, + {file = "coverage-7.2.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6599bf92f33ab041e36e06d25890afbdf12078aacfe1f1d08c713906e49a3fe5"}, + {file = "coverage-7.2.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:857abe2fa6a4973f8663e039ead8d22215d31db613ace76e4a98f52ec919068e"}, + {file = "coverage-7.2.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f5cab2d7f0c12f8187a376cc6582c477d2df91d63f75341307fcdcb5d60303"}, + {file = "coverage-7.2.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:aa387bd7489f3e1787ff82068b295bcaafbf6f79c3dad3cbc82ef88ce3f48ad3"}, + {file = "coverage-7.2.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:156192e5fd3dbbcb11cd777cc469cf010a294f4c736a2b2c891c77618cb1379a"}, + {file = "coverage-7.2.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bd3b4b8175c1db502adf209d06136c000df4d245105c8839e9d0be71c94aefe1"}, + {file = "coverage-7.2.5-cp39-cp39-win32.whl", hash = "sha256:ddc5a54edb653e9e215f75de377354e2455376f416c4378e1d43b08ec50acc31"}, + {file = "coverage-7.2.5-cp39-cp39-win_amd64.whl", hash = "sha256:338aa9d9883aaaad53695cb14ccdeb36d4060485bb9388446330bef9c361c252"}, + {file = "coverage-7.2.5-pp37.pp38.pp39-none-any.whl", hash = "sha256:8877d9b437b35a85c18e3c6499b23674684bf690f5d96c1006a1ef61f9fdf0f3"}, + {file = "coverage-7.2.5.tar.gz", hash = "sha256:f99ef080288f09ffc687423b8d60978cf3a465d3f404a18d1a05474bd8575a47"}, ] [package.dependencies] @@ -548,14 +548,14 @@ lua = ["lupa (>=1.14,<2.0)"] [[package]] name = "fastapi" -version = "0.94.1" +version = "0.95.1" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "fastapi-0.94.1-py3-none-any.whl", hash = "sha256:451387550c2d25a972193f22e408a82e75a8e7867c834a03076704fe20df3256"}, - {file = "fastapi-0.94.1.tar.gz", hash = "sha256:4a75936dbf9eb74be5eb0d41a793adefe9f3fc6ba66dbdabd160120fd3c2d9cd"}, + {file = "fastapi-0.95.1-py3-none-any.whl", hash = "sha256:a870d443e5405982e1667dfe372663abf10754f246866056336d7f01c21dab07"}, + {file = "fastapi-0.95.1.tar.gz", hash = "sha256:9569f0a381f8a457ec479d90fa01005cfddaae07546eb1f3fa035bc4797ae7d5"}, ] [package.dependencies] @@ -736,14 +736,14 @@ files = [ [[package]] name = "httpcore" -version = "0.16.3" +version = "0.17.0" description = "A minimal low-level HTTP client." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "httpcore-0.16.3-py3-none-any.whl", hash = "sha256:da1fb708784a938aa084bde4feb8317056c55037247c787bd7e19eb2c2949dc0"}, - {file = "httpcore-0.16.3.tar.gz", hash = "sha256:c5d6f04e2fc530f39e0c077e6a30caa53f1451096120f1f38b954afd0b17c0cb"}, + {file = "httpcore-0.17.0-py3-none-any.whl", hash = "sha256:0fdfea45e94f0c9fd96eab9286077f9ff788dd186635ae61b312693e4d943599"}, + {file = "httpcore-0.17.0.tar.gz", hash = "sha256:cc045a3241afbf60ce056202301b4d8b6af08845e3294055eb26b09913ef903c"}, ] [package.dependencies] @@ -758,25 +758,25 @@ socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "httpx" -version = "0.23.3" +version = "0.24.0" description = "The next generation HTTP client." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "httpx-0.23.3-py3-none-any.whl", hash = "sha256:a211fcce9b1254ea24f0cd6af9869b3d29aba40154e947d2a07bb499b3e310d6"}, - {file = "httpx-0.23.3.tar.gz", hash = "sha256:9818458eb565bb54898ccb9b8b251a28785dd4a55afbc23d0eb410754fe7d0f9"}, + {file = "httpx-0.24.0-py3-none-any.whl", hash = "sha256:447556b50c1921c351ea54b4fe79d91b724ed2b027462ab9a329465d147d5a4e"}, + {file = "httpx-0.24.0.tar.gz", hash = "sha256:507d676fc3e26110d41df7d35ebd8b3b8585052450f4097401c9be59d928c63e"}, ] [package.dependencies] certifi = "*" -httpcore = ">=0.15.0,<0.17.0" -rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} +httpcore = ">=0.15.0,<0.18.0" +idna = "*" sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] -cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<13)"] +cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (>=1.0.0,<2.0.0)"] @@ -1255,14 +1255,14 @@ twisted = ["twisted"] [[package]] name = "prometheus-fastapi-instrumentator" -version = "5.11.2" +version = "6.0.0" description = "Instrument your FastAPI with Prometheus metrics." category = "main" optional = false python-versions = ">=3.7.0,<4.0.0" files = [ - {file = "prometheus_fastapi_instrumentator-5.11.2-py3-none-any.whl", hash = "sha256:c84ae3dc98bebb44f29d0af0c17c9f0782c2fb964ef83353664d9858a632cf81"}, - {file = "prometheus_fastapi_instrumentator-5.11.2.tar.gz", hash = "sha256:9d8d0df8de7d6a73ae387121629dbf32fe022cdfc63e8bacd51f4b8ff21059ea"}, + {file = "prometheus_fastapi_instrumentator-6.0.0-py3-none-any.whl", hash = "sha256:6f66a951a4801667f7311d161f3aebfe0cd202391d0f067fbbe169792e2d987b"}, + {file = "prometheus_fastapi_instrumentator-6.0.0.tar.gz", hash = "sha256:f1ddd0b8ead75e71d055bdf4cb7e995ec6a6ca63543245e7bbc5ca9b14c45191"}, ] [package.dependencies] @@ -1271,25 +1271,25 @@ prometheus-client = ">=0.8.0,<1.0.0" [[package]] name = "protobuf" -version = "4.22.3" +version = "4.22.4" description = "" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "protobuf-4.22.3-cp310-abi3-win32.whl", hash = "sha256:8b54f56d13ae4a3ec140076c9d937221f887c8f64954673d46f63751209e839a"}, - {file = "protobuf-4.22.3-cp310-abi3-win_amd64.whl", hash = "sha256:7760730063329d42a9d4c4573b804289b738d4931e363ffbe684716b796bde51"}, - {file = "protobuf-4.22.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:d14fc1a41d1a1909998e8aff7e80d2a7ae14772c4a70e4bf7db8a36690b54425"}, - {file = "protobuf-4.22.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:70659847ee57a5262a65954538088a1d72dfc3e9882695cab9f0c54ffe71663b"}, - {file = "protobuf-4.22.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:13233ee2b9d3bd9a5f216c1fa2c321cd564b93d8f2e4f521a85b585447747997"}, - {file = "protobuf-4.22.3-cp37-cp37m-win32.whl", hash = "sha256:ecae944c6c2ce50dda6bf76ef5496196aeb1b85acb95df5843cd812615ec4b61"}, - {file = "protobuf-4.22.3-cp37-cp37m-win_amd64.whl", hash = "sha256:d4b66266965598ff4c291416be429cef7989d8fae88b55b62095a2331511b3fa"}, - {file = "protobuf-4.22.3-cp38-cp38-win32.whl", hash = "sha256:f08aa300b67f1c012100d8eb62d47129e53d1150f4469fd78a29fa3cb68c66f2"}, - {file = "protobuf-4.22.3-cp38-cp38-win_amd64.whl", hash = "sha256:f2f4710543abec186aee332d6852ef5ae7ce2e9e807a3da570f36de5a732d88e"}, - {file = "protobuf-4.22.3-cp39-cp39-win32.whl", hash = "sha256:7cf56e31907c532e460bb62010a513408e6cdf5b03fb2611e4b67ed398ad046d"}, - {file = "protobuf-4.22.3-cp39-cp39-win_amd64.whl", hash = "sha256:e0e630d8e6a79f48c557cd1835865b593d0547dce221c66ed1b827de59c66c97"}, - {file = "protobuf-4.22.3-py3-none-any.whl", hash = "sha256:52f0a78141078077cfe15fe333ac3e3a077420b9a3f5d1bf9b5fe9d286b4d881"}, - {file = "protobuf-4.22.3.tar.gz", hash = "sha256:23452f2fdea754a8251d0fc88c0317735ae47217e0d27bf330a30eec2848811a"}, + {file = "protobuf-4.22.4-cp310-abi3-win32.whl", hash = "sha256:a4e661247896c2ffea4b894bca2d8657e752bedb8f3c66d7befa2557291be1e8"}, + {file = "protobuf-4.22.4-cp310-abi3-win_amd64.whl", hash = "sha256:7b42086d6027be2730151b49f27b2f5be40f3b036adf7b8da5917f4567f268c3"}, + {file = "protobuf-4.22.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:4bfb28d48628deacdb66a95aaa7b6640f3dc82b4edd34db444c7a3cdd90b01fb"}, + {file = "protobuf-4.22.4-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:e98e26328d7c668541d1052b02de4205b1094ef6b2ce57167440d3e39876db48"}, + {file = "protobuf-4.22.4-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:8fd329e5dd7b6c4b878cab4b85bb6cec880e2adaf4e8aa2c75944dcbb05e1ff1"}, + {file = "protobuf-4.22.4-cp37-cp37m-win32.whl", hash = "sha256:b7728b5da9eee15c0aa3baaee79e94fa877ddcf7e3d2f34b1eab586cd26eea89"}, + {file = "protobuf-4.22.4-cp37-cp37m-win_amd64.whl", hash = "sha256:f4a711588c3a79b6f9c44af4d7f4a2ae868e27063654683932ab6462f90e9656"}, + {file = "protobuf-4.22.4-cp38-cp38-win32.whl", hash = "sha256:11b28b4e779d7f275e3ea0efa3938f4d4e8ed3ca818f9fec3b193f8e9ada99fd"}, + {file = "protobuf-4.22.4-cp38-cp38-win_amd64.whl", hash = "sha256:144d5b46df5e44f914f715accaadf88d617242ba5a40cacef4e8de7effa79954"}, + {file = "protobuf-4.22.4-cp39-cp39-win32.whl", hash = "sha256:5128b4d5efcaef92189e076077ae389700606ff81d2126b8361dc01f3e026197"}, + {file = "protobuf-4.22.4-cp39-cp39-win_amd64.whl", hash = "sha256:9537ae27d43318acf8ce27d0359fe28e6ebe4179c3350bc055bb60ff4dc4fcd3"}, + {file = "protobuf-4.22.4-py3-none-any.whl", hash = "sha256:3b21074b7fb748d8e123acaef9fa63a84fdc1436dc71199d2317b139f77dd6f4"}, + {file = "protobuf-4.22.4.tar.gz", hash = "sha256:21fbaef7f012232eb8d6cb8ba334e931fc6ff8570f5aaedc77d5b22a439aa909"}, ] [[package]] @@ -1437,18 +1437,18 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no [[package]] name = "pytest-asyncio" -version = "0.20.3" +version = "0.21.0" description = "Pytest support for asyncio" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-asyncio-0.20.3.tar.gz", hash = "sha256:83cbf01169ce3e8eb71c6c278ccb0574d1a7a3bb8eaaf5e50e0ad342afb33b36"}, - {file = "pytest_asyncio-0.20.3-py3-none-any.whl", hash = "sha256:f129998b209d04fcc65c96fc85c11e5316738358909a8399e93be553d7656442"}, + {file = "pytest-asyncio-0.21.0.tar.gz", hash = "sha256:2b38a496aef56f56b0e87557ec313e11e1ab9276fc3863f6a7be0f1d0e415e1b"}, + {file = "pytest_asyncio-0.21.0-py3-none-any.whl", hash = "sha256:f2b3366b7cd501a4056858bd39349d5af19742aed2d81660b7998b6341c7eb9c"}, ] [package.dependencies] -pytest = ">=6.1.0" +pytest = ">=7.0.0" [package.extras] docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] @@ -1561,44 +1561,26 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)" [[package]] name = "requests" -version = "2.29.0" +version = "2.30.0" description = "Python HTTP for Humans." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "requests-2.29.0-py3-none-any.whl", hash = "sha256:e8f3c9be120d3333921d213eef078af392fba3933ab7ed2d1cba3b56f2568c3b"}, - {file = "requests-2.29.0.tar.gz", hash = "sha256:f2e34a75f4749019bb0e3effb66683630e4ffeaf75819fb51bebef1bf5aef059"}, + {file = "requests-2.30.0-py3-none-any.whl", hash = "sha256:10e94cc4f3121ee6da529d358cdaeaff2f1c409cd377dbc72b825852f2f7e294"}, + {file = "requests-2.30.0.tar.gz", hash = "sha256:239d7d4458afcb28a692cdd298d87542235f4ca8d36d03a15bfc128a6559a2f4"}, ] [package.dependencies] certifi = ">=2017.4.17" charset-normalizer = ">=2,<4" idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<1.27" +urllib3 = ">=1.21.1,<3" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] -[[package]] -name = "rfc3986" -version = "1.5.0" -description = "Validating URI References per RFC 3986" -category = "main" -optional = false -python-versions = "*" -files = [ - {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, - {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, -] - -[package.dependencies] -idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} - -[package.extras] -idna2008 = ["idna"] - [[package]] name = "setuptools" version = "67.7.2" @@ -1654,53 +1636,53 @@ files = [ [[package]] name = "sqlalchemy" -version = "1.4.47" +version = "1.4.48" description = "Database Abstraction Library" category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "SQLAlchemy-1.4.47-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:dcfb480bfc9e1fab726003ae00a6bfc67a29bad275b63a4e36d17fe7f13a624e"}, - {file = "SQLAlchemy-1.4.47-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:28fda5a69d6182589892422c5a9b02a8fd1125787aab1d83f1392aa955bf8d0a"}, - {file = "SQLAlchemy-1.4.47-cp27-cp27m-win32.whl", hash = "sha256:45e799c1a41822eba6bee4e59b0e38764e1a1ee69873ab2889079865e9ea0e23"}, - {file = "SQLAlchemy-1.4.47-cp27-cp27m-win_amd64.whl", hash = "sha256:10edbb92a9ef611f01b086e271a9f6c1c3e5157c3b0c5ff62310fb2187acbd4a"}, - {file = "SQLAlchemy-1.4.47-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7a4df53472c9030a8ddb1cce517757ba38a7a25699bbcabd57dcc8a5d53f324e"}, - {file = "SQLAlchemy-1.4.47-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:511d4abc823152dec49461209607bbfb2df60033c8c88a3f7c93293b8ecbb13d"}, - {file = "SQLAlchemy-1.4.47-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbe57f39f531c5d68d5594ea4613daa60aba33bb51a8cc42f96f17bbd6305e8d"}, - {file = "SQLAlchemy-1.4.47-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ca8ab6748e3ec66afccd8b23ec2f92787a58d5353ce9624dccd770427ee67c82"}, - {file = "SQLAlchemy-1.4.47-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:299b5c5c060b9fbe51808d0d40d8475f7b3873317640b9b7617c7f988cf59fda"}, - {file = "SQLAlchemy-1.4.47-cp310-cp310-win32.whl", hash = "sha256:684e5c773222781775c7f77231f412633d8af22493bf35b7fa1029fdf8066d10"}, - {file = "SQLAlchemy-1.4.47-cp310-cp310-win_amd64.whl", hash = "sha256:2bba39b12b879c7b35cde18b6e14119c5f1a16bd064a48dd2ac62d21366a5e17"}, - {file = "SQLAlchemy-1.4.47-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:795b5b9db573d3ed61fae74285d57d396829e3157642794d3a8f72ec2a5c719b"}, - {file = "SQLAlchemy-1.4.47-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:989c62b96596b7938cbc032e39431e6c2d81b635034571d6a43a13920852fb65"}, - {file = "SQLAlchemy-1.4.47-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3b67bda733da1dcdccaf354e71ef01b46db483a4f6236450d3f9a61efdba35a"}, - {file = "SQLAlchemy-1.4.47-cp311-cp311-win32.whl", hash = "sha256:9a198f690ac12a3a807e03a5a45df6a30cd215935f237a46f4248faed62e69c8"}, - {file = "SQLAlchemy-1.4.47-cp311-cp311-win_amd64.whl", hash = "sha256:03be6f3cb66e69fb3a09b5ea89d77e4bc942f3bf84b207dba84666a26799c166"}, - {file = "SQLAlchemy-1.4.47-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:16ee6fea316790980779268da47a9260d5dd665c96f225d28e7750b0bb2e2a04"}, - {file = "SQLAlchemy-1.4.47-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:557675e0befafa08d36d7a9284e8761c97490a248474d778373fb96b0d7fd8de"}, - {file = "SQLAlchemy-1.4.47-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bb2797fee8a7914fb2c3dc7de404d3f96eb77f20fc60e9ee38dc6b0ca720f2c2"}, - {file = "SQLAlchemy-1.4.47-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28297aa29e035f29cba6b16aacd3680fbc6a9db682258d5f2e7b49ec215dbe40"}, - {file = "SQLAlchemy-1.4.47-cp36-cp36m-win32.whl", hash = "sha256:998e782c8d9fd57fa8704d149ccd52acf03db30d7dd76f467fd21c1c21b414fa"}, - {file = "SQLAlchemy-1.4.47-cp36-cp36m-win_amd64.whl", hash = "sha256:dde4d02213f1deb49eaaf8be8a6425948963a7af84983b3f22772c63826944de"}, - {file = "SQLAlchemy-1.4.47-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:e98ef1babe34f37f443b7211cd3ee004d9577a19766e2dbacf62fce73c76245a"}, - {file = "SQLAlchemy-1.4.47-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14a3879853208a242b5913f3a17c6ac0eae9dc210ff99c8f10b19d4a1ed8ed9b"}, - {file = "SQLAlchemy-1.4.47-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7120a2f72599d4fed7c001fa1cbbc5b4d14929436135768050e284f53e9fbe5e"}, - {file = "SQLAlchemy-1.4.47-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:048509d7f3ac27b83ad82fd96a1ab90a34c8e906e4e09c8d677fc531d12c23c5"}, - {file = "SQLAlchemy-1.4.47-cp37-cp37m-win32.whl", hash = "sha256:6572d7c96c2e3e126d0bb27bfb1d7e2a195b68d951fcc64c146b94f088e5421a"}, - {file = "SQLAlchemy-1.4.47-cp37-cp37m-win_amd64.whl", hash = "sha256:a6c3929df5eeaf3867724003d5c19fed3f0c290f3edc7911616616684f200ecf"}, - {file = "SQLAlchemy-1.4.47-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:71d4bf7768169c4502f6c2b0709a02a33703544f611810fb0c75406a9c576ee1"}, - {file = "SQLAlchemy-1.4.47-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd45c60cc4f6d68c30d5179e2c2c8098f7112983532897566bb69c47d87127d3"}, - {file = "SQLAlchemy-1.4.47-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0fdbb8e9d4e9003f332a93d6a37bca48ba8095086c97a89826a136d8eddfc455"}, - {file = "SQLAlchemy-1.4.47-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f216a51451a0a0466e082e163591f6dcb2f9ec182adb3f1f4b1fd3688c7582c"}, - {file = "SQLAlchemy-1.4.47-cp38-cp38-win32.whl", hash = "sha256:bd988b3362d7e586ef581eb14771bbb48793a4edb6fcf62da75d3f0f3447060b"}, - {file = "SQLAlchemy-1.4.47-cp38-cp38-win_amd64.whl", hash = "sha256:32ab09f2863e3de51529aa84ff0e4fe89a2cb1bfbc11e225b6dbc60814e44c94"}, - {file = "SQLAlchemy-1.4.47-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:07764b240645627bc3e82596435bd1a1884646bfc0721642d24c26b12f1df194"}, - {file = "SQLAlchemy-1.4.47-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e2a42017984099ef6f56438a6b898ce0538f6fadddaa902870c5aa3e1d82583"}, - {file = "SQLAlchemy-1.4.47-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6b6d807c76c20b4bc143a49ad47782228a2ac98bdcdcb069da54280e138847fc"}, - {file = "SQLAlchemy-1.4.47-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a94632ba26a666e7be0a7d7cc3f7acab622a04259a3aa0ee50ff6d44ba9df0d"}, - {file = "SQLAlchemy-1.4.47-cp39-cp39-win32.whl", hash = "sha256:f80915681ea9001f19b65aee715115f2ad310730c8043127cf3e19b3009892dd"}, - {file = "SQLAlchemy-1.4.47-cp39-cp39-win_amd64.whl", hash = "sha256:fc700b862e0a859a37faf85367e205e7acaecae5a098794aff52fdd8aea77b12"}, - {file = "SQLAlchemy-1.4.47.tar.gz", hash = "sha256:95fc02f7fc1f3199aaa47a8a757437134cf618e9d994c84effd53f530c38586f"}, + {file = "SQLAlchemy-1.4.48-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:4bac3aa3c3d8bc7408097e6fe8bf983caa6e9491c5d2e2488cfcfd8106f13b6a"}, + {file = "SQLAlchemy-1.4.48-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:dbcae0e528d755f4522cad5842f0942e54b578d79f21a692c44d91352ea6d64e"}, + {file = "SQLAlchemy-1.4.48-cp27-cp27m-win32.whl", hash = "sha256:cbbe8b8bffb199b225d2fe3804421b7b43a0d49983f81dc654d0431d2f855543"}, + {file = "SQLAlchemy-1.4.48-cp27-cp27m-win_amd64.whl", hash = "sha256:627e04a5d54bd50628fc8734d5fc6df2a1aa5962f219c44aad50b00a6cdcf965"}, + {file = "SQLAlchemy-1.4.48-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9af1db7a287ef86e0f5cd990b38da6bd9328de739d17e8864f1817710da2d217"}, + {file = "SQLAlchemy-1.4.48-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:ce7915eecc9c14a93b73f4e1c9d779ca43e955b43ddf1e21df154184f39748e5"}, + {file = "SQLAlchemy-1.4.48-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5381ddd09a99638f429f4cbe1b71b025bed318f6a7b23e11d65f3eed5e181c33"}, + {file = "SQLAlchemy-1.4.48-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:87609f6d4e81a941a17e61a4c19fee57f795e96f834c4f0a30cee725fc3f81d9"}, + {file = "SQLAlchemy-1.4.48-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb0808ad34167f394fea21bd4587fc62f3bd81bba232a1e7fbdfa17e6cfa7cd7"}, + {file = "SQLAlchemy-1.4.48-cp310-cp310-win32.whl", hash = "sha256:d53cd8bc582da5c1c8c86b6acc4ef42e20985c57d0ebc906445989df566c5603"}, + {file = "SQLAlchemy-1.4.48-cp310-cp310-win_amd64.whl", hash = "sha256:4355e5915844afdc5cf22ec29fba1010166e35dd94a21305f49020022167556b"}, + {file = "SQLAlchemy-1.4.48-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:066c2b0413e8cb980e6d46bf9d35ca83be81c20af688fedaef01450b06e4aa5e"}, + {file = "SQLAlchemy-1.4.48-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c99bf13e07140601d111a7c6f1fc1519914dd4e5228315bbda255e08412f61a4"}, + {file = "SQLAlchemy-1.4.48-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ee26276f12614d47cc07bc85490a70f559cba965fb178b1c45d46ffa8d73fda"}, + {file = "SQLAlchemy-1.4.48-cp311-cp311-win32.whl", hash = "sha256:49c312bcff4728bffc6fb5e5318b8020ed5c8b958a06800f91859fe9633ca20e"}, + {file = "SQLAlchemy-1.4.48-cp311-cp311-win_amd64.whl", hash = "sha256:cef2e2abc06eab187a533ec3e1067a71d7bbec69e582401afdf6d8cad4ba3515"}, + {file = "SQLAlchemy-1.4.48-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:3509159e050bd6d24189ec7af373359f07aed690db91909c131e5068176c5a5d"}, + {file = "SQLAlchemy-1.4.48-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fc2ab4d9f6d9218a5caa4121bdcf1125303482a1cdcfcdbd8567be8518969c0"}, + {file = "SQLAlchemy-1.4.48-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e1ddbbcef9bcedaa370c03771ebec7e39e3944782bef49e69430383c376a250b"}, + {file = "SQLAlchemy-1.4.48-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f82d8efea1ca92b24f51d3aea1a82897ed2409868a0af04247c8c1e4fef5890"}, + {file = "SQLAlchemy-1.4.48-cp36-cp36m-win32.whl", hash = "sha256:e3e98d4907805b07743b583a99ecc58bf8807ecb6985576d82d5e8ae103b5272"}, + {file = "SQLAlchemy-1.4.48-cp36-cp36m-win_amd64.whl", hash = "sha256:25887b4f716e085a1c5162f130b852f84e18d2633942c8ca40dfb8519367c14f"}, + {file = "SQLAlchemy-1.4.48-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:0817c181271b0ce5df1aa20949f0a9e2426830fed5ecdcc8db449618f12c2730"}, + {file = "SQLAlchemy-1.4.48-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe1dd2562313dd9fe1778ed56739ad5d9aae10f9f43d9f4cf81d65b0c85168bb"}, + {file = "SQLAlchemy-1.4.48-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:68413aead943883b341b2b77acd7a7fe2377c34d82e64d1840860247cec7ff7c"}, + {file = "SQLAlchemy-1.4.48-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbde5642104ac6e95f96e8ad6d18d9382aa20672008cf26068fe36f3004491df"}, + {file = "SQLAlchemy-1.4.48-cp37-cp37m-win32.whl", hash = "sha256:11c6b1de720f816c22d6ad3bbfa2f026f89c7b78a5c4ffafb220e0183956a92a"}, + {file = "SQLAlchemy-1.4.48-cp37-cp37m-win_amd64.whl", hash = "sha256:eb5464ee8d4bb6549d368b578e9529d3c43265007193597ddca71c1bae6174e6"}, + {file = "SQLAlchemy-1.4.48-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:92e6133cf337c42bfee03ca08c62ba0f2d9695618c8abc14a564f47503157be9"}, + {file = "SQLAlchemy-1.4.48-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44d29a3fc6d9c45962476b470a81983dd8add6ad26fdbfae6d463b509d5adcda"}, + {file = "SQLAlchemy-1.4.48-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:005e942b451cad5285015481ae4e557ff4154dde327840ba91b9ac379be3b6ce"}, + {file = "SQLAlchemy-1.4.48-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c8cfe951ed074ba5e708ed29c45397a95c4143255b0d022c7c8331a75ae61f3"}, + {file = "SQLAlchemy-1.4.48-cp38-cp38-win32.whl", hash = "sha256:2b9af65cc58726129d8414fc1a1a650dcdd594ba12e9c97909f1f57d48e393d3"}, + {file = "SQLAlchemy-1.4.48-cp38-cp38-win_amd64.whl", hash = "sha256:2b562e9d1e59be7833edf28b0968f156683d57cabd2137d8121806f38a9d58f4"}, + {file = "SQLAlchemy-1.4.48-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:a1fc046756cf2a37d7277c93278566ddf8be135c6a58397b4c940abf837011f4"}, + {file = "SQLAlchemy-1.4.48-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d9b55252d2ca42a09bcd10a697fa041e696def9dfab0b78c0aaea1485551a08"}, + {file = "SQLAlchemy-1.4.48-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6dab89874e72a9ab5462997846d4c760cdb957958be27b03b49cf0de5e5c327c"}, + {file = "SQLAlchemy-1.4.48-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fd8b5ee5a3acc4371f820934b36f8109ce604ee73cc668c724abb054cebcb6e"}, + {file = "SQLAlchemy-1.4.48-cp39-cp39-win32.whl", hash = "sha256:eee09350fd538e29cfe3a496ec6f148504d2da40dbf52adefb0d2f8e4d38ccc4"}, + {file = "SQLAlchemy-1.4.48-cp39-cp39-win_amd64.whl", hash = "sha256:7ad2b0f6520ed5038e795cc2852eb5c1f20fa6831d73301ced4aafbe3a10e1f6"}, + {file = "SQLAlchemy-1.4.48.tar.gz", hash = "sha256:b47bc287096d989a0838ce96f7d8e966914a24da877ed41a7531d44b55cdb8df"}, ] [package.dependencies] @@ -1843,14 +1825,14 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "uvicorn" -version = "0.21.1" +version = "0.22.0" description = "The lightning-fast ASGI server." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "uvicorn-0.21.1-py3-none-any.whl", hash = "sha256:e47cac98a6da10cd41e6fd036d472c6f58ede6c5dbee3dbee3ef7a100ed97742"}, - {file = "uvicorn-0.21.1.tar.gz", hash = "sha256:0fac9cb342ba099e0d582966005f3fdba5b0290579fed4a6266dc702ca7bb032"}, + {file = "uvicorn-0.22.0-py3-none-any.whl", hash = "sha256:e9434d3bbf05f310e762147f769c9f21235ee118ba2d2bf1155a7196448bd996"}, + {file = "uvicorn-0.22.0.tar.gz", hash = "sha256:79277ae03db57ce7d9aa0567830bbb51d7a612f54d6e1e3e92da3ef24c2c8ed8"}, ] [package.dependencies] @@ -1862,30 +1844,34 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", [[package]] name = "watchfiles" -version = "0.18.1" +version = "0.19.0" description = "Simple, modern and high performance file watching and code reload in python." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "watchfiles-0.18.1-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:9891d3c94272108bcecf5597a592e61105279def1313521e637f2d5acbe08bc9"}, - {file = "watchfiles-0.18.1-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:7102342d60207fa635e24c02a51c6628bf0472e5fef067f78a612386840407fc"}, - {file = "watchfiles-0.18.1-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:00ea0081eca5e8e695cffbc3a726bb90da77f4e3f78ce29b86f0d95db4e70ef7"}, - {file = "watchfiles-0.18.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b8e6db99e49cd7125d8a4c9d33c0735eea7b75a942c6ad68b75be3e91c242fb"}, - {file = "watchfiles-0.18.1-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bc7c726855f04f22ac79131b51bf0c9f728cb2117419ed830a43828b2c4a5fcb"}, - {file = "watchfiles-0.18.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbaff354d12235002e62d9d3fa8bcf326a8490c1179aa5c17195a300a9e5952f"}, - {file = "watchfiles-0.18.1-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:888db233e06907c555eccd10da99b9cd5ed45deca47e41766954292dc9f7b198"}, - {file = "watchfiles-0.18.1-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:dde79930d1b28f15994ad6613aa2865fc7a403d2bb14585a8714a53233b15717"}, - {file = "watchfiles-0.18.1-cp37-abi3-win32.whl", hash = "sha256:e2b2bdd26bf8d6ed90763e6020b475f7634f919dbd1730ea1b6f8cb88e21de5d"}, - {file = "watchfiles-0.18.1-cp37-abi3-win_amd64.whl", hash = "sha256:c541e0f2c3e95e83e4f84561c893284ba984e9d0025352057396d96dceb09f44"}, - {file = "watchfiles-0.18.1-cp37-abi3-win_arm64.whl", hash = "sha256:9a26272ef3e930330fc0c2c148cc29706cc2c40d25760c7ccea8d768a8feef8b"}, - {file = "watchfiles-0.18.1-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:9fb12a5e2b42e0b53769455ff93546e6bc9ab14007fbd436978d827a95ca5bd1"}, - {file = "watchfiles-0.18.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:548d6b42303d40264118178053c78820533b683b20dfbb254a8706ca48467357"}, - {file = "watchfiles-0.18.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e0d8fdfebc50ac7569358f5c75f2b98bb473befccf9498cf23b3e39993bb45a"}, - {file = "watchfiles-0.18.1-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:0f9a22fff1745e2bb930b1e971c4c5b67ea3b38ae17a6adb9019371f80961219"}, - {file = "watchfiles-0.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b02e7fa03cd4059dd61ff0600080a5a9e7a893a85cb8e5178943533656eec65e"}, - {file = "watchfiles-0.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a868ce2c7565137f852bd4c863a164dc81306cae7378dbdbe4e2aca51ddb8857"}, - {file = "watchfiles-0.18.1.tar.gz", hash = "sha256:4ec0134a5e31797eb3c6c624dbe9354f2a8ee9c720e0b46fc5b7bab472b7c6d4"}, + {file = "watchfiles-0.19.0-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:91633e64712df3051ca454ca7d1b976baf842d7a3640b87622b323c55f3345e7"}, + {file = "watchfiles-0.19.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:b6577b8c6c8701ba8642ea9335a129836347894b666dd1ec2226830e263909d3"}, + {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:18b28f6ad871b82df9542ff958d0c86bb0d8310bb09eb8e87d97318a3b5273af"}, + {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fac19dc9cbc34052394dbe81e149411a62e71999c0a19e1e09ce537867f95ae0"}, + {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:09ea3397aecbc81c19ed7f025e051a7387feefdb789cf768ff994c1228182fda"}, + {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c0376deac92377817e4fb8f347bf559b7d44ff556d9bc6f6208dd3f79f104aaf"}, + {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c75eff897786ee262c9f17a48886f4e98e6cfd335e011c591c305e5d083c056"}, + {file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb5d45c4143c1dd60f98a16187fd123eda7248f84ef22244818c18d531a249d1"}, + {file = "watchfiles-0.19.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:79c533ff593db861ae23436541f481ec896ee3da4e5db8962429b441bbaae16e"}, + {file = "watchfiles-0.19.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:3d7d267d27aceeeaa3de0dd161a0d64f0a282264d592e335fff7958cc0cbae7c"}, + {file = "watchfiles-0.19.0-cp37-abi3-win32.whl", hash = "sha256:176a9a7641ec2c97b24455135d58012a5be5c6217fc4d5fef0b2b9f75dbf5154"}, + {file = "watchfiles-0.19.0-cp37-abi3-win_amd64.whl", hash = "sha256:945be0baa3e2440151eb3718fd8846751e8b51d8de7b884c90b17d271d34cae8"}, + {file = "watchfiles-0.19.0-cp37-abi3-win_arm64.whl", hash = "sha256:0089c6dc24d436b373c3c57657bf4f9a453b13767150d17284fc6162b2791911"}, + {file = "watchfiles-0.19.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:cae3dde0b4b2078f31527acff6f486e23abed307ba4d3932466ba7cdd5ecec79"}, + {file = "watchfiles-0.19.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f3920b1285a7d3ce898e303d84791b7bf40d57b7695ad549dc04e6a44c9f120"}, + {file = "watchfiles-0.19.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9afd0d69429172c796164fd7fe8e821ade9be983f51c659a38da3faaaaac44dc"}, + {file = "watchfiles-0.19.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68dce92b29575dda0f8d30c11742a8e2b9b8ec768ae414b54f7453f27bdf9545"}, + {file = "watchfiles-0.19.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:5569fc7f967429d4bc87e355cdfdcee6aabe4b620801e2cf5805ea245c06097c"}, + {file = "watchfiles-0.19.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5471582658ea56fca122c0f0d0116a36807c63fefd6fdc92c71ca9a4491b6b48"}, + {file = "watchfiles-0.19.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b538014a87f94d92f98f34d3e6d2635478e6be6423a9ea53e4dd96210065e193"}, + {file = "watchfiles-0.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20b44221764955b1e703f012c74015306fb7e79a00c15370785f309b1ed9aa8d"}, + {file = "watchfiles-0.19.0.tar.gz", hash = "sha256:d9b073073e048081e502b6c6b0b88714c026a1a4c890569238d04aca5f9ca74b"}, ] [package.dependencies] @@ -1905,14 +1891,14 @@ files = [ [[package]] name = "werkzeug" -version = "2.3.2" +version = "2.3.3" description = "The comprehensive WSGI web application library." category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "Werkzeug-2.3.2-py3-none-any.whl", hash = "sha256:b7b8bc1609f35ae8e45d48a9b58d7a4eb1e41eec148d37e977e5df6ebf3398b2"}, - {file = "Werkzeug-2.3.2.tar.gz", hash = "sha256:2f3278e9ef61511cdf82cc28fc5da0f5b501dd8f01ecf5ef6a5d810048f68702"}, + {file = "Werkzeug-2.3.3-py3-none-any.whl", hash = "sha256:4866679a0722de00796a74086238bb3b98d90f423f05de039abb09315487254a"}, + {file = "Werkzeug-2.3.3.tar.gz", hash = "sha256:a987caf1092edc7523edb139edb20c70571c4a8d5eed02e0b547b4739174d091"}, ] [package.dependencies] @@ -1955,4 +1941,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "7eba1b2d0fd17dacea153cb3f6ebdcb11d7888902cbb3a88a65f3c6c38f65699" +content-hash = "9974b6c53a244765e15677b5266c0922601f51ea16068cb621184c89ce4b7f22" diff --git a/pyproject.toml b/pyproject.toml index d75a1d4c..ea94f2cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,48 +62,49 @@ asgiref = "^3.6.0" bcrypt = "^4.0.1" bleach = "^6.0.0" email-validator = "^1.3.1" -fakeredis = "^2.10.0" +fakeredis = "^2.11.2" feedgen = "^0.9.0" -httpx = "^0.23.3" +httpx = "^0.24.0" itsdangerous = "^2.1.2" lxml = "^4.9.2" -orjson = "^3.8.7" -protobuf = "^4.22.1" -pygit2 = "^1.11.1" +orjson = "^3.8.11" +protobuf = "^4.22.4" +pygit2 = "^1.12.0" python-multipart = "^0.0.6" -redis = "^4.5.1" -requests = "^2.28.2" +redis = "^4.5.4" +requests = "^2.30.0" paginate = "^0.5.6" +urllib3 = "^1.26.15" # SQL -alembic = "^1.10.2" +alembic = "^1.10.4" mysqlclient = "^2.1.1" Authlib = "^1.2.0" Jinja2 = "^3.1.2" -Markdown = "^3.4.1" -Werkzeug = "^2.2.3" -SQLAlchemy = "^1.4.46" +Markdown = "^3.4.3" +Werkzeug = "^2.3.3" +SQLAlchemy = "^1.4.48" # ASGI -uvicorn = "^0.21.0" +uvicorn = "^0.22.0" gunicorn = "^20.1.0" Hypercorn = "^0.14.3" -prometheus-fastapi-instrumentator = "^5.11.1" +prometheus-fastapi-instrumentator = "^6.0.0" pytest-xdist = "^3.2.1" -filelock = "^3.9.1" +filelock = "^3.12.0" posix-ipc = "^1.1.1" pyalpm = "^0.10.6" -fastapi = "^0.94.1" +fastapi = "^0.95.1" srcinfo = "^0.1.2" -tomlkit = "^0.11.6" +tomlkit = "^0.11.8" [tool.poetry.dev-dependencies] -coverage = "^7.2.1" -pytest = "^7.2.2" -pytest-asyncio = "^0.20.3" +coverage = "^7.2.5" +pytest = "^7.3.1" +pytest-asyncio = "^0.21.0" pytest-cov = "^4.0.0" pytest-tap = "^3.3" -watchfiles = "^0.18.1" +watchfiles = "^0.19.0" [tool.poetry.scripts] aurweb-git-auth = "aurweb.git.auth:main" From 1d627edbe72de5267cbd8b4f239bb1c61cbaba4c Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Sat, 6 May 2023 20:34:54 +0100 Subject: [PATCH 030/178] chore(release): prepare for 6.2.3 Signed-off-by: Leonidas Spyropoulos --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ea94f2cd..83d10b5d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ combine_as_imports = true # [tool.poetry] name = "aurweb" -version = "v6.2.2" +version = "v6.2.3" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From d2e8fa02491f1b7824daf37ca3a1646fd06c17e7 Mon Sep 17 00:00:00 2001 From: "Daniel M. Capella" Date: Sat, 6 May 2023 16:46:07 -0400 Subject: [PATCH 031/178] chore(deps): "Group all minor and patch updates together" Treat FastAPI separately due to regular breakage. Co-authored-by: moson-mo --- renovate.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index 39a2b6e9..b6721721 100644 --- a/renovate.json +++ b/renovate.json @@ -1,6 +1,13 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ - "config:base" + "config:base", + "group:allNonMajor" + ], + "packageRules": [ + { + "groupName": "fastapi", + "matchPackageNames": ["fastapi"] + } ] } From 3253a6ad29dc3ed83d0fde90d8f93c8b0c1a6730 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sun, 7 May 2023 09:58:17 +0200 Subject: [PATCH 032/178] fix(deps): remove urllib3 from dependency list Previously pinned urllib3 to v1.x. This is not needed though. The incompatibility of v2.x is with poetry itself, but not aurweb. Signed-off-by: moson-mo --- poetry.lock | 33 +++++++++++++++++---------------- pyproject.toml | 3 +-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/poetry.lock b/poetry.lock index 54a7701d..388379d9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -151,14 +151,14 @@ css = ["tinycss2 (>=1.1.0,<1.2)"] [[package]] name = "certifi" -version = "2022.12.7" +version = "2023.5.7" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, - {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, + {file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"}, + {file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"}, ] [[package]] @@ -482,18 +482,18 @@ wmi = ["wmi (>=1.5.1,<2.0.0)"] [[package]] name = "email-validator" -version = "1.3.1" +version = "2.0.0.post2" description = "A robust email address syntax and deliverability validation library." category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.7" files = [ - {file = "email_validator-1.3.1-py2.py3-none-any.whl", hash = "sha256:49a72f5fa6ed26be1c964f0567d931d10bf3fdeeacdf97bc26ef1cd2a44e0bda"}, - {file = "email_validator-1.3.1.tar.gz", hash = "sha256:d178c5c6fa6c6824e9b04f199cf23e79ac15756786573c190d2ad13089411ad2"}, + {file = "email_validator-2.0.0.post2-py3-none-any.whl", hash = "sha256:2466ba57cda361fb7309fd3d5a225723c788ca4bbad32a0ebd5373b99730285c"}, + {file = "email_validator-2.0.0.post2.tar.gz", hash = "sha256:1ff6e86044200c56ae23595695c54e9614f4a9551e0e393614f764860b3d7900"}, ] [package.dependencies] -dnspython = ">=1.15.0" +dnspython = ">=2.0.0" idna = ">=2.0.0" [[package]] @@ -1808,20 +1808,21 @@ files = [ [[package]] name = "urllib3" -version = "1.26.15" +version = "2.0.2" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = ">=3.7" files = [ - {file = "urllib3-1.26.15-py2.py3-none-any.whl", hash = "sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42"}, - {file = "urllib3-1.26.15.tar.gz", hash = "sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305"}, + {file = "urllib3-2.0.2-py3-none-any.whl", hash = "sha256:d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e"}, + {file = "urllib3-2.0.2.tar.gz", hash = "sha256:61717a1095d7e155cdb737ac7bb2f4324a858a1e2e6466f6d03ff630ca68d3cc"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uvicorn" @@ -1941,4 +1942,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "9974b6c53a244765e15677b5266c0922601f51ea16068cb621184c89ce4b7f22" +content-hash = "6a96903be0358aa6d6ef1926edf6158dd36060f8bec66bd8bf8b0ee04e7795df" diff --git a/pyproject.toml b/pyproject.toml index 83d10b5d..b27d281a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ aiofiles = "^23.1.0" asgiref = "^3.6.0" bcrypt = "^4.0.1" bleach = "^6.0.0" -email-validator = "^1.3.1" +email-validator = "^2.0.0.post2" fakeredis = "^2.11.2" feedgen = "^0.9.0" httpx = "^0.24.0" @@ -74,7 +74,6 @@ python-multipart = "^0.0.6" redis = "^4.5.4" requests = "^2.30.0" paginate = "^0.5.6" -urllib3 = "^1.26.15" # SQL alembic = "^1.10.4" From d0b0e4d88b465796bf3ff5bfbd6f709e4e367560 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Wed, 17 May 2023 18:22:53 +0200 Subject: [PATCH 033/178] fix: update repo information with aurblup script Currently, the "Repo" column in "OfficialProviders" is not updated when a package is moved from one repository to another. Note that we only save a package/provides combination once, hence if a package is available in core and testing at the same time, it would only put just one record into the OfficialProviders table. We iterate through the repos one by one and the last value is kept for mapping a (package/provides) combination to a repo. Due to that, the repos listed in the "sync-db" config setting should be ordered such that the "testing" repos are listed first. Signed-off-by: moson-mo --- aurweb/scripts/aurblup.py | 11 +++++++++++ test/test_aurblup.py | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/aurweb/scripts/aurblup.py b/aurweb/scripts/aurblup.py index 340d1ccd..10da1d98 100755 --- a/aurweb/scripts/aurblup.py +++ b/aurweb/scripts/aurblup.py @@ -49,6 +49,7 @@ def _main(force: bool = False): .all() ) + # delete providers not existing in any of our alpm repos for name, provides in old_providers.difference(providers): db.delete_all( db.query(OfficialProvider).filter( @@ -59,10 +60,20 @@ def _main(force: bool = False): ) ) + # add new providers that do not yet exist in our DB for name, provides in providers.difference(old_providers): repo = repomap.get((name, provides)) db.create(OfficialProvider, Name=name, Repo=repo, Provides=provides) + # update providers where a pkg was moved from one repo to another + all_providers = db.query(OfficialProvider) + + for op in all_providers: + new_repo = repomap.get((op.Name, op.Provides)) + + if op.Repo != new_repo: + op.Repo = new_repo + def main(force: bool = False): db.get_engine() diff --git a/test/test_aurblup.py b/test/test_aurblup.py index 93a832f9..1489677d 100644 --- a/test/test_aurblup.py +++ b/test/test_aurblup.py @@ -87,3 +87,23 @@ def test_aurblup_cleanup(alpm_db: AlpmDatabase): db.query(OfficialProvider).filter(OfficialProvider.Name == "fake package").all() ) assert len(providers) == 0 + + +def test_aurblup_repo_change(alpm_db: AlpmDatabase): + # Add a package and sync up the database. + alpm_db.add("pkg", "1.0", "x86_64", provides=["pkg2", "pkg3"]) + aurblup.main() + + # We should find an entry with repo "test" + op = db.query(OfficialProvider).filter(OfficialProvider.Name == "pkg").first() + assert op.Repo == "test" + + # Modify the repo to something that does not exist. + op.Repo = "nonsense" + + # Run our script. + aurblup.main() + + # Repo should be set back to "test" + db.refresh(op) + assert op.Repo == "test" From 146943b3b6bccfb07cfbd534248810805774d09c Mon Sep 17 00:00:00 2001 From: moson-mo Date: Thu, 18 May 2023 13:06:21 +0200 Subject: [PATCH 034/178] housekeep: support new default repos after git migration community is merged into extra testing -> core-testing & extra-testing Announcement: https://archlinux.org/news/git-migration-announcement/ We list "testing" repos first: See d0b0e4d88b465796bf3ff5bfbd6f709e4e367560 Co-authored-by: artafinde Signed-off-by: moson-mo --- conf/config.defaults | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/config.defaults b/conf/config.defaults index 0cd4b9d4..bb390d8a 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -119,7 +119,7 @@ max-blob-size = 256000 [aurblup] db-path = /srv/http/aurweb/aurblup/ -sync-dbs = core extra community multilib testing community-testing +sync-dbs = core-testing extra-testing multilib-testing core extra multilib server = https://mirrors.kernel.org/archlinux/%s/os/x86_64 [mkpkglists] From f24fae0ce6547367de6e99a1075ab1009d6e0d14 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Mon, 8 May 2023 18:22:16 +0200 Subject: [PATCH 035/178] feat: Add "Requests" filter option for package name - Add package name textbox for filtering requests (with auto-suggest) - Make "x pending requests" a link for TU/Dev on the package details page Signed-off-by: moson-mo --- aurweb/routers/requests.py | 16 +++++++++- po/aurweb.pot | 4 +++ static/js/typeahead-requests.js | 6 ++++ templates/partials/packages/actions.html | 18 +++++++---- templates/requests.html | 11 ++++++- test/test_packages_routes.py | 24 ++++++++++++++- test/test_requests.py | 38 ++++++++++++++++++++++++ 7 files changed, 109 insertions(+), 8 deletions(-) create mode 100644 static/js/typeahead-requests.js diff --git a/aurweb/routers/requests.py b/aurweb/routers/requests.py index a259dd63..585dc157 100644 --- a/aurweb/routers/requests.py +++ b/aurweb/routers/requests.py @@ -40,13 +40,21 @@ async def requests( filter_accepted: bool = False, filter_rejected: bool = False, filter_maintainer_requests: bool = False, + filter_pkg_name: str = None, ): context = make_context(request, "Requests") context["q"] = dict(request.query_params) + # Set pending filter by default if no status filter was provided. + # In case we got a package name filter, but no status filter, + # we enable the other ones too. if not dict(request.query_params).keys() & FILTER_PARAMS: filter_pending = True + if filter_pkg_name: + filter_closed = True + filter_accepted = True + filter_rejected = True O, PP = util.sanitize_params(str(O), str(PP)) context["O"] = O @@ -56,6 +64,7 @@ async def requests( context["filter_accepted"] = filter_accepted context["filter_rejected"] = filter_rejected context["filter_maintainer_requests"] = filter_maintainer_requests + context["filter_pkg_name"] = filter_pkg_name Maintainer = orm.aliased(User) # A PackageRequest query @@ -78,7 +87,7 @@ async def requests( rejected_count = 0 + query.filter(PackageRequest.Status == REJECTED_ID).count() context["rejected_requests"] = rejected_count - # Apply filters + # Apply status filters in_filters = [] if filter_pending: in_filters.append(PENDING_ID) @@ -89,6 +98,11 @@ async def requests( if filter_rejected: in_filters.append(REJECTED_ID) filtered = query.filter(PackageRequest.Status.in_(in_filters)) + + # Name filter + if filter_pkg_name: + filtered = filtered.filter(PackageBase.Name == filter_pkg_name) + # Additionally filter for requests made from package maintainer if filter_maintainer_requests: filtered = filtered.filter(PackageRequest.UsersID == PackageBase.MaintainerUID) diff --git a/po/aurweb.pot b/po/aurweb.pot index f4e3c1ba..b975ab91 100644 --- a/po/aurweb.pot +++ b/po/aurweb.pot @@ -2362,3 +2362,7 @@ msgstr "" #: templates/partials/packages/comment_form.html msgid "Cancel" msgstr "" + +#: templates/requests.html +msgid "Package name" +msgstr "" diff --git a/static/js/typeahead-requests.js b/static/js/typeahead-requests.js new file mode 100644 index 00000000..9f636eab --- /dev/null +++ b/static/js/typeahead-requests.js @@ -0,0 +1,6 @@ +document.addEventListener('DOMContentLoaded', function() { + const input = document.getElementById('id_filter_pkg_name'); + const form = document.getElementById('todolist_filter'); + const type = 'suggest-pkgbase'; + typeahead.init(type, input, form); +}); diff --git a/templates/partials/packages/actions.html b/templates/partials/packages/actions.html index fa8c994f..ae8cf141 100644 --- a/templates/partials/packages/actions.html +++ b/templates/partials/packages/actions.html @@ -97,11 +97,19 @@ {% endif %} {% if requests %} -

  • - - {{ requests | tn("%d pending request", "%d pending requests") | format(requests) }} - -
  • + {% if request.user.has_credential(creds.PKGREQ_LIST) %} +
  • + + {{ requests | tn("%d pending request", "%d pending requests") | format(requests) }} + +
  • + {% else %} +
  • + + {{ requests | tn("%d pending request", "%d pending requests") | format(requests) }} + +
  • + {% endif %} {% endif %}
  • diff --git a/templates/requests.html b/templates/requests.html index 697fbedb..9eb911f5 100644 --- a/templates/requests.html +++ b/templates/requests.html @@ -62,7 +62,13 @@ value="True" {{ "checked" if filter_maintainer_requests == true }}/>
  • - + + +
    +
    +
    +
    @@ -194,4 +200,7 @@ {% include "partials/pager.html" %} {% endif %}
    + + + {% endblock %} diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 21ccdd7b..93dc404a 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -555,6 +555,16 @@ def test_package_authenticated(client: TestClient, user: User, package: Package) for expected_text in expected: assert expected_text in resp.text + # make sure we don't have these. Only for Maintainer/TUs/Devs + not_expected = [ + "Disown Package", + "View Requests", + "Delete Package", + "Merge Package", + ] + for unexpected_text in not_expected: + assert unexpected_text not in resp.text + # When no requests are up, make sure we don't see the display for them. root = parse_root(resp.text) selector = '//div[@id="actionlist"]/ul/li/span[@class="flagged"]' @@ -586,8 +596,19 @@ def test_package_authenticated_maintainer( for expected_text in expected: assert expected_text in resp.text + # make sure we don't have these. Only for TUs/Devs + not_expected = [ + "1 pending request", + "Delete Package", + "Merge Package", + ] + for unexpected_text in not_expected: + assert unexpected_text not 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, pkgreq: PackageRequest +): cookies = {"AURSID": tu_user.login(Request(), "testPassword")} with client as request: request.cookies = cookies @@ -603,6 +624,7 @@ def test_package_authenticated_tu(client: TestClient, tu_user: User, package: Pa "Vote for this package", "Enable notifications", "Manage Co-Maintainers", + "1 pending request", "Submit Request", "Delete Package", "Merge Package", diff --git a/test/test_requests.py b/test/test_requests.py index eb05596c..7ddb76a0 100644 --- a/test/test_requests.py +++ b/test/test_requests.py @@ -912,6 +912,44 @@ def test_requests_for_maintainer_requests( assert len(rows) == 2 +def test_requests_with_package_name_filter( + client: TestClient, + tu_user: User, + user2: User, + packages: list[Package], + requests: list[PackageRequest], +): + # test as TU + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + with client as request: + request.cookies = cookies + resp = request.get( + "/requests", + params={"filter_pkg_name": packages[0].PackageBase.Name}, + ) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + # We only expect 1 request for our first package + assert len(rows) == 1 + + # test as regular user, not related to our package + cookies = {"AURSID": user2.login(Request(), "testPassword")} + with client as request: + request.cookies = cookies + resp = request.get( + "/requests", + params={"filter_pkg_name": packages[0].PackageBase.Name}, + ) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + # We don't expect to get any requests + assert len(rows) == 0 + + def test_requests_by_deleted_users( client: TestClient, user: User, tu_user: User, pkgreq: PackageRequest ): From 7a88aeb673c420da1dea0b0a29d5f0b8e921b3a0 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Mon, 8 May 2023 21:24:17 +0200 Subject: [PATCH 036/178] chore: update .gitignore for test-emails emails generated when running tests are stored in test-emails/ dir Signed-off-by: moson-mo --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 414077be..a3314c27 100644 --- a/.gitignore +++ b/.gitignore @@ -47,5 +47,9 @@ doc/rpc.html # Ignore coverage report coverage.xml + # Ignore pytest report report.xml + +# Ignore test emails +test-emails/ From 1b41e8572a087c8d9b1d2cc59fffa459e89ed5ac Mon Sep 17 00:00:00 2001 From: renovate Date: Fri, 26 May 2023 02:24:39 +0000 Subject: [PATCH 037/178] fix(deps): update all non-major dependencies --- poetry.lock | 360 ++++++++++++++++++++++++------------------------- pyproject.toml | 2 +- 2 files changed, 180 insertions(+), 182 deletions(-) diff --git a/poetry.lock b/poetry.lock index 388379d9..3a273be4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -14,14 +14,14 @@ files = [ [[package]] name = "alembic" -version = "1.10.4" +version = "1.11.1" description = "A database migration tool for SQLAlchemy." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "alembic-1.10.4-py3-none-any.whl", hash = "sha256:43942c3d4bf2620c466b91c0f4fca136fe51ae972394a0cc8b90810d664e4f5c"}, - {file = "alembic-1.10.4.tar.gz", hash = "sha256:295b54bbb92c4008ab6a7dcd1e227e668416d6f84b98b3c4446a2bc6214a556b"}, + {file = "alembic-1.11.1-py3-none-any.whl", hash = "sha256:dc871798a601fab38332e38d6ddb38d5e734f60034baeb8e2db5b642fccd8ab8"}, + {file = "alembic-1.11.1.tar.gz", hash = "sha256:6a810a6b012c88b33458fceb869aef09ac75d6ace5291915ba7fae44de372c01"}, ] [package.dependencies] @@ -55,16 +55,19 @@ trio = ["trio (>=0.16,<0.22)"] [[package]] name = "asgiref" -version = "3.6.0" +version = "3.7.1" description = "ASGI specs, helper code, and adapters" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "asgiref-3.6.0-py3-none-any.whl", hash = "sha256:71e68008da809b957b7ee4b43dbccff33d1b23519fb8344e33f049897077afac"}, - {file = "asgiref-3.6.0.tar.gz", hash = "sha256:9567dfe7bd8d3c8c892227827c41cce860b368104c3431da67a0c5a65a949506"}, + {file = "asgiref-3.7.1-py3-none-any.whl", hash = "sha256:33958cb2e4b3cd8b1b06ef295bd8605cde65b11df51d3beab39e2e149a610ab3"}, + {file = "asgiref-3.7.1.tar.gz", hash = "sha256:8de379fcc383bcfe4507e229fc31209ea23d4831c850f74063b2c11639474dd2"}, ] +[package.dependencies] +typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} + [package.extras] tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] @@ -352,63 +355,63 @@ files = [ [[package]] name = "coverage" -version = "7.2.5" +version = "7.2.6" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "coverage-7.2.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:883123d0bbe1c136f76b56276074b0c79b5817dd4238097ffa64ac67257f4b6c"}, - {file = "coverage-7.2.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d2fbc2a127e857d2f8898aaabcc34c37771bf78a4d5e17d3e1f5c30cd0cbc62a"}, - {file = "coverage-7.2.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f3671662dc4b422b15776cdca89c041a6349b4864a43aa2350b6b0b03bbcc7f"}, - {file = "coverage-7.2.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780551e47d62095e088f251f5db428473c26db7829884323e56d9c0c3118791a"}, - {file = "coverage-7.2.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:066b44897c493e0dcbc9e6a6d9f8bbb6607ef82367cf6810d387c09f0cd4fe9a"}, - {file = "coverage-7.2.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b9a4ee55174b04f6af539218f9f8083140f61a46eabcaa4234f3c2a452c4ed11"}, - {file = "coverage-7.2.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:706ec567267c96717ab9363904d846ec009a48d5f832140b6ad08aad3791b1f5"}, - {file = "coverage-7.2.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ae453f655640157d76209f42c62c64c4d4f2c7f97256d3567e3b439bd5c9b06c"}, - {file = "coverage-7.2.5-cp310-cp310-win32.whl", hash = "sha256:f81c9b4bd8aa747d417407a7f6f0b1469a43b36a85748145e144ac4e8d303cb5"}, - {file = "coverage-7.2.5-cp310-cp310-win_amd64.whl", hash = "sha256:dc945064a8783b86fcce9a0a705abd7db2117d95e340df8a4333f00be5efb64c"}, - {file = "coverage-7.2.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:40cc0f91c6cde033da493227797be2826cbf8f388eaa36a0271a97a332bfd7ce"}, - {file = "coverage-7.2.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a66e055254a26c82aead7ff420d9fa8dc2da10c82679ea850d8feebf11074d88"}, - {file = "coverage-7.2.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c10fbc8a64aa0f3ed136b0b086b6b577bc64d67d5581acd7cc129af52654384e"}, - {file = "coverage-7.2.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a22cbb5ede6fade0482111fa7f01115ff04039795d7092ed0db43522431b4f2"}, - {file = "coverage-7.2.5-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:292300f76440651529b8ceec283a9370532f4ecba9ad67d120617021bb5ef139"}, - {file = "coverage-7.2.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7ff8f3fb38233035028dbc93715551d81eadc110199e14bbbfa01c5c4a43f8d8"}, - {file = "coverage-7.2.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:a08c7401d0b24e8c2982f4e307124b671c6736d40d1c39e09d7a8687bddf83ed"}, - {file = "coverage-7.2.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef9659d1cda9ce9ac9585c045aaa1e59223b143f2407db0eaee0b61a4f266fb6"}, - {file = "coverage-7.2.5-cp311-cp311-win32.whl", hash = "sha256:30dcaf05adfa69c2a7b9f7dfd9f60bc8e36b282d7ed25c308ef9e114de7fc23b"}, - {file = "coverage-7.2.5-cp311-cp311-win_amd64.whl", hash = "sha256:97072cc90f1009386c8a5b7de9d4fc1a9f91ba5ef2146c55c1f005e7b5c5e068"}, - {file = "coverage-7.2.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bebea5f5ed41f618797ce3ffb4606c64a5de92e9c3f26d26c2e0aae292f015c1"}, - {file = "coverage-7.2.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:828189fcdda99aae0d6bf718ea766b2e715eabc1868670a0a07bf8404bf58c33"}, - {file = "coverage-7.2.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e8a95f243d01ba572341c52f89f3acb98a3b6d1d5d830efba86033dd3687ade"}, - {file = "coverage-7.2.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8834e5f17d89e05697c3c043d3e58a8b19682bf365048837383abfe39adaed5"}, - {file = "coverage-7.2.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d1f25ee9de21a39b3a8516f2c5feb8de248f17da7eead089c2e04aa097936b47"}, - {file = "coverage-7.2.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1637253b11a18f453e34013c665d8bf15904c9e3c44fbda34c643fbdc9d452cd"}, - {file = "coverage-7.2.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8e575a59315a91ccd00c7757127f6b2488c2f914096077c745c2f1ba5b8c0969"}, - {file = "coverage-7.2.5-cp37-cp37m-win32.whl", hash = "sha256:509ecd8334c380000d259dc66feb191dd0a93b21f2453faa75f7f9cdcefc0718"}, - {file = "coverage-7.2.5-cp37-cp37m-win_amd64.whl", hash = "sha256:12580845917b1e59f8a1c2ffa6af6d0908cb39220f3019e36c110c943dc875b0"}, - {file = "coverage-7.2.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b5016e331b75310610c2cf955d9f58a9749943ed5f7b8cfc0bb89c6134ab0a84"}, - {file = "coverage-7.2.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:373ea34dca98f2fdb3e5cb33d83b6d801007a8074f992b80311fc589d3e6b790"}, - {file = "coverage-7.2.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a063aad9f7b4c9f9da7b2550eae0a582ffc7623dca1c925e50c3fbde7a579771"}, - {file = "coverage-7.2.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38c0a497a000d50491055805313ed83ddba069353d102ece8aef5d11b5faf045"}, - {file = "coverage-7.2.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2b3b05e22a77bb0ae1a3125126a4e08535961c946b62f30985535ed40e26614"}, - {file = "coverage-7.2.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0342a28617e63ad15d96dca0f7ae9479a37b7d8a295f749c14f3436ea59fdcb3"}, - {file = "coverage-7.2.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cf97ed82ca986e5c637ea286ba2793c85325b30f869bf64d3009ccc1a31ae3fd"}, - {file = "coverage-7.2.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c2c41c1b1866b670573657d584de413df701f482574bad7e28214a2362cb1fd1"}, - {file = "coverage-7.2.5-cp38-cp38-win32.whl", hash = "sha256:10b15394c13544fce02382360cab54e51a9e0fd1bd61ae9ce012c0d1e103c813"}, - {file = "coverage-7.2.5-cp38-cp38-win_amd64.whl", hash = "sha256:a0b273fe6dc655b110e8dc89b8ec7f1a778d78c9fd9b4bda7c384c8906072212"}, - {file = "coverage-7.2.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c587f52c81211d4530fa6857884d37f514bcf9453bdeee0ff93eaaf906a5c1b"}, - {file = "coverage-7.2.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4436cc9ba5414c2c998eaedee5343f49c02ca93b21769c5fdfa4f9d799e84200"}, - {file = "coverage-7.2.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6599bf92f33ab041e36e06d25890afbdf12078aacfe1f1d08c713906e49a3fe5"}, - {file = "coverage-7.2.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:857abe2fa6a4973f8663e039ead8d22215d31db613ace76e4a98f52ec919068e"}, - {file = "coverage-7.2.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f5cab2d7f0c12f8187a376cc6582c477d2df91d63f75341307fcdcb5d60303"}, - {file = "coverage-7.2.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:aa387bd7489f3e1787ff82068b295bcaafbf6f79c3dad3cbc82ef88ce3f48ad3"}, - {file = "coverage-7.2.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:156192e5fd3dbbcb11cd777cc469cf010a294f4c736a2b2c891c77618cb1379a"}, - {file = "coverage-7.2.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bd3b4b8175c1db502adf209d06136c000df4d245105c8839e9d0be71c94aefe1"}, - {file = "coverage-7.2.5-cp39-cp39-win32.whl", hash = "sha256:ddc5a54edb653e9e215f75de377354e2455376f416c4378e1d43b08ec50acc31"}, - {file = "coverage-7.2.5-cp39-cp39-win_amd64.whl", hash = "sha256:338aa9d9883aaaad53695cb14ccdeb36d4060485bb9388446330bef9c361c252"}, - {file = "coverage-7.2.5-pp37.pp38.pp39-none-any.whl", hash = "sha256:8877d9b437b35a85c18e3c6499b23674684bf690f5d96c1006a1ef61f9fdf0f3"}, - {file = "coverage-7.2.5.tar.gz", hash = "sha256:f99ef080288f09ffc687423b8d60978cf3a465d3f404a18d1a05474bd8575a47"}, + {file = "coverage-7.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:496b86f1fc9c81a1cd53d8842ef712e950a4611bba0c42d33366a7b91ba969ec"}, + {file = "coverage-7.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fbe6e8c0a9a7193ba10ee52977d4d5e7652957c1f56ccefed0701db8801a2a3b"}, + {file = "coverage-7.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d06b721c2550c01a60e5d3093f417168658fb454e5dfd9a23570e9bffe39a1"}, + {file = "coverage-7.2.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:77a04b84d01f0e12c66f16e69e92616442dc675bbe51b90bfb074b1e5d1c7fbd"}, + {file = "coverage-7.2.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35db06450272473eab4449e9c2ad9bc6a0a68dab8e81a0eae6b50d9c2838767e"}, + {file = "coverage-7.2.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6727a0d929ff0028b1ed8b3e7f8701670b1d7032f219110b55476bb60c390bfb"}, + {file = "coverage-7.2.6-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aac1d5fdc5378f6bac2c0c7ebe7635a6809f5b4376f6cf5d43243c1917a67087"}, + {file = "coverage-7.2.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1c9e4a5eb1bbc3675ee57bc31f8eea4cd7fb0cbcbe4912cf1cb2bf3b754f4a80"}, + {file = "coverage-7.2.6-cp310-cp310-win32.whl", hash = "sha256:71f739f97f5f80627f1fee2331e63261355fd1e9a9cce0016394b6707ac3f4ec"}, + {file = "coverage-7.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:fde5c7a9d9864d3e07992f66767a9817f24324f354caa3d8129735a3dc74f126"}, + {file = "coverage-7.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bc7b667f8654376e9353dd93e55e12ce2a59fb6d8e29fce40de682273425e044"}, + {file = "coverage-7.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:697f4742aa3f26c107ddcb2b1784a74fe40180014edbd9adaa574eac0529914c"}, + {file = "coverage-7.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:541280dde49ce74a4262c5e395b48ea1207e78454788887118c421cb4ffbfcac"}, + {file = "coverage-7.2.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e7f1a8328eeec34c54f1d5968a708b50fc38d31e62ca8b0560e84a968fbf9a9"}, + {file = "coverage-7.2.6-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4bbd58eb5a2371bf160590f4262109f66b6043b0b991930693134cb617bc0169"}, + {file = "coverage-7.2.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ae82c5f168d2a39a5d69a12a69d4dc23837a43cf2ca99be60dfe59996ea6b113"}, + {file = "coverage-7.2.6-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f5440cdaf3099e7ab17a5a7065aed59aff8c8b079597b61c1f8be6f32fe60636"}, + {file = "coverage-7.2.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a6f03f87fea579d55e0b690d28f5042ec1368650466520fbc400e7aeaf09e995"}, + {file = "coverage-7.2.6-cp311-cp311-win32.whl", hash = "sha256:dc4d5187ef4d53e0d4c8eaf530233685667844c5fb0b855fea71ae659017854b"}, + {file = "coverage-7.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:c93d52c3dc7b9c65e39473704988602300e3cc1bad08b5ab5b03ca98bbbc68c1"}, + {file = "coverage-7.2.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:42c692b55a647a832025a4c048007034fe77b162b566ad537ce65ad824b12a84"}, + {file = "coverage-7.2.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7786b2fa7809bf835f830779ad285215a04da76293164bb6745796873f0942d"}, + {file = "coverage-7.2.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25bad4196104761bc26b1dae9b57383826542ec689ff0042f7f4f4dd7a815cba"}, + {file = "coverage-7.2.6-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2692306d3d4cb32d2cceed1e47cebd6b1d2565c993d6d2eda8e6e6adf53301e6"}, + {file = "coverage-7.2.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:392154d09bd4473b9d11351ab5d63391f3d5d24d752f27b3be7498b0ee2b5226"}, + {file = "coverage-7.2.6-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:fa079995432037b5e2ef5ddbb270bcd2ded9f52b8e191a5de11fe59a00ea30d8"}, + {file = "coverage-7.2.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d712cefff15c712329113b01088ba71bbcef0f7ea58478ca0bbec63a824844cb"}, + {file = "coverage-7.2.6-cp37-cp37m-win32.whl", hash = "sha256:004948e296149644d208964300cb3d98affc5211e9e490e9979af4030b0d6473"}, + {file = "coverage-7.2.6-cp37-cp37m-win_amd64.whl", hash = "sha256:c1d7a31603c3483ac49c1726723b0934f88f2c011c660e6471e7bd735c2fa110"}, + {file = "coverage-7.2.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3436927d1794fa6763b89b60c896f9e3bd53212001026ebc9080d23f0c2733c1"}, + {file = "coverage-7.2.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44c9b9f1a245f3d0d202b1a8fa666a80b5ecbe4ad5d0859c0fb16a52d9763224"}, + {file = "coverage-7.2.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e3783a286d5a93a2921396d50ce45a909aa8f13eee964465012f110f0cbb611"}, + {file = "coverage-7.2.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cff6980fe7100242170092bb40d2b1cdad79502cd532fd26b12a2b8a5f9aee0"}, + {file = "coverage-7.2.6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c534431153caffc7c495c3eddf7e6a6033e7f81d78385b4e41611b51e8870446"}, + {file = "coverage-7.2.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3062fd5c62df988cea9f2972c593f77fed1182bfddc5a3b12b1e606cb7aba99e"}, + {file = "coverage-7.2.6-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6284a2005e4f8061c58c814b1600ad0074ccb0289fe61ea709655c5969877b70"}, + {file = "coverage-7.2.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:97729e6828643f168a2a3f07848e1b1b94a366b13a9f5aba5484c2215724edc8"}, + {file = "coverage-7.2.6-cp38-cp38-win32.whl", hash = "sha256:dc11b42fa61ff1e788dd095726a0aed6aad9c03d5c5984b54cb9e1e67b276aa5"}, + {file = "coverage-7.2.6-cp38-cp38-win_amd64.whl", hash = "sha256:cbcc874f454ee51f158afd604a315f30c0e31dff1d5d5bf499fc529229d964dd"}, + {file = "coverage-7.2.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d3cacc6a665221108ecdf90517a8028d07a2783df3417d12dcfef1c517e67478"}, + {file = "coverage-7.2.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:272ab31228a9df857ab5df5d67936d8861464dc89c5d3fab35132626e9369379"}, + {file = "coverage-7.2.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a8723ccec4e564d4b9a79923246f7b9a8de4ec55fa03ec4ec804459dade3c4f"}, + {file = "coverage-7.2.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5906f6a84b47f995cd1bf0aca1c72d591c55ee955f98074e93660d64dfc66eb9"}, + {file = "coverage-7.2.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52c139b7ab3f0b15f9aad0a3fedef5a1f8c0b2bdc291d88639ca2c97d3682416"}, + {file = "coverage-7.2.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a5ffd45c6b93c23a8507e2f436983015c6457aa832496b6a095505ca2f63e8f1"}, + {file = "coverage-7.2.6-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4f3c7c19581d471af0e9cb49d928172cd8492cd78a2b7a4e82345d33662929bb"}, + {file = "coverage-7.2.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2e8c0e79820cdd67978e1120983786422d279e07a381dbf89d03bbb23ec670a6"}, + {file = "coverage-7.2.6-cp39-cp39-win32.whl", hash = "sha256:13cde6bb0e58fb67d09e2f373de3899d1d1e866c5a9ff05d93615f2f54fbd2bb"}, + {file = "coverage-7.2.6-cp39-cp39-win_amd64.whl", hash = "sha256:6b9f64526286255735847aed0221b189486e0b9ed943446936e41b7e44b08783"}, + {file = "coverage-7.2.6-pp37.pp38.pp39-none-any.whl", hash = "sha256:6babcbf1e66e46052442f10833cfc4a0d3554d8276aa37af8531a83ed3c1a01d"}, + {file = "coverage-7.2.6.tar.gz", hash = "sha256:2025f913f2edb0272ef15d00b1f335ff8908c921c8eb2013536fcaf61f5a683d"}, ] [package.dependencies] @@ -528,14 +531,14 @@ testing = ["pre-commit"] [[package]] name = "fakeredis" -version = "2.11.2" +version = "2.13.0" description = "Fake implementation of redis API for testing purposes." category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "fakeredis-2.11.2-py3-none-any.whl", hash = "sha256:69a504328a89e5e5f2d05a4236b570fb45244c96997c5002c8c6a0503b95f289"}, - {file = "fakeredis-2.11.2.tar.gz", hash = "sha256:e0fef512b8ec49679d373456aa4698a4103005ecd7ca0b13170a2c1d3af949c5"}, + {file = "fakeredis-2.13.0-py3-none-any.whl", hash = "sha256:df7bb44fb9e593970c626325230e1c321f954ce7b204d4c4452eae5233d554ed"}, + {file = "fakeredis-2.13.0.tar.gz", hash = "sha256:53f00f44f771d2b794f1ea036fa07a33476ab7368f1b0e908daab3eff80336f6"}, ] [package.dependencies] @@ -758,14 +761,14 @@ socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "httpx" -version = "0.24.0" +version = "0.24.1" description = "The next generation HTTP client." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "httpx-0.24.0-py3-none-any.whl", hash = "sha256:447556b50c1921c351ea54b4fe79d91b724ed2b027462ab9a329465d147d5a4e"}, - {file = "httpx-0.24.0.tar.gz", hash = "sha256:507d676fc3e26110d41df7d35ebd8b3b8585052450f4097401c9be59d928c63e"}, + {file = "httpx-0.24.1-py3-none-any.whl", hash = "sha256:06781eb9ac53cde990577af654bd990a4949de37a28bdb4a230d434f3a30b9bd"}, + {file = "httpx-0.24.1.tar.gz", hash = "sha256:5853a43053df830c20f8110c5e69fe44d035d850b2dfe795e196f00fdb774bdd"}, ] [package.dependencies] @@ -1101,63 +1104,58 @@ files = [ [[package]] name = "orjson" -version = "3.8.11" +version = "3.8.14" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" category = "main" optional = false -python-versions = ">= 3.7" +python-versions = ">=3.7" files = [ - {file = "orjson-3.8.11-cp310-cp310-macosx_11_0_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:9fa900bdd84b4576c8dd6f3e2a00b35797f29283af328c6e3d70addfa4c2d599"}, - {file = "orjson-3.8.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1103e597c16f82c241e1b02beadc9c91cecd93e60433ca73cb6464dcc235f37c"}, - {file = "orjson-3.8.11-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d70b6db9d4e1e6057829cd7fe119c217cebaf989f88d14b2445fa69fc568d03e"}, - {file = "orjson-3.8.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3afccf7f8684dca7f017837a315de0a1ab5c095de22a4eed206d079f9325ed72"}, - {file = "orjson-3.8.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1fedcc428416e23a6c9de62a000c22ae33bbe0108302ad5d5935e29ea739bf37"}, - {file = "orjson-3.8.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf48ed8d4b6ab9f23b7ee642462369d7133412d72824bad89f9bf4311c06c6a1"}, - {file = "orjson-3.8.11-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:3c55065bc2075a5ea6ffb30462d84fd3aa5bbb7ae600855c325ee5753feec715"}, - {file = "orjson-3.8.11-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:08729e339ff3146e6de56c1166f014c3d2ec3e79ffb76d6c55d52cc892e5e477"}, - {file = "orjson-3.8.11-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:358e515b8b19a275b259f5ee1e0efa2859b1d976b5ed5d016ac59f9e6c8788a3"}, - {file = "orjson-3.8.11-cp310-none-win_amd64.whl", hash = "sha256:62eb8bdcf6f4cdbe12743e88ad98696277a75f91a35e8fb93a7ea2b9f4a7000c"}, - {file = "orjson-3.8.11-cp311-cp311-macosx_11_0_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:982ab319b7a5ece4199caf2a2b3a28e62a8e289cb6418548ef98bced7e2a6cfe"}, - {file = "orjson-3.8.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e14903bfeb591a9117b7d40d81e3ebca9700b4e77bd829d6f22ea57941bb0ebf"}, - {file = "orjson-3.8.11-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:58c068f93d701f9466f667bf3b5cb4e4946aee940df2b07ca5101f1cf1b60ce4"}, - {file = "orjson-3.8.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9486963d2e65482c565dacb366adb36d22aa22acf7274b61490244c3d87fa631"}, - {file = "orjson-3.8.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c3b5405edc3a5f9e34516ee1a729f6c46aecf6de960ae07a7b3e95ebdd0e1d9"}, - {file = "orjson-3.8.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b65424ceee82b94e3613233b67ef110dc58f9d83b0076ec47a506289552a861"}, - {file = "orjson-3.8.11-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:173b8f8c750590f432757292cfb197582e5c14347b913b4017561d47af0e759b"}, - {file = "orjson-3.8.11-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:37f38c8194ce086e6a9816b4b8dde5e7f383feeed92feec0385d99baf64f9b6e"}, - {file = "orjson-3.8.11-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:553fdaf9f4b5060a0dcc517ae0c511c289c184a83d6719d03c5602ed0eef0390"}, - {file = "orjson-3.8.11-cp311-none-win_amd64.whl", hash = "sha256:12f647d4da0aab1997e25bed4fa2b76782b5b9d2d1bf3066b5f0a57d34d833c4"}, - {file = "orjson-3.8.11-cp37-cp37m-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:71a656f1c62e84c69060093e20cedff6a92e472d53ff5b8b9026b1b298542a68"}, - {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:176d742f53434541e50a5e659694073aa51dcbd8f29a1708a4fa1a320193c615"}, - {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b369019e597b59c4b97e9f925a3b725321fa1481c129d76c74c6ea3823f5d1e8"}, - {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a53b3c02a38aadc5302661c2ca18645093971488992df77ce14fef16f598b2e"}, - {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6d7b050135669d2335e40120215ad4120e29958c139f8bab68ce06a1cb1a1b2c"}, - {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66f0c9e4e8f6641497a7dc50591af3704b11468e9fc90cfb5874f28b0a61edb5"}, - {file = "orjson-3.8.11-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:235926b38ed9b76ab2bca99ff26ece79c1c46bc10079b06e660b087aecffbe69"}, - {file = "orjson-3.8.11-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c2d3e6b65458ed71b6797f321d6e8bfeeadee9d3d31cac47806a608ea745edd7"}, - {file = "orjson-3.8.11-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4118dcd2b5a27a22af5ad92414073f25d93bca1868f1f580056003c84841062f"}, - {file = "orjson-3.8.11-cp37-none-win_amd64.whl", hash = "sha256:b68a07794834b7bd53ae2a8b4fe4bf010734cae3f0917d434c83b97acf8e5bce"}, - {file = "orjson-3.8.11-cp38-cp38-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:98befa717efaab7ddb847ebe47d473f6bd6f0cb53e98e6c3d487c7c58ba2e174"}, - {file = "orjson-3.8.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f9415b86ef154bf247fa78a6918aac50089c296e26fb6cf15bc9d7e6402a1f8"}, - {file = "orjson-3.8.11-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f7aeefac55848aeb29f20b91fa55f9e488f446201bb1bb31dc17480d113d8955"}, - {file = "orjson-3.8.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d47f97b99beb9bcac6e288a76b559543a61e0187443d8089204b757726b1d000"}, - {file = "orjson-3.8.11-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7d5aecccfaf2052cd07ed5bec8efba9ddfea055682fcd346047b1a3e9da3034"}, - {file = "orjson-3.8.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04b60dfc1251742e79bb075d7a7c4e37078b932a02e6f005c45761bd90c69189"}, - {file = "orjson-3.8.11-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:ef52f1d5a2f89ef9049781c90ea35d5edf74374ed6ed515c286a706d1b290267"}, - {file = "orjson-3.8.11-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7c7b4fae3b8fc69c8e76f1c0694f3decfe8a57f87e7ac7779ebb59cd71135438"}, - {file = "orjson-3.8.11-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f4e4a1001933166fd1c257b920b241b35322bef99ed7329338bf266ac053abe7"}, - {file = "orjson-3.8.11-cp38-none-win_amd64.whl", hash = "sha256:5ff10789cbc08a9fd94507c907ba55b9315e99f20345ff8ef34fac432dacd948"}, - {file = "orjson-3.8.11-cp39-cp39-macosx_11_0_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:c67ac094a4dde914297543af19f22532d7124f3a35245580d8b756c4ff2f5884"}, - {file = "orjson-3.8.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdf201e77d3fac9d8d6f68d872ef45dccfe46f30b268bb88b6c5af5065b433aa"}, - {file = "orjson-3.8.11-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3485c458670c0edb79ca149fe201f199dd9ccfe7ca3acbdef617e3c683e7b97f"}, - {file = "orjson-3.8.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e97fdbb779a3b8f5d9fc7dfddef5325f81ee45897eb7cb4638d5d9734d42514"}, - {file = "orjson-3.8.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2fc050f8e7f2e4061c8c9968ad0be745b11b03913b77ffa8ceca65914696886c"}, - {file = "orjson-3.8.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2ef933da50b31c112b252be03d1ef59e0d0552c1a08e48295bd529ce42aaab8"}, - {file = "orjson-3.8.11-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:714c3e2be6ed7e4ff6e887926d6e171bfd94fdee76d7d3bfa74ee19237a2d49d"}, - {file = "orjson-3.8.11-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7e4ded77ac7432a155d1d27a83bcadf722750aea3b9e6c4d47f2a92054ab71cb"}, - {file = "orjson-3.8.11-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:382f15861a4bf447ab9d07106010e61b217ef6d4245c6cf64af0c12c4c5e2346"}, - {file = "orjson-3.8.11-cp39-none-win_amd64.whl", hash = "sha256:0bc3d1b93a73b46a698c054697eb2d27bdedbc5ea0d11ec5f1a6bfbec36346b5"}, - {file = "orjson-3.8.11.tar.gz", hash = "sha256:882c77126c42dd93bb35288632d69b1e393863a2b752de3e5fe0112833609496"}, + {file = "orjson-3.8.14-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7a7b0fead2d0115ef927fa46ad005d7a3988a77187500bf895af67b365c10d1f"}, + {file = "orjson-3.8.14-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca90db8f551b8960da95b0d4cad6c0489df52ea03585b6979595be7b31a3f946"}, + {file = "orjson-3.8.14-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f4ac01a3db4e6a98a8ad1bb1a3e8bfc777928939e87c04e93e0d5006df574a4b"}, + {file = "orjson-3.8.14-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bf6825e160e4eb0ef65ce37d8c221edcab96ff2ffba65e5da2437a60a12b3ad1"}, + {file = "orjson-3.8.14-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f80e62afe49e6bfc706e041faa351d7520b5f86572b8e31455802251ea989613"}, + {file = "orjson-3.8.14-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6112194c11e611596eed72f46efb0e6b4812682eff3c7b48473d1146c3fa0efb"}, + {file = "orjson-3.8.14-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:739f9f633e1544f2a477fa3bef380f488c8dca6e2521c8dc36424b12554ee31e"}, + {file = "orjson-3.8.14-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7d3d8faded5a514b80b56d0429eb38b429d7a810f8749d25dc10a0cc15b8a3c8"}, + {file = "orjson-3.8.14-cp310-none-win_amd64.whl", hash = "sha256:0bf00c42333412a9338297bf888d7428c99e281e20322070bde8c2314775508b"}, + {file = "orjson-3.8.14-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d66966fd94719beb84e8ed84833bc59c3c005d3d2d0c42f11d7552d3267c6de7"}, + {file = "orjson-3.8.14-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:087c0dc93379e8ba2d59e9f586fab8de8c137d164fccf8afd5523a2137570917"}, + {file = "orjson-3.8.14-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04c70dc8ca79b0072a16d82f94b9d9dd6598a43dd753ab20039e9f7d2b14f017"}, + {file = "orjson-3.8.14-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aedba48264fe87e5060c0e9c2b28909f1e60626e46dc2f77e0c8c16939e2e1f7"}, + {file = "orjson-3.8.14-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:01640ab79111dd97515cba9fab7c66cb3b0967b0892cc74756a801ff681a01b6"}, + {file = "orjson-3.8.14-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b206cca6836a4c6683bcaa523ab467627b5f03902e5e1082dc59cd010e6925f"}, + {file = "orjson-3.8.14-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ee0299b2dda9afce351a5e8c148ea7a886de213f955aa0288fb874fb44829c36"}, + {file = "orjson-3.8.14-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:31a2a29be559e92dcc5c278787b4166da6f0d45675b59a11c4867f5d1455ebf4"}, + {file = "orjson-3.8.14-cp311-none-win_amd64.whl", hash = "sha256:20b7ffc7736000ea205f9143df322b03961f287b4057606291c62c842ff3c5b5"}, + {file = "orjson-3.8.14-cp37-cp37m-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:de1ee13d6b6727ee1db38722695250984bae81b8fc9d05f1176c74d14b1322d9"}, + {file = "orjson-3.8.14-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ee09bfbf1d54c127d3061f6721a1a11d2ce502b50597c3d0d2e1bd2d235b764"}, + {file = "orjson-3.8.14-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:97ebb7fab5f1ae212a6501f17cb7750a6838ffc2f1cebbaa5dec1a90038ca3c6"}, + {file = "orjson-3.8.14-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38ca39bae7fbc050332a374062d4cdec28095540fa8bb245eada467897a3a0bb"}, + {file = "orjson-3.8.14-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:92374bc35b6da344a927d5a850f7db80a91c7b837de2f0ea90fc870314b1ff44"}, + {file = "orjson-3.8.14-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9393a63cb0424515ec5e434078b3198de6ec9e057f1d33bad268683935f0a5d5"}, + {file = "orjson-3.8.14-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5fb66f0ac23e861b817c858515ac1f74d1cd9e72e3f82a5b2c9bae9f92286adc"}, + {file = "orjson-3.8.14-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:19415aaf30525a5baff0d72a089fcdd68f19a3674998263c885c3908228c1086"}, + {file = "orjson-3.8.14-cp37-none-win_amd64.whl", hash = "sha256:87ba7882e146e24a7d8b4a7971c20212c2af75ead8096fc3d55330babb1015fb"}, + {file = "orjson-3.8.14-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9f5cf61b6db68f213c805c55bf0aab9b4cb75a4e9c7f5bfbd4deb3a0aef0ec53"}, + {file = "orjson-3.8.14-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33bc310da4ad2ffe8f7f1c9e89692146d9ec5aec2d1c9ef6b67f8dc5e2d63241"}, + {file = "orjson-3.8.14-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:67a7e883b6f782b106683979ccc43d89b98c28a1f4a33fe3a22e253577499bb1"}, + {file = "orjson-3.8.14-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9df820e6c8c84c52ec39ea2cc9c79f7999c839c7d1481a056908dce3b90ce9f9"}, + {file = "orjson-3.8.14-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ebca14ae80814219ea3327e3dfa7ff618621ff335e45781fac26f5cd0b48f2b4"}, + {file = "orjson-3.8.14-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27967be4c16bd09f4aeff8896d9be9cbd00fd72f5815d5980e4776f821e2f77c"}, + {file = "orjson-3.8.14-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:062829b5e20cd8648bf4c11c3a5ee7cf196fa138e573407b5312c849b0cf354d"}, + {file = "orjson-3.8.14-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e53bc5beb612df8ddddb065f079d3fd30b5b4e73053518524423549d61177f3f"}, + {file = "orjson-3.8.14-cp38-none-win_amd64.whl", hash = "sha256:d03f29b0369bb1ab55c8a67103eb3a9675daaf92f04388568034fe16be48fa5d"}, + {file = "orjson-3.8.14-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:716a3994e039203f0a59056efa28185d4cac51b922cc5bf27ab9182cfa20e12e"}, + {file = "orjson-3.8.14-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cb35dd3ba062c1d984d57e6477768ed7b62ed9260f31362b2d69106f9c60ebd"}, + {file = "orjson-3.8.14-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0bc6b7abf27f1dc192dadad249df9b513912506dd420ce50fd18864a33789b71"}, + {file = "orjson-3.8.14-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e2f75b7d9285e35c3d4dff9811185535ff2ea637f06b2b242cb84385f8ffe63"}, + {file = "orjson-3.8.14-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:017de5ba22e58dfa6f41914f5edb8cd052d23f171000684c26b2d2ab219db31e"}, + {file = "orjson-3.8.14-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09a3bf3154f40299b8bc95e9fb8da47436a59a2106fc22cae15f76d649e062da"}, + {file = "orjson-3.8.14-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:64b4fca0531030040e611c6037aaf05359e296877ab0a8e744c26ef9c32738b9"}, + {file = "orjson-3.8.14-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8a896a12b38fe201a72593810abc1f4f1597e65b8c869d5fc83bbcf75d93398f"}, + {file = "orjson-3.8.14-cp39-none-win_amd64.whl", hash = "sha256:9725226478d1dafe46d26f758eadecc6cf98dcbb985445e14a9c74aaed6ccfea"}, + {file = "orjson-3.8.14.tar.gz", hash = "sha256:5ea93fd3ef7be7386f2516d728c877156de1559cda09453fc7dd7b696d0439b3"}, ] [[package]] @@ -1271,25 +1269,25 @@ prometheus-client = ">=0.8.0,<1.0.0" [[package]] name = "protobuf" -version = "4.22.4" +version = "4.23.1" description = "" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "protobuf-4.22.4-cp310-abi3-win32.whl", hash = "sha256:a4e661247896c2ffea4b894bca2d8657e752bedb8f3c66d7befa2557291be1e8"}, - {file = "protobuf-4.22.4-cp310-abi3-win_amd64.whl", hash = "sha256:7b42086d6027be2730151b49f27b2f5be40f3b036adf7b8da5917f4567f268c3"}, - {file = "protobuf-4.22.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:4bfb28d48628deacdb66a95aaa7b6640f3dc82b4edd34db444c7a3cdd90b01fb"}, - {file = "protobuf-4.22.4-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:e98e26328d7c668541d1052b02de4205b1094ef6b2ce57167440d3e39876db48"}, - {file = "protobuf-4.22.4-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:8fd329e5dd7b6c4b878cab4b85bb6cec880e2adaf4e8aa2c75944dcbb05e1ff1"}, - {file = "protobuf-4.22.4-cp37-cp37m-win32.whl", hash = "sha256:b7728b5da9eee15c0aa3baaee79e94fa877ddcf7e3d2f34b1eab586cd26eea89"}, - {file = "protobuf-4.22.4-cp37-cp37m-win_amd64.whl", hash = "sha256:f4a711588c3a79b6f9c44af4d7f4a2ae868e27063654683932ab6462f90e9656"}, - {file = "protobuf-4.22.4-cp38-cp38-win32.whl", hash = "sha256:11b28b4e779d7f275e3ea0efa3938f4d4e8ed3ca818f9fec3b193f8e9ada99fd"}, - {file = "protobuf-4.22.4-cp38-cp38-win_amd64.whl", hash = "sha256:144d5b46df5e44f914f715accaadf88d617242ba5a40cacef4e8de7effa79954"}, - {file = "protobuf-4.22.4-cp39-cp39-win32.whl", hash = "sha256:5128b4d5efcaef92189e076077ae389700606ff81d2126b8361dc01f3e026197"}, - {file = "protobuf-4.22.4-cp39-cp39-win_amd64.whl", hash = "sha256:9537ae27d43318acf8ce27d0359fe28e6ebe4179c3350bc055bb60ff4dc4fcd3"}, - {file = "protobuf-4.22.4-py3-none-any.whl", hash = "sha256:3b21074b7fb748d8e123acaef9fa63a84fdc1436dc71199d2317b139f77dd6f4"}, - {file = "protobuf-4.22.4.tar.gz", hash = "sha256:21fbaef7f012232eb8d6cb8ba334e931fc6ff8570f5aaedc77d5b22a439aa909"}, + {file = "protobuf-4.23.1-cp310-abi3-win32.whl", hash = "sha256:410bcc0a5b279f634d3e16082ce221dfef7c3392fac723500e2e64d1806dd2be"}, + {file = "protobuf-4.23.1-cp310-abi3-win_amd64.whl", hash = "sha256:32e78beda26d7a101fecf15d7a4a792278a0d26a31bc327ff05564a9d68ab8ee"}, + {file = "protobuf-4.23.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f9510cac91e764e86acd74e2b7f7bc5e6127a7f3fb646d7c8033cfb84fd1176a"}, + {file = "protobuf-4.23.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:346990f634272caac1f09efbcfbbacb23098b1f606d172534c6fa2d9758bb436"}, + {file = "protobuf-4.23.1-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:3ce113b3f3362493bddc9069c2163a38f240a9ed685ff83e7bcb756b05e1deb0"}, + {file = "protobuf-4.23.1-cp37-cp37m-win32.whl", hash = "sha256:2036a3a1e7fc27f973fa0a7888dce712393af644f4695385f117886abc792e39"}, + {file = "protobuf-4.23.1-cp37-cp37m-win_amd64.whl", hash = "sha256:3b8905eafe4439076e1f58e9d1fa327025fd2777cf90f14083092ae47f77b0aa"}, + {file = "protobuf-4.23.1-cp38-cp38-win32.whl", hash = "sha256:5b9cd6097e6acae48a68cb29b56bc79339be84eca65b486910bb1e7a30e2b7c1"}, + {file = "protobuf-4.23.1-cp38-cp38-win_amd64.whl", hash = "sha256:decf119d54e820f298ee6d89c72d6b289ea240c32c521f00433f9dc420595f38"}, + {file = "protobuf-4.23.1-cp39-cp39-win32.whl", hash = "sha256:91fac0753c3c4951fbb98a93271c43cc7cf3b93cf67747b3e600bb1e5cc14d61"}, + {file = "protobuf-4.23.1-cp39-cp39-win_amd64.whl", hash = "sha256:ac50be82491369a9ec3710565777e4da87c6d2e20404e0abb1f3a8f10ffd20f0"}, + {file = "protobuf-4.23.1-py3-none-any.whl", hash = "sha256:65f0ac96ef67d7dd09b19a46aad81a851b6f85f89725577f16de38f2d68ad477"}, + {file = "protobuf-4.23.1.tar.gz", hash = "sha256:95789b569418a3e32a53f43d7763be3d490a831e9c08042539462b6d972c2d7e"}, ] [[package]] @@ -1370,43 +1368,43 @@ email = ["email-validator (>=1.0.3)"] [[package]] name = "pygit2" -version = "1.12.0" +version = "1.12.1" description = "Python bindings for libgit2." category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "pygit2-1.12.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b44a3b38e62dbf8cb559a40d2b39506a638d13542502ddb927f1c05565048f27"}, - {file = "pygit2-1.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:834cf5b54d9b49c562669ec986be54c7915585638690c11f1dc4e6a55bc5d79d"}, - {file = "pygit2-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ecb096cdbbf142d8787cf879ab927fc9777d36580d2e5758d02c9474a3b015c"}, - {file = "pygit2-1.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15620696743ffac71cfdaf270944d9363b70442c1fbe96f5e4a69639c2fe7c23"}, - {file = "pygit2-1.12.0-cp310-cp310-win32.whl", hash = "sha256:de21194e18e4d93f793740b2b979dbe9dd6607f342a4fad3ecedeaf26ec743df"}, - {file = "pygit2-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:0a9d49f71bec7c4f2ff8273e0c7caba4b2f21bfc56e2071e429028b20ab9d762"}, - {file = "pygit2-1.12.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a428970b44827b703cc3267de8d71648f491546d5b9276505ef5f232a921a34e"}, - {file = "pygit2-1.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2bb7b674124a38b12a5aaacca3b8c1e29674f3b46cb907af0b3ba75d90e5952a"}, - {file = "pygit2-1.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de46940b46bee12f4c938aadf4f59617798f704c8ac5f08b5a84914459d604be"}, - {file = "pygit2-1.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fbfb3ebe7f57fe7873d86e84b476869f407d6bb204a39a3e7d04e4a7f0e43c1"}, - {file = "pygit2-1.12.0-cp311-cp311-win32.whl", hash = "sha256:db98978d559d6e84187d463fb3aa83cf6120dadf62058e3d05a97457f9f27247"}, - {file = "pygit2-1.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:8734a44e0dab8a5e6668e4a926f7171b59b87d65981bd3732efba57c327cec6d"}, - {file = "pygit2-1.12.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1bb73ffb345400f8c6fe391431e06b93e26bc4d2048b1ac3f7c54dae5f7b6dc2"}, - {file = "pygit2-1.12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fdeaf1631803616d303b808cd644ee17164fb675241ab1b0bb243d4a3d3de59f"}, - {file = "pygit2-1.12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:652b3f0510ad21ec6275b246aa3e7a2e20f2f9c37a9844804887fabc2db49ca3"}, - {file = "pygit2-1.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2419cd1034bf593847466b188a65bd9d512e13b7da0e8c3a74b487d8014a6c1"}, - {file = "pygit2-1.12.0-cp38-cp38-win32.whl", hash = "sha256:6a445a537de152364b334e73047af9225fe8c6f54c7d815d8c751cb23b79cbef"}, - {file = "pygit2-1.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:ad1cca4533beee034277fe01f0d4029da40d2bd1a944a8cd17bffccc0331cc53"}, - {file = "pygit2-1.12.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ad7b21e35e759d033dede5dc4971f6c9b3408f9096b26fabc7cedb49e319680"}, - {file = "pygit2-1.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e303aa9d7de6039cc4450a1fbd5911fab22867dc4e05f148b0cd7c56f7b84b2"}, - {file = "pygit2-1.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:869e68cfae7e0e00a799efa26bba3f829bdeafa1462225a7db1317dacb4e6a4e"}, - {file = "pygit2-1.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c779c15bf6ebce986cb753c8113ccfb329c12d4a73b303ee7ac2c8961288b8cd"}, - {file = "pygit2-1.12.0-cp39-cp39-win32.whl", hash = "sha256:c6ac2fd8ed30016235b06aacc28e5f10e1a17d0f02eab35f5f503138bbee763d"}, - {file = "pygit2-1.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:2483e4aa8bb4290ab157d575b00b830528c669869d710646a1d4af7209d59e81"}, - {file = "pygit2-1.12.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8fca4ca59928436fca5df3d54a7d591e7aa12ebaeaeb1801a99e09970fb8f1d3"}, - {file = "pygit2-1.12.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0746791741ba1879faafd12be0b7fb8edd06633508bbf8aabfd28415f1c0b13f"}, - {file = "pygit2-1.12.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b9d8b7e1d143415d462d82fc5d9dd5922c527474871c7b3c3a8aec009b74b1c"}, - {file = "pygit2-1.12.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:69ee34f8b77fc60dcf93524fd843eacc416be906b7471746d2ee8214d5a591a0"}, - {file = "pygit2-1.12.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c290dadcf42e9d857ea20c37781168de1d1ac31b196b450400f962279aa405f"}, - {file = "pygit2-1.12.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1d9bdd2837f9f1cacb571889ac4226844a41476509c325732af06b622293782"}, - {file = "pygit2-1.12.0.tar.gz", hash = "sha256:e9440d08665e35278989939590a53f37a938eada4f9446844930aa2ee30d73be"}, + {file = "pygit2-1.12.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:50a155528aa611e4a217be31a9d2d8da283cfd978dbba07494cd04ea3d7c8768"}, + {file = "pygit2-1.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:248e22ccb1ea31f569373a3da3fa73d110ba2585c6326ff74b03c9579fb7b913"}, + {file = "pygit2-1.12.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e575e672c5a6cb39234b0076423a560e016d6b88cd50947c2df3bf59c5ccdf3d"}, + {file = "pygit2-1.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad9b46b52997d131b31ff46f699b074e9745c8fea8d0efb6b72ace43ab25828c"}, + {file = "pygit2-1.12.1-cp310-cp310-win32.whl", hash = "sha256:a8f495df877da04c572ecec4d532ae195680b4781dbf229bab4e801fa9ef20e9"}, + {file = "pygit2-1.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f1e1355c7fe2938a2bca0d6204a00c02950d13008722879e54a335b3e874006"}, + {file = "pygit2-1.12.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8a5c56b0b5dc8a317561070ef7557e180d4937d8b115c5a762d85e0109a216f3"}, + {file = "pygit2-1.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b7c9ca8bc8a722863fc873234748fef3422007d5a6ea90ba3ae338d2907d3d6e"}, + {file = "pygit2-1.12.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71c02a11f10bc4e329ab941f0c70874d39053c8f78544aefeb506f04cedb621a"}, + {file = "pygit2-1.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b3af334adf325b7c973417efa220fd5a9ce946b936262eceabc8ad8d46e0310"}, + {file = "pygit2-1.12.1-cp311-cp311-win32.whl", hash = "sha256:86c393962d1341893bbfa91829b3b8545e8ac7622f8b53b9a0b835b9cc1b5198"}, + {file = "pygit2-1.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:86c7e75ddc76f4e5593b47f9c2074fff242322ed9f4126116749f7c86021520a"}, + {file = "pygit2-1.12.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:939d11677f434024ea25a9137d8a525ef9f9ac474fb8b86399bc9526e6a7bff5"}, + {file = "pygit2-1.12.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:946f9215c0442995042ea512f764f7a6638d3a09f9d0484d3aeedbf8833f89e6"}, + {file = "pygit2-1.12.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd574620d3cc80df0b23bf2b7b08d8726e75a338d0fa1b67e4d6738d3ee56635"}, + {file = "pygit2-1.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24d0adeff5c43229913f3bdae71c36e77ed19f36bd8dd6b5c141820964b1f5b3"}, + {file = "pygit2-1.12.1-cp38-cp38-win32.whl", hash = "sha256:ed8e2ef97171e994bf4d46c6c6534a3c12dd2dbbc47741e5995eaf8c2c92f71c"}, + {file = "pygit2-1.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:5318817055a3ca3906bf88344b9a6dc70c640f9b6bc236ac9e767d12bad54361"}, + {file = "pygit2-1.12.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cb9c803151ffeb0b8de52a93381108a2c6a9a446c55d659a135f52645e1650eb"}, + {file = "pygit2-1.12.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:47bf1e196dc23fe38018ad49b021d425edc319328169c597df45d73cf46b62ef"}, + {file = "pygit2-1.12.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:948479df72223bbcd16b2a88904dc2a3886c15a0107a7cf3b5373c8e34f52f31"}, + {file = "pygit2-1.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4bebe8b310edc2662cbffb94ef1a758252fe2e4c92bc83fac0eaf2bedf8b871"}, + {file = "pygit2-1.12.1-cp39-cp39-win32.whl", hash = "sha256:77bc0ab778ab6fe631f5f9eb831b426376a7b71426c5a913aaa9088382ef1dc9"}, + {file = "pygit2-1.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:e87b2306a266f6abca94ab37dda807033a6f40faad05c4d1e089f9e8354130a8"}, + {file = "pygit2-1.12.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5d5e8a3b67f5d4ba8e3838c492254688997747989b184b5f1a3af4fef7f9f53e"}, + {file = "pygit2-1.12.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2500b749759f2efdfa5096c0aafeb2d92152766708f5700284427bd658e5c407"}, + {file = "pygit2-1.12.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c21759ca9cc755faa2d17180cd49af004486ca84f3166cac089a2083dcb09114"}, + {file = "pygit2-1.12.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d73074ab64b383e3a1ab03e8070f6b195ef89b9d379ca5682c38dd9c289cc6e2"}, + {file = "pygit2-1.12.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:865c0d1925c52426455317f29c1db718187ec69ed5474faaf3e1c68ff2135767"}, + {file = "pygit2-1.12.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ebebbe9125b068337b5415565ec94c9e092c708e430851b2d02e51217bdce4a"}, + {file = "pygit2-1.12.1.tar.gz", hash = "sha256:8218922abedc88a65d5092308d533ca4c4ed634aec86a3493d3bdf1a25aeeff3"}, ] [package.dependencies] @@ -1456,14 +1454,14 @@ testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy [[package]] name = "pytest-cov" -version = "4.0.0" +version = "4.1.0" description = "Pytest plugin for measuring coverage." category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, - {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, + {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, + {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, ] [package.dependencies] @@ -1491,14 +1489,14 @@ pytest = ">=3.0" [[package]] name = "pytest-xdist" -version = "3.2.1" +version = "3.3.1" description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-xdist-3.2.1.tar.gz", hash = "sha256:1849bd98d8b242b948e472db7478e090bf3361912a8fed87992ed94085f54727"}, - {file = "pytest_xdist-3.2.1-py3-none-any.whl", hash = "sha256:37290d161638a20b672401deef1cba812d110ac27e35d213f091d15b8beb40c9"}, + {file = "pytest-xdist-3.3.1.tar.gz", hash = "sha256:d5ee0520eb1b7bcca50a60a518ab7a7707992812c578198f8b44fdfac78e8c93"}, + {file = "pytest_xdist-3.3.1-py3-none-any.whl", hash = "sha256:ff9daa7793569e6a68544850fd3927cd257cc03a7ef76c95e86915355e82b5f2"}, ] [package.dependencies] @@ -1542,18 +1540,18 @@ dev = ["atomicwrites (==1.2.1)", "attrs (==19.2.0)", "coverage (==6.5.0)", "hatc [[package]] name = "redis" -version = "4.5.4" +version = "4.5.5" description = "Python client for Redis database and key-value store" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "redis-4.5.4-py3-none-any.whl", hash = "sha256:2c19e6767c474f2e85167909061d525ed65bea9301c0770bb151e041b7ac89a2"}, - {file = "redis-4.5.4.tar.gz", hash = "sha256:73ec35da4da267d6847e47f68730fdd5f62e2ca69e3ef5885c6a78a9374c3893"}, + {file = "redis-4.5.5-py3-none-any.whl", hash = "sha256:77929bc7f5dab9adf3acba2d3bb7d7658f1e0c2f1cafe7eb36434e751c471119"}, + {file = "redis-4.5.5.tar.gz", hash = "sha256:dc87a0bdef6c8bfe1ef1e1c40be7034390c2ae02d92dcd0c7ca1729443899880"}, ] [package.dependencies] -async-timeout = {version = ">=4.0.2", markers = "python_version <= \"3.11.2\""} +async-timeout = {version = ">=4.0.2", markers = "python_full_version <= \"3.11.2\""} [package.extras] hiredis = ["hiredis (>=1.0.0)"] @@ -1561,14 +1559,14 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)" [[package]] name = "requests" -version = "2.30.0" +version = "2.31.0" description = "Python HTTP for Humans." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "requests-2.30.0-py3-none-any.whl", hash = "sha256:10e94cc4f3121ee6da529d358cdaeaff2f1c409cd377dbc72b825852f2f7e294"}, - {file = "requests-2.30.0.tar.gz", hash = "sha256:239d7d4458afcb28a692cdd298d87542235f4ca8d36d03a15bfc128a6559a2f4"}, + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, ] [package.dependencies] @@ -1892,14 +1890,14 @@ files = [ [[package]] name = "werkzeug" -version = "2.3.3" +version = "2.3.4" description = "The comprehensive WSGI web application library." category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "Werkzeug-2.3.3-py3-none-any.whl", hash = "sha256:4866679a0722de00796a74086238bb3b98d90f423f05de039abb09315487254a"}, - {file = "Werkzeug-2.3.3.tar.gz", hash = "sha256:a987caf1092edc7523edb139edb20c70571c4a8d5eed02e0b547b4739174d091"}, + {file = "Werkzeug-2.3.4-py3-none-any.whl", hash = "sha256:48e5e61472fee0ddee27ebad085614ebedb7af41e88f687aaf881afb723a162f"}, + {file = "Werkzeug-2.3.4.tar.gz", hash = "sha256:1d5a58e0377d1fe39d061a5de4469e414e78ccb1e1e59c0f5ad6fa1c36c52b76"}, ] [package.dependencies] @@ -1942,4 +1940,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "6a96903be0358aa6d6ef1926edf6158dd36060f8bec66bd8bf8b0ee04e7795df" +content-hash = "caf2a21e3bff699216e53a37697a7a544103fdea9f84a5d54ee94ded3e810973" diff --git a/pyproject.toml b/pyproject.toml index b27d281a..f04deb14 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ aiofiles = "^23.1.0" asgiref = "^3.6.0" bcrypt = "^4.0.1" bleach = "^6.0.0" -email-validator = "^2.0.0.post2" +email-validator = "^2.0.0-post.0" fakeredis = "^2.11.2" feedgen = "^0.9.0" httpx = "^0.24.0" From 5fe375bdc3c5ee1bb39acc3c92e6791b3606b942 Mon Sep 17 00:00:00 2001 From: "Daniel M. Capella" Date: Thu, 25 May 2023 17:18:30 -0400 Subject: [PATCH 038/178] feat: add link to MergeBaseName in requests.html --- templates/requests.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/templates/requests.html b/templates/requests.html index 9eb911f5..352ed820 100644 --- a/templates/requests.html +++ b/templates/requests.html @@ -109,7 +109,9 @@ {{ result.RequestType.name_display() | tr }} {# If the RequestType is a merge and request.MergeBaseName is valid... #} {% if result.RequestType.ID == 3 and result.MergeBaseName %} - ({{ result.MergeBaseName }}) + + ({{ result.MergeBaseName }}) + {% endif %} {# Comments #} From 2eacc84cd02802704a9d686843d3c2224f35dcb5 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Thu, 25 May 2023 13:23:37 +0200 Subject: [PATCH 039/178] fix: properly evaluate AURREMEMBER cookie Whenever the AURREMEMBER cookie was defined, regardless of its value, "remember_me" is always set to True The get method of a dict returns a string, converting a value of str "False" into a bool -> True We have to check AURREMEMBERs value instead. Signed-off-by: moson-mo --- aurweb/auth/__init__.py | 4 +--- aurweb/cookies.py | 2 +- aurweb/users/update.py | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/aurweb/auth/__init__.py b/aurweb/auth/__init__.py index 5a1fc8d0..83dd424c 100644 --- a/aurweb/auth/__init__.py +++ b/aurweb/auth/__init__.py @@ -104,9 +104,7 @@ class BasicAuthBackend(AuthenticationBackend): return unauthenticated timeout = aurweb.config.getint("options", "login_timeout") - remembered = "AURREMEMBER" in conn.cookies and bool( - conn.cookies.get("AURREMEMBER") - ) + remembered = conn.cookies.get("AURREMEMBER") == "True" if remembered: timeout = aurweb.config.getint("options", "persistent_cookie_timeout") diff --git a/aurweb/cookies.py b/aurweb/cookies.py index 841e9adc..2bfcf7a7 100644 --- a/aurweb/cookies.py +++ b/aurweb/cookies.py @@ -65,7 +65,7 @@ def update_response_cookies( "AURLANG", aurlang, secure=secure, httponly=secure, samesite=samesite() ) if aursid: - remember_me = bool(request.cookies.get("AURREMEMBER", False)) + remember_me = request.cookies.get("AURREMEMBER") == "True" response.set_cookie( "AURSID", aursid, diff --git a/aurweb/users/update.py b/aurweb/users/update.py index 21349a39..ace9dace 100644 --- a/aurweb/users/update.py +++ b/aurweb/users/update.py @@ -131,7 +131,7 @@ def password( user.update_password(P) if user == request.user: - remember_me = request.cookies.get("AURREMEMBER", False) + remember_me = request.cookies.get("AURREMEMBER") == "True" # If the target user is the request user, login with # the updated password to update the Session record. From edc4ac332d1872c8b4b5fab5d9e789d66d36f795 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Thu, 25 May 2023 13:41:59 +0200 Subject: [PATCH 040/178] chore: remove setting AURLANG and AURTZ on account edit We don't need to set these cookies when an account is edited. These settings are saved to the DB anyways. (and they are picked up from there as well for any web requests, when no cookies are given) Setting these cookies can even be counter-productive: Imagine a TU/Dev editing another users account. They would overwrite their own cookies with the other users TZ/LANG settings. Signed-off-by: moson-mo --- aurweb/cookies.py | 12 ------------ aurweb/routers/accounts.py | 6 ++---- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/aurweb/cookies.py b/aurweb/cookies.py index 2bfcf7a7..cb4396d7 100644 --- a/aurweb/cookies.py +++ b/aurweb/cookies.py @@ -38,8 +38,6 @@ def timeout(extended: bool) -> int: 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 @@ -50,20 +48,10 @@ def update_response_cookies( :param request: FastAPI request :param response: FastAPI response - :param aurtz: Optional AURTZ cookie value - :param aurlang: Optional AURLANG cookie value :param aursid: Optional AURSID cookie value :returns: Updated response """ secure = config.getboolean("options", "disable_http_login") - if aurtz: - response.set_cookie( - "AURTZ", aurtz, secure=secure, httponly=secure, samesite=samesite() - ) - if aurlang: - response.set_cookie( - "AURLANG", aurlang, secure=secure, httponly=secure, samesite=samesite() - ) if aursid: remember_me = request.cookies.get("AURREMEMBER") == "True" response.set_cookie( diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 77988d7f..010aae58 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -8,7 +8,7 @@ from fastapi.responses import HTMLResponse, RedirectResponse from sqlalchemy import and_, or_ import aurweb.config -from aurweb import aur_logging, cookies, db, l10n, models, util +from aurweb import aur_logging, db, l10n, models, util from aurweb.auth import account_type_required, creds, requires_auth, requires_guest from aurweb.captcha import get_captcha_salts from aurweb.exceptions import ValidationError, handle_form_exceptions @@ -473,9 +473,7 @@ async def account_edit_post( if not errors: context["complete"] = True - # 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 render_template(request, "account/edit.html", context) @router.get("/account/{username}") From 638ca7b1d081f14c21db6d5c40e23678b865d258 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Thu, 25 May 2023 13:47:50 +0200 Subject: [PATCH 041/178] chore: remove setting AURLANG and AURTZ on login We don't need to set these cookies when logging in. These settings are saved to the DB anyways. (and they are picked up from there as well for any web requests, when no cookies are given) Signed-off-by: moson-mo --- aurweb/routers/auth.py | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index 0e675559..71547429 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -85,20 +85,6 @@ async def login_post( 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, @@ -125,5 +111,5 @@ async def logout(request: Request, next: str = Form(default="/")): # to redirect to a get request. response = RedirectResponse(url=next, status_code=HTTPStatus.SEE_OTHER) response.delete_cookie("AURSID") - response.delete_cookie("AURTZ") + response.delete_cookie("AURREMEMBER") return response From 57c154a72cc6dbc997c07b159e76a1ddd5cc02ee Mon Sep 17 00:00:00 2001 From: moson-mo Date: Thu, 25 May 2023 14:07:27 +0200 Subject: [PATCH 042/178] fix: increase expiry for AURLANG cookie; only set when needed We add a new config option for cookies with a 400 day lifetime. AURLANG should survive longer for unauthenticated users. Today they have to set this again after each browser restart. (for users whose browsers wipe session cookies on close) authenticated users don't need this cookie since the setting is saved to the DB Signed-off-by: moson-mo --- aurweb/routers/html.py | 29 +++++++++++++++++++---------- conf/config.defaults | 4 ++++ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index 33aeb904..38303837 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -56,19 +56,28 @@ async def language( query_string = "?" + q if q else str() - # If the user is authenticated, update the user's LangPreference. - if request.user.is_authenticated(): - with db.begin(): - 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 ) - secure = aurweb.config.getboolean("options", "disable_http_login") - response.set_cookie( - "AURLANG", set_lang, secure=secure, httponly=secure, samesite=cookies.samesite() - ) + + # If the user is authenticated, update the user's LangPreference. + # Otherwise set an AURLANG cookie + if request.user.is_authenticated(): + with db.begin(): + request.user.LangPreference = set_lang + else: + secure = aurweb.config.getboolean("options", "disable_http_login") + perma_timeout = aurweb.config.getint("options", "permanent_cookie_timeout") + + response.set_cookie( + "AURLANG", + set_lang, + secure=secure, + httponly=secure, + max_age=perma_timeout, + samesite=cookies.samesite(), + ) + return response diff --git a/conf/config.defaults b/conf/config.defaults index bb390d8a..17e81b7b 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -14,8 +14,12 @@ passwd_min_len = 8 default_lang = en default_timezone = UTC sql_debug = 0 +; 2 hours - default login_timeout login_timeout = 7200 +; 30 days - default persistent_cookie_timeout persistent_cookie_timeout = 2592000 +; 400 days - default permanent_cookie_timeout +permanent_cookie_timeout = 34560000 max_filesize_uncompressed = 8388608 disable_http_login = 1 aur_location = https://aur.archlinux.org From d3663772313037d3734b7795f0f8828e625a5e2e Mon Sep 17 00:00:00 2001 From: moson-mo Date: Thu, 25 May 2023 14:20:38 +0200 Subject: [PATCH 043/178] fix: make AURREMEMBER cookie a permanent one If it's a session cookie it poses issues for users whose browsers wipe session cookies after close. They'd be logged out early even if they chose the "remember me" option when they log in. Signed-off-by: moson-mo --- aurweb/routers/auth.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index 71547429..98a655e3 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -70,6 +70,7 @@ async def login_post( return await login_template(request, next, errors=["Account Suspended"]) cookie_timeout = cookies.timeout(remember_me) + perma_timeout = aurweb.config.getint("options", "permanent_cookie_timeout") sid = _retry_login(request, user, passwd, cookie_timeout) if not sid: return await login_template(request, next, errors=["Bad username or password."]) @@ -88,6 +89,7 @@ async def login_post( response.set_cookie( "AURREMEMBER", remember_me, + max_age=perma_timeout, secure=secure, httponly=secure, samesite=cookies.samesite(), From 0807ae6b7caada569c8fab45c4f3403ff950b6d1 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Thu, 25 May 2023 14:22:51 +0200 Subject: [PATCH 044/178] test: add tests for cookie handling add a bunch of test cases to ensure our cookies work properly Signed-off-by: moson-mo --- test/test_cookies.py | 145 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 test/test_cookies.py diff --git a/test/test_cookies.py b/test/test_cookies.py new file mode 100644 index 00000000..a0ace68f --- /dev/null +++ b/test/test_cookies.py @@ -0,0 +1,145 @@ +from datetime import datetime + +import pytest +from fastapi.testclient import TestClient + +from aurweb import config, db +from aurweb.asgi import app +from aurweb.models.account_type import USER_ID +from aurweb.models.user import User +from aurweb.testing.requests import Request + +# Some test global constants. +TEST_USERNAME = "test" +TEST_EMAIL = "test@example.org" +TEST_REFERER = { + "referer": config.get("options", "aur_location") + "/login", +} + + +@pytest.fixture(autouse=True) +def setup(db_test): + return + + +@pytest.fixture +def client() -> TestClient: + client = TestClient(app=app) + + # Necessary for forged login CSRF protection on the login route. Set here + # instead of only on the necessary requests for convenience. + client.headers.update(TEST_REFERER) + + # disable redirects for our tests + client.follow_redirects = False + yield client + + +@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, + ) + yield user + + +def test_cookies_login(client: TestClient, user: User): + # Log in with "Remember me" disabled + data = {"user": user.Username, "passwd": "testPassword", "next": "/"} + with client as request: + resp = request.post("/login", data=data) + + local_time = int(datetime.now().timestamp()) + expected_timeout = local_time + config.getint("options", "login_timeout") + expected_permanent = local_time + config.getint( + "options", "permanent_cookie_timeout" + ) + + # Check if we got permanent cookies with expected expiry date. + # Allow 1 second difference to account for timing issues + # between the request and current time. + assert "AURSID", "AURREMEMBER" in resp.cookies + for cookie in resp.cookies.jar: + if cookie.name == "AURSID": + assert abs(cookie.expires - expected_timeout) < 2 + + if cookie.name == "AURREMEMBER": + assert abs(cookie.expires - expected_permanent) < 2 + + # Make some random http call. + # We should get an (updated) AURSID cookie with each request. + sid = resp.cookies.get("AURSID") + with client as request: + request.cookies = {"AURSID": sid} + resp = request.get("/") + + assert "AURSID" in resp.cookies + + # Log out + with client as request: + request.cookies = resp.cookies + resp = request.post("/logout", data=data) + + # Make sure AURSID cookie is removed after logout + assert "AURSID" not in resp.cookies + + # Log in with "Remember me" enabled + data = { + "user": user.Username, + "passwd": "testPassword", + "next": "/", + "remember_me": "True", + } + with client as request: + resp = request.post("/login", data=data) + + # Check if we got a permanent cookie with expected expiry date. + # Allow 1 second difference to account for timing issues + # between the request and current time. + expected_persistent = local_time + config.getint( + "options", "persistent_cookie_timeout" + ) + assert "AURSID" in resp.cookies + for cookie in resp.cookies.jar: + if cookie.name in "AURSID": + assert abs(cookie.expires - expected_persistent) < 2 + + +def test_cookie_language(client: TestClient, user: User): + # Unauthenticated reqeuests should set AURLANG cookie + data = {"set_lang": "en", "next": "/"} + with client as request: + resp = request.post("/language", data=data) + + local_time = int(datetime.now().timestamp()) + expected_permanent = local_time + config.getint( + "options", "permanent_cookie_timeout" + ) + + # Make sure we got an AURLANG cookie + assert "AURLANG" in resp.cookies + assert resp.cookies.get("AURLANG") == "en" + + # Check if we got a permanent cookie with expected expiry date. + # Allow 1 second difference to account for timing issues + # between the request and current time. + for cookie in resp.cookies.jar: + if cookie.name in "AURLANG": + assert abs(cookie.expires - expected_permanent) < 2 + + # Login and change the language + # We should not get a cookie since we store + # our language setting in the DB anyways + sid = user.login(Request(), "testPassword") + data = {"set_lang": "en", "next": "/"} + with client as request: + request.cookies = {"AURSID": sid} + resp = request.post("/language", data=data) + + assert "AURLANG" not in resp.cookies From 22fe4a988a31c78f01ddc62bd1d9cb9c5074046b Mon Sep 17 00:00:00 2001 From: moson-mo Date: Fri, 26 May 2023 11:21:16 +0200 Subject: [PATCH 045/178] fix: make AURSID a session cookie if "remember me" is not checked This should match more closely the expectation of a user. A session cookie should vanish on browser close and you thus they need to authenticate again. There is no need to bump the expiration of AURSID either, so we can remove that part. Signed-off-by: moson-mo --- aurweb/cookies.py | 33 --------------------------------- aurweb/routers/auth.py | 7 ++++++- aurweb/templates.py | 13 ++----------- doc/web-auth.md | 18 ++++++------------ test/test_cookies.py | 30 ++++++++++++++++++------------ 5 files changed, 32 insertions(+), 69 deletions(-) diff --git a/aurweb/cookies.py b/aurweb/cookies.py index cb4396d7..022cff1e 100644 --- a/aurweb/cookies.py +++ b/aurweb/cookies.py @@ -1,6 +1,3 @@ -from fastapi import Request -from fastapi.responses import Response - from aurweb import config @@ -33,33 +30,3 @@ def timeout(extended: bool) -> int: if bool(extended): timeout = config.getint("options", "persistent_cookie_timeout") return timeout - - -def update_response_cookies( - request: Request, - response: Response, - 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, - which is retrieved from `request`. - - :param request: FastAPI request - :param response: FastAPI response - :param aursid: Optional AURSID cookie value - :returns: Updated response - """ - secure = config.getboolean("options", "disable_http_login") - if aursid: - remember_me = request.cookies.get("AURREMEMBER") == "True" - response.set_cookie( - "AURSID", - aursid, - secure=secure, - httponly=secure, - max_age=timeout(remember_me), - samesite=samesite(), - ) - return response diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index 98a655e3..46dee3a4 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -69,7 +69,12 @@ async def login_post( if user.Suspended: return await login_template(request, next, errors=["Account Suspended"]) - cookie_timeout = cookies.timeout(remember_me) + # If "remember me" was not ticked, we set a session cookie for AURSID, + # otherwise we make it a persistent cookie + cookie_timeout = None + if remember_me: + cookie_timeout = aurweb.config.getint("options", "persistent_cookie_timeout") + perma_timeout = aurweb.config.getint("options", "permanent_cookie_timeout") sid = _retry_login(request, user, passwd, cookie_timeout) if not sid: diff --git a/aurweb/templates.py b/aurweb/templates.py index 89316d6d..d20cbe85 100644 --- a/aurweb/templates.py +++ b/aurweb/templates.py @@ -10,7 +10,7 @@ from fastapi import Request from fastapi.responses import HTMLResponse import aurweb.config -from aurweb import cookies, l10n, time +from aurweb import l10n, time # Prepare jinja2 objects. _loader = jinja2.FileSystemLoader( @@ -145,13 +145,4 @@ def render_template( ): """Render a template as an HTMLResponse.""" rendered = render_raw_template(request, path, context) - response = HTMLResponse(rendered, status_code=int(status_code)) - - sid = None - if request.user.is_authenticated(): - sid = request.cookies.get("AURSID") - - # Re-emit SID via update_response_cookies with an updated expiration. - # This extends the life of a user session based on the AURREMEMBER - # cookie, which is always set to the "Remember Me" state on login. - return cookies.update_response_cookies(request, response, aursid=sid) + return HTMLResponse(rendered, status_code=int(status_code)) diff --git a/doc/web-auth.md b/doc/web-auth.md index dbb4403d..c8604fed 100644 --- a/doc/web-auth.md +++ b/doc/web-auth.md @@ -22,17 +22,11 @@ in the following ways: ### Max-Age The value used for the `AURSID` Max-Age attribute is decided based -off of the "Remember Me" checkbox on the login page. Both paths -use their own independent configuration for the number of seconds -that each type of session should stay alive. - -- "Remember Me" unchecked while logging in - - `options.login_timeout` is used -- "Remember Me" checked while logging in - - `options.persistent_cookie_timeout` is used - -Both `options.login_timeout` and `options.persistent_cookie_timeout` -indicate the number of seconds the session should live. +off of the "Remember Me" checkbox on the login page. If it was not +checked, we don't set Max-Age and it becomes a session cookie. +Otherwise we make it a persistent cookie and for the expiry date +we use `options.persistent_cookie_timeout`. +It indicates the number of seconds the session should live. ### Notes @@ -89,7 +83,7 @@ The following list of steps describes exactly how this verification works: 1. Was the `AURSID` cookie delivered? 1. No, the algorithm ends, you are considered unauthenticated 2. Yes, move on to 2 -2. Was the `AURREMEMBER` cookie delivered with a value of 1? +2. Was the `AURREMEMBER` cookie delivered with a value of `True`? 1. No, set the expected session timeout **T** to `options.login_timeout` 2. Yes, set the expected session timeout **T** to `options.persistent_cookie_timeout` diff --git a/test/test_cookies.py b/test/test_cookies.py index a0ace68f..dd4143cb 100644 --- a/test/test_cookies.py +++ b/test/test_cookies.py @@ -1,4 +1,5 @@ from datetime import datetime +from http import HTTPStatus import pytest from fastapi.testclient import TestClient @@ -56,7 +57,6 @@ def test_cookies_login(client: TestClient, user: User): resp = request.post("/login", data=data) local_time = int(datetime.now().timestamp()) - expected_timeout = local_time + config.getint("options", "login_timeout") expected_permanent = local_time + config.getint( "options", "permanent_cookie_timeout" ) @@ -64,22 +64,15 @@ def test_cookies_login(client: TestClient, user: User): # Check if we got permanent cookies with expected expiry date. # Allow 1 second difference to account for timing issues # between the request and current time. + # AURSID should be a session cookie (no expiry date) assert "AURSID", "AURREMEMBER" in resp.cookies for cookie in resp.cookies.jar: if cookie.name == "AURSID": - assert abs(cookie.expires - expected_timeout) < 2 + assert cookie.expires is None if cookie.name == "AURREMEMBER": assert abs(cookie.expires - expected_permanent) < 2 - - # Make some random http call. - # We should get an (updated) AURSID cookie with each request. - sid = resp.cookies.get("AURSID") - with client as request: - request.cookies = {"AURSID": sid} - resp = request.get("/") - - assert "AURSID" in resp.cookies + assert cookie.value == "False" # Log out with client as request: @@ -102,14 +95,27 @@ def test_cookies_login(client: TestClient, user: User): # Check if we got a permanent cookie with expected expiry date. # Allow 1 second difference to account for timing issues # between the request and current time. + # AURSID should be a persistent cookie expected_persistent = local_time + config.getint( "options", "persistent_cookie_timeout" ) - assert "AURSID" in resp.cookies + assert "AURSID", "AURREMEMBER" in resp.cookies for cookie in resp.cookies.jar: if cookie.name in "AURSID": assert abs(cookie.expires - expected_persistent) < 2 + if cookie.name == "AURREMEMBER": + assert abs(cookie.expires - expected_permanent) < 2 + assert cookie.value == "True" + + # log in again even though we already have a session + with client as request: + resp = request.post("/login", data=data) + + # we are logged in already and should have been redirected + assert resp.status_code == int(HTTPStatus.SEE_OTHER) + assert resp.headers.get("location") == "/" + def test_cookie_language(client: TestClient, user: User): # Unauthenticated reqeuests should set AURLANG cookie From a7882c75339189dbb32145fcf88f02c08a4ff7b9 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Fri, 26 May 2023 23:02:38 +0200 Subject: [PATCH 046/178] refactor: remove session_time from user.login The parameter is not used, we can remove it and adapt the callers. Signed-off-by: moson-mo --- aurweb/cookies.py | 24 ------------------------ aurweb/models/user.py | 2 +- aurweb/routers/auth.py | 6 +++--- aurweb/users/update.py | 6 ++---- 4 files changed, 6 insertions(+), 32 deletions(-) diff --git a/aurweb/cookies.py b/aurweb/cookies.py index 022cff1e..84c43f9b 100644 --- a/aurweb/cookies.py +++ b/aurweb/cookies.py @@ -1,6 +1,3 @@ -from aurweb import config - - def samesite() -> str: """Produce cookie SameSite value. @@ -9,24 +6,3 @@ def samesite() -> str: :returns "lax" """ return "lax" - - -def timeout(extended: bool) -> int: - """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. - - The `extended` argument is typically the value of the AURREMEMBER - cookie, defaulted to False. - - If `extended` is False, options.login_timeout is returned. Otherwise, - if `extended` is True, options.persistent_cookie_timeout is returned. - - :param extended: Flag which generates an extended timeout when True - :returns: Cookie timeout based on configuration options - """ - timeout = config.getint("options", "login_timeout") - if bool(extended): - timeout = config.getint("options", "persistent_cookie_timeout") - return timeout diff --git a/aurweb/models/user.py b/aurweb/models/user.py index 9846d996..8612c259 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -95,7 +95,7 @@ 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: + def login(self, request: Request, password: str) -> str: """Login and authenticate a request.""" from aurweb import db diff --git a/aurweb/routers/auth.py b/aurweb/routers/auth.py index 46dee3a4..88eaa0e6 100644 --- a/aurweb/routers/auth.py +++ b/aurweb/routers/auth.py @@ -29,8 +29,8 @@ async def login_get(request: Request, next: str = "/"): @db.retry_deadlock -def _retry_login(request: Request, user: User, passwd: str, cookie_timeout: int) -> str: - return user.login(request, passwd, cookie_timeout) +def _retry_login(request: Request, user: User, passwd: str) -> str: + return user.login(request, passwd) @router.post("/login", response_class=HTMLResponse) @@ -76,7 +76,7 @@ async def login_post( cookie_timeout = aurweb.config.getint("options", "persistent_cookie_timeout") perma_timeout = aurweb.config.getint("options", "permanent_cookie_timeout") - sid = _retry_login(request, user, passwd, cookie_timeout) + sid = _retry_login(request, user, passwd) if not sid: return await login_template(request, next, errors=["Bad username or password."]) diff --git a/aurweb/users/update.py b/aurweb/users/update.py index ace9dace..759088cd 100644 --- a/aurweb/users/update.py +++ b/aurweb/users/update.py @@ -2,7 +2,7 @@ from typing import Any from fastapi import Request -from aurweb import cookies, db, models, time, util +from aurweb import db, models, time, util from aurweb.models import SSHPubKey from aurweb.models.ssh_pub_key import get_fingerprint from aurweb.util import strtobool @@ -131,11 +131,9 @@ def password( user.update_password(P) if user == request.user: - remember_me = request.cookies.get("AURREMEMBER") == "True" - # If the target user is the request user, login with # the updated password to update the Session record. - user.login(request, P, cookies.timeout(remember_me)) + user.login(request, P) @db.retry_deadlock From 49e98d64f4f1d6770f067db087f741eb8420548e Mon Sep 17 00:00:00 2001 From: moson-mo Date: Fri, 26 May 2023 23:03:38 +0200 Subject: [PATCH 047/178] chore: increase default session/cookie timeout change from 2 to 4 hours. Signed-off-by: moson-mo --- conf/config.defaults | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/config.defaults b/conf/config.defaults index 17e81b7b..c059444d 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -14,8 +14,8 @@ passwd_min_len = 8 default_lang = en default_timezone = UTC sql_debug = 0 -; 2 hours - default login_timeout -login_timeout = 7200 +; 4 hours - default login_timeout +login_timeout = 14400 ; 30 days - default persistent_cookie_timeout persistent_cookie_timeout = 2592000 ; 400 days - default permanent_cookie_timeout From d1a3fee9fe98ebc3bcdb4f472f8812fa738d3b12 Mon Sep 17 00:00:00 2001 From: renovate Date: Fri, 26 May 2023 18:24:33 +0000 Subject: [PATCH 048/178] fix(deps): update all non-major dependencies --- poetry.lock | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/poetry.lock b/poetry.lock index 3a273be4..06855cac 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1269,25 +1269,25 @@ prometheus-client = ">=0.8.0,<1.0.0" [[package]] name = "protobuf" -version = "4.23.1" +version = "4.23.2" description = "" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "protobuf-4.23.1-cp310-abi3-win32.whl", hash = "sha256:410bcc0a5b279f634d3e16082ce221dfef7c3392fac723500e2e64d1806dd2be"}, - {file = "protobuf-4.23.1-cp310-abi3-win_amd64.whl", hash = "sha256:32e78beda26d7a101fecf15d7a4a792278a0d26a31bc327ff05564a9d68ab8ee"}, - {file = "protobuf-4.23.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f9510cac91e764e86acd74e2b7f7bc5e6127a7f3fb646d7c8033cfb84fd1176a"}, - {file = "protobuf-4.23.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:346990f634272caac1f09efbcfbbacb23098b1f606d172534c6fa2d9758bb436"}, - {file = "protobuf-4.23.1-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:3ce113b3f3362493bddc9069c2163a38f240a9ed685ff83e7bcb756b05e1deb0"}, - {file = "protobuf-4.23.1-cp37-cp37m-win32.whl", hash = "sha256:2036a3a1e7fc27f973fa0a7888dce712393af644f4695385f117886abc792e39"}, - {file = "protobuf-4.23.1-cp37-cp37m-win_amd64.whl", hash = "sha256:3b8905eafe4439076e1f58e9d1fa327025fd2777cf90f14083092ae47f77b0aa"}, - {file = "protobuf-4.23.1-cp38-cp38-win32.whl", hash = "sha256:5b9cd6097e6acae48a68cb29b56bc79339be84eca65b486910bb1e7a30e2b7c1"}, - {file = "protobuf-4.23.1-cp38-cp38-win_amd64.whl", hash = "sha256:decf119d54e820f298ee6d89c72d6b289ea240c32c521f00433f9dc420595f38"}, - {file = "protobuf-4.23.1-cp39-cp39-win32.whl", hash = "sha256:91fac0753c3c4951fbb98a93271c43cc7cf3b93cf67747b3e600bb1e5cc14d61"}, - {file = "protobuf-4.23.1-cp39-cp39-win_amd64.whl", hash = "sha256:ac50be82491369a9ec3710565777e4da87c6d2e20404e0abb1f3a8f10ffd20f0"}, - {file = "protobuf-4.23.1-py3-none-any.whl", hash = "sha256:65f0ac96ef67d7dd09b19a46aad81a851b6f85f89725577f16de38f2d68ad477"}, - {file = "protobuf-4.23.1.tar.gz", hash = "sha256:95789b569418a3e32a53f43d7763be3d490a831e9c08042539462b6d972c2d7e"}, + {file = "protobuf-4.23.2-cp310-abi3-win32.whl", hash = "sha256:384dd44cb4c43f2ccddd3645389a23ae61aeb8cfa15ca3a0f60e7c3ea09b28b3"}, + {file = "protobuf-4.23.2-cp310-abi3-win_amd64.whl", hash = "sha256:09310bce43353b46d73ba7e3bca78273b9bc50349509b9698e64d288c6372c2a"}, + {file = "protobuf-4.23.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:b2cfab63a230b39ae603834718db74ac11e52bccaaf19bf20f5cce1a84cf76df"}, + {file = "protobuf-4.23.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:c52cfcbfba8eb791255edd675c1fe6056f723bf832fa67f0442218f8817c076e"}, + {file = "protobuf-4.23.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:86df87016d290143c7ce3be3ad52d055714ebaebb57cc659c387e76cfacd81aa"}, + {file = "protobuf-4.23.2-cp37-cp37m-win32.whl", hash = "sha256:281342ea5eb631c86697e1e048cb7e73b8a4e85f3299a128c116f05f5c668f8f"}, + {file = "protobuf-4.23.2-cp37-cp37m-win_amd64.whl", hash = "sha256:ce744938406de1e64b91410f473736e815f28c3b71201302612a68bf01517fea"}, + {file = "protobuf-4.23.2-cp38-cp38-win32.whl", hash = "sha256:6c081863c379bb1741be8f8193e893511312b1d7329b4a75445d1ea9955be69e"}, + {file = "protobuf-4.23.2-cp38-cp38-win_amd64.whl", hash = "sha256:25e3370eda26469b58b602e29dff069cfaae8eaa0ef4550039cc5ef8dc004511"}, + {file = "protobuf-4.23.2-cp39-cp39-win32.whl", hash = "sha256:efabbbbac1ab519a514579ba9ec52f006c28ae19d97915951f69fa70da2c9e91"}, + {file = "protobuf-4.23.2-cp39-cp39-win_amd64.whl", hash = "sha256:54a533b971288af3b9926e53850c7eb186886c0c84e61daa8444385a4720297f"}, + {file = "protobuf-4.23.2-py3-none-any.whl", hash = "sha256:8da6070310d634c99c0db7df48f10da495cc283fd9e9234877f0cd182d43ab7f"}, + {file = "protobuf-4.23.2.tar.gz", hash = "sha256:20874e7ca4436f683b64ebdbee2129a5a2c301579a67d1a7dda2cdf62fb7f5f7"}, ] [[package]] From 2709585a70a9437d10736e18141e44af053b3b55 Mon Sep 17 00:00:00 2001 From: renovate Date: Sat, 27 May 2023 11:24:46 +0000 Subject: [PATCH 049/178] fix(deps): update dependency fastapi to v0.95.2 --- poetry.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/poetry.lock b/poetry.lock index 06855cac..16b0f15a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -551,19 +551,19 @@ lua = ["lupa (>=1.14,<2.0)"] [[package]] name = "fastapi" -version = "0.95.1" +version = "0.95.2" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "fastapi-0.95.1-py3-none-any.whl", hash = "sha256:a870d443e5405982e1667dfe372663abf10754f246866056336d7f01c21dab07"}, - {file = "fastapi-0.95.1.tar.gz", hash = "sha256:9569f0a381f8a457ec479d90fa01005cfddaae07546eb1f3fa035bc4797ae7d5"}, + {file = "fastapi-0.95.2-py3-none-any.whl", hash = "sha256:d374dbc4ef2ad9b803899bd3360d34c534adc574546e25314ab72c0c4411749f"}, + {file = "fastapi-0.95.2.tar.gz", hash = "sha256:4d9d3e8c71c73f11874bcf5e33626258d143252e329a01002f767306c64fb982"}, ] [package.dependencies] pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" -starlette = ">=0.26.1,<0.27.0" +starlette = ">=0.27.0,<0.28.0" [package.extras] all = ["email-validator (>=1.1.1)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] @@ -1724,14 +1724,14 @@ parse = ">=1.19.0,<2.0.0" [[package]] name = "starlette" -version = "0.26.1" +version = "0.27.0" description = "The little ASGI library that shines." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "starlette-0.26.1-py3-none-any.whl", hash = "sha256:e87fce5d7cbdde34b76f0ac69013fd9d190d581d80681493016666e6f96c6d5e"}, - {file = "starlette-0.26.1.tar.gz", hash = "sha256:41da799057ea8620e4667a3e69a5b1923ebd32b1819c8fa75634bbe8d8bea9bd"}, + {file = "starlette-0.27.0-py3-none-any.whl", hash = "sha256:918416370e846586541235ccd38a474c08b80443ed31c578a418e2209b3eef91"}, + {file = "starlette-0.27.0.tar.gz", hash = "sha256:6a6b0d042acb8d469a01eba54e9cda6cbd24ac602c4cd016723117d6a7e73b75"}, ] [package.dependencies] From ed2f85ad047f4659b03f7b3730ff117522feaaa6 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Sat, 27 May 2023 14:28:48 +0100 Subject: [PATCH 050/178] chore(release): prepare for 6.2.4 Signed-off-by: Leonidas Spyropoulos --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index f04deb14..e25fe90a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ combine_as_imports = true # [tool.poetry] name = "aurweb" -version = "v6.2.3" +version = "v6.2.4" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From e9cc2fb4373cae8c24bab5043f24c019829ceb99 Mon Sep 17 00:00:00 2001 From: Christian Heusel Date: Fri, 2 Jun 2023 16:19:44 +0200 Subject: [PATCH 051/178] change: only require .SRCINFO in the latest revision This is done in order to relax the constraints so that dropping packages from the official repos can be done with preserving their history. Its sufficient to also have this present in the latest commit of a push. Signed-off-by: Christian Heusel --- aurweb/git/update.py | 163 +++++++++++++++++++--------------------- test/t1300-git-update.t | 4 +- 2 files changed, 80 insertions(+), 87 deletions(-) diff --git a/aurweb/git/update.py b/aurweb/git/update.py index b1256fdb..467b540f 100755 --- a/aurweb/git/update.py +++ b/aurweb/git/update.py @@ -258,6 +258,63 @@ def die_commit(msg, commit): exit(1) +def validate_metadata(metadata, commit): # noqa: C901 + try: + metadata_pkgbase = metadata["pkgbase"] + except KeyError: + 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)) + + if not metadata["packages"]: + die_commit("missing pkgname entry", str(commit.id)) + + for pkgname in set(metadata["packages"].keys()): + pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata) + + for field in ("pkgver", "pkgrel", "pkgname"): + if field not in pkginfo: + 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 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} + 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), + ) + + 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), + ) + + 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)) + 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)) + + def main(): # noqa: C901 repo = pygit2.Repository(repo_path) @@ -295,12 +352,30 @@ def main(): # noqa: C901 if sha1_old != "0" * 40: walker.hide(sha1_old) + head_commit = repo[sha1_new] + if ".SRCINFO" not in head_commit.tree: + die_commit("missing .SRCINFO", str(head_commit.id)) + + # Read .SRCINFO from the HEAD commit. + metadata_raw = repo[head_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: {:s}:\n".format(str(head_commit.id))) + for error in errors: + for err in error["error"]: + sys.stderr.write("error: line {:d}: {:s}\n".format(error["line"], err)) + exit(1) + + # check if there is a correct .SRCINFO file in the latest revision + validate_metadata(metadata, head_commit) + # Validate all new commits. for commit in walker: - for fname in (".SRCINFO", "PKGBUILD"): - if fname not in commit.tree: - die_commit("missing {:s}".format(fname), str(commit.id)) - + if "PKGBUILD" not in commit.tree: + die_commit("missing PKGBUILD", str(commit.id)) for treeobj in commit.tree: blob = repo[treeobj.id] @@ -320,82 +395,6 @@ def main(): # noqa: C901 str(commit.id), ) - 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: {: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) - ) - exit(1) - - try: - metadata_pkgbase = metadata["pkgbase"] - except KeyError: - 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)) - - if not metadata["packages"]: - die_commit("missing pkgname entry", str(commit.id)) - - for pkgname in set(metadata["packages"].keys()): - pkginfo = srcinfo.utils.get_merged_package(pkgname, metadata) - - for field in ("pkgver", "pkgrel", "pkgname"): - if field not in pkginfo: - 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 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} - 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), - ) - - 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), - ) - - 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) - ) - 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) - ) - # Display a warning if .SRCINFO is unchanged. if sha1_old not in ("0000000000000000000000000000000000000000", sha1_new): srcinfo_id_old = repo[sha1_old].tree[".SRCINFO"].id @@ -403,10 +402,6 @@ def main(): # noqa: C901 if srcinfo_id_old == srcinfo_id_new: 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, errors) = srcinfo.parse.parse_srcinfo(metadata_raw) - # Ensure that the package base name matches the repository name. metadata_pkgbase = metadata["pkgbase"] if metadata_pkgbase != pkgbase: diff --git a/test/t1300-git-update.t b/test/t1300-git-update.t index e9d943c0..a8ea5cab 100755 --- a/test/t1300-git-update.t +++ b/test/t1300-git-update.t @@ -175,10 +175,8 @@ test_expect_success 'Removing .SRCINFO with a follow-up fix.' ' git -C aur.git commit -q -m "Remove .SRCINFO" && git -C aur.git revert --no-edit HEAD && new=$(git -C aur.git rev-parse HEAD) && - test_must_fail \ env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ - cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && - grep -q "^error: missing .SRCINFO$" actual + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 ' test_expect_success 'Removing PKGBUILD.' ' From 26b2566b3fa5fe7165deaedd6e0be6b7da6a3b0f Mon Sep 17 00:00:00 2001 From: Christian Heusel Date: Thu, 8 Jun 2023 12:42:31 +0200 Subject: [PATCH 052/178] change: print the user name if connecting via ssh this is similar to the message that gitlab produces: $ ssh -T aur.archlinux.org Welcome to AUR, gromit! Interactive shell is disabled. Try `ssh ssh://aur@aur.archlinux.org help` for a list of commands. $ ssh -T gitlab.archlinux.org Welcome to GitLab, @gromit! Signed-off-by: Christian Heusel --- aurweb/git/serve.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aurweb/git/serve.py b/aurweb/git/serve.py index 8dbbf3f7..2ac1f10e 100755 --- a/aurweb/git/serve.py +++ b/aurweb/git/serve.py @@ -648,7 +648,7 @@ def main(): ssh_client = os.environ.get("SSH_CLIENT") if not ssh_cmd: - die_with_help("Interactive shell is disabled.") + die_with_help(f"Welcome to AUR, {user}! Interactive shell is disabled.") cmdargv = shlex.split(ssh_cmd) action = cmdargv[0] remote_addr = ssh_client.split(" ")[0] if ssh_client else None From 1c11c901a2d389bf497e886c990b634a70a4df7a Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sat, 10 Jun 2023 09:40:35 +0200 Subject: [PATCH 053/178] feat: switch requests filter for pkgname to "contains" Use "contains" filtering instead of an exact match when a package name filter is given. This makes it easier to find requests for a "group" of packages. Signed-off-by: moson-mo --- aurweb/routers/requests.py | 4 ++-- test/test_requests.py | 20 +++++++++++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/aurweb/routers/requests.py b/aurweb/routers/requests.py index 585dc157..4cfda269 100644 --- a/aurweb/routers/requests.py +++ b/aurweb/routers/requests.py @@ -99,9 +99,9 @@ async def requests( in_filters.append(REJECTED_ID) filtered = query.filter(PackageRequest.Status.in_(in_filters)) - # Name filter + # Name filter (contains) if filter_pkg_name: - filtered = filtered.filter(PackageBase.Name == filter_pkg_name) + filtered = filtered.filter(PackageBase.Name.like(f"%{filter_pkg_name}%")) # Additionally filter for requests made from package maintainer if filter_maintainer_requests: diff --git a/test/test_requests.py b/test/test_requests.py index 7ddb76a0..eb88cd94 100644 --- a/test/test_requests.py +++ b/test/test_requests.py @@ -925,14 +925,28 @@ def test_requests_with_package_name_filter( request.cookies = cookies resp = request.get( "/requests", - params={"filter_pkg_name": packages[0].PackageBase.Name}, + params={"filter_pkg_name": "kg_1"}, ) assert resp.status_code == int(HTTPStatus.OK) root = parse_root(resp.text) rows = root.xpath('//table[@class="results"]/tbody/tr') - # We only expect 1 request for our first package - assert len(rows) == 1 + # We expect 11 requests for all packages containing "kg_1" + assert len(rows) == 11 + + # test as TU, no results + with client as request: + request.cookies = cookies + resp = request.get( + "/requests", + params={"filter_pkg_name": "x"}, + ) + assert resp.status_code == int(HTTPStatus.OK) + + root = parse_root(resp.text) + rows = root.xpath('//table[@class="results"]/tbody/tr') + # We expect 0 requests since we don't have anything containing "x" + assert len(rows) == 0 # test as regular user, not related to our package cookies = {"AURSID": user2.login(Request(), "testPassword")} From ed17486da6ada6c6bb1ca6fb1fddfbd1ccee4708 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sun, 11 Jun 2023 12:20:02 +0200 Subject: [PATCH 054/178] change(git): allow keys/pgp subdir with .asc files This allows migration of git history for packages dropped from a repo to AUR in case they contain PGP key material Signed-off-by: moson-mo --- aurweb/git/update.py | 53 +++++++++++++++------ test/t1300-git-update.t | 103 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 141 insertions(+), 15 deletions(-) diff --git a/aurweb/git/update.py b/aurweb/git/update.py index 467b540f..cd7813e0 100755 --- a/aurweb/git/update.py +++ b/aurweb/git/update.py @@ -315,6 +315,14 @@ def validate_metadata(metadata, commit): # noqa: C901 die_commit("missing source file: {:s}".format(fname), str(commit.id)) +def validate_blob_size(blob: pygit2.Object, commit: pygit2.Commit): + if isinstance(blob, pygit2.Blob) and blob.size > max_blob_size: + die_commit( + "maximum blob size ({:s}) exceeded".format(size_humanize(max_blob_size)), + str(commit.id), + ) + + def main(): # noqa: C901 repo = pygit2.Repository(repo_path) @@ -376,25 +384,42 @@ def main(): # noqa: C901 for commit in walker: if "PKGBUILD" not in commit.tree: die_commit("missing PKGBUILD", str(commit.id)) + + # Iterate over files in root dir for treeobj in commit.tree: - blob = repo[treeobj.id] - - if isinstance(blob, pygit2.Tree): + # Don't allow any subdirs besides "keys/" + if isinstance(treeobj, pygit2.Tree) and treeobj.name != "keys": 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)) - - if blob.size > max_blob_size: - die_commit( - "maximum blob size ({:s}) exceeded".format( - size_humanize(max_blob_size) - ), + "the repository must not contain subdirectories", str(commit.id), ) + # Check size of files in root dir + validate_blob_size(treeobj, commit) + + # If we got a subdir keys/, + # make sure it only contains a pgp/ subdir with key files + if "keys" in commit.tree: + # Check for forbidden files/dirs in keys/ + for keyobj in commit.tree["keys"]: + if not isinstance(keyobj, pygit2.Tree) or keyobj.name != "pgp": + die_commit( + "the keys/ subdir may only contain a pgp/ directory", + str(commit.id), + ) + # Check for forbidden files in keys/pgp/ + if "keys/pgp" in commit.tree: + for pgpobj in commit.tree["keys/pgp"]: + if not isinstance(pgpobj, pygit2.Blob) or not pgpobj.name.endswith( + ".asc" + ): + die_commit( + "the subdir may only contain .asc (PGP pub key) files", + str(commit.id), + ) + # Check file size for pgp key files + validate_blob_size(pgpobj, commit) + # Display a warning if .SRCINFO is unchanged. if sha1_old not in ("0000000000000000000000000000000000000000", sha1_new): srcinfo_id_old = repo[sha1_old].tree[".SRCINFO"].id diff --git a/test/t1300-git-update.t b/test/t1300-git-update.t index a8ea5cab..4fdb487b 100755 --- a/test/t1300-git-update.t +++ b/test/t1300-git-update.t @@ -191,7 +191,7 @@ test_expect_success 'Removing PKGBUILD.' ' grep -q "^error: missing PKGBUILD$" actual ' -test_expect_success 'Pushing a tree with a subdirectory.' ' +test_expect_success 'Pushing a tree with a forbidden subdirectory.' ' old=$(git -C aur.git rev-parse HEAD) && test_when_finished "git -C aur.git reset --hard $old" && mkdir aur.git/subdir && @@ -205,6 +205,107 @@ test_expect_success 'Pushing a tree with a subdirectory.' ' grep -q "^error: the repository must not contain subdirectories$" actual ' +test_expect_success 'Pushing a tree with an allowed subdirectory for pgp keys; wrong files.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir -p aur.git/keys/pgp/ && + touch aur.git/keys/pgp/nonsense && + git -C aur.git add keys/pgp/nonsense && + git -C aur.git commit -q -m "Add some nonsense" && + new=$(git -C aur.git rev-parse HEAD) && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: the subdir may only contain .asc (PGP pub key) files$" actual +' + +test_expect_success 'Pushing a tree with an allowed subdirectory for pgp keys; another subdir.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir -p aur.git/keys/pgp/bla/ && + touch aur.git/keys/pgp/bla/x.asc && + git -C aur.git add keys/pgp/bla/x.asc && + git -C aur.git commit -q -m "Add some nonsense" && + new=$(git -C aur.git rev-parse HEAD) && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: the subdir may only contain .asc (PGP pub key) files$" actual +' + +test_expect_success 'Pushing a tree with an allowed subdirectory for pgp keys; wrong subdir.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir -p aur.git/keys/xyz/ && + touch aur.git/keys/xyz/x.asc && + git -C aur.git add keys/xyz/x.asc && + git -C aur.git commit -q -m "Add some nonsense" && + new=$(git -C aur.git rev-parse HEAD) && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: the keys/ subdir may only contain a pgp/ directory$" actual +' + +test_expect_success 'Pushing a tree with an allowed subdirectory with pgp keys; additional files' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir -p aur.git/keys/pgp/ && + touch aur.git/keys/pgp/x.asc && + touch aur.git/keys/nonsense && + git -C aur.git add keys/pgp/x.asc && + git -C aur.git add keys/nonsense && + git -C aur.git commit -q -m "Add pgp key" && + new=$(git -C aur.git rev-parse HEAD) && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: the keys/ subdir may only contain a pgp/ directory$" actual +' + +test_expect_success 'Pushing a tree with an allowed subdirectory with pgp keys; additional subdir' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir -p aur.git/keys/pgp/ && + mkdir -p aur.git/somedir/ && + touch aur.git/keys/pgp/x.asc && + touch aur.git/somedir/nonsense && + git -C aur.git add keys/pgp/x.asc && + git -C aur.git add somedir/nonsense && + git -C aur.git commit -q -m "Add pgp key" && + new=$(git -C aur.git rev-parse HEAD) && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: the repository must not contain subdirectories$" actual +' + +test_expect_success 'Pushing a tree with an allowed subdirectory with pgp keys; keys to large' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir -p aur.git/keys/pgp/ && + printf "%256001s" x > aur.git/keys/pgp/x.asc && + git -C aur.git add keys/pgp/x.asc && + git -C aur.git commit -q -m "Add pgp key" && + new=$(git -C aur.git rev-parse HEAD) && + test_must_fail \ + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && + grep -q "^error: maximum blob size (250.00KiB) exceeded$" actual +' + +test_expect_success 'Pushing a tree with an allowed subdirectory with pgp keys.' ' + old=$(git -C aur.git rev-parse HEAD) && + test_when_finished "git -C aur.git reset --hard $old" && + mkdir -p aur.git/keys/pgp/ && + touch aur.git/keys/pgp/x.asc && + git -C aur.git add keys/pgp/x.asc && + git -C aur.git commit -q -m "Add pgp key" && + new=$(git -C aur.git rev-parse HEAD) && + env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ + cover "$GIT_UPDATE" refs/heads/master "$old" "$new" 2>&1 +' + test_expect_success 'Pushing a tree with a large blob.' ' old=$(git -C aur.git rev-parse HEAD) && test_when_finished "git -C aur.git reset --hard $old" && From 58158505b06c1856420c22b1827f42eec450b477 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sun, 11 Jun 2023 21:04:35 +0200 Subject: [PATCH 055/178] fix: browser hints for password fields Co-authored-by: eNV25 Signed-off-by: moson-mo --- templates/partials/account_form.html | 6 +++--- templates/passreset.html | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/partials/account_form.html b/templates/partials/account_form.html index 4d135a56..28dc0cd5 100644 --- a/templates/partials/account_form.html +++ b/templates/partials/account_form.html @@ -246,7 +246,7 @@ -

    @@ -255,7 +255,7 @@ {% trans %}Re-type password{% endtrans %}: -

    @@ -333,7 +333,7 @@ -

    {% else %} diff --git a/templates/passreset.html b/templates/passreset.html index 6a31109f..08493fe9 100644 --- a/templates/passreset.html +++ b/templates/passreset.html @@ -26,14 +26,14 @@ {% trans %}Enter your new password:{% endtrans %} - {% trans %}Confirm your new password:{% endtrans %} - From 32461f28eaf786b34d9ee3a8a27d97ee1356228a Mon Sep 17 00:00:00 2001 From: moson-mo Date: Thu, 15 Jun 2023 14:16:38 +0200 Subject: [PATCH 056/178] fix(docker): Suppress error PEP-668 When using docker (compose), we don't create a venv and just install python packages system-wide. With python 3.11 (PEP 668) we need to explicitly tell pip to allow this. Signed-off-by: moson-mo --- docker/scripts/install-python-deps.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docker/scripts/install-python-deps.sh b/docker/scripts/install-python-deps.sh index 01a6eaa7..f1942498 100755 --- a/docker/scripts/install-python-deps.sh +++ b/docker/scripts/install-python-deps.sh @@ -1,10 +1,8 @@ #!/bin/bash set -eou pipefail -# Upgrade PIP; Arch Linux's version of pip is outdated for Poetry. -pip install --upgrade pip - if [ ! -z "${COMPOSE+x}" ]; then + export PIP_BREAK_SYSTEM_PACKAGES=1 poetry config virtualenvs.create false fi poetry install --no-interaction --no-ansi From c6c81f0789e72e2a99dd4474941344350dd246c9 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Fri, 16 Jun 2023 13:33:39 +0200 Subject: [PATCH 057/178] housekeep: Amend .gitignore and .dockerignore Prevent some files/dirs to end up in the repo / docker image: * directories typically used for python virtualenvs * files that are being generated by running tests Signed-off-by: moson-mo --- .dockerignore | 19 ++++++++++++++++++- .gitignore | 8 ++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/.dockerignore b/.dockerignore index 6ec5547d..56ac1964 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,23 @@ -*/*.mo +# Config files conf/config conf/config.sqlite conf/config.sqlite.defaults conf/docker conf/docker.defaults + +# Compiled translation files +**/*.mo + +# Typical virtualenv directories +env/ +venv/ +.venv/ + +# Test output +htmlcov/ +test-emails/ +test/__pycache__ +test/test-results +test/trash_directory* +.coverage +.pytest_cache diff --git a/.gitignore b/.gitignore index a3314c27..68de7cd5 100644 --- a/.gitignore +++ b/.gitignore @@ -24,7 +24,6 @@ conf/docker conf/docker.defaults data.sql dummy-data.sql* -env/ fastapi_aw/ htmlcov/ po/*.mo @@ -32,7 +31,7 @@ po/*.po~ po/POTFILES schema/aur-schema-sqlite.sql test/test-results/ -test/trash directory* +test/trash_directory* web/locale/*/ web/html/*.gz @@ -53,3 +52,8 @@ report.xml # Ignore test emails test-emails/ + +# Ignore typical virtualenv directories +env/ +venv/ +.venv/ From 143575c9dec9d1126e087dc451417b1910352ed2 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sun, 11 Jun 2023 20:31:51 +0200 Subject: [PATCH 058/178] fix: restore command, remove premature creation of pkgbase We're currently creating a "PackageBases" when the "restore" command is executed. This is problematic for pkgbases that never existed before. In those cases it will create the record but fail in the update.py script. Thus it leaves an orphan "PackageBases" record in the DB (which does not have any related "Packages" record(s)) Navigating to such a packages /pkgbase/... URL will result in a crash since it is not foreseen to have "orphan" pkgbase records. We can safely remove the early creation of that record because it'll be taken care of in the update.py script that is being called We'll also fix some tests. Before it was executing a dummy script instead of "update.py" which might be a bit misleading since it did not check the real outcome of our "restore" action. Signed-off-by: moson-mo --- aurweb/git/serve.py | 24 +++++------------------- test/setup.sh | 9 +-------- test/t1200-git-serve.t | 23 +++++++++++++++-------- 3 files changed, 21 insertions(+), 35 deletions(-) diff --git a/aurweb/git/serve.py b/aurweb/git/serve.py index 2ac1f10e..333d0394 100755 --- a/aurweb/git/serve.py +++ b/aurweb/git/serve.py @@ -52,7 +52,7 @@ def list_repos(user): conn.close() -def create_pkgbase(pkgbase, user): +def validate_pkgbase(pkgbase, user): if not re.match(repo_regex, pkgbase): raise aurweb.exceptions.InvalidRepositoryNameException(pkgbase) if pkgbase_exists(pkgbase): @@ -62,26 +62,12 @@ def create_pkgbase(pkgbase, user): cur = conn.execute("SELECT ID FROM Users WHERE Username = ?", [user]) userid = cur.fetchone()[0] + + conn.close() + if userid == 0: 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], - ) - pkgbase_id = cur.lastrowid - - cur = conn.execute( - "INSERT INTO PackageNotifications " + "(PackageBaseID, UserID) VALUES (?, ?)", - [pkgbase_id, userid], - ) - - conn.commit() - conn.close() - def pkgbase_adopt(pkgbase, user, privileged): pkgbase_id = pkgbase_from_name(pkgbase) @@ -577,7 +563,7 @@ def serve(action, cmdargv, user, privileged, remote_addr): # noqa: C901 checkarg(cmdargv, "repository name") pkgbase = cmdargv[1] - create_pkgbase(pkgbase, user) + validate_pkgbase(pkgbase, user) os.environ["AUR_USER"] = user os.environ["AUR_PKGBASE"] = pkgbase diff --git a/test/setup.sh b/test/setup.sh index 2db897bf..ccf24086 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -56,7 +56,7 @@ ssh-options = restrict repo-path = ./aur.git/ repo-regex = [a-z0-9][a-z0-9.+_-]*$ git-shell-cmd = ./git-shell.sh -git-update-cmd = ./update.sh +git-update-cmd = $GIT_UPDATE ssh-cmdline = ssh aur@aur.archlinux.org [update] @@ -90,13 +90,6 @@ echo $GIT_NAMESPACE EOF chmod +x git-shell.sh -cat >update.sh <<-\EOF -#!/bin/sh -echo $AUR_USER -echo $AUR_PKGBASE -EOF -chmod +x update.sh - AUR_CONFIG=config export AUR_CONFIG diff --git a/test/t1200-git-serve.t b/test/t1200-git-serve.t index dbb465bc..bb3a004f 100755 --- a/test/t1200-git-serve.t +++ b/test/t1200-git-serve.t @@ -137,14 +137,21 @@ test_expect_success "Try to push to someone else's repository as Trusted User." ' test_expect_success "Test restore." ' + # Delete from DB echo "DELETE FROM PackageBases WHERE Name = '"'"'foobar'"'"';" | \ sqlite3 aur.db && - cat >expected <<-EOF && - user - foobar - EOF + # "Create branch" as if it had been there + new=$(git -C aur.git rev-parse HEAD^) && + echo $new > aur.git/.git/refs/heads/foobar && + # Restore deleted package SSH_ORIGINAL_COMMAND="restore foobar" AUR_USER=user AUR_PRIVILEGED=0 \ - cover "$GIT_SERVE" 2>&1 >actual + cover "$GIT_SERVE" 2>&1 && + # We should find foobar with a new ID (3) in the DB after restore + echo "SELECT ID FROM PackageBases WHERE Name = '"'"'foobar'"'"';" | \ + sqlite3 aur.db >actual && + cat >expected <<-EOF && + 3 + EOF test_cmp expected actual ' @@ -174,7 +181,7 @@ test_expect_success "Adopt a package base as a regular user." ' SSH_ORIGINAL_COMMAND="adopt foobar" AUR_USER=user AUR_PRIVILEGED=0 \ cover "$GIT_SERVE" 2>&1 && cat >expected <<-EOF && - *foobar + foobar EOF SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=user AUR_PRIVILEGED=0 \ cover "$GIT_SERVE" 2>&1 >actual && @@ -252,7 +259,7 @@ test_expect_success "Try to steal another user's package as a Trusted User." ' cover "$GIT_SERVE" 2>&1 >actual && test_cmp expected actual && cat >expected <<-EOF && - *foobar + foobar EOF SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=tu AUR_PRIVILEGED=1 \ cover "$GIT_SERVE" 2>&1 >actual && @@ -340,7 +347,7 @@ test_expect_success "Disown a package base and check (co-)maintainer list." ' SSH_ORIGINAL_COMMAND="disown foobar" AUR_USER=user AUR_PRIVILEGED=0 \ cover "$GIT_SERVE" 2>&1 && cat >expected <<-EOF && - *foobar + foobar EOF SSH_ORIGINAL_COMMAND="list-repos" AUR_USER=user2 AUR_PRIVILEGED=0 \ cover "$GIT_SERVE" 2>&1 >actual && From e2c113caee0f42584d1a25644423a5d9455ffde0 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Thu, 22 Jun 2023 19:22:56 +0100 Subject: [PATCH 059/178] chore(release): prepare for 6.2.5 Signed-off-by: Leonidas Spyropoulos --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e25fe90a..69f04fab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ combine_as_imports = true # [tool.poetry] name = "aurweb" -version = "v6.2.4" +version = "v6.2.5" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From c41f2e854a1aeb4aab963a3756cf0768374a742b Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sun, 2 Jul 2023 13:21:11 +0200 Subject: [PATCH 060/178] perf: tweak some search queries We currently sorting on two columns in different tables which is quite expensive in terms of performance: MariaDB is first merging the data into some temporary table to apply the sorting and record limiting. We can tweak a couple of these queries by changing the "order by" clause such that they refer to columns within the same table (PackageBases). So instead performing the second sorting on "Packages.Name", we do this on "PackageBases.Name" instead. This should still be "good enough" to produce properly sorted results. Signed-off-by: moson-mo --- aurweb/packages/search.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aurweb/packages/search.py b/aurweb/packages/search.py index 62de1ea8..78b27a9a 100644 --- a/aurweb/packages/search.py +++ b/aurweb/packages/search.py @@ -195,13 +195,13 @@ class PackageSearch: def _sort_by_votes(self, order: str): column = getattr(models.PackageBase.NumVotes, order) - name = getattr(models.Package.Name, order) + name = getattr(models.PackageBase.Name, order) self.query = self.query.order_by(column(), name()) return self def _sort_by_popularity(self, order: str): column = getattr(models.PackageBase.Popularity, order) - name = getattr(models.Package.Name, order) + name = getattr(models.PackageBase.Name, order) self.query = self.query.order_by(column(), name()) return self @@ -236,7 +236,7 @@ class PackageSearch: def _sort_by_last_modified(self, order: str): column = getattr(models.PackageBase.ModifiedTS, order) - name = getattr(models.Package.Name, order) + name = getattr(models.PackageBase.Name, order) self.query = self.query.order_by(column(), name()) return self From 7c8b9ba6bcacfe45e416ec37cf16fa1824659825 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sun, 2 Jul 2023 13:55:21 +0200 Subject: [PATCH 061/178] perf: add index to tweak our default search query Adds an index on PackageBases.Popularity and PackageBases.Name to improve performance of our default search query sorted by "Popularity" Signed-off-by: moson-mo --- ...0_add_index_on_packagebases_popularity_.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 migrations/versions/c5a6a9b661a0_add_index_on_packagebases_popularity_.py diff --git a/migrations/versions/c5a6a9b661a0_add_index_on_packagebases_popularity_.py b/migrations/versions/c5a6a9b661a0_add_index_on_packagebases_popularity_.py new file mode 100644 index 00000000..12f97028 --- /dev/null +++ b/migrations/versions/c5a6a9b661a0_add_index_on_packagebases_popularity_.py @@ -0,0 +1,24 @@ +"""Add index on PackageBases.Popularity and .Name + +Revision ID: c5a6a9b661a0 +Revises: e4e49ffce091 +Create Date: 2023-07-02 13:46:52.522146 + +""" +from alembic import op + +# revision identifiers, used by Alembic. +revision = "c5a6a9b661a0" +down_revision = "e4e49ffce091" +branch_labels = None +depends_on = None + + +def upgrade(): + op.create_index( + "BasesPopularityName", "PackageBases", ["Popularity", "Name"], unique=False + ) + + +def downgrade(): + op.drop_index("BasesPopularityName", table_name="PackageBases") From 3acfb08a0f839ce3582d9ce92c01e321e99e69f3 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sun, 2 Jul 2023 01:06:34 +0200 Subject: [PATCH 062/178] feat: cache package search results with Redis The queries being done on the package search page are quite costly. (Especially the default one ordered by "Popularity" when navigating to /packages) Let's add the search results to the Redis cache: Every result of a search query is being pushed to Redis until we hit our maximum of 50k. An entry expires after 3 minutes before it's evicted from the cache. Lifetime an Max values are configurable. Signed-off-by: moson-mo --- aurweb/cache.py | 38 ++++++++--- aurweb/routers/html.py | 20 +++--- aurweb/routers/packages.py | 15 ++++- aurweb/util.py | 8 +++ conf/config.defaults | 6 ++ test/test_cache.py | 121 ++++++++++++++++++++--------------- test/test_packages_routes.py | 13 +++- test/test_util.py | 26 +++++++- 8 files changed, 173 insertions(+), 74 deletions(-) diff --git a/aurweb/cache.py b/aurweb/cache.py index 1572e2fc..56bb45b7 100644 --- a/aurweb/cache.py +++ b/aurweb/cache.py @@ -1,21 +1,43 @@ -from redis import Redis +import pickle + from sqlalchemy import orm +from aurweb import config +from aurweb.aur_redis import redis_connection -async def db_count_cache( - redis: Redis, key: str, query: orm.Query, expire: int = None -) -> int: +_redis = redis_connection() + + +async def db_count_cache(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 :param query: SQLAlchemy ORM query :param expire: Optional expiration in seconds :return: query.count() """ - result = redis.get(key) + result = _redis.get(key) if result is None: - redis.set(key, (result := int(query.count()))) + _redis.set(key, (result := int(query.count()))) if expire: - redis.expire(key, expire) + _redis.expire(key, expire) return int(result) + + +async def db_query_cache(key: str, query: orm.Query, expire: int = None): + """Store and retrieve query results via redis cache. + + :param key: Redis key + :param query: SQLAlchemy ORM query + :param expire: Optional expiration in seconds + :return: query.all() + """ + result = _redis.get(key) + if result is None: + if _redis.dbsize() > config.getint("cache", "max_search_entries", 50000): + return query.all() + _redis.set(key, (result := pickle.dumps(query.all())), ex=expire) + if expire: + _redis.expire(key, expire) + + return pickle.loads(result) diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index 38303837..fc9f3519 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -89,22 +89,20 @@ async def index(request: Request): bases = db.query(models.PackageBase) - redis = aurweb.aur_redis.redis_connection() - cache_expire = 300 # Five minutes. - + cache_expire = aurweb.config.getint("cache", "expiry_time") # Package statistics. context["package_count"] = await db_count_cache( - redis, "package_count", bases, expire=cache_expire + "package_count", bases, expire=cache_expire ) query = bases.filter(models.PackageBase.MaintainerUID.is_(None)) context["orphan_count"] = await db_count_cache( - redis, "orphan_count", query, expire=cache_expire + "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 + "user_count", query, expire=cache_expire ) query = query.filter( @@ -114,7 +112,7 @@ async def index(request: Request): ) ) context["trusted_user_count"] = await db_count_cache( - redis, "trusted_user_count", query, expire=cache_expire + "trusted_user_count", query, expire=cache_expire ) # Current timestamp. @@ -130,26 +128,26 @@ async def index(request: Request): query = bases.filter(models.PackageBase.SubmittedTS >= seven_days_ago) context["seven_days_old_added"] = await db_count_cache( - redis, "seven_days_old_added", query, expire=cache_expire + "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 + "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 + "year_old_updated", query, expire=cache_expire ) query = bases.filter( models.PackageBase.ModifiedTS - models.PackageBase.SubmittedTS < 3600 ) context["never_updated"] = await db_count_cache( - redis, "never_updated", query, expire=cache_expire + "never_updated", query, expire=cache_expire ) # Get the 15 most recently updated packages. diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 83bfe6e2..779efb4b 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -7,6 +7,7 @@ from fastapi import APIRouter, Form, Query, Request, Response import aurweb.filters # noqa: F401 from aurweb import aur_logging, config, db, defaults, models, util from aurweb.auth import creds, requires_auth +from aurweb.cache import db_count_cache, db_query_cache from aurweb.exceptions import InvariantError, handle_form_exceptions from aurweb.models.relation_type import CONFLICTS_ID, PROVIDES_ID, REPLACES_ID from aurweb.packages import util as pkgutil @@ -14,6 +15,7 @@ from aurweb.packages.search import PackageSearch from aurweb.packages.util import get_pkg_or_base from aurweb.pkgbase import actions as pkgbase_actions, util as pkgbaseutil from aurweb.templates import make_context, make_variable_context, render_template +from aurweb.util import hash_query logger = aur_logging.get_logger(__name__) router = APIRouter() @@ -87,7 +89,11 @@ async def packages_get( # Collect search result count here; we've applied our keywords. # Including more query operations below, like ordering, will # increase the amount of time required to collect a count. - num_packages = search.count() + # we use redis for caching the results of the query + cache_expire = config.getint("cache", "expiry_time") + num_packages = await db_count_cache( + hash_query(search.query), search.query, cache_expire + ) # Apply user-specified sort column and ordering. search.sort_by(sort_by, sort_order) @@ -108,7 +114,12 @@ async def packages_get( models.PackageNotification.PackageBaseID.label("Notify"), ) - packages = results.limit(per_page).offset(offset) + # paging + results = results.limit(per_page).offset(offset) + + # we use redis for caching the results of the query + packages = await db_query_cache(hash_query(results), results, cache_expire) + context["packages"] = packages context["packages_count"] = num_packages diff --git a/aurweb/util.py b/aurweb/util.py index d80b0311..7050b482 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -4,6 +4,7 @@ import secrets import shlex import string from datetime import datetime +from hashlib import sha1 from http import HTTPStatus from subprocess import PIPE, Popen from typing import Callable, Iterable, Tuple, Union @@ -13,6 +14,7 @@ import fastapi import pygit2 from email_validator import EmailSyntaxError, validate_email from fastapi.responses import JSONResponse +from sqlalchemy.orm import Query import aurweb.config from aurweb import aur_logging, defaults @@ -200,3 +202,9 @@ def shell_exec(cmdline: str, cwd: str) -> Tuple[int, str, str]: proc = Popen(args, cwd=cwd, stdout=PIPE, stderr=PIPE) out, err = proc.communicate() return proc.returncode, out.decode().strip(), err.decode().strip() + + +def hash_query(query: Query): + return sha1( + str(query.statement.compile(compile_kwargs={"literal_binds": True})).encode() + ).hexdigest() diff --git a/conf/config.defaults b/conf/config.defaults index c059444d..4e2415ed 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -165,3 +165,9 @@ commit_url = https://gitlab.archlinux.org/archlinux/aurweb/-/commits/%s ; voted on based on `now + range_start <= End <= now + range_end`. range_start = 500 range_end = 172800 + +[cache] +; maximum number of keys/entries (for search results) in our redis cache, default is 50000 +max_search_entries = 50000 +; number of seconds after a cache entry expires, default is 3 minutes +expiry_time = 180 diff --git a/test/test_cache.py b/test/test_cache.py index 83a9755a..e19fa6a2 100644 --- a/test/test_cache.py +++ b/test/test_cache.py @@ -1,6 +1,8 @@ +from unittest import mock + import pytest -from aurweb import cache, db +from aurweb import cache, config, db from aurweb.models.account_type import USER_ID from aurweb.models.user import User @@ -10,68 +12,85 @@ def setup(db_test): return -class StubRedis: - """A class which acts as a RedisConnection without using Redis.""" - - cache = dict() - expires = dict() - - def get(self, key, *args): - if "key" not in self.cache: - self.cache[key] = None - return self.cache[key] - - def set(self, key, *args): - self.cache[key] = list(args)[0] - - def expire(self, key, *args): - self.expires[key] = list(args)[0] - - async def execute(self, command, key, *args): - f = getattr(self, command) - return f(key, *args) - - @pytest.fixture -def redis(): - yield StubRedis() +def user() -> User: + with db.begin(): + user = db.create( + User, + Username="test", + Email="test@example.org", + RealName="Test User", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) + yield user + + +@pytest.fixture(autouse=True) +def clear_fakeredis_cache(): + cache._redis.flushall() @pytest.mark.asyncio -async def test_db_count_cache(redis): - db.create( - User, - Username="user1", - Email="user1@example.org", - Passwd="testPassword", - AccountTypeID=USER_ID, - ) - +async def test_db_count_cache(user): query = db.query(User) - # Now, perform several checks that db_count_cache matches query.count(). - # We have no cached value yet. - assert await cache.db_count_cache(redis, "key1", query) == query.count() + assert cache._redis.get("key1") is None + + # Add to cache + assert await cache.db_count_cache("key1", query) == query.count() # It's cached now. - assert await cache.db_count_cache(redis, "key1", query) == query.count() + assert cache._redis.get("key1") is not None + + # It does not expire + assert cache._redis.ttl("key1") == -1 + + # Cache a query with an expire. + value = await cache.db_count_cache("key2", query, 100) + assert value == query.count() + + assert cache._redis.ttl("key2") == 100 @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, - ) - +async def test_db_query_cache(user): query = db.query(User) - # Cache a query with an expire. - value = await cache.db_count_cache(redis, "key1", query, 100) - assert value == query.count() + # We have no cached value yet. + assert cache._redis.get("key1") is None - assert redis.expires["key1"] == 100 + # Add to cache + await cache.db_query_cache("key1", query) + + # It's cached now. + assert cache._redis.get("key1") is not None + + # Modify our user and make sure we got a cached value + user.Username = "changed" + cached = await cache.db_query_cache("key1", query) + assert cached[0].Username != query.all()[0].Username + + # It does not expire + assert cache._redis.ttl("key1") == -1 + + # Cache a query with an expire. + value = await cache.db_query_cache("key2", query, 100) + assert len(value) == query.count() + assert value[0].Username == query.all()[0].Username + + assert cache._redis.ttl("key2") == 100 + + # Test "max_search_entries" options + def mock_max_search_entries(section: str, key: str, fallback: int) -> str: + if section == "cache" and key == "max_search_entries": + return 1 + return config.getint(section, key) + + with mock.patch("aurweb.config.getint", side_effect=mock_max_search_entries): + # Try to add another entry (we already have 2) + await cache.db_query_cache("key3", query) + + # Make sure it was not added because it exceeds our max. + assert cache._redis.get("key3") is None diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index 93dc404a..fb12e65e 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -5,7 +5,7 @@ from unittest import mock import pytest from fastapi.testclient import TestClient -from aurweb import asgi, config, db, time +from aurweb import asgi, cache, config, db, time from aurweb.filters import datetime_display from aurweb.models import License, PackageLicense from aurweb.models.account_type import USER_ID, AccountType @@ -63,6 +63,11 @@ def setup(db_test): return +@pytest.fixture(autouse=True) +def clear_fakeredis_cache(): + cache._redis.flushall() + + @pytest.fixture def client() -> TestClient: """Yield a FastAPI TestClient.""" @@ -815,6 +820,8 @@ def test_packages_search_by_keywords(client: TestClient, packages: list[Package] # And request packages with that keyword, we should get 1 result. with client as request: + # clear fakeredis cache + cache._redis.flushall() response = request.get("/packages", params={"SeB": "k", "K": "testKeyword"}) assert response.status_code == int(HTTPStatus.OK) @@ -870,6 +877,8 @@ def test_packages_search_by_maintainer( # This time, we should get `package` returned, since it's now an orphan. with client as request: + # clear fakeredis cache + cache._redis.flushall() response = request.get("/packages", params={"SeB": "m"}) assert response.status_code == int(HTTPStatus.OK) root = parse_root(response.text) @@ -902,6 +911,8 @@ def test_packages_search_by_comaintainer( # Then test that it's returned by our search. with client as request: + # clear fakeredis cache + cache._redis.flushall() response = request.get( "/packages", params={"SeB": "c", "K": maintainer.Username} ) diff --git a/test/test_util.py b/test/test_util.py index a138d912..042b9ad9 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -5,7 +5,8 @@ import fastapi import pytest from fastapi.responses import JSONResponse -from aurweb import filters, util +from aurweb import db, filters, util +from aurweb.models.user import User from aurweb.testing.requests import Request @@ -146,3 +147,26 @@ def assert_multiple_keys(pks): assert key1 == k1[1] assert pfx2 == k2[0] assert key2 == k2[1] + + +def test_hash_query(): + # No conditions + query = db.query(User) + assert util.hash_query(query) == "75e76026b7d576536e745ec22892cf8f5d7b5d62" + + # With where clause + query = db.query(User).filter(User.Username == "bla") + assert util.hash_query(query) == "4dca710f33b1344c27ec6a3c266970f4fa6a8a00" + + # With where clause and sorting + query = db.query(User).filter(User.Username == "bla").order_by(User.Username) + assert util.hash_query(query) == "ee2c7846fede430776e140f8dfe1d83cd21d2eed" + + # With where clause, sorting and specific columns + query = ( + db.query(User) + .filter(User.Username == "bla") + .order_by(User.Username) + .with_entities(User.Username) + ) + assert util.hash_query(query) == "c1db751be61443d266cf643005eee7a884dac103" From 814ccf6b04e97659c30ecc18dd63607a3ba485e6 Mon Sep 17 00:00:00 2001 From: moson-mo Date: Tue, 4 Jul 2023 09:40:39 +0200 Subject: [PATCH 063/178] feat: add Prometheus metrics for Redis cache Adding a Prometheus counter to be able to monitor cache hits/misses for search queries Signed-off-by: moson-mo --- aurweb/cache.py | 13 +++++++++++-- test/test_metrics.py | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 test/test_metrics.py diff --git a/aurweb/cache.py b/aurweb/cache.py index 56bb45b7..fe1e5f1d 100644 --- a/aurweb/cache.py +++ b/aurweb/cache.py @@ -1,5 +1,6 @@ import pickle +from prometheus_client import Counter from sqlalchemy import orm from aurweb import config @@ -7,6 +8,11 @@ from aurweb.aur_redis import redis_connection _redis = redis_connection() +# Prometheus metrics +SEARCH_REQUESTS = Counter( + "search_requests", "Number of search requests by cache hit/miss", ["cache"] +) + async def db_count_cache(key: str, query: orm.Query, expire: int = None) -> int: """Store and retrieve a query.count() via redis cache. @@ -24,7 +30,7 @@ async def db_count_cache(key: str, query: orm.Query, expire: int = None) -> int: return int(result) -async def db_query_cache(key: str, query: orm.Query, expire: int = None): +async def db_query_cache(key: str, query: orm.Query, expire: int = None) -> list: """Store and retrieve query results via redis cache. :param key: Redis key @@ -34,10 +40,13 @@ async def db_query_cache(key: str, query: orm.Query, expire: int = None): """ result = _redis.get(key) if result is None: + SEARCH_REQUESTS.labels(cache="miss").inc() if _redis.dbsize() > config.getint("cache", "max_search_entries", 50000): return query.all() - _redis.set(key, (result := pickle.dumps(query.all())), ex=expire) + _redis.set(key, (result := pickle.dumps(query.all()))) if expire: _redis.expire(key, expire) + else: + SEARCH_REQUESTS.labels(cache="hit").inc() return pickle.loads(result) diff --git a/test/test_metrics.py b/test/test_metrics.py new file mode 100644 index 00000000..1859d8cb --- /dev/null +++ b/test/test_metrics.py @@ -0,0 +1,40 @@ +import pytest +from prometheus_client import REGISTRY, generate_latest + +from aurweb import db +from aurweb.cache import db_query_cache +from aurweb.models.account_type import USER_ID +from aurweb.models.user import User + + +@pytest.fixture(autouse=True) +def setup(db_test): + return + + +@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, + ) + yield user + + +@pytest.mark.asyncio +async def test_search_cache_metrics(user: User): + # Fire off 3 identical queries for caching + for _ in range(3): + await db_query_cache("key", db.query(User)) + + # Get metrics + metrics = str(generate_latest(REGISTRY)) + + # We should have 1 miss and 2 hits + assert 'search_requests_total{cache="miss"} 1.0' in metrics + assert 'search_requests_total{cache="hit"} 2.0' in metrics From 9fe8d524ffabcbd171cbadbbe9b42edc1f5fa91d Mon Sep 17 00:00:00 2001 From: moson Date: Sat, 8 Jul 2023 10:32:26 +0200 Subject: [PATCH 064/178] fix(test): MariaDB 11 upgrade, query result order Fix order of recipients for "FlagNotification" test. Apply sorting to the recipients query. (only relevant for tests, but who knows when they change things again) MariaDB 11 includes some changes related to the query optimizer. Turns out that this might have effects on how records are ordered for certain queries. (in case no ORDER BY clause was specified) https://mariadb.com/kb/en/mariadb-11-0-0-release-notes/ Signed-off-by: moson --- aurweb/scripts/notify.py | 1 + test/test_notify.py | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index ac9022c3..f55254d7 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -334,6 +334,7 @@ class FlagNotification(Notification): .filter(and_(PackageBase.ID == pkgbase_id, User.Suspended == 0)) .with_entities(User.Email, User.LangPreference) .distinct() + .order_by(User.Email) ) self._recipients = [(u.Email, u.LangPreference) for u in query] diff --git a/test/test_notify.py b/test/test_notify.py index 9e61d9ee..1fd7cd83 100644 --- a/test/test_notify.py +++ b/test/test_notify.py @@ -127,20 +127,20 @@ def test_out_of_date(user: User, user1: User, user2: User, pkgbases: list[Packag # Should've gotten three emails: maintainer + the two comaintainers. assert Email.count() == 3 - # Comaintainer 1. + # Maintainer. first = Email(1).parse() - assert first.headers.get("To") == user1.Email + assert first.headers.get("To") == user.Email expected = f"AUR Out-of-date Notification for {pkgbase.Name}" assert first.headers.get("Subject") == expected - # Comaintainer 2. + # Comaintainer 1. second = Email(2).parse() - assert second.headers.get("To") == user2.Email + assert second.headers.get("To") == user1.Email - # Maintainer. + # Comaintainer 2. third = Email(3).parse() - assert third.headers.get("To") == user.Email + assert third.headers.get("To") == user2.Email def test_reset(user: User): From f3f8c0a8710838ba176f4486eb886ce37565b78a Mon Sep 17 00:00:00 2001 From: moson-mo Date: Sat, 1 Jul 2023 12:55:14 +0200 Subject: [PATCH 065/178] fix: add recipients to BCC when email is hidden Package requests are sent to the ML as well as users (CC). For those who chose to hide their mail address, we should add them to the BCC list instead. Signed-off-by: moson-mo --- aurweb/scripts/notify.py | 21 +++++++++++---- po/aurweb.pot | 8 ++++++ templates/partials/account_form.html | 7 ++++- test/test_notify.py | 38 ++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index f55254d7..a85339ce 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -45,6 +45,9 @@ class Notification: def get_cc(self): return [] + def get_bcc(self): + return [] + def get_body_fmt(self, lang): body = "" for line in self.get_body(lang).splitlines(): @@ -114,7 +117,7 @@ class Notification: server.login(user, passwd) server.set_debuglevel(0) - deliver_to = [to] + self.get_cc() + deliver_to = [to] + self.get_cc() + self.get_bcc() server.sendmail(sender, deliver_to, msg.as_bytes()) server.quit() @@ -578,10 +581,11 @@ class RequestOpenNotification(Notification): ), ) .filter(and_(PackageRequest.ID == reqid, User.Suspended == 0)) - .with_entities(User.Email) + .with_entities(User.Email, User.HideEmail) .distinct() ) - self._cc = [u.Email for u in query] + self._cc = [u.Email for u in query if u.HideEmail == 0] + self._bcc = [u.Email for u in query if u.HideEmail == 1] pkgreq = ( db.query(PackageRequest.Comments).filter(PackageRequest.ID == reqid).first() @@ -598,6 +602,9 @@ class RequestOpenNotification(Notification): def get_cc(self): return self._cc + def get_bcc(self): + return self._bcc + def get_subject(self, lang): return "[PRQ#%d] %s Request for %s" % ( self._reqid, @@ -665,10 +672,11 @@ class RequestCloseNotification(Notification): ), ) .filter(and_(PackageRequest.ID == reqid, User.Suspended == 0)) - .with_entities(User.Email) + .with_entities(User.Email, User.HideEmail) .distinct() ) - self._cc = [u.Email for u in query] + self._cc = [u.Email for u in query if u.HideEmail == 0] + self._bcc = [u.Email for u in query if u.HideEmail == 1] pkgreq = ( db.query(PackageRequest) @@ -695,6 +703,9 @@ class RequestCloseNotification(Notification): def get_cc(self): return self._cc + def get_bcc(self): + return self._bcc + def get_subject(self, lang): return "[PRQ#%d] %s Request for %s %s" % ( self._reqid, diff --git a/po/aurweb.pot b/po/aurweb.pot index b975ab91..77bca3b0 100644 --- a/po/aurweb.pot +++ b/po/aurweb.pot @@ -2366,3 +2366,11 @@ msgstr "" #: templates/requests.html msgid "Package name" msgstr "" + +#: templates/partials/account_form.html +msgid "Note that if you hide your email address, it'll " +"end up on the BCC list for any request notifications. " +"In case someone replies to these notifications, you won't " +"receive an email. However, replies are typically sent to the " +"mailing-list and would then be visible in the archive." +msgstr "" diff --git a/templates/partials/account_form.html b/templates/partials/account_form.html index 28dc0cd5..7595dcaf 100644 --- a/templates/partials/account_form.html +++ b/templates/partials/account_form.html @@ -115,7 +115,12 @@ {{ "If you do not hide your email address, it is " "visible to all registered AUR users. If you hide your " "email address, it is visible to members of the Arch " - "Linux staff only." | tr }} + "Linux staff only." | tr }}
    + {{ "Note that if you hide your email address, it'll " + "end up on the BCC list for any request notifications. " + "In case someone replies to these notifications, you won't " + "receive an email. However, replies are typically sent to the " + "mailing-list and would then be visible in the archive." | tr }}

    diff --git a/test/test_notify.py b/test/test_notify.py index 1fd7cd83..fbcf350b 100644 --- a/test/test_notify.py +++ b/test/test_notify.py @@ -479,6 +479,44 @@ def test_close_request_comaintainer_cc( assert email.headers.get("Cc") == ", ".join([user.Email, user2.Email]) +def test_open_close_request_hidden_email( + user2: User, pkgreq: PackageRequest, pkgbases: list[PackageBase] +): + pkgbase = pkgbases[0] + + # Enable the "HideEmail" option for our requester + with db.begin(): + user2.HideEmail = 1 + + # Send an open request notification. + notif = notify.RequestOpenNotification( + user2.ID, pkgreq.ID, pkgreq.RequestType.Name, pkgbase.ID + ) + + # Make sure our address got added to the bcc list + assert user2.Email in notif.get_bcc() + + notif.send() + assert Email.count() == 1 + + email = Email(1).parse() + # Make sure we don't have our address in the Cc header + assert user2.Email not in email.headers.get("Cc") + + # Create a closure notification on the pkgbase we just opened. + notif = notify.RequestCloseNotification(user2.ID, pkgreq.ID, "rejected") + + # Make sure our address got added to the bcc list + assert user2.Email in notif.get_bcc() + + notif.send() + assert Email.count() == 2 + + email = Email(2).parse() + # Make sure we don't have our address in the Cc header + assert user2.Email not in email.headers.get("Cc") + + def test_close_request_closure_comment( user: User, user2: User, pkgreq: PackageRequest, pkgbases: list[PackageBase] ): From 7cde1ca56041afb9aa00d2d0c46bfd10c2291080 Mon Sep 17 00:00:00 2001 From: renovate Date: Sat, 8 Jul 2023 09:25:09 +0000 Subject: [PATCH 066/178] fix(deps): update all non-major dependencies --- poetry.lock | 622 +++++++++++++++++++++++++++------------------------- 1 file changed, 321 insertions(+), 301 deletions(-) diff --git a/poetry.lock b/poetry.lock index 16b0f15a..dcdcf819 100644 --- a/poetry.lock +++ b/poetry.lock @@ -55,14 +55,14 @@ trio = ["trio (>=0.16,<0.22)"] [[package]] name = "asgiref" -version = "3.7.1" +version = "3.7.2" description = "ASGI specs, helper code, and adapters" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "asgiref-3.7.1-py3-none-any.whl", hash = "sha256:33958cb2e4b3cd8b1b06ef295bd8605cde65b11df51d3beab39e2e149a610ab3"}, - {file = "asgiref-3.7.1.tar.gz", hash = "sha256:8de379fcc383bcfe4507e229fc31209ea23d4831c850f74063b2c11639474dd2"}, + {file = "asgiref-3.7.2-py3-none-any.whl", hash = "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e"}, + {file = "asgiref-3.7.2.tar.gz", hash = "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed"}, ] [package.dependencies] @@ -85,14 +85,14 @@ files = [ [[package]] name = "authlib" -version = "1.2.0" +version = "1.2.1" description = "The ultimate Python library in building OAuth and OpenID Connect servers and clients." category = "main" optional = false python-versions = "*" files = [ - {file = "Authlib-1.2.0-py2.py3-none-any.whl", hash = "sha256:4ddf4fd6cfa75c9a460b361d4bd9dac71ffda0be879dbe4292a02e92349ad55a"}, - {file = "Authlib-1.2.0.tar.gz", hash = "sha256:4fa3e80883a5915ef9f5bc28630564bc4ed5b5af39812a3ff130ec76bd631e9d"}, + {file = "Authlib-1.2.1-py2.py3-none-any.whl", hash = "sha256:c88984ea00149a90e3537c964327da930779afa4564e354edfd98410bea01911"}, + {file = "Authlib-1.2.1.tar.gz", hash = "sha256:421f7c6b468d907ca2d9afede256f068f87e34d23dd221c07d13d4c234726afb"}, ] [package.dependencies] @@ -355,63 +355,72 @@ files = [ [[package]] name = "coverage" -version = "7.2.6" +version = "7.2.7" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "coverage-7.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:496b86f1fc9c81a1cd53d8842ef712e950a4611bba0c42d33366a7b91ba969ec"}, - {file = "coverage-7.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fbe6e8c0a9a7193ba10ee52977d4d5e7652957c1f56ccefed0701db8801a2a3b"}, - {file = "coverage-7.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d06b721c2550c01a60e5d3093f417168658fb454e5dfd9a23570e9bffe39a1"}, - {file = "coverage-7.2.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:77a04b84d01f0e12c66f16e69e92616442dc675bbe51b90bfb074b1e5d1c7fbd"}, - {file = "coverage-7.2.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35db06450272473eab4449e9c2ad9bc6a0a68dab8e81a0eae6b50d9c2838767e"}, - {file = "coverage-7.2.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6727a0d929ff0028b1ed8b3e7f8701670b1d7032f219110b55476bb60c390bfb"}, - {file = "coverage-7.2.6-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aac1d5fdc5378f6bac2c0c7ebe7635a6809f5b4376f6cf5d43243c1917a67087"}, - {file = "coverage-7.2.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1c9e4a5eb1bbc3675ee57bc31f8eea4cd7fb0cbcbe4912cf1cb2bf3b754f4a80"}, - {file = "coverage-7.2.6-cp310-cp310-win32.whl", hash = "sha256:71f739f97f5f80627f1fee2331e63261355fd1e9a9cce0016394b6707ac3f4ec"}, - {file = "coverage-7.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:fde5c7a9d9864d3e07992f66767a9817f24324f354caa3d8129735a3dc74f126"}, - {file = "coverage-7.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bc7b667f8654376e9353dd93e55e12ce2a59fb6d8e29fce40de682273425e044"}, - {file = "coverage-7.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:697f4742aa3f26c107ddcb2b1784a74fe40180014edbd9adaa574eac0529914c"}, - {file = "coverage-7.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:541280dde49ce74a4262c5e395b48ea1207e78454788887118c421cb4ffbfcac"}, - {file = "coverage-7.2.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e7f1a8328eeec34c54f1d5968a708b50fc38d31e62ca8b0560e84a968fbf9a9"}, - {file = "coverage-7.2.6-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4bbd58eb5a2371bf160590f4262109f66b6043b0b991930693134cb617bc0169"}, - {file = "coverage-7.2.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ae82c5f168d2a39a5d69a12a69d4dc23837a43cf2ca99be60dfe59996ea6b113"}, - {file = "coverage-7.2.6-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f5440cdaf3099e7ab17a5a7065aed59aff8c8b079597b61c1f8be6f32fe60636"}, - {file = "coverage-7.2.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a6f03f87fea579d55e0b690d28f5042ec1368650466520fbc400e7aeaf09e995"}, - {file = "coverage-7.2.6-cp311-cp311-win32.whl", hash = "sha256:dc4d5187ef4d53e0d4c8eaf530233685667844c5fb0b855fea71ae659017854b"}, - {file = "coverage-7.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:c93d52c3dc7b9c65e39473704988602300e3cc1bad08b5ab5b03ca98bbbc68c1"}, - {file = "coverage-7.2.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:42c692b55a647a832025a4c048007034fe77b162b566ad537ce65ad824b12a84"}, - {file = "coverage-7.2.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7786b2fa7809bf835f830779ad285215a04da76293164bb6745796873f0942d"}, - {file = "coverage-7.2.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25bad4196104761bc26b1dae9b57383826542ec689ff0042f7f4f4dd7a815cba"}, - {file = "coverage-7.2.6-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2692306d3d4cb32d2cceed1e47cebd6b1d2565c993d6d2eda8e6e6adf53301e6"}, - {file = "coverage-7.2.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:392154d09bd4473b9d11351ab5d63391f3d5d24d752f27b3be7498b0ee2b5226"}, - {file = "coverage-7.2.6-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:fa079995432037b5e2ef5ddbb270bcd2ded9f52b8e191a5de11fe59a00ea30d8"}, - {file = "coverage-7.2.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d712cefff15c712329113b01088ba71bbcef0f7ea58478ca0bbec63a824844cb"}, - {file = "coverage-7.2.6-cp37-cp37m-win32.whl", hash = "sha256:004948e296149644d208964300cb3d98affc5211e9e490e9979af4030b0d6473"}, - {file = "coverage-7.2.6-cp37-cp37m-win_amd64.whl", hash = "sha256:c1d7a31603c3483ac49c1726723b0934f88f2c011c660e6471e7bd735c2fa110"}, - {file = "coverage-7.2.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3436927d1794fa6763b89b60c896f9e3bd53212001026ebc9080d23f0c2733c1"}, - {file = "coverage-7.2.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44c9b9f1a245f3d0d202b1a8fa666a80b5ecbe4ad5d0859c0fb16a52d9763224"}, - {file = "coverage-7.2.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e3783a286d5a93a2921396d50ce45a909aa8f13eee964465012f110f0cbb611"}, - {file = "coverage-7.2.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cff6980fe7100242170092bb40d2b1cdad79502cd532fd26b12a2b8a5f9aee0"}, - {file = "coverage-7.2.6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c534431153caffc7c495c3eddf7e6a6033e7f81d78385b4e41611b51e8870446"}, - {file = "coverage-7.2.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3062fd5c62df988cea9f2972c593f77fed1182bfddc5a3b12b1e606cb7aba99e"}, - {file = "coverage-7.2.6-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6284a2005e4f8061c58c814b1600ad0074ccb0289fe61ea709655c5969877b70"}, - {file = "coverage-7.2.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:97729e6828643f168a2a3f07848e1b1b94a366b13a9f5aba5484c2215724edc8"}, - {file = "coverage-7.2.6-cp38-cp38-win32.whl", hash = "sha256:dc11b42fa61ff1e788dd095726a0aed6aad9c03d5c5984b54cb9e1e67b276aa5"}, - {file = "coverage-7.2.6-cp38-cp38-win_amd64.whl", hash = "sha256:cbcc874f454ee51f158afd604a315f30c0e31dff1d5d5bf499fc529229d964dd"}, - {file = "coverage-7.2.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d3cacc6a665221108ecdf90517a8028d07a2783df3417d12dcfef1c517e67478"}, - {file = "coverage-7.2.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:272ab31228a9df857ab5df5d67936d8861464dc89c5d3fab35132626e9369379"}, - {file = "coverage-7.2.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a8723ccec4e564d4b9a79923246f7b9a8de4ec55fa03ec4ec804459dade3c4f"}, - {file = "coverage-7.2.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5906f6a84b47f995cd1bf0aca1c72d591c55ee955f98074e93660d64dfc66eb9"}, - {file = "coverage-7.2.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52c139b7ab3f0b15f9aad0a3fedef5a1f8c0b2bdc291d88639ca2c97d3682416"}, - {file = "coverage-7.2.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a5ffd45c6b93c23a8507e2f436983015c6457aa832496b6a095505ca2f63e8f1"}, - {file = "coverage-7.2.6-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4f3c7c19581d471af0e9cb49d928172cd8492cd78a2b7a4e82345d33662929bb"}, - {file = "coverage-7.2.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2e8c0e79820cdd67978e1120983786422d279e07a381dbf89d03bbb23ec670a6"}, - {file = "coverage-7.2.6-cp39-cp39-win32.whl", hash = "sha256:13cde6bb0e58fb67d09e2f373de3899d1d1e866c5a9ff05d93615f2f54fbd2bb"}, - {file = "coverage-7.2.6-cp39-cp39-win_amd64.whl", hash = "sha256:6b9f64526286255735847aed0221b189486e0b9ed943446936e41b7e44b08783"}, - {file = "coverage-7.2.6-pp37.pp38.pp39-none-any.whl", hash = "sha256:6babcbf1e66e46052442f10833cfc4a0d3554d8276aa37af8531a83ed3c1a01d"}, - {file = "coverage-7.2.6.tar.gz", hash = "sha256:2025f913f2edb0272ef15d00b1f335ff8908c921c8eb2013536fcaf61f5a683d"}, + {file = "coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8"}, + {file = "coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495"}, + {file = "coverage-7.2.7-cp310-cp310-win32.whl", hash = "sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818"}, + {file = "coverage-7.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850"}, + {file = "coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f"}, + {file = "coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a"}, + {file = "coverage-7.2.7-cp311-cp311-win32.whl", hash = "sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a"}, + {file = "coverage-7.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562"}, + {file = "coverage-7.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d"}, + {file = "coverage-7.2.7-cp312-cp312-win32.whl", hash = "sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511"}, + {file = "coverage-7.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3"}, + {file = "coverage-7.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02"}, + {file = "coverage-7.2.7-cp37-cp37m-win32.whl", hash = "sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f"}, + {file = "coverage-7.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0"}, + {file = "coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5"}, + {file = "coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f"}, + {file = "coverage-7.2.7-cp38-cp38-win32.whl", hash = "sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e"}, + {file = "coverage-7.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c"}, + {file = "coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9"}, + {file = "coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2"}, + {file = "coverage-7.2.7-cp39-cp39-win32.whl", hash = "sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb"}, + {file = "coverage-7.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27"}, + {file = "coverage-7.2.7-pp37.pp38.pp39-none-any.whl", hash = "sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d"}, + {file = "coverage-7.2.7.tar.gz", hash = "sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59"}, ] [package.dependencies] @@ -531,19 +540,19 @@ testing = ["pre-commit"] [[package]] name = "fakeredis" -version = "2.13.0" -description = "Fake implementation of redis API for testing purposes." +version = "2.16.0" +description = "Python implementation of redis API, can be used for testing purposes." category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "fakeredis-2.13.0-py3-none-any.whl", hash = "sha256:df7bb44fb9e593970c626325230e1c321f954ce7b204d4c4452eae5233d554ed"}, - {file = "fakeredis-2.13.0.tar.gz", hash = "sha256:53f00f44f771d2b794f1ea036fa07a33476ab7368f1b0e908daab3eff80336f6"}, + {file = "fakeredis-2.16.0-py3-none-any.whl", hash = "sha256:188514cbd7120ff28c88f2a31e2fddd18fb1b28504478dfa3669c683134c4d82"}, + {file = "fakeredis-2.16.0.tar.gz", hash = "sha256:5abdd734de4ead9d6c7acbd3add1c4aa9b3ab35219339530472d9dd2bdf13057"}, ] [package.dependencies] redis = ">=4" -sortedcontainers = ">=2.4,<3.0" +sortedcontainers = ">=2,<3" [package.extras] json = ["jsonpath-ng (>=1.5,<2.0)"] @@ -588,19 +597,19 @@ python-dateutil = "*" [[package]] name = "filelock" -version = "3.12.0" +version = "3.12.2" description = "A platform independent file lock." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "filelock-3.12.0-py3-none-any.whl", hash = "sha256:ad98852315c2ab702aeb628412cbf7e95b7ce8c3bf9565670b4eaecf1db370a9"}, - {file = "filelock-3.12.0.tar.gz", hash = "sha256:fc03ae43288c013d2ea83c8597001b1129db351aad9c57fe2409327916b8e718"}, + {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, + {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, ] [package.extras] -docs = ["furo (>=2023.3.27)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] [[package]] name = "greenlet" @@ -896,96 +905,109 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "lxml" -version = "4.9.2" +version = "4.9.3" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" files = [ - {file = "lxml-4.9.2-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:76cf573e5a365e790396a5cc2b909812633409306c6531a6877c59061e42c4f2"}, - {file = "lxml-4.9.2-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b1f42b6921d0e81b1bcb5e395bc091a70f41c4d4e55ba99c6da2b31626c44892"}, - {file = "lxml-4.9.2-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9f102706d0ca011de571de32c3247c6476b55bb6bc65a20f682f000b07a4852a"}, - {file = "lxml-4.9.2-cp27-cp27m-win32.whl", hash = "sha256:8d0b4612b66ff5d62d03bcaa043bb018f74dfea51184e53f067e6fdcba4bd8de"}, - {file = "lxml-4.9.2-cp27-cp27m-win_amd64.whl", hash = "sha256:4c8f293f14abc8fd3e8e01c5bd86e6ed0b6ef71936ded5bf10fe7a5efefbaca3"}, - {file = "lxml-4.9.2-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2899456259589aa38bfb018c364d6ae7b53c5c22d8e27d0ec7609c2a1ff78b50"}, - {file = "lxml-4.9.2-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6749649eecd6a9871cae297bffa4ee76f90b4504a2a2ab528d9ebe912b101975"}, - {file = "lxml-4.9.2-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:a08cff61517ee26cb56f1e949cca38caabe9ea9fbb4b1e10a805dc39844b7d5c"}, - {file = "lxml-4.9.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:85cabf64adec449132e55616e7ca3e1000ab449d1d0f9d7f83146ed5bdcb6d8a"}, - {file = "lxml-4.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8340225bd5e7a701c0fa98284c849c9b9fc9238abf53a0ebd90900f25d39a4e4"}, - {file = "lxml-4.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:1ab8f1f932e8f82355e75dda5413a57612c6ea448069d4fb2e217e9a4bed13d4"}, - {file = "lxml-4.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:699a9af7dffaf67deeae27b2112aa06b41c370d5e7633e0ee0aea2e0b6c211f7"}, - {file = "lxml-4.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b9cc34af337a97d470040f99ba4282f6e6bac88407d021688a5d585e44a23184"}, - {file = "lxml-4.9.2-cp310-cp310-win32.whl", hash = "sha256:d02a5399126a53492415d4906ab0ad0375a5456cc05c3fc0fc4ca11771745cda"}, - {file = "lxml-4.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:a38486985ca49cfa574a507e7a2215c0c780fd1778bb6290c21193b7211702ab"}, - {file = "lxml-4.9.2-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c83203addf554215463b59f6399835201999b5e48019dc17f182ed5ad87205c9"}, - {file = "lxml-4.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:2a87fa548561d2f4643c99cd13131acb607ddabb70682dcf1dff5f71f781a4bf"}, - {file = "lxml-4.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:d6b430a9938a5a5d85fc107d852262ddcd48602c120e3dbb02137c83d212b380"}, - {file = "lxml-4.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3efea981d956a6f7173b4659849f55081867cf897e719f57383698af6f618a92"}, - {file = "lxml-4.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:df0623dcf9668ad0445e0558a21211d4e9a149ea8f5666917c8eeec515f0a6d1"}, - {file = "lxml-4.9.2-cp311-cp311-win32.whl", hash = "sha256:da248f93f0418a9e9d94b0080d7ebc407a9a5e6d0b57bb30db9b5cc28de1ad33"}, - {file = "lxml-4.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:3818b8e2c4b5148567e1b09ce739006acfaa44ce3156f8cbbc11062994b8e8dd"}, - {file = "lxml-4.9.2-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ca989b91cf3a3ba28930a9fc1e9aeafc2a395448641df1f387a2d394638943b0"}, - {file = "lxml-4.9.2-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:822068f85e12a6e292803e112ab876bc03ed1f03dddb80154c395f891ca6b31e"}, - {file = "lxml-4.9.2-cp35-cp35m-win32.whl", hash = "sha256:be7292c55101e22f2a3d4d8913944cbea71eea90792bf914add27454a13905df"}, - {file = "lxml-4.9.2-cp35-cp35m-win_amd64.whl", hash = "sha256:998c7c41910666d2976928c38ea96a70d1aa43be6fe502f21a651e17483a43c5"}, - {file = "lxml-4.9.2-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:b26a29f0b7fc6f0897f043ca366142d2b609dc60756ee6e4e90b5f762c6adc53"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:ab323679b8b3030000f2be63e22cdeea5b47ee0abd2d6a1dc0c8103ddaa56cd7"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:689bb688a1db722485e4610a503e3e9210dcc20c520b45ac8f7533c837be76fe"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f49e52d174375a7def9915c9f06ec4e569d235ad428f70751765f48d5926678c"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:36c3c175d34652a35475a73762b545f4527aec044910a651d2bf50de9c3352b1"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a35f8b7fa99f90dd2f5dc5a9fa12332642f087a7641289ca6c40d6e1a2637d8e"}, - {file = "lxml-4.9.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:58bfa3aa19ca4c0f28c5dde0ff56c520fbac6f0daf4fac66ed4c8d2fb7f22e74"}, - {file = "lxml-4.9.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc718cd47b765e790eecb74d044cc8d37d58562f6c314ee9484df26276d36a38"}, - {file = "lxml-4.9.2-cp36-cp36m-win32.whl", hash = "sha256:d5bf6545cd27aaa8a13033ce56354ed9e25ab0e4ac3b5392b763d8d04b08e0c5"}, - {file = "lxml-4.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:3ab9fa9d6dc2a7f29d7affdf3edebf6ece6fb28a6d80b14c3b2fb9d39b9322c3"}, - {file = "lxml-4.9.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:05ca3f6abf5cf78fe053da9b1166e062ade3fa5d4f92b4ed688127ea7d7b1d03"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:a5da296eb617d18e497bcf0a5c528f5d3b18dadb3619fbdadf4ed2356ef8d941"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:04876580c050a8c5341d706dd464ff04fd597095cc8c023252566a8826505726"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c9ec3eaf616d67db0764b3bb983962b4f385a1f08304fd30c7283954e6a7869b"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2a29ba94d065945944016b6b74e538bdb1751a1db6ffb80c9d3c2e40d6fa9894"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a82d05da00a58b8e4c0008edbc8a4b6ec5a4bc1e2ee0fb6ed157cf634ed7fa45"}, - {file = "lxml-4.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:223f4232855ade399bd409331e6ca70fb5578efef22cf4069a6090acc0f53c0e"}, - {file = "lxml-4.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d17bc7c2ccf49c478c5bdd447594e82692c74222698cfc9b5daae7ae7e90743b"}, - {file = "lxml-4.9.2-cp37-cp37m-win32.whl", hash = "sha256:b64d891da92e232c36976c80ed7ebb383e3f148489796d8d31a5b6a677825efe"}, - {file = "lxml-4.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:a0a336d6d3e8b234a3aae3c674873d8f0e720b76bc1d9416866c41cd9500ffb9"}, - {file = "lxml-4.9.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:da4dd7c9c50c059aba52b3524f84d7de956f7fef88f0bafcf4ad7dde94a064e8"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:821b7f59b99551c69c85a6039c65b75f5683bdc63270fec660f75da67469ca24"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:e5168986b90a8d1f2f9dc1b841467c74221bd752537b99761a93d2d981e04889"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:8e20cb5a47247e383cf4ff523205060991021233ebd6f924bca927fcf25cf86f"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:13598ecfbd2e86ea7ae45ec28a2a54fb87ee9b9fdb0f6d343297d8e548392c03"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:880bbbcbe2fca64e2f4d8e04db47bcdf504936fa2b33933efd945e1b429bea8c"}, - {file = "lxml-4.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7d2278d59425777cfcb19735018d897ca8303abe67cc735f9f97177ceff8027f"}, - {file = "lxml-4.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5344a43228767f53a9df6e5b253f8cdca7dfc7b7aeae52551958192f56d98457"}, - {file = "lxml-4.9.2-cp38-cp38-win32.whl", hash = "sha256:925073b2fe14ab9b87e73f9a5fde6ce6392da430f3004d8b72cc86f746f5163b"}, - {file = "lxml-4.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:9b22c5c66f67ae00c0199f6055705bc3eb3fcb08d03d2ec4059a2b1b25ed48d7"}, - {file = "lxml-4.9.2-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:5f50a1c177e2fa3ee0667a5ab79fdc6b23086bc8b589d90b93b4bd17eb0e64d1"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:090c6543d3696cbe15b4ac6e175e576bcc3f1ccfbba970061b7300b0c15a2140"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:63da2ccc0857c311d764e7d3d90f429c252e83b52d1f8f1d1fe55be26827d1f4"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:5b4545b8a40478183ac06c073e81a5ce4cf01bf1734962577cf2bb569a5b3bbf"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2e430cd2824f05f2d4f687701144556646bae8f249fd60aa1e4c768ba7018947"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6804daeb7ef69e7b36f76caddb85cccd63d0c56dedb47555d2fc969e2af6a1a5"}, - {file = "lxml-4.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a6e441a86553c310258aca15d1c05903aaf4965b23f3bc2d55f200804e005ee5"}, - {file = "lxml-4.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ca34efc80a29351897e18888c71c6aca4a359247c87e0b1c7ada14f0ab0c0fb2"}, - {file = "lxml-4.9.2-cp39-cp39-win32.whl", hash = "sha256:6b418afe5df18233fc6b6093deb82a32895b6bb0b1155c2cdb05203f583053f1"}, - {file = "lxml-4.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:f1496ea22ca2c830cbcbd473de8f114a320da308438ae65abad6bab7867fe38f"}, - {file = "lxml-4.9.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:b264171e3143d842ded311b7dccd46ff9ef34247129ff5bf5066123c55c2431c"}, - {file = "lxml-4.9.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0dc313ef231edf866912e9d8f5a042ddab56c752619e92dfd3a2c277e6a7299a"}, - {file = "lxml-4.9.2-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:16efd54337136e8cd72fb9485c368d91d77a47ee2d42b057564aae201257d419"}, - {file = "lxml-4.9.2-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:0f2b1e0d79180f344ff9f321327b005ca043a50ece8713de61d1cb383fb8ac05"}, - {file = "lxml-4.9.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:7b770ed79542ed52c519119473898198761d78beb24b107acf3ad65deae61f1f"}, - {file = "lxml-4.9.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:efa29c2fe6b4fdd32e8ef81c1528506895eca86e1d8c4657fda04c9b3786ddf9"}, - {file = "lxml-4.9.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7e91ee82f4199af8c43d8158024cbdff3d931df350252288f0d4ce656df7f3b5"}, - {file = "lxml-4.9.2-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:b23e19989c355ca854276178a0463951a653309fb8e57ce674497f2d9f208746"}, - {file = "lxml-4.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:01d36c05f4afb8f7c20fd9ed5badca32a2029b93b1750f571ccc0b142531caf7"}, - {file = "lxml-4.9.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7b515674acfdcadb0eb5d00d8a709868173acece5cb0be3dd165950cbfdf5409"}, - {file = "lxml-4.9.2.tar.gz", hash = "sha256:2455cfaeb7ac70338b3257f41e21f0724f4b5b0c0e7702da67ee6c3640835b67"}, + {file = "lxml-4.9.3-cp27-cp27m-macosx_11_0_x86_64.whl", hash = "sha256:b0a545b46b526d418eb91754565ba5b63b1c0b12f9bd2f808c852d9b4b2f9b5c"}, + {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:075b731ddd9e7f68ad24c635374211376aa05a281673ede86cbe1d1b3455279d"}, + {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1e224d5755dba2f4a9498e150c43792392ac9b5380aa1b845f98a1618c94eeef"}, + {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c0781a98ff5e6586926293e59480b64ddd46282953203c76ae15dbbbf302e8bb"}, + {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cef2502e7e8a96fe5ad686d60b49e1ab03e438bd9123987994528febd569868e"}, + {file = "lxml-4.9.3-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b86164d2cff4d3aaa1f04a14685cbc072efd0b4f99ca5708b2ad1b9b5988a991"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:42871176e7896d5d45138f6d28751053c711ed4d48d8e30b498da155af39aebd"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ae8b9c6deb1e634ba4f1930eb67ef6e6bf6a44b6eb5ad605642b2d6d5ed9ce3c"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:411007c0d88188d9f621b11d252cce90c4a2d1a49db6c068e3c16422f306eab8"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:cd47b4a0d41d2afa3e58e5bf1f62069255aa2fd6ff5ee41604418ca925911d76"}, + {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0e2cb47860da1f7e9a5256254b74ae331687b9672dfa780eed355c4c9c3dbd23"}, + {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1247694b26342a7bf47c02e513d32225ededd18045264d40758abeb3c838a51f"}, + {file = "lxml-4.9.3-cp310-cp310-win32.whl", hash = "sha256:cdb650fc86227eba20de1a29d4b2c1bfe139dc75a0669270033cb2ea3d391b85"}, + {file = "lxml-4.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:97047f0d25cd4bcae81f9ec9dc290ca3e15927c192df17331b53bebe0e3ff96d"}, + {file = "lxml-4.9.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:1f447ea5429b54f9582d4b955f5f1985f278ce5cf169f72eea8afd9502973dd5"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:57d6ba0ca2b0c462f339640d22882acc711de224d769edf29962b09f77129cbf"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:9767e79108424fb6c3edf8f81e6730666a50feb01a328f4a016464a5893f835a"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:71c52db65e4b56b8ddc5bb89fb2e66c558ed9d1a74a45ceb7dcb20c191c3df2f"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d73d8ecf8ecf10a3bd007f2192725a34bd62898e8da27eb9d32a58084f93962b"}, + {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0a3d3487f07c1d7f150894c238299934a2a074ef590b583103a45002035be120"}, + {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e28c51fa0ce5674be9f560c6761c1b441631901993f76700b1b30ca6c8378d6"}, + {file = "lxml-4.9.3-cp311-cp311-win32.whl", hash = "sha256:0bfd0767c5c1de2551a120673b72e5d4b628737cb05414f03c3277bf9bed3305"}, + {file = "lxml-4.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:25f32acefac14ef7bd53e4218fe93b804ef6f6b92ffdb4322bb6d49d94cad2bc"}, + {file = "lxml-4.9.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:d3ff32724f98fbbbfa9f49d82852b159e9784d6094983d9a8b7f2ddaebb063d4"}, + {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:48d6ed886b343d11493129e019da91d4039826794a3e3027321c56d9e71505be"}, + {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9a92d3faef50658dd2c5470af249985782bf754c4e18e15afb67d3ab06233f13"}, + {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b4e4bc18382088514ebde9328da057775055940a1f2e18f6ad2d78aa0f3ec5b9"}, + {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fc9b106a1bf918db68619fdcd6d5ad4f972fdd19c01d19bdb6bf63f3589a9ec5"}, + {file = "lxml-4.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:d37017287a7adb6ab77e1c5bee9bcf9660f90ff445042b790402a654d2ad81d8"}, + {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:56dc1f1ebccc656d1b3ed288f11e27172a01503fc016bcabdcbc0978b19352b7"}, + {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:578695735c5a3f51569810dfebd05dd6f888147a34f0f98d4bb27e92b76e05c2"}, + {file = "lxml-4.9.3-cp35-cp35m-win32.whl", hash = "sha256:704f61ba8c1283c71b16135caf697557f5ecf3e74d9e453233e4771d68a1f42d"}, + {file = "lxml-4.9.3-cp35-cp35m-win_amd64.whl", hash = "sha256:c41bfca0bd3532d53d16fd34d20806d5c2b1ace22a2f2e4c0008570bf2c58833"}, + {file = "lxml-4.9.3-cp36-cp36m-macosx_11_0_x86_64.whl", hash = "sha256:64f479d719dc9f4c813ad9bb6b28f8390360660b73b2e4beb4cb0ae7104f1c12"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:dd708cf4ee4408cf46a48b108fb9427bfa00b9b85812a9262b5c668af2533ea5"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c31c7462abdf8f2ac0577d9f05279727e698f97ecbb02f17939ea99ae8daa98"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e3cd95e10c2610c360154afdc2f1480aea394f4a4f1ea0a5eacce49640c9b190"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:4930be26af26ac545c3dffb662521d4e6268352866956672231887d18f0eaab2"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4aec80cde9197340bc353d2768e2a75f5f60bacda2bab72ab1dc499589b3878c"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:14e019fd83b831b2e61baed40cab76222139926b1fb5ed0e79225bc0cae14584"}, + {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0c0850c8b02c298d3c7006b23e98249515ac57430e16a166873fc47a5d549287"}, + {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:aca086dc5f9ef98c512bac8efea4483eb84abbf926eaeedf7b91479feb092458"}, + {file = "lxml-4.9.3-cp36-cp36m-win32.whl", hash = "sha256:50baa9c1c47efcaef189f31e3d00d697c6d4afda5c3cde0302d063492ff9b477"}, + {file = "lxml-4.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bef4e656f7d98aaa3486d2627e7d2df1157d7e88e7efd43a65aa5dd4714916cf"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:46f409a2d60f634fe550f7133ed30ad5321ae2e6630f13657fb9479506b00601"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4c28a9144688aef80d6ea666c809b4b0e50010a2aca784c97f5e6bf143d9f129"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:141f1d1a9b663c679dc524af3ea1773e618907e96075262726c7612c02b149a4"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:53ace1c1fd5a74ef662f844a0413446c0629d151055340e9893da958a374f70d"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:17a753023436a18e27dd7769e798ce302963c236bc4114ceee5b25c18c52c693"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7d298a1bd60c067ea75d9f684f5f3992c9d6766fadbc0bcedd39750bf344c2f4"}, + {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:081d32421db5df44c41b7f08a334a090a545c54ba977e47fd7cc2deece78809a"}, + {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:23eed6d7b1a3336ad92d8e39d4bfe09073c31bfe502f20ca5116b2a334f8ec02"}, + {file = "lxml-4.9.3-cp37-cp37m-win32.whl", hash = "sha256:1509dd12b773c02acd154582088820893109f6ca27ef7291b003d0e81666109f"}, + {file = "lxml-4.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:120fa9349a24c7043854c53cae8cec227e1f79195a7493e09e0c12e29f918e52"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4d2d1edbca80b510443f51afd8496be95529db04a509bc8faee49c7b0fb6d2cc"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8d7e43bd40f65f7d97ad8ef5c9b1778943d02f04febef12def25f7583d19baac"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:71d66ee82e7417828af6ecd7db817913cb0cf9d4e61aa0ac1fde0583d84358db"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:6fc3c450eaa0b56f815c7b62f2b7fba7266c4779adcf1cece9e6deb1de7305ce"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65299ea57d82fb91c7f019300d24050c4ddeb7c5a190e076b5f48a2b43d19c42"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:eadfbbbfb41b44034a4c757fd5d70baccd43296fb894dba0295606a7cf3124aa"}, + {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3e9bdd30efde2b9ccfa9cb5768ba04fe71b018a25ea093379c857c9dad262c40"}, + {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fcdd00edfd0a3001e0181eab3e63bd5c74ad3e67152c84f93f13769a40e073a7"}, + {file = "lxml-4.9.3-cp38-cp38-win32.whl", hash = "sha256:57aba1bbdf450b726d58b2aea5fe47c7875f5afb2c4a23784ed78f19a0462574"}, + {file = "lxml-4.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:92af161ecbdb2883c4593d5ed4815ea71b31fafd7fd05789b23100d081ecac96"}, + {file = "lxml-4.9.3-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:9bb6ad405121241e99a86efff22d3ef469024ce22875a7ae045896ad23ba2340"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8ed74706b26ad100433da4b9d807eae371efaa266ffc3e9191ea436087a9d6a7"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fbf521479bcac1e25a663df882c46a641a9bff6b56dc8b0fafaebd2f66fb231b"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:303bf1edce6ced16bf67a18a1cf8339d0db79577eec5d9a6d4a80f0fb10aa2da"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:5515edd2a6d1a5a70bfcdee23b42ec33425e405c5b351478ab7dc9347228f96e"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:690dafd0b187ed38583a648076865d8c229661ed20e48f2335d68e2cf7dc829d"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b6420a005548ad52154c8ceab4a1290ff78d757f9e5cbc68f8c77089acd3c432"}, + {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bb3bb49c7a6ad9d981d734ef7c7193bc349ac338776a0360cc671eaee89bcf69"}, + {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d27be7405547d1f958b60837dc4c1007da90b8b23f54ba1f8b728c78fdb19d50"}, + {file = "lxml-4.9.3-cp39-cp39-win32.whl", hash = "sha256:8df133a2ea5e74eef5e8fc6f19b9e085f758768a16e9877a60aec455ed2609b2"}, + {file = "lxml-4.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:4dd9a263e845a72eacb60d12401e37c616438ea2e5442885f65082c276dfb2b2"}, + {file = "lxml-4.9.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6689a3d7fd13dc687e9102a27e98ef33730ac4fe37795d5036d18b4d527abd35"}, + {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f6bdac493b949141b733c5345b6ba8f87a226029cbabc7e9e121a413e49441e0"}, + {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:05186a0f1346ae12553d66df1cfce6f251589fea3ad3da4f3ef4e34b2d58c6a3"}, + {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c2006f5c8d28dee289f7020f721354362fa304acbaaf9745751ac4006650254b"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-macosx_11_0_x86_64.whl", hash = "sha256:5c245b783db29c4e4fbbbfc9c5a78be496c9fea25517f90606aa1f6b2b3d5f7b"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4fb960a632a49f2f089d522f70496640fdf1218f1243889da3822e0a9f5f3ba7"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:50670615eaf97227d5dc60de2dc99fb134a7130d310d783314e7724bf163f75d"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9719fe17307a9e814580af1f5c6e05ca593b12fb7e44fe62450a5384dbf61b4b"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3331bece23c9ee066e0fb3f96c61322b9e0f54d775fccefff4c38ca488de283a"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-macosx_11_0_x86_64.whl", hash = "sha256:ed667f49b11360951e201453fc3967344d0d0263aa415e1619e85ae7fd17b4e0"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8b77946fd508cbf0fccd8e400a7f71d4ac0e1595812e66025bac475a8e811694"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e4da8ca0c0c0aea88fd46be8e44bd49716772358d648cce45fe387f7b92374a7"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fe4bda6bd4340caa6e5cf95e73f8fea5c4bfc55763dd42f1b50a94c1b4a2fbd4"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f3df3db1d336b9356dd3112eae5f5c2b8b377f3bc826848567f10bfddfee77e9"}, + {file = "lxml-4.9.3.tar.gz", hash = "sha256:48628bd53a426c9eb9bc066a923acaa0878d1e86129fd5359aee99285f4eed9c"}, ] [package.extras] cssselect = ["cssselect (>=0.7)"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -source = ["Cython (>=0.29.7)"] +source = ["Cython (>=0.29.35)"] [[package]] name = "mako" @@ -1087,75 +1109,75 @@ files = [ [[package]] name = "mysqlclient" -version = "2.1.1" +version = "2.2.0" description = "Python interface to MySQL" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "mysqlclient-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:c1ed71bd6244993b526113cca3df66428609f90e4652f37eb51c33496d478b37"}, - {file = "mysqlclient-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:c812b67e90082a840efb82a8978369e6e69fc62ce1bda4ca8f3084a9d862308b"}, - {file = "mysqlclient-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:0d1cd3a5a4d28c222fa199002810e8146cffd821410b67851af4cc80aeccd97c"}, - {file = "mysqlclient-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:b355c8b5a7d58f2e909acdbb050858390ee1b0e13672ae759e5e784110022994"}, - {file = "mysqlclient-2.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:996924f3483fd36a34a5812210c69e71dea5a3d5978d01199b78b7f6d485c855"}, - {file = "mysqlclient-2.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:dea88c8d3f5a5d9293dfe7f087c16dd350ceb175f2f6631c9cf4caf3e19b7a96"}, - {file = "mysqlclient-2.1.1.tar.gz", hash = "sha256:828757e419fb11dd6c5ed2576ec92c3efaa93a0f7c39e263586d1ee779c3d782"}, + {file = "mysqlclient-2.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:68837b6bb23170acffb43ae411e47533a560b6360c06dac39aa55700972c93b2"}, + {file = "mysqlclient-2.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:5670679ff1be1cc3fef0fa81bf39f0cd70605ba121141050f02743eb878ac114"}, + {file = "mysqlclient-2.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:004fe1d30d2c2ff8072f8ea513bcec235fd9b896f70dad369461d0ad7e570e98"}, + {file = "mysqlclient-2.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:9c6b142836c7dba4f723bf9c93cc46b6e5081d65b2af807f400dda9eb85a16d0"}, + {file = "mysqlclient-2.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:955dba905a7443ce4788c63fdb9f8d688316260cf60b20ff51ac3b1c77616ede"}, + {file = "mysqlclient-2.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:530ece9995a36cadb6211b9787f0c9e05cdab6702549bdb4236af5e9b535ed6a"}, + {file = "mysqlclient-2.2.0.tar.gz", hash = "sha256:04368445f9c487d8abb7a878e3d23e923e6072c04a6c320f9e0dc8a82efba14e"}, ] [[package]] name = "orjson" -version = "3.8.14" +version = "3.9.2" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "orjson-3.8.14-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7a7b0fead2d0115ef927fa46ad005d7a3988a77187500bf895af67b365c10d1f"}, - {file = "orjson-3.8.14-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca90db8f551b8960da95b0d4cad6c0489df52ea03585b6979595be7b31a3f946"}, - {file = "orjson-3.8.14-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f4ac01a3db4e6a98a8ad1bb1a3e8bfc777928939e87c04e93e0d5006df574a4b"}, - {file = "orjson-3.8.14-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bf6825e160e4eb0ef65ce37d8c221edcab96ff2ffba65e5da2437a60a12b3ad1"}, - {file = "orjson-3.8.14-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f80e62afe49e6bfc706e041faa351d7520b5f86572b8e31455802251ea989613"}, - {file = "orjson-3.8.14-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6112194c11e611596eed72f46efb0e6b4812682eff3c7b48473d1146c3fa0efb"}, - {file = "orjson-3.8.14-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:739f9f633e1544f2a477fa3bef380f488c8dca6e2521c8dc36424b12554ee31e"}, - {file = "orjson-3.8.14-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7d3d8faded5a514b80b56d0429eb38b429d7a810f8749d25dc10a0cc15b8a3c8"}, - {file = "orjson-3.8.14-cp310-none-win_amd64.whl", hash = "sha256:0bf00c42333412a9338297bf888d7428c99e281e20322070bde8c2314775508b"}, - {file = "orjson-3.8.14-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d66966fd94719beb84e8ed84833bc59c3c005d3d2d0c42f11d7552d3267c6de7"}, - {file = "orjson-3.8.14-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:087c0dc93379e8ba2d59e9f586fab8de8c137d164fccf8afd5523a2137570917"}, - {file = "orjson-3.8.14-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04c70dc8ca79b0072a16d82f94b9d9dd6598a43dd753ab20039e9f7d2b14f017"}, - {file = "orjson-3.8.14-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aedba48264fe87e5060c0e9c2b28909f1e60626e46dc2f77e0c8c16939e2e1f7"}, - {file = "orjson-3.8.14-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:01640ab79111dd97515cba9fab7c66cb3b0967b0892cc74756a801ff681a01b6"}, - {file = "orjson-3.8.14-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b206cca6836a4c6683bcaa523ab467627b5f03902e5e1082dc59cd010e6925f"}, - {file = "orjson-3.8.14-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ee0299b2dda9afce351a5e8c148ea7a886de213f955aa0288fb874fb44829c36"}, - {file = "orjson-3.8.14-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:31a2a29be559e92dcc5c278787b4166da6f0d45675b59a11c4867f5d1455ebf4"}, - {file = "orjson-3.8.14-cp311-none-win_amd64.whl", hash = "sha256:20b7ffc7736000ea205f9143df322b03961f287b4057606291c62c842ff3c5b5"}, - {file = "orjson-3.8.14-cp37-cp37m-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:de1ee13d6b6727ee1db38722695250984bae81b8fc9d05f1176c74d14b1322d9"}, - {file = "orjson-3.8.14-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ee09bfbf1d54c127d3061f6721a1a11d2ce502b50597c3d0d2e1bd2d235b764"}, - {file = "orjson-3.8.14-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:97ebb7fab5f1ae212a6501f17cb7750a6838ffc2f1cebbaa5dec1a90038ca3c6"}, - {file = "orjson-3.8.14-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38ca39bae7fbc050332a374062d4cdec28095540fa8bb245eada467897a3a0bb"}, - {file = "orjson-3.8.14-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:92374bc35b6da344a927d5a850f7db80a91c7b837de2f0ea90fc870314b1ff44"}, - {file = "orjson-3.8.14-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9393a63cb0424515ec5e434078b3198de6ec9e057f1d33bad268683935f0a5d5"}, - {file = "orjson-3.8.14-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5fb66f0ac23e861b817c858515ac1f74d1cd9e72e3f82a5b2c9bae9f92286adc"}, - {file = "orjson-3.8.14-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:19415aaf30525a5baff0d72a089fcdd68f19a3674998263c885c3908228c1086"}, - {file = "orjson-3.8.14-cp37-none-win_amd64.whl", hash = "sha256:87ba7882e146e24a7d8b4a7971c20212c2af75ead8096fc3d55330babb1015fb"}, - {file = "orjson-3.8.14-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9f5cf61b6db68f213c805c55bf0aab9b4cb75a4e9c7f5bfbd4deb3a0aef0ec53"}, - {file = "orjson-3.8.14-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33bc310da4ad2ffe8f7f1c9e89692146d9ec5aec2d1c9ef6b67f8dc5e2d63241"}, - {file = "orjson-3.8.14-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:67a7e883b6f782b106683979ccc43d89b98c28a1f4a33fe3a22e253577499bb1"}, - {file = "orjson-3.8.14-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9df820e6c8c84c52ec39ea2cc9c79f7999c839c7d1481a056908dce3b90ce9f9"}, - {file = "orjson-3.8.14-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ebca14ae80814219ea3327e3dfa7ff618621ff335e45781fac26f5cd0b48f2b4"}, - {file = "orjson-3.8.14-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27967be4c16bd09f4aeff8896d9be9cbd00fd72f5815d5980e4776f821e2f77c"}, - {file = "orjson-3.8.14-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:062829b5e20cd8648bf4c11c3a5ee7cf196fa138e573407b5312c849b0cf354d"}, - {file = "orjson-3.8.14-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e53bc5beb612df8ddddb065f079d3fd30b5b4e73053518524423549d61177f3f"}, - {file = "orjson-3.8.14-cp38-none-win_amd64.whl", hash = "sha256:d03f29b0369bb1ab55c8a67103eb3a9675daaf92f04388568034fe16be48fa5d"}, - {file = "orjson-3.8.14-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:716a3994e039203f0a59056efa28185d4cac51b922cc5bf27ab9182cfa20e12e"}, - {file = "orjson-3.8.14-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cb35dd3ba062c1d984d57e6477768ed7b62ed9260f31362b2d69106f9c60ebd"}, - {file = "orjson-3.8.14-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0bc6b7abf27f1dc192dadad249df9b513912506dd420ce50fd18864a33789b71"}, - {file = "orjson-3.8.14-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e2f75b7d9285e35c3d4dff9811185535ff2ea637f06b2b242cb84385f8ffe63"}, - {file = "orjson-3.8.14-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:017de5ba22e58dfa6f41914f5edb8cd052d23f171000684c26b2d2ab219db31e"}, - {file = "orjson-3.8.14-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09a3bf3154f40299b8bc95e9fb8da47436a59a2106fc22cae15f76d649e062da"}, - {file = "orjson-3.8.14-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:64b4fca0531030040e611c6037aaf05359e296877ab0a8e744c26ef9c32738b9"}, - {file = "orjson-3.8.14-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8a896a12b38fe201a72593810abc1f4f1597e65b8c869d5fc83bbcf75d93398f"}, - {file = "orjson-3.8.14-cp39-none-win_amd64.whl", hash = "sha256:9725226478d1dafe46d26f758eadecc6cf98dcbb985445e14a9c74aaed6ccfea"}, - {file = "orjson-3.8.14.tar.gz", hash = "sha256:5ea93fd3ef7be7386f2516d728c877156de1559cda09453fc7dd7b696d0439b3"}, + {file = "orjson-3.9.2-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7323e4ca8322b1ecb87562f1ec2491831c086d9faa9a6c6503f489dadbed37d7"}, + {file = "orjson-3.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1272688ea1865f711b01ba479dea2d53e037ea00892fd04196b5875f7021d9d3"}, + {file = "orjson-3.9.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b9a26f1d1427a9101a1e8910f2e2df1f44d3d18ad5480ba031b15d5c1cb282e"}, + {file = "orjson-3.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6a5ca55b0d8f25f18b471e34abaee4b175924b6cd62f59992945b25963443141"}, + {file = "orjson-3.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:877872db2c0f41fbe21f852ff642ca842a43bc34895b70f71c9d575df31fffb4"}, + {file = "orjson-3.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a39c2529d75373b7167bf84c814ef9b8f3737a339c225ed6c0df40736df8748"}, + {file = "orjson-3.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:84ebd6fdf138eb0eb4280045442331ee71c0aab5e16397ba6645f32f911bfb37"}, + {file = "orjson-3.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5a60a1cfcfe310547a1946506dd4f1ed0a7d5bd5b02c8697d9d5dcd8d2e9245e"}, + {file = "orjson-3.9.2-cp310-none-win_amd64.whl", hash = "sha256:c290c4f81e8fd0c1683638802c11610b2f722b540f8e5e858b6914b495cf90c8"}, + {file = "orjson-3.9.2-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:02ef014f9a605e84b675060785e37ec9c0d2347a04f1307a9d6840ab8ecd6f55"}, + {file = "orjson-3.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:992af54265ada1c1579500d6594ed73fe333e726de70d64919cf37f93defdd06"}, + {file = "orjson-3.9.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a40958f7af7c6d992ee67b2da4098dca8b770fc3b4b3834d540477788bfa76d3"}, + {file = "orjson-3.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93864dec3e3dd058a2dbe488d11ac0345214a6a12697f53a63e34de7d28d4257"}, + {file = "orjson-3.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16fdf5a82df80c544c3c91516ab3882cd1ac4f1f84eefeafa642e05cef5f6699"}, + {file = "orjson-3.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:275b5a18fd9ed60b2720543d3ddac170051c43d680e47d04ff5203d2c6d8ebf1"}, + {file = "orjson-3.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b9aea6dcb99fcbc9f6d1dd84fca92322fda261da7fb014514bb4689c7c2097a8"}, + {file = "orjson-3.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7d74ae0e101d17c22ef67b741ba356ab896fc0fa64b301c2bf2bb0a4d874b190"}, + {file = "orjson-3.9.2-cp311-none-win_amd64.whl", hash = "sha256:6320b28e7bdb58c3a3a5efffe04b9edad3318d82409e84670a9b24e8035a249d"}, + {file = "orjson-3.9.2-cp37-cp37m-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:368e9cc91ecb7ac21f2aa475e1901204110cf3e714e98649c2502227d248f947"}, + {file = "orjson-3.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58e9e70f0dcd6a802c35887f306b555ff7a214840aad7de24901fc8bd9cf5dde"}, + {file = "orjson-3.9.2-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:00c983896c2e01c94c0ef72fd7373b2aa06d0c0eed0342c4884559f812a6835b"}, + {file = "orjson-3.9.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ee743e8890b16c87a2f89733f983370672272b61ee77429c0a5899b2c98c1a7"}, + {file = "orjson-3.9.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7b065942d362aad4818ff599d2f104c35a565c2cbcbab8c09ec49edba91da75"}, + {file = "orjson-3.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e46e9c5b404bb9e41d5555762fd410d5466b7eb1ec170ad1b1609cbebe71df21"}, + {file = "orjson-3.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8170157288714678ffd64f5de33039e1164a73fd8b6be40a8a273f80093f5c4f"}, + {file = "orjson-3.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e3e2f087161947dafe8319ea2cfcb9cea4bb9d2172ecc60ac3c9738f72ef2909"}, + {file = "orjson-3.9.2-cp37-none-win_amd64.whl", hash = "sha256:d7de3dbbe74109ae598692113cec327fd30c5a30ebca819b21dfa4052f7b08ef"}, + {file = "orjson-3.9.2-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:8cd4385c59bbc1433cad4a80aca65d2d9039646a9c57f8084897549b55913b17"}, + {file = "orjson-3.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a74036aab1a80c361039290cdbc51aa7adc7ea13f56e5ef94e9be536abd227bd"}, + {file = "orjson-3.9.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1aaa46d7d4ae55335f635eadc9be0bd9bcf742e6757209fc6dc697e390010adc"}, + {file = "orjson-3.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e52c67ed6bb368083aa2078ea3ccbd9721920b93d4b06c43eb4e20c4c860046"}, + {file = "orjson-3.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a6cdfcf9c7dd4026b2b01fdff56986251dc0cc1e980c690c79eec3ae07b36e7"}, + {file = "orjson-3.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1882a70bb69595b9ec5aac0040a819e94d2833fe54901e2b32f5e734bc259a8b"}, + {file = "orjson-3.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:fc05e060d452145ab3c0b5420769e7356050ea311fc03cb9d79c481982917cca"}, + {file = "orjson-3.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f8bc2c40d9bb26efefb10949d261a47ca196772c308babc538dd9f4b73e8d386"}, + {file = "orjson-3.9.2-cp38-none-win_amd64.whl", hash = "sha256:3164fc20a585ec30a9aff33ad5de3b20ce85702b2b2a456852c413e3f0d7ab09"}, + {file = "orjson-3.9.2-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7a6ccadf788531595ed4728aa746bc271955448d2460ff0ef8e21eb3f2a281ba"}, + {file = "orjson-3.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3245d230370f571c945f69aab823c279a868dc877352817e22e551de155cb06c"}, + {file = "orjson-3.9.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:205925b179550a4ee39b8418dd4c94ad6b777d165d7d22614771c771d44f57bd"}, + {file = "orjson-3.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0325fe2d69512187761f7368c8cda1959bcb75fc56b8e7a884e9569112320e57"}, + {file = "orjson-3.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:806704cd58708acc66a064a9a58e3be25cf1c3f9f159e8757bd3f515bfabdfa1"}, + {file = "orjson-3.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03fb36f187a0c19ff38f6289418863df8b9b7880cdbe279e920bef3a09d8dab1"}, + {file = "orjson-3.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:20925d07a97c49c6305bff1635318d9fc1804aa4ccacb5fb0deb8a910e57d97a"}, + {file = "orjson-3.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:eebfed53bec5674e981ebe8ed2cf00b3f7bcda62d634733ff779c264307ea505"}, + {file = "orjson-3.9.2-cp39-none-win_amd64.whl", hash = "sha256:869b961df5fcedf6c79f4096119b35679b63272362e9b745e668f0391a892d39"}, + {file = "orjson-3.9.2.tar.gz", hash = "sha256:24257c8f641979bf25ecd3e27251b5cc194cdd3a6e96004aac8446f5e63d9664"}, ] [[package]] @@ -1189,6 +1211,7 @@ category = "main" optional = false python-versions = "*" files = [ + {file = "parse-1.19.0-py2.py3-none-any.whl", hash = "sha256:6ce007645384a91150cb7cd7c8a9db2559e273c2e2542b508cd1e342508c2601"}, {file = "parse-1.19.0.tar.gz", hash = "sha256:9ff82852bcb65d139813e2a5197627a94966245c897796760a3a2a8eb66f020b"}, ] @@ -1269,25 +1292,25 @@ prometheus-client = ">=0.8.0,<1.0.0" [[package]] name = "protobuf" -version = "4.23.2" +version = "4.23.4" description = "" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "protobuf-4.23.2-cp310-abi3-win32.whl", hash = "sha256:384dd44cb4c43f2ccddd3645389a23ae61aeb8cfa15ca3a0f60e7c3ea09b28b3"}, - {file = "protobuf-4.23.2-cp310-abi3-win_amd64.whl", hash = "sha256:09310bce43353b46d73ba7e3bca78273b9bc50349509b9698e64d288c6372c2a"}, - {file = "protobuf-4.23.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:b2cfab63a230b39ae603834718db74ac11e52bccaaf19bf20f5cce1a84cf76df"}, - {file = "protobuf-4.23.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:c52cfcbfba8eb791255edd675c1fe6056f723bf832fa67f0442218f8817c076e"}, - {file = "protobuf-4.23.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:86df87016d290143c7ce3be3ad52d055714ebaebb57cc659c387e76cfacd81aa"}, - {file = "protobuf-4.23.2-cp37-cp37m-win32.whl", hash = "sha256:281342ea5eb631c86697e1e048cb7e73b8a4e85f3299a128c116f05f5c668f8f"}, - {file = "protobuf-4.23.2-cp37-cp37m-win_amd64.whl", hash = "sha256:ce744938406de1e64b91410f473736e815f28c3b71201302612a68bf01517fea"}, - {file = "protobuf-4.23.2-cp38-cp38-win32.whl", hash = "sha256:6c081863c379bb1741be8f8193e893511312b1d7329b4a75445d1ea9955be69e"}, - {file = "protobuf-4.23.2-cp38-cp38-win_amd64.whl", hash = "sha256:25e3370eda26469b58b602e29dff069cfaae8eaa0ef4550039cc5ef8dc004511"}, - {file = "protobuf-4.23.2-cp39-cp39-win32.whl", hash = "sha256:efabbbbac1ab519a514579ba9ec52f006c28ae19d97915951f69fa70da2c9e91"}, - {file = "protobuf-4.23.2-cp39-cp39-win_amd64.whl", hash = "sha256:54a533b971288af3b9926e53850c7eb186886c0c84e61daa8444385a4720297f"}, - {file = "protobuf-4.23.2-py3-none-any.whl", hash = "sha256:8da6070310d634c99c0db7df48f10da495cc283fd9e9234877f0cd182d43ab7f"}, - {file = "protobuf-4.23.2.tar.gz", hash = "sha256:20874e7ca4436f683b64ebdbee2129a5a2c301579a67d1a7dda2cdf62fb7f5f7"}, + {file = "protobuf-4.23.4-cp310-abi3-win32.whl", hash = "sha256:5fea3c64d41ea5ecf5697b83e41d09b9589e6f20b677ab3c48e5f242d9b7897b"}, + {file = "protobuf-4.23.4-cp310-abi3-win_amd64.whl", hash = "sha256:7b19b6266d92ca6a2a87effa88ecc4af73ebc5cfde194dc737cf8ef23a9a3b12"}, + {file = "protobuf-4.23.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8547bf44fe8cec3c69e3042f5c4fb3e36eb2a7a013bb0a44c018fc1e427aafbd"}, + {file = "protobuf-4.23.4-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:fee88269a090ada09ca63551bf2f573eb2424035bcf2cb1b121895b01a46594a"}, + {file = "protobuf-4.23.4-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:effeac51ab79332d44fba74660d40ae79985901ac21bca408f8dc335a81aa597"}, + {file = "protobuf-4.23.4-cp37-cp37m-win32.whl", hash = "sha256:c3e0939433c40796ca4cfc0fac08af50b00eb66a40bbbc5dee711998fb0bbc1e"}, + {file = "protobuf-4.23.4-cp37-cp37m-win_amd64.whl", hash = "sha256:9053df6df8e5a76c84339ee4a9f5a2661ceee4a0dab019e8663c50ba324208b0"}, + {file = "protobuf-4.23.4-cp38-cp38-win32.whl", hash = "sha256:e1c915778d8ced71e26fcf43c0866d7499891bca14c4368448a82edc61fdbc70"}, + {file = "protobuf-4.23.4-cp38-cp38-win_amd64.whl", hash = "sha256:351cc90f7d10839c480aeb9b870a211e322bf05f6ab3f55fcb2f51331f80a7d2"}, + {file = "protobuf-4.23.4-cp39-cp39-win32.whl", hash = "sha256:6dd9b9940e3f17077e820b75851126615ee38643c2c5332aa7a359988820c720"}, + {file = "protobuf-4.23.4-cp39-cp39-win_amd64.whl", hash = "sha256:0a5759f5696895de8cc913f084e27fd4125e8fb0914bb729a17816a33819f474"}, + {file = "protobuf-4.23.4-py3-none-any.whl", hash = "sha256:e9d0be5bf34b275b9f87ba7407796556abeeba635455d036c7351f7c183ef8ff"}, + {file = "protobuf-4.23.4.tar.gz", hash = "sha256:ccd9430c0719dce806b93f89c91de7977304729e55377f872a92465d548329a9"}, ] [[package]] @@ -1368,43 +1391,43 @@ email = ["email-validator (>=1.0.3)"] [[package]] name = "pygit2" -version = "1.12.1" +version = "1.12.2" description = "Python bindings for libgit2." category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "pygit2-1.12.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:50a155528aa611e4a217be31a9d2d8da283cfd978dbba07494cd04ea3d7c8768"}, - {file = "pygit2-1.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:248e22ccb1ea31f569373a3da3fa73d110ba2585c6326ff74b03c9579fb7b913"}, - {file = "pygit2-1.12.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e575e672c5a6cb39234b0076423a560e016d6b88cd50947c2df3bf59c5ccdf3d"}, - {file = "pygit2-1.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad9b46b52997d131b31ff46f699b074e9745c8fea8d0efb6b72ace43ab25828c"}, - {file = "pygit2-1.12.1-cp310-cp310-win32.whl", hash = "sha256:a8f495df877da04c572ecec4d532ae195680b4781dbf229bab4e801fa9ef20e9"}, - {file = "pygit2-1.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f1e1355c7fe2938a2bca0d6204a00c02950d13008722879e54a335b3e874006"}, - {file = "pygit2-1.12.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8a5c56b0b5dc8a317561070ef7557e180d4937d8b115c5a762d85e0109a216f3"}, - {file = "pygit2-1.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b7c9ca8bc8a722863fc873234748fef3422007d5a6ea90ba3ae338d2907d3d6e"}, - {file = "pygit2-1.12.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71c02a11f10bc4e329ab941f0c70874d39053c8f78544aefeb506f04cedb621a"}, - {file = "pygit2-1.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b3af334adf325b7c973417efa220fd5a9ce946b936262eceabc8ad8d46e0310"}, - {file = "pygit2-1.12.1-cp311-cp311-win32.whl", hash = "sha256:86c393962d1341893bbfa91829b3b8545e8ac7622f8b53b9a0b835b9cc1b5198"}, - {file = "pygit2-1.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:86c7e75ddc76f4e5593b47f9c2074fff242322ed9f4126116749f7c86021520a"}, - {file = "pygit2-1.12.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:939d11677f434024ea25a9137d8a525ef9f9ac474fb8b86399bc9526e6a7bff5"}, - {file = "pygit2-1.12.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:946f9215c0442995042ea512f764f7a6638d3a09f9d0484d3aeedbf8833f89e6"}, - {file = "pygit2-1.12.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd574620d3cc80df0b23bf2b7b08d8726e75a338d0fa1b67e4d6738d3ee56635"}, - {file = "pygit2-1.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24d0adeff5c43229913f3bdae71c36e77ed19f36bd8dd6b5c141820964b1f5b3"}, - {file = "pygit2-1.12.1-cp38-cp38-win32.whl", hash = "sha256:ed8e2ef97171e994bf4d46c6c6534a3c12dd2dbbc47741e5995eaf8c2c92f71c"}, - {file = "pygit2-1.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:5318817055a3ca3906bf88344b9a6dc70c640f9b6bc236ac9e767d12bad54361"}, - {file = "pygit2-1.12.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cb9c803151ffeb0b8de52a93381108a2c6a9a446c55d659a135f52645e1650eb"}, - {file = "pygit2-1.12.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:47bf1e196dc23fe38018ad49b021d425edc319328169c597df45d73cf46b62ef"}, - {file = "pygit2-1.12.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:948479df72223bbcd16b2a88904dc2a3886c15a0107a7cf3b5373c8e34f52f31"}, - {file = "pygit2-1.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4bebe8b310edc2662cbffb94ef1a758252fe2e4c92bc83fac0eaf2bedf8b871"}, - {file = "pygit2-1.12.1-cp39-cp39-win32.whl", hash = "sha256:77bc0ab778ab6fe631f5f9eb831b426376a7b71426c5a913aaa9088382ef1dc9"}, - {file = "pygit2-1.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:e87b2306a266f6abca94ab37dda807033a6f40faad05c4d1e089f9e8354130a8"}, - {file = "pygit2-1.12.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5d5e8a3b67f5d4ba8e3838c492254688997747989b184b5f1a3af4fef7f9f53e"}, - {file = "pygit2-1.12.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2500b749759f2efdfa5096c0aafeb2d92152766708f5700284427bd658e5c407"}, - {file = "pygit2-1.12.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c21759ca9cc755faa2d17180cd49af004486ca84f3166cac089a2083dcb09114"}, - {file = "pygit2-1.12.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d73074ab64b383e3a1ab03e8070f6b195ef89b9d379ca5682c38dd9c289cc6e2"}, - {file = "pygit2-1.12.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:865c0d1925c52426455317f29c1db718187ec69ed5474faaf3e1c68ff2135767"}, - {file = "pygit2-1.12.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ebebbe9125b068337b5415565ec94c9e092c708e430851b2d02e51217bdce4a"}, - {file = "pygit2-1.12.1.tar.gz", hash = "sha256:8218922abedc88a65d5092308d533ca4c4ed634aec86a3493d3bdf1a25aeeff3"}, + {file = "pygit2-1.12.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:79fbd99d3e08ca7478150eeba28ca4d4103f564148eab8d00aba8f1e6fc60654"}, + {file = "pygit2-1.12.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:be3bb0139f464947523022a5af343a2e862c4ff250a57ec9f631449e7c0ba7c0"}, + {file = "pygit2-1.12.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4df3e5745fdf3111a6ccc905eae99f22f1a180728f714795138ca540cc2a50a"}, + {file = "pygit2-1.12.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:214bd214784fcbef7a8494d1d59e0cd3a731c0d24ce0f230dcc843322ee33b08"}, + {file = "pygit2-1.12.2-cp310-cp310-win32.whl", hash = "sha256:336c864ac961e7be8ba06e9ed8c999e4f624a8ccd90121cc4e40956d8b57acac"}, + {file = "pygit2-1.12.2-cp310-cp310-win_amd64.whl", hash = "sha256:fb9eb57b75ce586928053692a25aae2a50fef3ad36661c57c07d4902899b1df3"}, + {file = "pygit2-1.12.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f8f813d35d836c5b0d1962c387754786bcc7f1c3c8e11207b9eeb30238ac4cc7"}, + {file = "pygit2-1.12.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:25a6548930328c5247bfb7c67d29104e63b036cb5390f032d9f91f63efb70434"}, + {file = "pygit2-1.12.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a365ffca23d910381749fdbcc367db52fe808f9aa4852914dd9ef8b711384a32"}, + {file = "pygit2-1.12.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec04c27be5d5af1ceecdcc0464e07081222f91f285f156dc53b23751d146569a"}, + {file = "pygit2-1.12.2-cp311-cp311-win32.whl", hash = "sha256:546091316c9a8c37b9867ddcc6c9f7402ca4d0b9db3f349212a7b5e71988e359"}, + {file = "pygit2-1.12.2-cp311-cp311-win_amd64.whl", hash = "sha256:8bf14196cbfffbcd286f459a1d4fc660c5d5dfa8fb422e21216961df575410d6"}, + {file = "pygit2-1.12.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7bb30ab1fdaa4c30821fed33892958b6d92d50dbd03c76f7775b4e5d62f53a2e"}, + {file = "pygit2-1.12.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e7e705aaecad85b883022e81e054fbd27d26023fc031618ee61c51516580517e"}, + {file = "pygit2-1.12.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac2b5f408eb882e79645ebb43039ac37739c3edd25d857cc97d7482a684b613f"}, + {file = "pygit2-1.12.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22e7f3ad2b7b0c80be991bb47d8a2f2535cc9bf090746eb8679231ee565fde81"}, + {file = "pygit2-1.12.2-cp38-cp38-win32.whl", hash = "sha256:5b3ab4d6302990f7adb2b015bcbda1f0715277008d0c66440497e6f8313bf9cb"}, + {file = "pygit2-1.12.2-cp38-cp38-win_amd64.whl", hash = "sha256:c74e7601cb8b8dc3d02fd32274e200a7761cffd20ee531442bf1fa115c8f99a5"}, + {file = "pygit2-1.12.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6a4083ba093c69142e0400114a4ef75e87834637d2bbfd77b964614bf70f624f"}, + {file = "pygit2-1.12.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:926f2e48c4eaa179249d417b8382290b86b0f01dbf41d289f763576209276b9f"}, + {file = "pygit2-1.12.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14ae27491347a0ac4bbe8347b09d752cfe7fea1121c14525415e0cca6db4a836"}, + {file = "pygit2-1.12.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f65483ab5e3563c58f60debe2acc0979fdf6fd633432fcfbddf727a9a265ba4"}, + {file = "pygit2-1.12.2-cp39-cp39-win32.whl", hash = "sha256:8da8517809635ea3da950d9cf99c6d1851352d92b6db309382db88a01c3b0bfd"}, + {file = "pygit2-1.12.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9c2359b99eed8e7fac30c06e6b4ae277a6a0537d6b4b88a190828c3d7eb9ef2"}, + {file = "pygit2-1.12.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:685378852ef8eb081333bc80dbdfc4f1333cf4a8f3baf614c4135e02ad1ee38a"}, + {file = "pygit2-1.12.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdf655e5f801990f5cad721b6ccbe7610962f0a4f1c20373dbf9c0be39374a81"}, + {file = "pygit2-1.12.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:857c5cde635d470f58803d67bfb281dc4f6336065a0253bfbed001f18e2d0767"}, + {file = "pygit2-1.12.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fe35a72af61961dbb7fb4abcdaa36d5f1c85b2cd3daae94137eeb9c07215cdd3"}, + {file = "pygit2-1.12.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f443d3641762b2bb9c76400bb18beb4ba27dd35bc098a8bfae82e6a190c52ab"}, + {file = "pygit2-1.12.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c1e26649e1540b6a774f812e2fc9890320ff4d33f16db1bb02626318b5ceae2"}, + {file = "pygit2-1.12.2.tar.gz", hash = "sha256:56e85d0e66de957d599d1efb2409d39afeefd8f01009bfda0796b42a4b678358"}, ] [package.dependencies] @@ -1412,14 +1435,14 @@ cffi = ">=1.9.1" [[package]] name = "pytest" -version = "7.3.1" +version = "7.4.0" description = "pytest: simple powerful testing with Python" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"}, - {file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"}, + {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"}, + {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"}, ] [package.dependencies] @@ -1431,7 +1454,7 @@ pluggy = ">=0.12,<2.0" tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-asyncio" @@ -1540,14 +1563,14 @@ dev = ["atomicwrites (==1.2.1)", "attrs (==19.2.0)", "coverage (==6.5.0)", "hatc [[package]] name = "redis" -version = "4.5.5" +version = "4.6.0" description = "Python client for Redis database and key-value store" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "redis-4.5.5-py3-none-any.whl", hash = "sha256:77929bc7f5dab9adf3acba2d3bb7d7658f1e0c2f1cafe7eb36434e751c471119"}, - {file = "redis-4.5.5.tar.gz", hash = "sha256:dc87a0bdef6c8bfe1ef1e1c40be7034390c2ae02d92dcd0c7ca1729443899880"}, + {file = "redis-4.6.0-py3-none-any.whl", hash = "sha256:e2b03db868160ee4591de3cb90d40ebb50a90dd302138775937f6a42b7ed183c"}, + {file = "redis-4.6.0.tar.gz", hash = "sha256:585dc516b9eb042a619ef0a39c3d7d55fe81bdb4df09a52c9cdde0d07bf1aa7d"}, ] [package.dependencies] @@ -1634,53 +1657,50 @@ files = [ [[package]] name = "sqlalchemy" -version = "1.4.48" +version = "1.4.49" description = "Database Abstraction Library" category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "SQLAlchemy-1.4.48-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:4bac3aa3c3d8bc7408097e6fe8bf983caa6e9491c5d2e2488cfcfd8106f13b6a"}, - {file = "SQLAlchemy-1.4.48-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:dbcae0e528d755f4522cad5842f0942e54b578d79f21a692c44d91352ea6d64e"}, - {file = "SQLAlchemy-1.4.48-cp27-cp27m-win32.whl", hash = "sha256:cbbe8b8bffb199b225d2fe3804421b7b43a0d49983f81dc654d0431d2f855543"}, - {file = "SQLAlchemy-1.4.48-cp27-cp27m-win_amd64.whl", hash = "sha256:627e04a5d54bd50628fc8734d5fc6df2a1aa5962f219c44aad50b00a6cdcf965"}, - {file = "SQLAlchemy-1.4.48-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9af1db7a287ef86e0f5cd990b38da6bd9328de739d17e8864f1817710da2d217"}, - {file = "SQLAlchemy-1.4.48-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:ce7915eecc9c14a93b73f4e1c9d779ca43e955b43ddf1e21df154184f39748e5"}, - {file = "SQLAlchemy-1.4.48-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5381ddd09a99638f429f4cbe1b71b025bed318f6a7b23e11d65f3eed5e181c33"}, - {file = "SQLAlchemy-1.4.48-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:87609f6d4e81a941a17e61a4c19fee57f795e96f834c4f0a30cee725fc3f81d9"}, - {file = "SQLAlchemy-1.4.48-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb0808ad34167f394fea21bd4587fc62f3bd81bba232a1e7fbdfa17e6cfa7cd7"}, - {file = "SQLAlchemy-1.4.48-cp310-cp310-win32.whl", hash = "sha256:d53cd8bc582da5c1c8c86b6acc4ef42e20985c57d0ebc906445989df566c5603"}, - {file = "SQLAlchemy-1.4.48-cp310-cp310-win_amd64.whl", hash = "sha256:4355e5915844afdc5cf22ec29fba1010166e35dd94a21305f49020022167556b"}, - {file = "SQLAlchemy-1.4.48-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:066c2b0413e8cb980e6d46bf9d35ca83be81c20af688fedaef01450b06e4aa5e"}, - {file = "SQLAlchemy-1.4.48-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c99bf13e07140601d111a7c6f1fc1519914dd4e5228315bbda255e08412f61a4"}, - {file = "SQLAlchemy-1.4.48-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ee26276f12614d47cc07bc85490a70f559cba965fb178b1c45d46ffa8d73fda"}, - {file = "SQLAlchemy-1.4.48-cp311-cp311-win32.whl", hash = "sha256:49c312bcff4728bffc6fb5e5318b8020ed5c8b958a06800f91859fe9633ca20e"}, - {file = "SQLAlchemy-1.4.48-cp311-cp311-win_amd64.whl", hash = "sha256:cef2e2abc06eab187a533ec3e1067a71d7bbec69e582401afdf6d8cad4ba3515"}, - {file = "SQLAlchemy-1.4.48-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:3509159e050bd6d24189ec7af373359f07aed690db91909c131e5068176c5a5d"}, - {file = "SQLAlchemy-1.4.48-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fc2ab4d9f6d9218a5caa4121bdcf1125303482a1cdcfcdbd8567be8518969c0"}, - {file = "SQLAlchemy-1.4.48-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e1ddbbcef9bcedaa370c03771ebec7e39e3944782bef49e69430383c376a250b"}, - {file = "SQLAlchemy-1.4.48-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f82d8efea1ca92b24f51d3aea1a82897ed2409868a0af04247c8c1e4fef5890"}, - {file = "SQLAlchemy-1.4.48-cp36-cp36m-win32.whl", hash = "sha256:e3e98d4907805b07743b583a99ecc58bf8807ecb6985576d82d5e8ae103b5272"}, - {file = "SQLAlchemy-1.4.48-cp36-cp36m-win_amd64.whl", hash = "sha256:25887b4f716e085a1c5162f130b852f84e18d2633942c8ca40dfb8519367c14f"}, - {file = "SQLAlchemy-1.4.48-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:0817c181271b0ce5df1aa20949f0a9e2426830fed5ecdcc8db449618f12c2730"}, - {file = "SQLAlchemy-1.4.48-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe1dd2562313dd9fe1778ed56739ad5d9aae10f9f43d9f4cf81d65b0c85168bb"}, - {file = "SQLAlchemy-1.4.48-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:68413aead943883b341b2b77acd7a7fe2377c34d82e64d1840860247cec7ff7c"}, - {file = "SQLAlchemy-1.4.48-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbde5642104ac6e95f96e8ad6d18d9382aa20672008cf26068fe36f3004491df"}, - {file = "SQLAlchemy-1.4.48-cp37-cp37m-win32.whl", hash = "sha256:11c6b1de720f816c22d6ad3bbfa2f026f89c7b78a5c4ffafb220e0183956a92a"}, - {file = "SQLAlchemy-1.4.48-cp37-cp37m-win_amd64.whl", hash = "sha256:eb5464ee8d4bb6549d368b578e9529d3c43265007193597ddca71c1bae6174e6"}, - {file = "SQLAlchemy-1.4.48-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:92e6133cf337c42bfee03ca08c62ba0f2d9695618c8abc14a564f47503157be9"}, - {file = "SQLAlchemy-1.4.48-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44d29a3fc6d9c45962476b470a81983dd8add6ad26fdbfae6d463b509d5adcda"}, - {file = "SQLAlchemy-1.4.48-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:005e942b451cad5285015481ae4e557ff4154dde327840ba91b9ac379be3b6ce"}, - {file = "SQLAlchemy-1.4.48-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c8cfe951ed074ba5e708ed29c45397a95c4143255b0d022c7c8331a75ae61f3"}, - {file = "SQLAlchemy-1.4.48-cp38-cp38-win32.whl", hash = "sha256:2b9af65cc58726129d8414fc1a1a650dcdd594ba12e9c97909f1f57d48e393d3"}, - {file = "SQLAlchemy-1.4.48-cp38-cp38-win_amd64.whl", hash = "sha256:2b562e9d1e59be7833edf28b0968f156683d57cabd2137d8121806f38a9d58f4"}, - {file = "SQLAlchemy-1.4.48-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:a1fc046756cf2a37d7277c93278566ddf8be135c6a58397b4c940abf837011f4"}, - {file = "SQLAlchemy-1.4.48-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d9b55252d2ca42a09bcd10a697fa041e696def9dfab0b78c0aaea1485551a08"}, - {file = "SQLAlchemy-1.4.48-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6dab89874e72a9ab5462997846d4c760cdb957958be27b03b49cf0de5e5c327c"}, - {file = "SQLAlchemy-1.4.48-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fd8b5ee5a3acc4371f820934b36f8109ce604ee73cc668c724abb054cebcb6e"}, - {file = "SQLAlchemy-1.4.48-cp39-cp39-win32.whl", hash = "sha256:eee09350fd538e29cfe3a496ec6f148504d2da40dbf52adefb0d2f8e4d38ccc4"}, - {file = "SQLAlchemy-1.4.48-cp39-cp39-win_amd64.whl", hash = "sha256:7ad2b0f6520ed5038e795cc2852eb5c1f20fa6831d73301ced4aafbe3a10e1f6"}, - {file = "SQLAlchemy-1.4.48.tar.gz", hash = "sha256:b47bc287096d989a0838ce96f7d8e966914a24da877ed41a7531d44b55cdb8df"}, + {file = "SQLAlchemy-1.4.49-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e126cf98b7fd38f1e33c64484406b78e937b1a280e078ef558b95bf5b6895f6"}, + {file = "SQLAlchemy-1.4.49-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:03db81b89fe7ef3857b4a00b63dedd632d6183d4ea5a31c5d8a92e000a41fc71"}, + {file = "SQLAlchemy-1.4.49-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:95b9df9afd680b7a3b13b38adf6e3a38995da5e162cc7524ef08e3be4e5ed3e1"}, + {file = "SQLAlchemy-1.4.49-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a63e43bf3f668c11bb0444ce6e809c1227b8f067ca1068898f3008a273f52b09"}, + {file = "SQLAlchemy-1.4.49-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f835c050ebaa4e48b18403bed2c0fda986525896efd76c245bdd4db995e51a4c"}, + {file = "SQLAlchemy-1.4.49-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c21b172dfb22e0db303ff6419451f0cac891d2e911bb9fbf8003d717f1bcf91"}, + {file = "SQLAlchemy-1.4.49-cp310-cp310-win32.whl", hash = "sha256:5fb1ebdfc8373b5a291485757bd6431de8d7ed42c27439f543c81f6c8febd729"}, + {file = "SQLAlchemy-1.4.49-cp310-cp310-win_amd64.whl", hash = "sha256:f8a65990c9c490f4651b5c02abccc9f113a7f56fa482031ac8cb88b70bc8ccaa"}, + {file = "SQLAlchemy-1.4.49-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8923dfdf24d5aa8a3adb59723f54118dd4fe62cf59ed0d0d65d940579c1170a4"}, + {file = "SQLAlchemy-1.4.49-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9ab2c507a7a439f13ca4499db6d3f50423d1d65dc9b5ed897e70941d9e135b0"}, + {file = "SQLAlchemy-1.4.49-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5debe7d49b8acf1f3035317e63d9ec8d5e4d904c6e75a2a9246a119f5f2fdf3d"}, + {file = "SQLAlchemy-1.4.49-cp311-cp311-win32.whl", hash = "sha256:82b08e82da3756765c2e75f327b9bf6b0f043c9c3925fb95fb51e1567fa4ee87"}, + {file = "SQLAlchemy-1.4.49-cp311-cp311-win_amd64.whl", hash = "sha256:171e04eeb5d1c0d96a544caf982621a1711d078dbc5c96f11d6469169bd003f1"}, + {file = "SQLAlchemy-1.4.49-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:36e58f8c4fe43984384e3fbe6341ac99b6b4e083de2fe838f0fdb91cebe9e9cb"}, + {file = "SQLAlchemy-1.4.49-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b31e67ff419013f99ad6f8fc73ee19ea31585e1e9fe773744c0f3ce58c039c30"}, + {file = "SQLAlchemy-1.4.49-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c14b29d9e1529f99efd550cd04dbb6db6ba5d690abb96d52de2bff4ed518bc95"}, + {file = "SQLAlchemy-1.4.49-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c40f3470e084d31247aea228aa1c39bbc0904c2b9ccbf5d3cfa2ea2dac06f26d"}, + {file = "SQLAlchemy-1.4.49-cp36-cp36m-win32.whl", hash = "sha256:706bfa02157b97c136547c406f263e4c6274a7b061b3eb9742915dd774bbc264"}, + {file = "SQLAlchemy-1.4.49-cp36-cp36m-win_amd64.whl", hash = "sha256:a7f7b5c07ae5c0cfd24c2db86071fb2a3d947da7bd487e359cc91e67ac1c6d2e"}, + {file = "SQLAlchemy-1.4.49-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:4afbbf5ef41ac18e02c8dc1f86c04b22b7a2125f2a030e25bbb4aff31abb224b"}, + {file = "SQLAlchemy-1.4.49-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24e300c0c2147484a002b175f4e1361f102e82c345bf263242f0449672a4bccf"}, + {file = "SQLAlchemy-1.4.49-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:201de072b818f8ad55c80d18d1a788729cccf9be6d9dc3b9d8613b053cd4836d"}, + {file = "SQLAlchemy-1.4.49-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7653ed6817c710d0c95558232aba799307d14ae084cc9b1f4c389157ec50df5c"}, + {file = "SQLAlchemy-1.4.49-cp37-cp37m-win32.whl", hash = "sha256:647e0b309cb4512b1f1b78471fdaf72921b6fa6e750b9f891e09c6e2f0e5326f"}, + {file = "SQLAlchemy-1.4.49-cp37-cp37m-win_amd64.whl", hash = "sha256:ab73ed1a05ff539afc4a7f8cf371764cdf79768ecb7d2ec691e3ff89abbc541e"}, + {file = "SQLAlchemy-1.4.49-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:37ce517c011560d68f1ffb28af65d7e06f873f191eb3a73af5671e9c3fada08a"}, + {file = "SQLAlchemy-1.4.49-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1878ce508edea4a879015ab5215546c444233881301e97ca16fe251e89f1c55"}, + {file = "SQLAlchemy-1.4.49-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0e8e608983e6f85d0852ca61f97e521b62e67969e6e640fe6c6b575d4db68557"}, + {file = "SQLAlchemy-1.4.49-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ccf956da45290df6e809ea12c54c02ace7f8ff4d765d6d3dfb3655ee876ce58d"}, + {file = "SQLAlchemy-1.4.49-cp38-cp38-win32.whl", hash = "sha256:f167c8175ab908ce48bd6550679cc6ea20ae169379e73c7720a28f89e53aa532"}, + {file = "SQLAlchemy-1.4.49-cp38-cp38-win_amd64.whl", hash = "sha256:45806315aae81a0c202752558f0df52b42d11dd7ba0097bf71e253b4215f34f4"}, + {file = "SQLAlchemy-1.4.49-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:b6d0c4b15d65087738a6e22e0ff461b407533ff65a73b818089efc8eb2b3e1de"}, + {file = "SQLAlchemy-1.4.49-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a843e34abfd4c797018fd8d00ffffa99fd5184c421f190b6ca99def4087689bd"}, + {file = "SQLAlchemy-1.4.49-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1c890421651b45a681181301b3497e4d57c0d01dc001e10438a40e9a9c25ee77"}, + {file = "SQLAlchemy-1.4.49-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d26f280b8f0a8f497bc10573849ad6dc62e671d2468826e5c748d04ed9e670d5"}, + {file = "SQLAlchemy-1.4.49-cp39-cp39-win32.whl", hash = "sha256:ec2268de67f73b43320383947e74700e95c6770d0c68c4e615e9897e46296294"}, + {file = "SQLAlchemy-1.4.49-cp39-cp39-win_amd64.whl", hash = "sha256:bbdf16372859b8ed3f4d05f925a984771cd2abd18bd187042f24be4886c2a15f"}, + {file = "SQLAlchemy-1.4.49.tar.gz", hash = "sha256:06ff25cbae30c396c4b7737464f2a7fc37a67b7da409993b182b024cec80aed9"}, ] [package.dependencies] @@ -1890,14 +1910,14 @@ files = [ [[package]] name = "werkzeug" -version = "2.3.4" +version = "2.3.6" description = "The comprehensive WSGI web application library." category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "Werkzeug-2.3.4-py3-none-any.whl", hash = "sha256:48e5e61472fee0ddee27ebad085614ebedb7af41e88f687aaf881afb723a162f"}, - {file = "Werkzeug-2.3.4.tar.gz", hash = "sha256:1d5a58e0377d1fe39d061a5de4469e414e78ccb1e1e59c0f5ad6fa1c36c52b76"}, + {file = "Werkzeug-2.3.6-py3-none-any.whl", hash = "sha256:935539fa1413afbb9195b24880778422ed620c0fc09670945185cce4d91a8890"}, + {file = "Werkzeug-2.3.6.tar.gz", hash = "sha256:98c774df2f91b05550078891dee5f0eb0cb797a522c757a2452b9cee5b202330"}, ] [package.dependencies] From 81d29b4c66b284459a020b92c8db8de0f2c71bfc Mon Sep 17 00:00:00 2001 From: renovate Date: Sat, 8 Jul 2023 11:24:29 +0000 Subject: [PATCH 067/178] fix(deps): update dependency fastapi to ^0.100.0 --- poetry.lock | 16 +++++++--------- pyproject.toml | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/poetry.lock b/poetry.lock index dcdcf819..f3f19d11 100644 --- a/poetry.lock +++ b/poetry.lock @@ -560,25 +560,23 @@ lua = ["lupa (>=1.14,<2.0)"] [[package]] name = "fastapi" -version = "0.95.2" +version = "0.100.0" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "fastapi-0.95.2-py3-none-any.whl", hash = "sha256:d374dbc4ef2ad9b803899bd3360d34c534adc574546e25314ab72c0c4411749f"}, - {file = "fastapi-0.95.2.tar.gz", hash = "sha256:4d9d3e8c71c73f11874bcf5e33626258d143252e329a01002f767306c64fb982"}, + {file = "fastapi-0.100.0-py3-none-any.whl", hash = "sha256:271662daf986da8fa98dc2b7c7f61c4abdfdccfb4786d79ed8b2878f172c6d5f"}, + {file = "fastapi-0.100.0.tar.gz", hash = "sha256:acb5f941ea8215663283c10018323ba7ea737c571b67fc7e88e9469c7eb1d12e"}, ] [package.dependencies] -pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" +pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<3.0.0" starlette = ">=0.27.0,<0.28.0" +typing-extensions = ">=4.5.0" [package.extras] -all = ["email-validator (>=1.1.1)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] -dev = ["pre-commit (>=2.17.0,<3.0.0)", "ruff (==0.0.138)", "uvicorn[standard] (>=0.12.0,<0.21.0)"] -doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer-cli (>=0.0.13,<0.0.14)", "typer[all] (>=0.6.1,<0.8.0)"] -test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==23.1.0)", "coverage[toml] (>=6.5.0,<8.0)", "databases[sqlite] (>=0.3.2,<0.7.0)", "email-validator (>=1.1.1,<2.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.23.0,<0.24.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.982)", "orjson (>=3.2.1,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=7.1.3,<8.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.7)", "pyyaml (>=5.3.1,<7.0.0)", "ruff (==0.0.138)", "sqlalchemy (>=1.3.18,<1.4.43)", "types-orjson (==3.6.2)", "types-ujson (==5.7.0.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] +all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "feedgen" @@ -1960,4 +1958,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "caf2a21e3bff699216e53a37697a7a544103fdea9f84a5d54ee94ded3e810973" +content-hash = "bbab458ee508b073ea3693caaa5d8704ff1a800ddecd816bf39a6561729777c0" diff --git a/pyproject.toml b/pyproject.toml index 69f04fab..34c5a135 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -93,7 +93,7 @@ pytest-xdist = "^3.2.1" filelock = "^3.12.0" posix-ipc = "^1.1.1" pyalpm = "^0.10.6" -fastapi = "^0.95.1" +fastapi = "^0.100.0" srcinfo = "^0.1.2" tomlkit = "^0.11.8" From 1f40f6c5a0a6c22a071e0729d5bdff60018b303c Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Sat, 8 Jul 2023 12:38:19 +0100 Subject: [PATCH 068/178] housekeep: set current maintainers Signed-off-by: Leonidas Spyropoulos --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 34c5a135..012658a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,8 @@ authors = [ "Kevin Morris " ] maintainers = [ - "Eli Schwartz " + "Leonidas Spyropoulos ", + "Mario Oenning " ] packages = [ { include = "aurweb" } From 4821fc131286bcea51ca0ea257d90b9ae20b85b0 Mon Sep 17 00:00:00 2001 From: moson Date: Sat, 8 Jul 2023 13:23:32 +0200 Subject: [PATCH 069/178] fix: show placeholder for deleted user in comments show "" in comment headers in case a user deleted their account. Signed-off-by: moson --- templates/partials/packages/comment.html | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/templates/partials/packages/comment.html b/templates/partials/packages/comment.html index faac0753..3573a914 100644 --- a/templates/partials/packages/comment.html +++ b/templates/partials/packages/comment.html @@ -1,5 +1,9 @@ {% set header_cls = "comment-header" %} {% set article_cls = "article-content" %} +{% set comment_by = comment.User.Username %} +{% if not comment.User %} + {% set comment_by = "<deleted-account>" %} +{% endif %} {% if comment.Deleter %} {% set header_cls = "%s %s" | format(header_cls, "comment-deleted") %} {% set article_cls = "%s %s" | format(article_cls, "comment-deleted") %} @@ -9,15 +13,15 @@ {% if not (request.user.HideDeletedComments and comment.DelTS) %}

    {% set commented_at = comment.CommentTS | dt | as_timezone(timezone) %} - {% set view_account_info = 'View account information for %s' | tr | format(comment.User.Username) %} + {% set view_account_info = 'View account information for %s' | tr | format(comment_by) %} {{ "%s commented on %s" | tr | format( ('%s' | format( - comment.User.Username, + comment_by, view_account_info, - comment.User.Username - )) if request.user.is_authenticated() else - (comment.User.Username), + comment_by + )) if request.user.is_authenticated() and comment.User else + (comment_by), '%s' | format( comment.ID, datetime_display(comment.CommentTS) From 225ce23761938dcfbb02809ac2371697038c037b Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Sat, 8 Jul 2023 12:54:43 +0100 Subject: [PATCH 070/178] chore(release): prepare for 6.2.6 Signed-off-by: Leonidas Spyropoulos --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 012658a0..ddd4f638 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ combine_as_imports = true # [tool.poetry] name = "aurweb" -version = "v6.2.5" +version = "v6.2.6" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From 5ccfa7c0fdc491df8556550092fac40fb0027284 Mon Sep 17 00:00:00 2001 From: moson Date: Sun, 9 Jul 2023 14:52:15 +0200 Subject: [PATCH 071/178] fix: same ssh key entered multiple times Users might accidentally past their ssh key multiple times when they try to register or edit their account. Convert our of list of keys to a set, removing any double keys. Signed-off-by: moson --- aurweb/util.py | 4 ++-- test/test_accounts_routes.py | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/aurweb/util.py b/aurweb/util.py index 7050b482..3410e4d8 100644 --- a/aurweb/util.py +++ b/aurweb/util.py @@ -192,9 +192,9 @@ def parse_ssh_key(string: str) -> Tuple[str, str]: return prefix, key -def parse_ssh_keys(string: str) -> list[Tuple[str, str]]: +def parse_ssh_keys(string: str) -> set[Tuple[str, str]]: """Parse a list of SSH public keys.""" - return [parse_ssh_key(e) for e in string.strip().splitlines(True) if e.strip()] + return set([parse_ssh_key(e) for e in string.strip().splitlines(True) if e.strip()]) def shell_exec(cmdline: str, cwd: str) -> Tuple[int, str, str]: diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index d3ddb174..c9d77c1f 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -644,6 +644,18 @@ def test_post_register_with_ssh_pubkey(client: TestClient): assert response.status_code == int(HTTPStatus.OK) + # Let's create another user accidentally pasting their key twice + with db.begin(): + db.query(SSHPubKey).delete() + + pk_double = pk + "\n" + pk + with client as request: + response = post_register( + request, U="doubleKey", E="doubleKey@email.org", PK=pk_double + ) + + assert response.status_code == int(HTTPStatus.OK) + def test_get_account_edit_tu_as_tu(client: TestClient, tu_user: User): """Test edit get route of another TU as a TU.""" @@ -1082,6 +1094,19 @@ def test_post_account_edit_ssh_pub_key(client: TestClient, user: User): assert response.status_code == int(HTTPStatus.OK) + # Accidentally enter the same key twice + pk = make_ssh_pubkey() + post_data["PK"] = pk + "\n" + pk + + with client as request: + request.cookies = {"AURSID": sid} + response = request.post( + "/account/test/edit", + data=post_data, + ) + + assert response.status_code == int(HTTPStatus.OK) + def test_post_account_edit_missing_ssh_pubkey(client: TestClient, user: User): request = Request() From c0bbe21d8183ed2d07eadcb5e0fd27526c70b78f Mon Sep 17 00:00:00 2001 From: moson Date: Sun, 9 Jul 2023 16:13:02 +0200 Subject: [PATCH 072/178] fix(test): correct test for ssh-key parsing Our set of keys returned by "util.parse_ssh_keys" is unordered so we have to adapt our test to not rely on a specific order for multiple keys. Fixes: 5ccfa7c0fdc4 ("fix: same ssh key entered multiple times") Signed-off-by: moson --- test/test_util.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test/test_util.py b/test/test_util.py index 042b9ad9..1c3b51af 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -142,11 +142,8 @@ def assert_multiple_keys(pks): keys = util.parse_ssh_keys(pks) assert len(keys) == 2 pfx1, key1, pfx2, key2 = pks.split() - k1, k2 = keys - assert pfx1 == k1[0] - assert key1 == k1[1] - assert pfx2 == k2[0] - assert key2 == k2[1] + assert (pfx1, key1) in keys + assert (pfx2, key2) in keys def test_hash_query(): From fa1212f2dee216bd02b321e3747c22fc854b31a5 Mon Sep 17 00:00:00 2001 From: moson Date: Mon, 10 Jul 2023 18:02:20 +0200 Subject: [PATCH 073/178] fix: translations not containing string formatting In some translations we might be missing replacement placeholders (%). This turns out to be problematic when calling the format function. Wrap the jinja2 format function and just return the string unformatted when % is missing. Fixes: #341 Signed-off-by: moson --- aurweb/filters.py | 15 +++++++++++++++ test/test_filters.py | 17 +++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/aurweb/filters.py b/aurweb/filters.py index 893f21af..38322cdf 100644 --- a/aurweb/filters.py +++ b/aurweb/filters.py @@ -8,6 +8,7 @@ from zoneinfo import ZoneInfo import fastapi import paginate from jinja2 import pass_context +from jinja2.filters import do_format import aurweb.models from aurweb import config, l10n @@ -164,3 +165,17 @@ def date_display(context: dict[str, Any], dt: Union[int, datetime]) -> str: @pass_context def datetime_display(context: dict[str, Any], dt: Union[int, datetime]) -> str: return date_strftime(context, dt, "%Y-%m-%d %H:%M (%Z)") + + +@register_filter("format") +def safe_format(value: str, *args: Any, **kwargs: Any) -> str: + """Wrapper for jinja2 format function to perform additional checks.""" + + # If we don't have anything to be formatted, just return the value. + # We have some translations that do not contain placeholders for replacement. + # In these cases the jinja2 function is throwing an error: + # "TypeError: not all arguments converted during string formatting" + if "%" not in value: + return value + + return do_format(value, *args, **kwargs) diff --git a/test/test_filters.py b/test/test_filters.py index e74ddb87..b56b80ab 100644 --- a/test/test_filters.py +++ b/test/test_filters.py @@ -1,6 +1,8 @@ from datetime import datetime from zoneinfo import ZoneInfo +import pytest + from aurweb import filters, time @@ -34,3 +36,18 @@ def test_to_qs(): query = {"a": "b", "c": [1, 2, 3]} qs = filters.to_qs(query) assert qs == "a=b&c=1&c=2&c=3" + + +@pytest.mark.parametrize( + "value, args, expected", + [ + ("", (), ""), + ("a", (), "a"), + ("a", (1,), "a"), + ("%s", ("a",), "a"), + ("%s", ("ab",), "ab"), + ("%s%d", ("a", 1), "a1"), + ], +) +def test_safe_format(value: str, args: tuple, expected: str): + assert filters.safe_format(value, *args) == expected From 27819b4465cd6cde7ef86caca812b1dd6f285880 Mon Sep 17 00:00:00 2001 From: moson Date: Thu, 13 Jul 2023 18:27:02 +0200 Subject: [PATCH 074/178] fix: /rss lazy load issue & perf improvements Some fixes for the /rss endpoints * Load all data in one go: Previously data was lazy loaded thus it made several sub-queries per package (> 200 queries for composing the rss data for a single request). Now we are performing a single SQL query. (request time improvement: 550ms -> 130ms) This also fixes aurweb-errors#510 and alike * Remove some "dead code": The fields "source, author, link" were never included in the rss output (wrong or insufficient data passed to the different entry.xyz functions) Nobody seems to be missing them anyways, so let's remove em. * Remove "Last-Modified" header: Obsolete since nginx can/will only handle "If-Modified-Since" requests in it's current configuration. All requests are passed to fastapi anyways. Signed-off-by: moson --- aurweb/routers/rss.py | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/aurweb/routers/rss.py b/aurweb/routers/rss.py index ee85b738..727d2b6a 100644 --- a/aurweb/routers/rss.py +++ b/aurweb/routers/rss.py @@ -1,5 +1,3 @@ -from datetime import datetime - from fastapi import APIRouter, Request from fastapi.responses import Response from feedgen.feed import FeedGenerator @@ -10,12 +8,11 @@ from aurweb.models import Package, PackageBase router = APIRouter() -def make_rss_feed(request: Request, packages: list, date_attr: str): +def make_rss_feed(request: Request, packages: list): """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 - :param date_attr: The date attribute (DB column) to use :return: RSS Feed string """ @@ -36,18 +33,11 @@ def make_rss_feed(request: Request, packages: list, date_attr: str): entry = feed.add_entry(order="append") entry.title(pkg.Name) entry.link(href=f"{base}/packages/{pkg.Name}", rel="alternate") - entry.link(href=f"{base}/rss", rel="self", type="application/rss+xml") entry.description(pkg.Description or str()) - - attr = getattr(pkg.PackageBase, date_attr) - dt = filters.timestamp_to_datetime(attr) + dt = filters.timestamp_to_datetime(pkg.Timestamp) dt = filters.as_timezone(dt, request.user.Timezone) entry.pubDate(dt.strftime("%Y-%m-%d %H:%M:%S%z")) - - entry.source(f"{base}") - if pkg.PackageBase.Maintainer: - entry.author(author={"name": pkg.PackageBase.Maintainer.Username}) - entry.guid(f"{pkg.Name} - {attr}") + entry.guid(f"{pkg.Name}-{pkg.Timestamp}") return feed.rss_str() @@ -59,15 +49,15 @@ async def rss(request: Request): .join(PackageBase) .order_by(PackageBase.SubmittedTS.desc()) .limit(100) + .with_entities( + Package.Name, + Package.Description, + PackageBase.SubmittedTS.label("Timestamp"), + ) ) - feed = make_rss_feed(request, packages, "SubmittedTS") + feed = make_rss_feed(request, packages) response = Response(feed, media_type="application/rss+xml") - package = packages.first() - if package: - dt = datetime.utcfromtimestamp(package.PackageBase.SubmittedTS) - modified = dt.strftime("%a, %d %m %Y %H:%M:%S GMT") - response.headers["Last-Modified"] = modified return response @@ -79,14 +69,14 @@ async def rss_modified(request: Request): .join(PackageBase) .order_by(PackageBase.ModifiedTS.desc()) .limit(100) + .with_entities( + Package.Name, + Package.Description, + PackageBase.ModifiedTS.label("Timestamp"), + ) ) - feed = make_rss_feed(request, packages, "ModifiedTS") + feed = make_rss_feed(request, packages) response = Response(feed, media_type="application/rss+xml") - package = packages.first() - if package: - dt = datetime.utcfromtimestamp(package.PackageBase.ModifiedTS) - modified = dt.strftime("%a, %d %m %Y %H:%M:%S GMT") - response.headers["Last-Modified"] = modified return response From 862221f5ce244323208f9034b5c14bb0852d2cf8 Mon Sep 17 00:00:00 2001 From: renovate Date: Sat, 15 Jul 2023 20:27:12 +0000 Subject: [PATCH 075/178] fix(deps): update all non-major dependencies --- poetry.lock | 52 ++++++++++++++++++++------------------------------ pyproject.toml | 2 +- 2 files changed, 22 insertions(+), 32 deletions(-) diff --git a/poetry.lock b/poetry.lock index f3f19d11..368371db 100644 --- a/poetry.lock +++ b/poetry.lock @@ -792,27 +792,27 @@ socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "hypercorn" -version = "0.14.3" +version = "0.14.4" description = "A ASGI Server based on Hyper libraries and inspired by Gunicorn" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "Hypercorn-0.14.3-py3-none-any.whl", hash = "sha256:7c491d5184f28ee960dcdc14ab45d14633ca79d72ddd13cf4fcb4cb854d679ab"}, - {file = "Hypercorn-0.14.3.tar.gz", hash = "sha256:4a87a0b7bbe9dc75fab06dbe4b301b9b90416e9866c23a377df21a969d6ab8dd"}, + {file = "hypercorn-0.14.4-py3-none-any.whl", hash = "sha256:f956200dbf8677684e6e976219ffa6691d6cf795281184b41dbb0b135ab37b8d"}, + {file = "hypercorn-0.14.4.tar.gz", hash = "sha256:3fa504efc46a271640023c9b88c3184fd64993f47a282e8ae1a13ccb285c2f67"}, ] [package.dependencies] h11 = "*" h2 = ">=3.1.0" priority = "*" -toml = "*" +tomli = {version = "*", markers = "python_version < \"3.11\""} wsproto = ">=0.14.0" [package.extras] docs = ["pydata_sphinx_theme"] h3 = ["aioquic (>=0.9.0,<1.0)"] -trio = ["trio (>=0.11.0)"] +trio = ["exceptiongroup (>=1.1.0)", "trio (>=0.22.0)"] uvloop = ["uvloop"] [[package]] @@ -912,6 +912,8 @@ files = [ {file = "lxml-4.9.3-cp27-cp27m-macosx_11_0_x86_64.whl", hash = "sha256:b0a545b46b526d418eb91754565ba5b63b1c0b12f9bd2f808c852d9b4b2f9b5c"}, {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:075b731ddd9e7f68ad24c635374211376aa05a281673ede86cbe1d1b3455279d"}, {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1e224d5755dba2f4a9498e150c43792392ac9b5380aa1b845f98a1618c94eeef"}, + {file = "lxml-4.9.3-cp27-cp27m-win32.whl", hash = "sha256:2c74524e179f2ad6d2a4f7caf70e2d96639c0954c943ad601a9e146c76408ed7"}, + {file = "lxml-4.9.3-cp27-cp27m-win_amd64.whl", hash = "sha256:4f1026bc732b6a7f96369f7bfe1a4f2290fb34dce00d8644bc3036fb351a4ca1"}, {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c0781a98ff5e6586926293e59480b64ddd46282953203c76ae15dbbbf302e8bb"}, {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cef2502e7e8a96fe5ad686d60b49e1ab03e438bd9123987994528febd569868e"}, {file = "lxml-4.9.3-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b86164d2cff4d3aaa1f04a14685cbc072efd0b4f99ca5708b2ad1b9b5988a991"}, @@ -1274,14 +1276,14 @@ twisted = ["twisted"] [[package]] name = "prometheus-fastapi-instrumentator" -version = "6.0.0" +version = "6.1.0" description = "Instrument your FastAPI with Prometheus metrics." category = "main" optional = false python-versions = ">=3.7.0,<4.0.0" files = [ - {file = "prometheus_fastapi_instrumentator-6.0.0-py3-none-any.whl", hash = "sha256:6f66a951a4801667f7311d161f3aebfe0cd202391d0f067fbbe169792e2d987b"}, - {file = "prometheus_fastapi_instrumentator-6.0.0.tar.gz", hash = "sha256:f1ddd0b8ead75e71d055bdf4cb7e995ec6a6ca63543245e7bbc5ca9b14c45191"}, + {file = "prometheus_fastapi_instrumentator-6.1.0-py3-none-any.whl", hash = "sha256:2279ac1cf5b9566a4c3a07f78c9c5ee19648ed90976ab87d73d672abc1bfa017"}, + {file = "prometheus_fastapi_instrumentator-6.1.0.tar.gz", hash = "sha256:1820d7a90389ce100f7d1285495ead388818ae0882e761c1f3e6e62a410bdf13"}, ] [package.dependencies] @@ -1456,14 +1458,14 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no [[package]] name = "pytest-asyncio" -version = "0.21.0" +version = "0.21.1" description = "Pytest support for asyncio" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-asyncio-0.21.0.tar.gz", hash = "sha256:2b38a496aef56f56b0e87557ec313e11e1ab9276fc3863f6a7be0f1d0e415e1b"}, - {file = "pytest_asyncio-0.21.0-py3-none-any.whl", hash = "sha256:f2b3366b7cd501a4056858bd39349d5af19742aed2d81660b7998b6341c7eb9c"}, + {file = "pytest-asyncio-0.21.1.tar.gz", hash = "sha256:40a7eae6dded22c7b604986855ea48400ab15b069ae38116e8c01238e9eeb64d"}, + {file = "pytest_asyncio-0.21.1-py3-none-any.whl", hash = "sha256:8666c1c8ac02631d7c51ba282e0c69a8a452b211ffedf2599099845da5c5c37b"}, ] [package.dependencies] @@ -1494,14 +1496,14 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale [[package]] name = "pytest-tap" -version = "3.3" +version = "3.4" description = "Test Anything Protocol (TAP) reporting plugin for pytest" category = "dev" optional = false python-versions = "*" files = [ - {file = "pytest-tap-3.3.tar.gz", hash = "sha256:5f0919a147cf0396b2f10d64d365a0bf8062e06543e93c675c9d37f5605e983c"}, - {file = "pytest_tap-3.3-py3-none-any.whl", hash = "sha256:4fbbc0e090c2e94f6199bee4e4f68ab3c5e176b37a72a589ad84e0f72a2fce55"}, + {file = "pytest-tap-3.4.tar.gz", hash = "sha256:a7c2a4a3e8b4bf18522e46d74208f8579a191dd972c59182104ad9a4967318fb"}, + {file = "pytest_tap-3.4-py3-none-any.whl", hash = "sha256:d97a2115c94415086f6faec395d243b3c18ea846ce1c1653a4b2588082be35d8"}, ] [package.dependencies] @@ -1774,18 +1776,6 @@ files = [ [package.extras] yaml = ["PyYAML (>=5.1)", "more-itertools"] -[[package]] -name = "toml" -version = "0.10.2" -description = "Python Library for Tom's Obvious, Minimal Language" -category = "main" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, - {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, -] - [[package]] name = "tomli" version = "2.0.1" @@ -1842,14 +1832,14 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uvicorn" -version = "0.22.0" +version = "0.23.0" description = "The lightning-fast ASGI server." category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "uvicorn-0.22.0-py3-none-any.whl", hash = "sha256:e9434d3bbf05f310e762147f769c9f21235ee118ba2d2bf1155a7196448bd996"}, - {file = "uvicorn-0.22.0.tar.gz", hash = "sha256:79277ae03db57ce7d9aa0567830bbb51d7a612f54d6e1e3e92da3ef24c2c8ed8"}, + {file = "uvicorn-0.23.0-py3-none-any.whl", hash = "sha256:479599b2c0bb1b9b394c6d43901a1eb0c1ec72c7d237b5bafea23c5b2d4cdf10"}, + {file = "uvicorn-0.23.0.tar.gz", hash = "sha256:d38ab90c0e2c6fe3a054cddeb962cfd5d0e0e6608eaaff4a01d5c36a67f3168c"}, ] [package.dependencies] @@ -1958,4 +1948,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "bbab458ee508b073ea3693caaa5d8704ff1a800ddecd816bf39a6561729777c0" +content-hash = "b67f1b1599794a6890b0a31b2b127880d75c84beeeae3df4ecb3ae92296948da" diff --git a/pyproject.toml b/pyproject.toml index ddd4f638..e98e887f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,7 +86,7 @@ Werkzeug = "^2.3.3" SQLAlchemy = "^1.4.48" # ASGI -uvicorn = "^0.22.0" +uvicorn = "^0.23.0" gunicorn = "^20.1.0" Hypercorn = "^0.14.3" prometheus-fastapi-instrumentator = "^6.0.0" From 5729d6787f43574e70f6b87543065838d475f880 Mon Sep 17 00:00:00 2001 From: moson Date: Sun, 16 Jul 2023 13:27:02 +0200 Subject: [PATCH 076/178] fix: git links in comments for multiple OIDs The chance of finding multiple object IDs when performing lookups with a shortened SHA1 hash (7 digits) seems to be quite high. In those cases pygit2 will throw an error. Let's catch those exceptions and gracefully handle them. Fixes: aurweb-errors#496 (and alike) Signed-off-by: moson --- aurweb/scripts/rendercomment.py | 9 ++++++-- test/test_rendercomment.py | 39 +++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py index e640c1d4..31f3fdd4 100755 --- a/aurweb/scripts/rendercomment.py +++ b/aurweb/scripts/rendercomment.py @@ -72,8 +72,13 @@ class GitCommitsInlineProcessor(markdown.inlinepatterns.InlineProcessor): def handleMatch(self, m, data): oid = m.group(1) - if oid not in self._repo: - # Unknown OID; preserve the orginal text. + # Lookup might raise ValueError in case multiple object ID's were found + try: + if oid not in self._repo: + # Unknown OID; preserve the orginal text. + return None, None, None + except ValueError: + # Multiple OID's found; preserve the orginal text. return None, None, None el = Element("a") diff --git a/test/test_rendercomment.py b/test/test_rendercomment.py index 59eb7191..f9edb45b 100644 --- a/test/test_rendercomment.py +++ b/test/test_rendercomment.py @@ -1,5 +1,7 @@ +import os from unittest import mock +import pygit2 import pytest from aurweb import aur_logging, config, db, time @@ -166,6 +168,43 @@ http://example.com/{commit_hash}\ assert comment.RenderedComment == expected +def test_git_commit_link_multiple_oids( + git: GitRepository, user: User, package: Package +): + # Make sure we get reproducible hashes by hardcoding the dates + date = "Sun, 16 Jul 2023 06:06:06 +0200" + os.environ["GIT_COMMITTER_DATE"] = date + os.environ["GIT_AUTHOR_DATE"] = date + + # Package names that cause two object IDs starting with "09a3468" + pkgnames = [ + "bfa3e330-23c5-11ee-9b6c-9c2dcdf2810d", + "54c6a420-23c6-11ee-9b6c-9c2dcdf2810d", + ] + + # Create our commits + for pkgname in pkgnames: + with db.begin(): + package = db.create( + Package, PackageBase=package.PackageBase, Name=pkgname, Version="1.0" + ) + git.commit(package, pkgname) + + repo_path = config.get("serve", "repo-path") + repo = pygit2.Repository(repo_path) + + # Make sure we get an error when we search the git repo for "09a3468" + with pytest.raises(ValueError) as oid_error: + assert "09a3468" in repo + assert "ambiguous OID prefix" in oid_error + + # Create a comment, referencing "09a3468" + comment = create_comment(user, package.PackageBase, "Commit 09a3468 is nasty!") + + # Make sure our comment does not contain a link. + assert comment.RenderedComment == "

    Commit 09a3468 is nasty!

    " + + def test_flyspray_issue_link(user: User, pkgbase: PackageBase): text = """\ FS#1234567. From bc03d8b8f20ac0a1e6a2b03069632c8a064332f0 Mon Sep 17 00:00:00 2001 From: moson Date: Thu, 20 Jul 2023 18:21:05 +0200 Subject: [PATCH 077/178] fix: Fix middleware checking for accepted terms The current query is a bit mixed up. The intention was to return the number of unaccepted records. Now it does also count all records that were accepted by some other user though. Let's check the total number of terms vs. the number of accepted records (by our user) instead. Signed-off-by: moson --- aurweb/asgi.py | 19 ++++++++----------- test/test_accounts_routes.py | 6 ++++++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/aurweb/asgi.py b/aurweb/asgi.py index eb02413b..1be77ff9 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -14,7 +14,7 @@ from fastapi.responses import RedirectResponse from fastapi.staticfiles import StaticFiles from jinja2 import TemplateNotFound from prometheus_client import multiprocess -from sqlalchemy import and_, or_ +from sqlalchemy import and_ from starlette.exceptions import HTTPException as StarletteHTTPException from starlette.middleware.authentication import AuthenticationMiddleware from starlette.middleware.sessions import SessionMiddleware @@ -277,21 +277,18 @@ 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.""" if request.user.is_authenticated() and request.url.path != "/tos": - unaccepted = ( + accepted = ( 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, - ), - ) + and_( + AcceptedTerm.UsersID == request.user.ID, + AcceptedTerm.TermsID == Term.ID, + AcceptedTerm.Revision >= Term.Revision, + ), ) ) - if query(Term).count() > unaccepted.count(): + if query(Term).count() - accepted.count() > 0: return RedirectResponse("/tos", status_code=int(http.HTTPStatus.SEE_OTHER)) return await util.error_or_result(call_next, request) diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index c9d77c1f..3c481d0a 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -1915,6 +1915,12 @@ def test_get_terms_of_service(client: TestClient, user: User): # We accepted the term, there's nothing left to accept. assert response.status_code == int(HTTPStatus.SEE_OTHER) + # Make sure we don't get redirected to /tos when browsing "Home" + with client as request: + request.cookies = cookies + response = request.get("/") + assert response.status_code == int(HTTPStatus.OK) + # Bump the term's revision. with db.begin(): term.Revision = 2 From 347c2ce721b5782ff0324eb80fdc5613b4ebe478 Mon Sep 17 00:00:00 2001 From: moson Date: Sat, 22 Jul 2023 10:43:19 +0200 Subject: [PATCH 078/178] change: Change order of commit validation routine We currently validate all commits going from latest -> oldest. It would be nicer to go oldest -> latest so that, in case of errors, we would indicate which commit "introduced" the problem. Signed-off-by: moson --- aurweb/git/update.py | 2 +- test/t1300-git-update.t | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/aurweb/git/update.py b/aurweb/git/update.py index cd7813e0..4c4fff0f 100755 --- a/aurweb/git/update.py +++ b/aurweb/git/update.py @@ -356,7 +356,7 @@ def main(): # noqa: C901 die("denying non-fast-forward (you should pull first)") # Prepare the walker that validates new commits. - walker = repo.walk(sha1_new, pygit2.GIT_SORT_TOPOLOGICAL) + walker = repo.walk(sha1_new, pygit2.GIT_SORT_REVERSE) if sha1_old != "0" * 40: walker.hide(sha1_old) diff --git a/test/t1300-git-update.t b/test/t1300-git-update.t index 4fdb487b..0fb2da17 100755 --- a/test/t1300-git-update.t +++ b/test/t1300-git-update.t @@ -312,11 +312,16 @@ test_expect_success 'Pushing a tree with a large blob.' ' printf "%256001s" x >aur.git/file && git -C aur.git add file && git -C aur.git commit -q -m "Add large blob" && + first_error=$(git -C aur.git rev-parse HEAD) && + touch aur.git/another.file && + git -C aur.git add another.file && + git -C aur.git commit -q -m "Add another commit" && new=$(git -C aur.git rev-parse HEAD) && test_must_fail \ env AUR_USER=user AUR_PKGBASE=foobar AUR_PRIVILEGED=0 \ cover "$GIT_UPDATE" refs/heads/master "$old" "$new" >actual 2>&1 && - grep -q "^error: maximum blob size (250.00KiB) exceeded$" actual + grep -q "^error: maximum blob size (250.00KiB) exceeded$" actual && + grep -q "^error: $first_error:$" actual ' test_expect_success 'Pushing .SRCINFO with a non-matching package base.' ' From 44c158b8c2667ace8e44d2cac3b7aed4efcc1464 Mon Sep 17 00:00:00 2001 From: moson Date: Sat, 22 Jul 2023 16:31:50 +0200 Subject: [PATCH 079/178] feat: Implement statistics class & additional metrics The new module/class helps us constructing queries and count records to expose various statistics on the homepage. We also utilize for some new prometheus metrics (package and user gauges). Record counts are being cached with Redis. Signed-off-by: moson --- aurweb/cache.py | 11 ++-- aurweb/prometheus.py | 18 ++++++- aurweb/routers/html.py | 72 ++++---------------------- aurweb/routers/packages.py | 6 +-- aurweb/statistics.py | 102 +++++++++++++++++++++++++++++++++++++ test/test_cache.py | 18 +++---- test/test_metrics.py | 5 +- 7 files changed, 143 insertions(+), 89 deletions(-) create mode 100644 aurweb/statistics.py diff --git a/aurweb/cache.py b/aurweb/cache.py index fe1e5f1d..bb374e57 100644 --- a/aurweb/cache.py +++ b/aurweb/cache.py @@ -1,20 +1,15 @@ import pickle -from prometheus_client import Counter from sqlalchemy import orm from aurweb import config from aurweb.aur_redis import redis_connection +from aurweb.prometheus import SEARCH_REQUESTS _redis = redis_connection() -# Prometheus metrics -SEARCH_REQUESTS = Counter( - "search_requests", "Number of search requests by cache hit/miss", ["cache"] -) - -async def db_count_cache(key: str, query: orm.Query, expire: int = None) -> int: +def db_count_cache(key: str, query: orm.Query, expire: int = None) -> int: """Store and retrieve a query.count() via redis cache. :param key: Redis key @@ -30,7 +25,7 @@ async def db_count_cache(key: str, query: orm.Query, expire: int = None) -> int: return int(result) -async def db_query_cache(key: str, query: orm.Query, expire: int = None) -> list: +def db_query_cache(key: str, query: orm.Query, expire: int = None) -> list: """Store and retrieve query results via redis cache. :param key: Redis key diff --git a/aurweb/prometheus.py b/aurweb/prometheus.py index b8b7984f..d3455551 100644 --- a/aurweb/prometheus.py +++ b/aurweb/prometheus.py @@ -1,6 +1,6 @@ from typing import Any, Callable, Optional -from prometheus_client import Counter +from prometheus_client import Counter, Gauge from prometheus_fastapi_instrumentator import Instrumentator from prometheus_fastapi_instrumentator.metrics import Info from starlette.routing import Match, Route @@ -11,10 +11,26 @@ logger = aur_logging.get_logger(__name__) _instrumentator = Instrumentator() +# Custom metrics +SEARCH_REQUESTS = Counter( + "aur_search_requests", "Number of search requests by cache hit/miss", ["cache"] +) +USERS = Gauge( + "aur_users", "Number of AUR users by type", ["type"], multiprocess_mode="livemax" +) +PACKAGES = Gauge( + "aur_packages", + "Number of AUR packages by state", + ["state"], + multiprocess_mode="livemax", +) + + def instrumentator(): return _instrumentator +# FastAPI metrics # Taken from https://github.com/stephenhillier/starlette_exporter # Their license is included in LICENSES/starlette_exporter. # The code has been modified to remove child route checks diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index fc9f3519..c3bcee49 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -17,11 +17,10 @@ from sqlalchemy import case, or_ import aurweb.config import aurweb.models.package_request from aurweb import aur_logging, cookies, db, models, time, util -from aurweb.cache import db_count_cache from aurweb.exceptions import handle_form_exceptions -from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID from aurweb.models.package_request import PENDING_ID from aurweb.packages.util import query_notified, query_voted, updated_packages +from aurweb.statistics import Statistics, update_prometheus_metrics from aurweb.templates import make_context, render_template logger = aur_logging.get_logger(__name__) @@ -87,68 +86,12 @@ async def index(request: Request): context = make_context(request, "Home") context["ssh_fingerprints"] = util.get_ssh_fingerprints() - bases = db.query(models.PackageBase) - cache_expire = aurweb.config.getint("cache", "expiry_time") + # Package statistics. - context["package_count"] = await db_count_cache( - "package_count", bases, expire=cache_expire - ) - - query = bases.filter(models.PackageBase.MaintainerUID.is_(None)) - context["orphan_count"] = await db_count_cache( - "orphan_count", query, expire=cache_expire - ) - - query = db.query(models.User) - context["user_count"] = await db_count_cache( - "user_count", query, expire=cache_expire - ) - - query = query.filter( - or_( - models.User.AccountTypeID == TRUSTED_USER_ID, - models.User.AccountTypeID == TRUSTED_USER_AND_DEV_ID, - ) - ) - context["trusted_user_count"] = await db_count_cache( - "trusted_user_count", query, expire=cache_expire - ) - - # Current timestamp. - now = time.utcnow() - - seven_days = 86400 * 7 # Seven days worth of seconds. - seven_days_ago = now - seven_days - - one_hour = 3600 - updated = bases.filter( - models.PackageBase.ModifiedTS - models.PackageBase.SubmittedTS >= one_hour - ) - - query = bases.filter(models.PackageBase.SubmittedTS >= seven_days_ago) - context["seven_days_old_added"] = await db_count_cache( - "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( - "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( - "year_old_updated", query, expire=cache_expire - ) - - query = bases.filter( - models.PackageBase.ModifiedTS - models.PackageBase.SubmittedTS < 3600 - ) - context["never_updated"] = await db_count_cache( - "never_updated", query, expire=cache_expire - ) + stats = Statistics(cache_expire) + for counter in stats.HOMEPAGE_COUNTERS: + context[counter] = stats.get_count(counter) # Get the 15 most recently updated packages. context["package_updates"] = updated_packages(15, cache_expire) @@ -193,7 +136,7 @@ async def index(request: Request): ) archive_time = aurweb.config.getint("options", "request_archive_time") - start = now - archive_time + start = time.utcnow() - archive_time # Package requests created by request.user. context["package_requests"] = ( @@ -269,6 +212,9 @@ async def metrics(request: Request): status_code=HTTPStatus.SERVICE_UNAVAILABLE, ) + # update prometheus gauges for packages and users + update_prometheus_metrics() + registry = CollectorRegistry() multiprocess.MultiProcessCollector(registry) data = generate_latest(registry) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index 779efb4b..f1b2a138 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -91,9 +91,7 @@ async def packages_get( # increase the amount of time required to collect a count. # we use redis for caching the results of the query cache_expire = config.getint("cache", "expiry_time") - num_packages = await db_count_cache( - hash_query(search.query), search.query, cache_expire - ) + num_packages = db_count_cache(hash_query(search.query), search.query, cache_expire) # Apply user-specified sort column and ordering. search.sort_by(sort_by, sort_order) @@ -118,7 +116,7 @@ async def packages_get( results = results.limit(per_page).offset(offset) # we use redis for caching the results of the query - packages = await db_query_cache(hash_query(results), results, cache_expire) + packages = db_query_cache(hash_query(results), results, cache_expire) context["packages"] = packages context["packages_count"] = num_packages diff --git a/aurweb/statistics.py b/aurweb/statistics.py new file mode 100644 index 00000000..934caa37 --- /dev/null +++ b/aurweb/statistics.py @@ -0,0 +1,102 @@ +from aurweb import config, db, time +from aurweb.cache import db_count_cache +from aurweb.models import PackageBase, User +from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID, USER_ID +from aurweb.prometheus import PACKAGES, USERS + + +class Statistics: + HOMEPAGE_COUNTERS = [ + "package_count", + "orphan_count", + "seven_days_old_added", + "seven_days_old_updated", + "year_old_updated", + "never_updated", + "user_count", + "trusted_user_count", + ] + PROMETHEUS_USER_COUNTERS = [ + ("trusted_user_count", "tu"), + ("regular_user_count", "user"), + ] + PROMETHEUS_PACKAGE_COUNTERS = [ + ("orphan_count", "orphan"), + ("never_updated", "not_updated"), + ("updated_packages", "updated"), + ] + + seven_days = 86400 * 7 + one_hour = 3600 + year = seven_days * 52 + + def __init__(self, cache_expire: int = None) -> "Statistics": + self.expiry_time = cache_expire + self.now = time.utcnow() + self.seven_days_ago = self.now - self.seven_days + self.year_ago = self.now - self.year + self.user_query = db.query(User) + self.bases_query = db.query(PackageBase) + self.updated_query = db.query(PackageBase).filter( + PackageBase.ModifiedTS - PackageBase.SubmittedTS >= self.one_hour + ) + + def get_count(self, counter: str) -> int: + query = None + match counter: + case "package_count": + query = self.bases_query + case "orphan_count": + query = self.bases_query.filter(PackageBase.MaintainerUID.is_(None)) + case "seven_days_old_added": + query = self.bases_query.filter( + PackageBase.SubmittedTS >= self.seven_days_ago + ) + case "seven_days_old_updated": + query = self.updated_query.filter( + PackageBase.ModifiedTS >= self.seven_days_ago + ) + case "year_old_updated": + query = self.updated_query.filter( + PackageBase.ModifiedTS >= self.year_ago + ) + case "never_updated": + query = self.bases_query.filter( + PackageBase.ModifiedTS - PackageBase.SubmittedTS < self.one_hour + ) + case "updated_packages": + query = self.bases_query.filter( + PackageBase.ModifiedTS - PackageBase.SubmittedTS > self.one_hour, + ~PackageBase.MaintainerUID.is_(None), + ) + case "user_count": + query = self.user_query + case "trusted_user_count": + query = self.user_query.filter( + User.AccountTypeID.in_( + ( + TRUSTED_USER_ID, + TRUSTED_USER_AND_DEV_ID, + ) + ) + ) + case "regular_user_count": + query = self.user_query.filter(User.AccountTypeID == USER_ID) + case _: + return -1 + + return db_count_cache(counter, query, expire=self.expiry_time) + + +def update_prometheus_metrics(): + cache_expire = config.getint("cache", "expiry_time") + stats = Statistics(cache_expire) + # Users gauge + for counter, utype in stats.PROMETHEUS_USER_COUNTERS: + count = stats.get_count(counter) + USERS.labels(utype).set(count) + + # Packages gauge + for counter, state in stats.PROMETHEUS_PACKAGE_COUNTERS: + count = stats.get_count(counter) + PACKAGES.labels(state).set(count) diff --git a/test/test_cache.py b/test/test_cache.py index e19fa6a2..a599ab32 100644 --- a/test/test_cache.py +++ b/test/test_cache.py @@ -31,15 +31,14 @@ def clear_fakeredis_cache(): cache._redis.flushall() -@pytest.mark.asyncio -async def test_db_count_cache(user): +def test_db_count_cache(user): query = db.query(User) # We have no cached value yet. assert cache._redis.get("key1") is None # Add to cache - assert await cache.db_count_cache("key1", query) == query.count() + assert cache.db_count_cache("key1", query) == query.count() # It's cached now. assert cache._redis.get("key1") is not None @@ -48,35 +47,34 @@ async def test_db_count_cache(user): assert cache._redis.ttl("key1") == -1 # Cache a query with an expire. - value = await cache.db_count_cache("key2", query, 100) + value = cache.db_count_cache("key2", query, 100) assert value == query.count() assert cache._redis.ttl("key2") == 100 -@pytest.mark.asyncio -async def test_db_query_cache(user): +def test_db_query_cache(user): query = db.query(User) # We have no cached value yet. assert cache._redis.get("key1") is None # Add to cache - await cache.db_query_cache("key1", query) + cache.db_query_cache("key1", query) # It's cached now. assert cache._redis.get("key1") is not None # Modify our user and make sure we got a cached value user.Username = "changed" - cached = await cache.db_query_cache("key1", query) + cached = cache.db_query_cache("key1", query) assert cached[0].Username != query.all()[0].Username # It does not expire assert cache._redis.ttl("key1") == -1 # Cache a query with an expire. - value = await cache.db_query_cache("key2", query, 100) + value = cache.db_query_cache("key2", query, 100) assert len(value) == query.count() assert value[0].Username == query.all()[0].Username @@ -90,7 +88,7 @@ async def test_db_query_cache(user): with mock.patch("aurweb.config.getint", side_effect=mock_max_search_entries): # Try to add another entry (we already have 2) - await cache.db_query_cache("key3", query) + cache.db_query_cache("key3", query) # Make sure it was not added because it exceeds our max. assert cache._redis.get("key3") is None diff --git a/test/test_metrics.py b/test/test_metrics.py index 1859d8cb..6f67d926 100644 --- a/test/test_metrics.py +++ b/test/test_metrics.py @@ -26,11 +26,10 @@ def user() -> User: yield user -@pytest.mark.asyncio -async def test_search_cache_metrics(user: User): +def test_search_cache_metrics(user: User): # Fire off 3 identical queries for caching for _ in range(3): - await db_query_cache("key", db.query(User)) + db_query_cache("key", db.query(User)) # Get metrics metrics = str(generate_latest(REGISTRY)) From 8699457917a05caae41a7cd2b7ecb6d94a7955b7 Mon Sep 17 00:00:00 2001 From: moson Date: Sat, 22 Jul 2023 21:23:16 +0200 Subject: [PATCH 080/178] feat: Separate cache expiry for stats and search Allows us to set different cache eviction timespans for search queries and statistics. Stats and especially "last package updates" should probably be refreshed more often, whereas we might want to cache search results for a bit longer. So this gives us a bit more flexibility playing around with different settings and tweak things. Signed-off-by: moson --- aurweb/routers/html.py | 2 +- aurweb/routers/packages.py | 2 +- aurweb/statistics.py | 2 +- conf/config.defaults | 6 ++++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index c3bcee49..2ec497bd 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -86,7 +86,7 @@ async def index(request: Request): context = make_context(request, "Home") context["ssh_fingerprints"] = util.get_ssh_fingerprints() - cache_expire = aurweb.config.getint("cache", "expiry_time") + cache_expire = aurweb.config.getint("cache", "expiry_time_statistics", 300) # Package statistics. stats = Statistics(cache_expire) diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index f1b2a138..3f96d71c 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -90,7 +90,7 @@ async def packages_get( # Including more query operations below, like ordering, will # increase the amount of time required to collect a count. # we use redis for caching the results of the query - cache_expire = config.getint("cache", "expiry_time") + cache_expire = config.getint("cache", "expiry_time_search", 600) num_packages = db_count_cache(hash_query(search.query), search.query, cache_expire) # Apply user-specified sort column and ordering. diff --git a/aurweb/statistics.py b/aurweb/statistics.py index 934caa37..6e9dbe1f 100644 --- a/aurweb/statistics.py +++ b/aurweb/statistics.py @@ -89,7 +89,7 @@ class Statistics: def update_prometheus_metrics(): - cache_expire = config.getint("cache", "expiry_time") + cache_expire = config.getint("cache", "expiry_time_statistics", 300) stats = Statistics(cache_expire) # Users gauge for counter, utype in stats.PROMETHEUS_USER_COUNTERS: diff --git a/conf/config.defaults b/conf/config.defaults index 4e2415ed..ab0a9b67 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -169,5 +169,7 @@ range_end = 172800 [cache] ; maximum number of keys/entries (for search results) in our redis cache, default is 50000 max_search_entries = 50000 -; number of seconds after a cache entry expires, default is 3 minutes -expiry_time = 180 +; number of seconds after a cache entry for search queries expires, default is 10 minutes +expiry_time_search = 600 +; number of seconds after a cache entry for statistics queries expires, default is 5 minutes +expiry_time_statistics = 300 From 6cd70a5c9fb57c42af7c2254045eba9fe6aa17e0 Mon Sep 17 00:00:00 2001 From: moson Date: Sun, 23 Jul 2023 11:34:50 +0200 Subject: [PATCH 081/178] test: Add tests for user/package statistics Signed-off-by: moson --- test/test_statistics.py | 125 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 test/test_statistics.py diff --git a/test/test_statistics.py b/test/test_statistics.py new file mode 100644 index 00000000..dda7b357 --- /dev/null +++ b/test/test_statistics.py @@ -0,0 +1,125 @@ +import pytest +from prometheus_client import REGISTRY, generate_latest + +from aurweb import cache, db, time +from aurweb.models.account_type import TRUSTED_USER_ID, USER_ID +from aurweb.models.package import Package +from aurweb.models.package_base import PackageBase +from aurweb.models.user import User +from aurweb.statistics import Statistics, update_prometheus_metrics + + +@pytest.fixture(autouse=True) +def setup(db_test): + return + + +@pytest.fixture(autouse=True) +def clear_fakeredis_cache(): + cache._redis.flushall() + + +@pytest.fixture +def test_data(): + # Create some test data (users and packages) + with db.begin(): + for i in range(10): + user = db.create( + User, + Username=f"test{i}", + Email=f"test{i}@example.org", + RealName=f"Test User {i}", + Passwd="testPassword", + AccountTypeID=USER_ID, + ) + + now = time.utcnow() + old = now - 60 * 60 * 24 * 8 # 8 days + older = now - 60 * 60 * 24 * 400 # 400 days + + pkgbase = db.create( + PackageBase, + Name=f"test-package{i}", + Maintainer=user, + SubmittedTS=old, + ModifiedTS=now, + ) + db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) + + # Modify some data to get some variances for our counters + if i == 1: + user.AccountTypeID = TRUSTED_USER_ID + pkgbase.Maintainer = None + pkgbase.SubmittedTS = now + + if i == 2: + pkgbase.SubmittedTS = older + + if i == 3: + pkgbase.SubmittedTS = older + pkgbase.ModifiedTS = old + yield + + +@pytest.fixture +def stats() -> Statistics: + yield Statistics() + + +@pytest.mark.parametrize( + "counter, expected", + [ + ("package_count", 10), + ("orphan_count", 1), + ("seven_days_old_added", 1), + ("seven_days_old_updated", 8), + ("year_old_updated", 9), + ("never_updated", 1), + ("user_count", 10), + ("trusted_user_count", 1), + ("regular_user_count", 9), + ("updated_packages", 9), + ("nonsense", -1), + ], +) +def test_get_count(stats: Statistics, test_data, counter: str, expected: int): + assert stats.get_count(counter) == expected + + +def test_get_count_change(stats: Statistics, test_data): + pkgs_before = stats.get_count("package_count") + tus_before = stats.get_count("trusted_user_count") + + assert pkgs_before == 10 + assert tus_before == 1 + + # Let's delete a package and promote a user to TU + with db.begin(): + pkgbase = db.query(PackageBase).first() + db.delete(pkgbase) + + user = db.query(User).filter(User.AccountTypeID == USER_ID).first() + user.AccountTypeID = TRUSTED_USER_ID + + # Values should end up in (fake) redis cache so they should be the same + assert stats.get_count("package_count") == pkgs_before + assert stats.get_count("trusted_user_count") == tus_before + + # Let's clear the cache and check again + cache._redis.flushall() + assert stats.get_count("package_count") != pkgs_before + assert stats.get_count("trusted_user_count") != tus_before + + +def test_update_prometheus_metrics(test_data): + metrics = str(generate_latest(REGISTRY)) + + assert "aur_users{" not in metrics + assert "aur_packages{" not in metrics + + # Let's update our metrics. We should find our gauges now + update_prometheus_metrics() + metrics = str(generate_latest(REGISTRY)) + + assert 'aur_users{type="user"} 9.0' in metrics + assert 'aur_packages{state="updated"} 9.0' in metrics From e45878a058071e59f0f08eb3dca597f560448298 Mon Sep 17 00:00:00 2001 From: moson Date: Sun, 23 Jul 2023 18:53:58 +0200 Subject: [PATCH 082/178] fix: Fix issue with requests totals Problem is that we join with PackageBase, thus we are missing requests for packages that were deleted. Fixes: #483 Signed-off-by: moson --- aurweb/routers/html.py | 11 ++--- aurweb/routers/requests.py | 16 ++----- aurweb/statistics.py | 95 ++++++++++++++++++++++++++++---------- test/test_statistics.py | 32 ++++++++++++- 4 files changed, 111 insertions(+), 43 deletions(-) diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index 2ec497bd..63cc3bb8 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -16,11 +16,10 @@ from sqlalchemy import case, or_ import aurweb.config import aurweb.models.package_request -from aurweb import aur_logging, cookies, db, models, time, util +from aurweb import aur_logging, cookies, db, models, statistics, time, util from aurweb.exceptions import handle_form_exceptions from aurweb.models.package_request import PENDING_ID from aurweb.packages.util import query_notified, query_voted, updated_packages -from aurweb.statistics import Statistics, update_prometheus_metrics from aurweb.templates import make_context, render_template logger = aur_logging.get_logger(__name__) @@ -89,9 +88,9 @@ async def index(request: Request): cache_expire = aurweb.config.getint("cache", "expiry_time_statistics", 300) # Package statistics. - stats = Statistics(cache_expire) - for counter in stats.HOMEPAGE_COUNTERS: - context[counter] = stats.get_count(counter) + counts = statistics.get_homepage_counts() + for k in counts: + context[k] = counts[k] # Get the 15 most recently updated packages. context["package_updates"] = updated_packages(15, cache_expire) @@ -213,7 +212,7 @@ async def metrics(request: Request): ) # update prometheus gauges for packages and users - update_prometheus_metrics() + statistics.update_prometheus_metrics() registry = CollectorRegistry() multiprocess.MultiProcessCollector(registry) diff --git a/aurweb/routers/requests.py b/aurweb/routers/requests.py index 4cfda269..a67419fe 100644 --- a/aurweb/routers/requests.py +++ b/aurweb/routers/requests.py @@ -16,6 +16,7 @@ from aurweb.models.package_request import ( ) from aurweb.requests.util import get_pkgreq_by_id from aurweb.scripts import notify +from aurweb.statistics import get_request_counts from aurweb.templates import make_context, render_template FILTER_PARAMS = { @@ -31,7 +32,7 @@ router = APIRouter() @router.get("/requests") @requires_auth -async def requests( +async def requests( # noqa: C901 request: Request, O: int = Query(default=defaults.O), PP: int = Query(default=defaults.PP), @@ -74,18 +75,11 @@ async def requests( .join(User, PackageRequest.UsersID == User.ID, isouter=True) .join(Maintainer, PackageBase.MaintainerUID == Maintainer.ID, isouter=True) ) - # query = db.query(PackageRequest).join(User) # Requests statistics - context["total_requests"] = query.count() - pending_count = 0 + query.filter(PackageRequest.Status == PENDING_ID).count() - context["pending_requests"] = pending_count - closed_count = 0 + query.filter(PackageRequest.Status == CLOSED_ID).count() - context["closed_requests"] = closed_count - accepted_count = 0 + query.filter(PackageRequest.Status == ACCEPTED_ID).count() - context["accepted_requests"] = accepted_count - rejected_count = 0 + query.filter(PackageRequest.Status == REJECTED_ID).count() - context["rejected_requests"] = rejected_count + counts = get_request_counts() + for k in counts: + context[k] = counts[k] # Apply status filters in_filters = [] diff --git a/aurweb/statistics.py b/aurweb/statistics.py index 6e9dbe1f..3c1298b7 100644 --- a/aurweb/statistics.py +++ b/aurweb/statistics.py @@ -1,31 +1,46 @@ from aurweb import config, db, time from aurweb.cache import db_count_cache -from aurweb.models import PackageBase, User +from aurweb.models import PackageBase, PackageRequest, User from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID, USER_ID +from aurweb.models.package_request import ( + ACCEPTED_ID, + CLOSED_ID, + PENDING_ID, + REJECTED_ID, +) from aurweb.prometheus import PACKAGES, USERS +cache_expire = config.getint("cache", "expiry_time_statistics", 300) + +HOMEPAGE_COUNTERS = [ + "package_count", + "orphan_count", + "seven_days_old_added", + "seven_days_old_updated", + "year_old_updated", + "never_updated", + "user_count", + "trusted_user_count", +] +REQUEST_COUNTERS = [ + "total_requests", + "pending_requests", + "closed_requests", + "accepted_requests", + "rejected_requests", +] +PROMETHEUS_USER_COUNTERS = [ + ("trusted_user_count", "tu"), + ("regular_user_count", "user"), +] +PROMETHEUS_PACKAGE_COUNTERS = [ + ("orphan_count", "orphan"), + ("never_updated", "not_updated"), + ("updated_packages", "updated"), +] + class Statistics: - HOMEPAGE_COUNTERS = [ - "package_count", - "orphan_count", - "seven_days_old_added", - "seven_days_old_updated", - "year_old_updated", - "never_updated", - "user_count", - "trusted_user_count", - ] - PROMETHEUS_USER_COUNTERS = [ - ("trusted_user_count", "tu"), - ("regular_user_count", "user"), - ] - PROMETHEUS_PACKAGE_COUNTERS = [ - ("orphan_count", "orphan"), - ("never_updated", "not_updated"), - ("updated_packages", "updated"), - ] - seven_days = 86400 * 7 one_hour = 3600 year = seven_days * 52 @@ -35,15 +50,18 @@ class Statistics: self.now = time.utcnow() self.seven_days_ago = self.now - self.seven_days self.year_ago = self.now - self.year + self.user_query = db.query(User) self.bases_query = db.query(PackageBase) self.updated_query = db.query(PackageBase).filter( PackageBase.ModifiedTS - PackageBase.SubmittedTS >= self.one_hour ) + self.request_query = db.query(PackageRequest) def get_count(self, counter: str) -> int: query = None match counter: + # Packages case "package_count": query = self.bases_query case "orphan_count": @@ -69,6 +87,7 @@ class Statistics: PackageBase.ModifiedTS - PackageBase.SubmittedTS > self.one_hour, ~PackageBase.MaintainerUID.is_(None), ) + # Users case "user_count": query = self.user_query case "trusted_user_count": @@ -82,6 +101,18 @@ class Statistics: ) case "regular_user_count": query = self.user_query.filter(User.AccountTypeID == USER_ID) + + # Requests + case "total_requests": + query = self.request_query + case "pending_requests": + query = self.request_query.filter(PackageRequest.Status == PENDING_ID) + case "closed_requests": + query = self.request_query.filter(PackageRequest.Status == CLOSED_ID) + case "accepted_requests": + query = self.request_query.filter(PackageRequest.Status == ACCEPTED_ID) + case "rejected_requests": + query = self.request_query.filter(PackageRequest.Status == REJECTED_ID) case _: return -1 @@ -89,14 +120,30 @@ class Statistics: def update_prometheus_metrics(): - cache_expire = config.getint("cache", "expiry_time_statistics", 300) stats = Statistics(cache_expire) # Users gauge - for counter, utype in stats.PROMETHEUS_USER_COUNTERS: + for counter, utype in PROMETHEUS_USER_COUNTERS: count = stats.get_count(counter) USERS.labels(utype).set(count) # Packages gauge - for counter, state in stats.PROMETHEUS_PACKAGE_COUNTERS: + for counter, state in PROMETHEUS_PACKAGE_COUNTERS: count = stats.get_count(counter) PACKAGES.labels(state).set(count) + + +def _get_counts(counters: list[str]) -> dict[str, int]: + stats = Statistics(cache_expire) + result = dict() + for counter in counters: + result[counter] = stats.get_count(counter) + + return result + + +def get_homepage_counts() -> dict[str, int]: + return _get_counts(HOMEPAGE_COUNTERS) + + +def get_request_counts() -> dict[str, int]: + return _get_counts(REQUEST_COUNTERS) diff --git a/test/test_statistics.py b/test/test_statistics.py index dda7b357..a6a814c5 100644 --- a/test/test_statistics.py +++ b/test/test_statistics.py @@ -2,9 +2,15 @@ import pytest from prometheus_client import REGISTRY, generate_latest from aurweb import cache, db, time +from aurweb.models import Package, PackageBase, PackageRequest from aurweb.models.account_type import TRUSTED_USER_ID, USER_ID -from aurweb.models.package import Package -from aurweb.models.package_base import PackageBase +from aurweb.models.package_request import ( + ACCEPTED_ID, + CLOSED_ID, + PENDING_ID, + REJECTED_ID, +) +from aurweb.models.request_type import DELETION_ID, ORPHAN_ID from aurweb.models.user import User from aurweb.statistics import Statistics, update_prometheus_metrics @@ -45,19 +51,36 @@ def test_data(): ModifiedTS=now, ) db.create(Package, PackageBase=pkgbase, Name=pkgbase.Name) + pkgreq = db.create( + PackageRequest, + ReqTypeID=ORPHAN_ID, + User=user, + PackageBase=pkgbase, + PackageBaseName=pkgbase.Name, + RequestTS=now, + Comments=str(), + ClosureComment=str(), + ) # Modify some data to get some variances for our counters if i == 1: user.AccountTypeID = TRUSTED_USER_ID pkgbase.Maintainer = None pkgbase.SubmittedTS = now + pkgreq.Status = PENDING_ID + pkgreq.ReqTypeID = DELETION_ID if i == 2: pkgbase.SubmittedTS = older + pkgreq.Status = ACCEPTED_ID if i == 3: pkgbase.SubmittedTS = older pkgbase.ModifiedTS = old + pkgreq.Status = CLOSED_ID + + if i == 4: + pkgreq.Status = REJECTED_ID yield @@ -79,6 +102,11 @@ def stats() -> Statistics: ("trusted_user_count", 1), ("regular_user_count", 9), ("updated_packages", 9), + ("total_requests", 10), + ("pending_requests", 7), + ("closed_requests", 1), + ("accepted_requests", 1), + ("rejected_requests", 1), ("nonsense", -1), ], ) From 375895f08011c2c91b52b79a2d41fe1504524acf Mon Sep 17 00:00:00 2001 From: moson Date: Sun, 23 Jul 2023 22:46:44 +0200 Subject: [PATCH 083/178] feat: Add Prometheus metrics for requests Adds gauge for requests by type and status Signed-off-by: moson --- aurweb/prometheus.py | 6 ++++++ aurweb/statistics.py | 22 +++++++++++++++++++--- test/test_statistics.py | 6 ++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/aurweb/prometheus.py b/aurweb/prometheus.py index d3455551..40b99a90 100644 --- a/aurweb/prometheus.py +++ b/aurweb/prometheus.py @@ -24,6 +24,12 @@ PACKAGES = Gauge( ["state"], multiprocess_mode="livemax", ) +REQUESTS = Gauge( + "aur_requests", + "Number of AUR requests by type and status", + ["type", "status"], + multiprocess_mode="livemax", +) def instrumentator(): diff --git a/aurweb/statistics.py b/aurweb/statistics.py index 3c1298b7..f301b59c 100644 --- a/aurweb/statistics.py +++ b/aurweb/statistics.py @@ -1,6 +1,8 @@ +from sqlalchemy import func + from aurweb import config, db, time -from aurweb.cache import db_count_cache -from aurweb.models import PackageBase, PackageRequest, User +from aurweb.cache import db_count_cache, db_query_cache +from aurweb.models import PackageBase, PackageRequest, RequestType, User from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID, USER_ID from aurweb.models.package_request import ( ACCEPTED_ID, @@ -8,7 +10,7 @@ from aurweb.models.package_request import ( PENDING_ID, REJECTED_ID, ) -from aurweb.prometheus import PACKAGES, USERS +from aurweb.prometheus import PACKAGES, REQUESTS, USERS cache_expire = config.getint("cache", "expiry_time_statistics", 300) @@ -131,6 +133,20 @@ def update_prometheus_metrics(): count = stats.get_count(counter) PACKAGES.labels(state).set(count) + # Requests gauge + query = ( + db.get_session() + .query(PackageRequest, func.count(PackageRequest.ID), RequestType.Name) + .join(RequestType) + .group_by(RequestType.Name, PackageRequest.Status) + ) + results = db_query_cache("request_metrics", query, cache_expire) + for record in results: + status = record[0].status_display() + count = record[1] + rtype = record[2] + REQUESTS.labels(type=rtype, status=status).set(count) + def _get_counts(counters: list[str]) -> dict[str, int]: stats = Statistics(cache_expire) diff --git a/test/test_statistics.py b/test/test_statistics.py index a6a814c5..db262fa3 100644 --- a/test/test_statistics.py +++ b/test/test_statistics.py @@ -144,6 +144,7 @@ def test_update_prometheus_metrics(test_data): assert "aur_users{" not in metrics assert "aur_packages{" not in metrics + assert "aur_requests{" not in metrics # Let's update our metrics. We should find our gauges now update_prometheus_metrics() @@ -151,3 +152,8 @@ def test_update_prometheus_metrics(test_data): assert 'aur_users{type="user"} 9.0' in metrics assert 'aur_packages{state="updated"} 9.0' in metrics + assert 'aur_requests{status="Pending",type="orphan"} 6.0' in metrics + assert 'aur_requests{status="Closed",type="orphan"} 1.0' in metrics + assert 'aur_requests{status="Accepted",type="orphan"} 1.0' in metrics + assert 'aur_requests{status="Rejected",type="orphan"} 1.0' in metrics + assert 'aur_requests{status="Pending",type="deletion"} 1.0' in metrics From f74f94b50170d82c1d3f899037dc0debd2222725 Mon Sep 17 00:00:00 2001 From: renovate Date: Mon, 24 Jul 2023 11:24:26 +0000 Subject: [PATCH 084/178] fix(deps): update dependency gunicorn to v21 --- poetry.lock | 27 +++++---------------------- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 23 deletions(-) diff --git a/poetry.lock b/poetry.lock index 368371db..42010de5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -685,18 +685,18 @@ test = ["objgraph", "psutil"] [[package]] name = "gunicorn" -version = "20.1.0" +version = "21.2.0" description = "WSGI HTTP Server for UNIX" category = "main" optional = false python-versions = ">=3.5" files = [ - {file = "gunicorn-20.1.0-py3-none-any.whl", hash = "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e"}, - {file = "gunicorn-20.1.0.tar.gz", hash = "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8"}, + {file = "gunicorn-21.2.0-py3-none-any.whl", hash = "sha256:3213aa5e8c24949e792bcacfc176fef362e7aac80b76c56f6b5122bf350722f0"}, + {file = "gunicorn-21.2.0.tar.gz", hash = "sha256:88ec8bff1d634f98e61b9f65bc4bf3cd918a90806c6f5c48bc5603849ec81033"}, ] [package.dependencies] -setuptools = ">=3.0" +packaging = "*" [package.extras] eventlet = ["eventlet (>=0.24.1)"] @@ -1602,23 +1602,6 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] -[[package]] -name = "setuptools" -version = "67.7.2" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "setuptools-67.7.2-py3-none-any.whl", hash = "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b"}, - {file = "setuptools-67.7.2.tar.gz", hash = "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990"}, -] - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] - [[package]] name = "six" version = "1.16.0" @@ -1948,4 +1931,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "b67f1b1599794a6890b0a31b2b127880d75c84beeeae3df4ecb3ae92296948da" +content-hash = "48d66bc7145b8cdac8da9977d6d2b0d554b382193a28f275743697d0a17d2f58" diff --git a/pyproject.toml b/pyproject.toml index e98e887f..e743e675 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -87,7 +87,7 @@ SQLAlchemy = "^1.4.48" # ASGI uvicorn = "^0.23.0" -gunicorn = "^20.1.0" +gunicorn = "^21.0.0" Hypercorn = "^0.14.3" prometheus-fastapi-instrumentator = "^6.0.0" pytest-xdist = "^3.2.1" From 969b84afe4f2d74a005bd35594d9a76de5351e95 Mon Sep 17 00:00:00 2001 From: renovate Date: Tue, 25 Jul 2023 11:24:30 +0000 Subject: [PATCH 085/178] fix(deps): update all non-major dependencies --- poetry.lock | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index 42010de5..9897fafb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -540,14 +540,14 @@ testing = ["pre-commit"] [[package]] name = "fakeredis" -version = "2.16.0" +version = "2.17.0" description = "Python implementation of redis API, can be used for testing purposes." category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "fakeredis-2.16.0-py3-none-any.whl", hash = "sha256:188514cbd7120ff28c88f2a31e2fddd18fb1b28504478dfa3669c683134c4d82"}, - {file = "fakeredis-2.16.0.tar.gz", hash = "sha256:5abdd734de4ead9d6c7acbd3add1c4aa9b3ab35219339530472d9dd2bdf13057"}, + {file = "fakeredis-2.17.0-py3-none-any.whl", hash = "sha256:a99ef6e5642c31e91d36be78809fec3743e2bf7aaa682685b0d65a849fecd148"}, + {file = "fakeredis-2.17.0.tar.gz", hash = "sha256:e304bc7addb2f862c3550cb7db58548418a0fadd4cd78a4de66464c84fbc2195"}, ] [package.dependencies] @@ -1815,19 +1815,20 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uvicorn" -version = "0.23.0" +version = "0.23.1" description = "The lightning-fast ASGI server." category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "uvicorn-0.23.0-py3-none-any.whl", hash = "sha256:479599b2c0bb1b9b394c6d43901a1eb0c1ec72c7d237b5bafea23c5b2d4cdf10"}, - {file = "uvicorn-0.23.0.tar.gz", hash = "sha256:d38ab90c0e2c6fe3a054cddeb962cfd5d0e0e6608eaaff4a01d5c36a67f3168c"}, + {file = "uvicorn-0.23.1-py3-none-any.whl", hash = "sha256:1d55d46b83ee4ce82b4e82f621f2050adb3eb7b5481c13f9af1744951cae2f1f"}, + {file = "uvicorn-0.23.1.tar.gz", hash = "sha256:da9b0c8443b2d7ee9db00a345f1eee6db7317432c9d4400f5049cc8d358383be"}, ] [package.dependencies] click = ">=7.0" h11 = ">=0.8" +typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} [package.extras] standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] From 7a44f379687cb10817b8b2b3f6a636e289832b36 Mon Sep 17 00:00:00 2001 From: renovate Date: Thu, 27 Jul 2023 19:24:28 +0000 Subject: [PATCH 086/178] fix(deps): update dependency fastapi to v0.100.1 --- poetry.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index 9897fafb..c4d3adb6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -560,14 +560,14 @@ lua = ["lupa (>=1.14,<2.0)"] [[package]] name = "fastapi" -version = "0.100.0" +version = "0.100.1" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "fastapi-0.100.0-py3-none-any.whl", hash = "sha256:271662daf986da8fa98dc2b7c7f61c4abdfdccfb4786d79ed8b2878f172c6d5f"}, - {file = "fastapi-0.100.0.tar.gz", hash = "sha256:acb5f941ea8215663283c10018323ba7ea737c571b67fc7e88e9469c7eb1d12e"}, + {file = "fastapi-0.100.1-py3-none-any.whl", hash = "sha256:ec6dd52bfc4eff3063cfcd0713b43c87640fefb2687bbbe3d8a08d94049cdf32"}, + {file = "fastapi-0.100.1.tar.gz", hash = "sha256:522700d7a469e4a973d92321ab93312448fbe20fca9c8da97effc7e7bc56df23"}, ] [package.dependencies] From 94b62d2949c0b627bbeac4107c681ab7eccfff7d Mon Sep 17 00:00:00 2001 From: moson Date: Fri, 4 Aug 2023 14:12:50 +0200 Subject: [PATCH 087/178] fix: Check if user exists when editing account We should check if a user (target) exists before validating permissions. Otherwise things crash when a TU is trying to edit an account that does not exist. Fixes: aurweb-errors#529 Signed-off-by: moson --- aurweb/routers/accounts.py | 3 +++ test/test_accounts_routes.py | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 010aae58..1c81ec1d 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -374,6 +374,9 @@ def cannot_edit( :param user: Target user to be edited :return: RedirectResponse if approval != granted else None """ + # raise 404 if user does not exist + if not user: + raise HTTPException(status_code=HTTPStatus.NOT_FOUND) approved = request.user.can_edit_user(user) if not approved and (to := "/"): if user: diff --git a/test/test_accounts_routes.py b/test/test_accounts_routes.py index 3c481d0a..3ff6291a 100644 --- a/test/test_accounts_routes.py +++ b/test/test_accounts_routes.py @@ -764,6 +764,17 @@ def test_get_account_edit_unauthorized(client: TestClient, user: User): assert response.headers.get("location") == expected +def test_get_account_edit_not_exists(client: TestClient, tu_user: User): + """Test that users do not have an Account Type field.""" + cookies = {"AURSID": tu_user.login(Request(), "testPassword")} + endpoint = "/account/doesnotexist/edit" + + with client as request: + request.cookies = cookies + response = request.get(endpoint) + assert response.status_code == int(HTTPStatus.NOT_FOUND) + + def test_post_account_edit(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") @@ -872,6 +883,19 @@ def test_post_account_edit_dev(client: TestClient, tu_user: User): assert expected in response.content.decode() +def test_post_account_edit_not_exists(client: TestClient, tu_user: User): + request = Request() + sid = tu_user.login(request, "testPassword") + + post_data = {"U": "test", "E": "test666@example.org", "passwd": "testPassword"} + + endpoint = "/account/doesnotexist/edit" + with client as request: + request.cookies = {"AURSID": sid} + response = request.post(endpoint, data=post_data) + assert response.status_code == int(HTTPStatus.NOT_FOUND) + + def test_post_account_edit_language(client: TestClient, user: User): request = Request() sid = user.login(request, "testPassword") From 8ad03522de34a40992165649fc0605390db93a98 Mon Sep 17 00:00:00 2001 From: renovate Date: Fri, 4 Aug 2023 14:25:22 +0000 Subject: [PATCH 088/178] fix(deps): update all non-major dependencies --- poetry.lock | 27 ++++++++++++++------------- pyproject.toml | 2 +- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/poetry.lock b/poetry.lock index c4d3adb6..623884a0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -14,14 +14,14 @@ files = [ [[package]] name = "alembic" -version = "1.11.1" +version = "1.11.2" description = "A database migration tool for SQLAlchemy." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "alembic-1.11.1-py3-none-any.whl", hash = "sha256:dc871798a601fab38332e38d6ddb38d5e734f60034baeb8e2db5b642fccd8ab8"}, - {file = "alembic-1.11.1.tar.gz", hash = "sha256:6a810a6b012c88b33458fceb869aef09ac75d6ace5291915ba7fae44de372c01"}, + {file = "alembic-1.11.2-py3-none-any.whl", hash = "sha256:7981ab0c4fad4fe1be0cf183aae17689fe394ff874fd2464adb774396faf0796"}, + {file = "alembic-1.11.2.tar.gz", hash = "sha256:678f662130dc540dac12de0ea73de9f89caea9dbea138f60ef6263149bf84657"}, ] [package.dependencies] @@ -1031,20 +1031,21 @@ testing = ["pytest"] [[package]] name = "markdown" -version = "3.4.3" +version = "3.4.4" description = "Python implementation of John Gruber's Markdown." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "Markdown-3.4.3-py3-none-any.whl", hash = "sha256:065fd4df22da73a625f14890dd77eb8040edcbd68794bcd35943be14490608b2"}, - {file = "Markdown-3.4.3.tar.gz", hash = "sha256:8bf101198e004dc93e84a12a7395e31aac6a9c9942848ae1d99b9d72cf9b3520"}, + {file = "Markdown-3.4.4-py3-none-any.whl", hash = "sha256:a4c1b65c0957b4bd9e7d86ddc7b3c9868fb9670660f6f99f6d1bca8954d5a941"}, + {file = "Markdown-3.4.4.tar.gz", hash = "sha256:225c6123522495d4119a90b3a3ba31a1e87a70369e03f14799ea9c0d7183a3d6"}, ] [package.dependencies] importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} [package.extras] +docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.0)", "mkdocs-nature (>=0.4)"] testing = ["coverage", "pyyaml"] [[package]] @@ -1773,14 +1774,14 @@ files = [ [[package]] name = "tomlkit" -version = "0.11.8" +version = "0.12.1" description = "Style preserving TOML library" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "tomlkit-0.11.8-py3-none-any.whl", hash = "sha256:8c726c4c202bdb148667835f68d68780b9a003a9ec34167b6c673b38eff2a171"}, - {file = "tomlkit-0.11.8.tar.gz", hash = "sha256:9330fc7faa1db67b541b28e62018c17d20be733177d290a13b24c62d1614e0c3"}, + {file = "tomlkit-0.12.1-py3-none-any.whl", hash = "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899"}, + {file = "tomlkit-0.12.1.tar.gz", hash = "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86"}, ] [[package]] @@ -1815,14 +1816,14 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uvicorn" -version = "0.23.1" +version = "0.23.2" description = "The lightning-fast ASGI server." category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "uvicorn-0.23.1-py3-none-any.whl", hash = "sha256:1d55d46b83ee4ce82b4e82f621f2050adb3eb7b5481c13f9af1744951cae2f1f"}, - {file = "uvicorn-0.23.1.tar.gz", hash = "sha256:da9b0c8443b2d7ee9db00a345f1eee6db7317432c9d4400f5049cc8d358383be"}, + {file = "uvicorn-0.23.2-py3-none-any.whl", hash = "sha256:1f9be6558f01239d4fdf22ef8126c39cb1ad0addf76c40e760549d2c2f43ab53"}, + {file = "uvicorn-0.23.2.tar.gz", hash = "sha256:4d3cc12d7727ba72b64d12d3cc7743124074c0a69f7b201512fc50c3e3f1569a"}, ] [package.dependencies] @@ -1932,4 +1933,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "48d66bc7145b8cdac8da9977d6d2b0d554b382193a28f275743697d0a17d2f58" +content-hash = "ac9dbb5b28292c4a3dd2318a2f5c9120dfaa117ee834fac05995c5d0cbdc460d" diff --git a/pyproject.toml b/pyproject.toml index e743e675..f4682bad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -96,7 +96,7 @@ posix-ipc = "^1.1.1" pyalpm = "^0.10.6" fastapi = "^0.100.0" srcinfo = "^0.1.2" -tomlkit = "^0.11.8" +tomlkit = "^0.12.0" [tool.poetry.dev-dependencies] coverage = "^7.2.5" From f05f1dbac798c5fd41e0f19c9b0419fa302c9bf4 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Fri, 4 Aug 2023 19:18:38 +0300 Subject: [PATCH 089/178] chore(release): prepare for 6.2.7 Signed-off-by: Leonidas Spyropoulos --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index f4682bad..359923a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ combine_as_imports = true # [tool.poetry] name = "aurweb" -version = "v6.2.6" +version = "v6.2.7" license = "GPL-2.0-only" description = "Source code for the Arch User Repository's website" homepage = "https://aur.archlinux.org" From 3005e82f607e7b20ac5e32d50f0ffb124a8737e0 Mon Sep 17 00:00:00 2001 From: moson Date: Fri, 18 Aug 2023 22:04:55 +0200 Subject: [PATCH 090/178] fix: Cleanup prometheus metrics for dead workers The current "cleanup" function that is removing orphan prometheus files is actually never invoked. We move this to a default gunicorn config file to register our hook(s). https://docs.gunicorn.org/en/stable/configure.html https://docs.gunicorn.org/en/stable/settings.html#child-exit Signed-off-by: moson --- aurweb/asgi.py | 7 ------- gunicorn.conf.py | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-) create mode 100644 gunicorn.conf.py diff --git a/aurweb/asgi.py b/aurweb/asgi.py index 1be77ff9..9b6ffcb3 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -13,7 +13,6 @@ from fastapi import FastAPI, HTTPException, Request, Response from fastapi.responses import RedirectResponse from fastapi.staticfiles import StaticFiles from jinja2 import TemplateNotFound -from prometheus_client import multiprocess from sqlalchemy import and_ from starlette.exceptions import HTTPException as StarletteHTTPException from starlette.middleware.authentication import AuthenticationMiddleware @@ -91,12 +90,6 @@ async def app_startup(): get_engine() -def child_exit(server, worker): # pragma: no cover - """This function is required for gunicorn customization - of prometheus multiprocessing.""" - multiprocess.mark_process_dead(worker.pid) - - async def internal_server_error(request: Request, exc: Exception) -> Response: """ Catch all uncaught Exceptions thrown in a route. diff --git a/gunicorn.conf.py b/gunicorn.conf.py new file mode 100644 index 00000000..4f1c3a8c --- /dev/null +++ b/gunicorn.conf.py @@ -0,0 +1,7 @@ +from prometheus_client import multiprocess + + +def child_exit(server, worker): # pragma: no cover + """This function is required for gunicorn customization + of prometheus multiprocessing.""" + multiprocess.mark_process_dead(worker.pid) From 6c610b26a39a56db562e4b1ed3c95420a73ee766 Mon Sep 17 00:00:00 2001 From: Kristian Klausen Date: Fri, 28 Jul 2023 22:42:44 +0200 Subject: [PATCH 091/178] feat: Add terraform config for review-app[1] Also removed the logic for deploying to the long gone aur-dev box. Ansible will be added in a upcoming commit for configurating and deploying aurweb on the VM. [1] https://docs.gitlab.com/ee/ci/review_apps/ --- .gitignore | 4 +++ .gitlab-ci.yml | 71 +++++++++++++++++++++++---------------- ci/tf/.terraform.lock.hcl | 61 +++++++++++++++++++++++++++++++++ ci/tf/main.tf | 67 ++++++++++++++++++++++++++++++++++++ ci/tf/terraform.tfvars | 4 +++ ci/tf/variables.tf | 36 ++++++++++++++++++++ ci/tf/versions.tf | 13 +++++++ 7 files changed, 227 insertions(+), 29 deletions(-) create mode 100644 ci/tf/.terraform.lock.hcl create mode 100644 ci/tf/main.tf create mode 100644 ci/tf/terraform.tfvars create mode 100644 ci/tf/variables.tf create mode 100644 ci/tf/versions.tf diff --git a/.gitignore b/.gitignore index 68de7cd5..97157118 100644 --- a/.gitignore +++ b/.gitignore @@ -57,3 +57,7 @@ test-emails/ env/ venv/ .venv/ + +# Ignore some terraform files +/ci/tf/.terraform +/ci/tf/terraform.tfstate* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 10dd1787..4bd71920 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -61,34 +61,47 @@ test: coverage_format: cobertura path: coverage.xml -deploy: - stage: deploy - tags: - - secure - rules: - - if: $CI_COMMIT_BRANCH == "pu" - when: manual - variables: - FASTAPI_BACKEND: gunicorn - FASTAPI_WORKERS: 5 - AURWEB_FASTAPI_PREFIX: https://aur-dev.archlinux.org - AURWEB_SSHD_PREFIX: ssh://aur@aur-dev.archlinux.org:2222 - COMMIT_HASH: $CI_COMMIT_SHA - GIT_DATA_DIR: git_data - script: - - pacman -Syu --noconfirm docker docker-compose socat openssh - - chmod 600 ${SSH_KEY} - - socat "UNIX-LISTEN:/tmp/docker.sock,reuseaddr,fork" EXEC:"ssh -o UserKnownHostsFile=${SSH_KNOWN_HOSTS} -Ti ${SSH_KEY} ${SSH_USER}@${SSH_HOST}" & - - export DOCKER_HOST="unix:///tmp/docker.sock" - # Set secure login config for aurweb. - - sed -ri "s/^(disable_http_login).*$/\1 = 1/" conf/config.dev - - docker-compose build - - docker-compose -f docker-compose.yml -f docker-compose.aur-dev.yml down --remove-orphans - - docker-compose -f docker-compose.yml -f docker-compose.aur-dev.yml up -d - - docker image prune -f - - docker container prune -f - - docker volume prune -f +.init_tf: &init_tf + - pacman -Syu --needed --noconfirm --cachedir .pkg-cache terraform + - export TF_VAR_name="aurweb-${CI_COMMIT_REF_SLUG}" + - TF_ADDRESS="${CI_API_V4_URL}/projects/${TF_STATE_PROJECT}/terraform/state/${CI_COMMIT_REF_SLUG}" + - cd ci/tf + - > + terraform init \ + -backend-config="address=${TF_ADDRESS}" \ + -backend-config="lock_address=${TF_ADDRESS}/lock" \ + -backend-config="unlock_address=${TF_ADDRESS}/lock" \ + -backend-config="username=x-access-token" \ + -backend-config="password=${TF_STATE_GITLAB_ACCESS_TOKEN}" \ + -backend-config="lock_method=POST" \ + -backend-config="unlock_method=DELETE" \ + -backend-config="retry_wait_min=5" +deploy_review: + stage: deploy + script: + - *init_tf + - terraform apply -auto-approve environment: - name: development - url: https://aur-dev.archlinux.org + name: review/$CI_COMMIT_REF_NAME + url: https://aurweb-$CI_ENVIRONMENT_SLUG.sandbox.archlinux.page + on_stop: stop_review + auto_stop_in: 1 week + rules: + - if: $CI_MERGE_REQUEST_ID && $CI_PROJECT_PATH == "archlinux/aurweb" + when: manual + +stop_review: + stage: deploy + needs: + - deploy_review + script: + - *init_tf + - terraform destroy -auto-approve + - 'curl --silent --show-error --fail --header "Private-Token: ${TF_STATE_GITLAB_ACCESS_TOKEN}" --request DELETE "${CI_API_V4_URL}/projects/${TF_STATE_PROJECT}/terraform/state/${CI_COMMIT_REF_SLUG}"' + environment: + name: review/$CI_COMMIT_REF_NAME + action: stop + rules: + - if: $CI_MERGE_REQUEST_ID && $CI_PROJECT_PATH == "archlinux/aurweb" + when: manual diff --git a/ci/tf/.terraform.lock.hcl b/ci/tf/.terraform.lock.hcl new file mode 100644 index 00000000..aa5501c4 --- /dev/null +++ b/ci/tf/.terraform.lock.hcl @@ -0,0 +1,61 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/dns" { + version = "3.3.2" + hashes = [ + "h1:HjskPLRqmCw8Q/kiSuzti3iJBSpcAvcBFdlwFFQuoDE=", + "zh:05d2d50e301318362a4a82e6b7a9734ace07bc01abaaa649c566baf98814755f", + "zh:1e9fd1c3bfdda777e83e42831dd45b7b9e794250a0f351e5fd39762e8a0fe15b", + "zh:40e715fc7a2ede21f919567249b613844692c2f8a64f93ee64e5b68bae7ac2a2", + "zh:454d7aa83000a6e2ba7a7bfde4bcf5d7ed36298b22d760995ca5738ab02ee468", + "zh:46124ded51b4153ad90f12b0305fdbe0c23261b9669aa58a94a31c9cca2f4b19", + "zh:55a4f13d20f73534515a6b05701abdbfc54f4e375ba25b2dffa12afdad20e49d", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:7903b1ceb8211e2b8c79290e2e70906a4b88f4fba71c900eb3a425ce12f1716a", + "zh:b79fc4f444ef7a2fd7111a80428c070ad824f43a681699e99ab7f83074dfedbd", + "zh:ca9f45e0c4cb94e7d62536c226024afef3018b1de84f1ea4608b51bcd497a2a0", + "zh:ddc8bd894559d7d176e0ceb0bb1ae266519b01b315362ebfee8327bb7e7e5fa8", + "zh:e77334c0794ef8f9354b10e606040f6b0b67b373f5ff1db65bddcdd4569b428b", + ] +} + +provider "registry.terraform.io/hashicorp/tls" { + version = "4.0.4" + hashes = [ + "h1:pe9vq86dZZKCm+8k1RhzARwENslF3SXb9ErHbQfgjXU=", + "zh:23671ed83e1fcf79745534841e10291bbf34046b27d6e68a5d0aab77206f4a55", + "zh:45292421211ffd9e8e3eb3655677700e3c5047f71d8f7650d2ce30242335f848", + "zh:59fedb519f4433c0fdb1d58b27c210b27415fddd0cd73c5312530b4309c088be", + "zh:5a8eec2409a9ff7cd0758a9d818c74bcba92a240e6c5e54b99df68fff312bbd5", + "zh:5e6a4b39f3171f53292ab88058a59e64825f2b842760a4869e64dc1dc093d1fe", + "zh:810547d0bf9311d21c81cc306126d3547e7bd3f194fc295836acf164b9f8424e", + "zh:824a5f3617624243bed0259d7dd37d76017097dc3193dac669be342b90b2ab48", + "zh:9361ccc7048be5dcbc2fafe2d8216939765b3160bd52734f7a9fd917a39ecbd8", + "zh:aa02ea625aaf672e649296bce7580f62d724268189fe9ad7c1b36bb0fa12fa60", + "zh:c71b4cd40d6ec7815dfeefd57d88bc592c0c42f5e5858dcc88245d371b4b8b1e", + "zh:dabcd52f36b43d250a3d71ad7abfa07b5622c69068d989e60b79b2bb4f220316", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} + +provider "registry.terraform.io/hetznercloud/hcloud" { + version = "1.42.0" + hashes = [ + "h1:cr9lh26H3YbWSHb7OUnCoYw169cYO3Cjpt3yPnRhXS0=", + "zh:153b5f39d780e9a18bc1ea377d872647d328d943813cbd25d3d20863f8a37782", + "zh:35b9e95760c58cca756e34ad5f4138ac6126aa3e8c41b4a0f1d5dc9ee5666c73", + "zh:47a3cdbce982f2b4e17f73d4934bdb3e905a849b36fb59b80f87d852496ed049", + "zh:6a718c244c2ba300fbd43791661a061ad1ab16225ef3e8aeaa3db8c9eff12c85", + "zh:a2cbfc95c5e2c9422ed0a7b6292192c38241220d5b7813c678f937ab3ef962ae", + "zh:b837e118e08fd36aa8be48af7e9d0d3d112d2680c79cfc71cfe2501fb40dbefa", + "zh:bf66db8c680e18b77e16dc1f20ed1cdcc7876bfb7848c320ccb86f0fb80661ed", + "zh:c1ad80bbe48dc8a272a02dcdb4b12f019606f445606651c01e561b9d72d816b1", + "zh:d4e616701128ad14a6b5a427b0e9145ece4cad02aa3b5f9945c6d0b9ada8ab70", + "zh:d9d01f727037d028720100a5bc9fd213cb01e63e4b439a16f2f482c147976530", + "zh:dea047ee4d679370d4376fb746c4b959bf51dd06047c1c2656b32789c2433643", + "zh:e5ad7a3c556894bd40b28a874e7d2f6924876fa75fa443136a7d6ab9a00abbaa", + "zh:edf6e7e129157bd45e3da4a330d1ace17a336d417c3b77c620f302d440c368e8", + "zh:f610bc729866d58da9cffa4deae34dbfdba96655e855a87c6bb2cb7b35a8961c", + ] +} diff --git a/ci/tf/main.tf b/ci/tf/main.tf new file mode 100644 index 00000000..b149a621 --- /dev/null +++ b/ci/tf/main.tf @@ -0,0 +1,67 @@ +terraform { + backend "http" { + } +} + +provider "hcloud" { + token = var.hcloud_token +} + +provider "dns" { + update { + server = var.dns_server + key_name = var.dns_tsig_key + key_algorithm = var.dns_tsig_algorithm + key_secret = var.dns_tsig_secret + } +} + +resource "tls_private_key" "this" { + algorithm = "ED25519" +} + +resource "hcloud_ssh_key" "this" { + name = var.name + public_key = tls_private_key.this.public_key_openssh +} + +data "hcloud_image" "this" { + with_selector = "custom_image=archlinux" + most_recent = true + with_status = ["available"] +} + +resource "hcloud_server" "this" { + name = var.name + image = data.hcloud_image.this.id + server_type = var.server_type + datacenter = var.datacenter + ssh_keys = [hcloud_ssh_key.this.name] + + public_net { + ipv4_enabled = true + ipv6_enabled = true + } +} + +resource "hcloud_rdns" "this" { + for_each = { ipv4 : hcloud_server.this.ipv4_address, ipv6 : hcloud_server.this.ipv6_address } + + server_id = hcloud_server.this.id + ip_address = each.value + dns_ptr = "${var.name}.${var.dns_zone}" +} + +resource "dns_a_record_set" "this" { + zone = "${var.dns_zone}." + name = var.name + addresses = [hcloud_server.this.ipv4_address] + ttl = 300 +} + +resource "dns_aaaa_record_set" "this" { + zone = "${var.dns_zone}." + name = var.name + addresses = [hcloud_server.this.ipv6_address] + ttl = 300 +} diff --git a/ci/tf/terraform.tfvars b/ci/tf/terraform.tfvars new file mode 100644 index 00000000..14818592 --- /dev/null +++ b/ci/tf/terraform.tfvars @@ -0,0 +1,4 @@ +server_type = "cpx11" +datacenter = "fsn1-dc14" +dns_server = "redirect.archlinux.org" +dns_zone = "sandbox.archlinux.page" diff --git a/ci/tf/variables.tf b/ci/tf/variables.tf new file mode 100644 index 00000000..a4e710ee --- /dev/null +++ b/ci/tf/variables.tf @@ -0,0 +1,36 @@ +variable "hcloud_token" { + type = string + sensitive = true +} + +variable "dns_server" { + type = string +} + +variable "dns_tsig_key" { + type = string +} + +variable "dns_tsig_algorithm" { + type = string +} + +variable "dns_tsig_secret" { + type = string +} + +variable "dns_zone" { + type = string +} + +variable "name" { + type = string +} + +variable "server_type" { + type = string +} + +variable "datacenter" { + type = string +} diff --git a/ci/tf/versions.tf b/ci/tf/versions.tf new file mode 100644 index 00000000..2c72215a --- /dev/null +++ b/ci/tf/versions.tf @@ -0,0 +1,13 @@ +terraform { + required_providers { + tls = { + source = "hashicorp/tls" + } + hcloud = { + source = "hetznercloud/hcloud" + } + dns = { + source = "hashicorp/dns" + } + } +} From 9eda6a42c69581dfdc14dc1b0d51f744985c7202 Mon Sep 17 00:00:00 2001 From: moson Date: Sun, 27 Aug 2023 13:54:39 +0200 Subject: [PATCH 092/178] feat: Add ansible provisioning step for review-app Clone infrastructure repository and run playbook to provision our VM with aurweb. Signed-off-by: moson --- .gitlab-ci.yml | 54 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4bd71920..cf80ab24 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,6 +13,8 @@ variables: TEST_RECURSION_LIMIT: 10000 CURRENT_DIR: "$(pwd)" LOG_CONFIG: logging.test.conf + DEV_FQDN: aurweb-$CI_COMMIT_REF_SLUG.sandbox.archlinux.page + INFRASTRUCTURE_REPO: https://gitlab.archlinux.org/archlinux/infrastructure.git lint: stage: .pre @@ -84,13 +86,63 @@ deploy_review: - terraform apply -auto-approve environment: name: review/$CI_COMMIT_REF_NAME - url: https://aurweb-$CI_ENVIRONMENT_SLUG.sandbox.archlinux.page + url: https://$DEV_FQDN on_stop: stop_review auto_stop_in: 1 week rules: - if: $CI_MERGE_REQUEST_ID && $CI_PROJECT_PATH == "archlinux/aurweb" when: manual +provision_review: + stage: deploy + needs: + - deploy_review + script: + - *init_tf + - pacman -Syu --noconfirm --needed --cachedir .pkg-cache ansible git openssh jq + # Get ssh key from terraform state file + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - terraform show -json | + jq -r '.values.root_module.resources[] | + select(.address == "tls_private_key.this") | + .values.private_key_openssh' > ~/.ssh/id_ed25519 + - chmod 400 ~/.ssh/id_ed25519 + # Clone infra repo + - git clone $INFRASTRUCTURE_REPO + - cd infrastructure + # Remove vault files + - rm $(git grep -l 'ANSIBLE_VAULT;1.1;AES256$') + # Remove vault config + - sed -i '/^vault/d' ansible.cfg + # Add host config + - mkdir -p host_vars/$DEV_FQDN + - 'echo "filesystem: btrfs" > host_vars/$DEV_FQDN/misc' + # Add host + - echo "$DEV_FQDN" > hosts + # Add our pubkey and hostkeys + - ssh-keyscan $DEV_FQDN >> ~/.ssh/known_hosts + - ssh-keygen -f ~/.ssh/id_ed25519 -y > pubkeys/aurweb-dev.pub + # Run our ansible playbook + - > + ansible-playbook playbooks/aur-dev.archlinux.org.yml \ + -e "aurdev_fqdn=$DEV_FQDN" \ + -e "aurweb_repository=$CI_REPOSITORY_URL" \ + -e "aurweb_version=$CI_COMMIT_SHA" \ + -e "{\"vault_mariadb_users\":{\"root\":\"aur\"}}" \ + -e "vault_aurweb_db_password=aur" \ + -e "vault_aurweb_gitlab_instance=https://does.not.exist" \ + -e "vault_aurweb_error_project=aur" \ + -e "vault_aurweb_error_token=aur" \ + -e "vault_aurweb_secret=aur" \ + -e "vault_goaurrpc_metrics_token=aur" \ + -e '{"root_additional_keys": ["moson.pub", "aurweb-dev.pub"]}' + environment: + name: review/$CI_COMMIT_REF_NAME + action: access + rules: + - if: $CI_MERGE_REQUEST_ID && $CI_PROJECT_PATH == "archlinux/aurweb" + stop_review: stage: deploy needs: From 5699e9bb41638fc1d6040f3e70a90fab38257458 Mon Sep 17 00:00:00 2001 From: moson Date: Sat, 26 Aug 2023 14:47:21 +0200 Subject: [PATCH 093/178] fix(test): Remove file locking and semaphore All tests within a file run in the same worker and out test DB names are unique per file as well. We don't really need a locking mechanism here. Same is valid for the test-emails. The only potential issue is that it might try to create the same directory multiple times and thus run into an error. However, that can be covered by specifying "exist_ok=True" with os.makedirs such that those errors are ignored. Signed-off-by: moson --- test/conftest.py | 40 +++++++++++----------------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/test/conftest.py b/test/conftest.py index 15a982aa..c36f78dd 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -43,7 +43,6 @@ 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 from sqlalchemy.engine.base import Engine @@ -54,7 +53,6 @@ import aurweb.config import aurweb.db from aurweb import aur_logging, initdb, testing from aurweb.testing.email import Email -from aurweb.testing.filelock import FileLock from aurweb.testing.git import GitRepository logger = aur_logging.get_logger(__name__) @@ -133,20 +131,16 @@ def _drop_database(engine: Engine, dbname: str) -> None: def setup_email(): - # TODO: Fix this data race! This try/catch is ugly; why is it even - # racing here? Perhaps we need to multiproc + multithread lock - # inside of setup_database to block the check? - with Semaphore("/test-emails", flags=O_CREAT, initial_value=1): - if not os.path.exists(Email.TEST_DIR): - # Create the directory. - os.makedirs(Email.TEST_DIR) + if not os.path.exists(Email.TEST_DIR): + # Create the directory. + os.makedirs(Email.TEST_DIR, exist_ok=True) - # Cleanup all email files for this test suite. - prefix = Email.email_prefix(suite=True) - files = os.listdir(Email.TEST_DIR) - for file in files: - if file.startswith(prefix): - os.remove(os.path.join(Email.TEST_DIR, file)) + # Cleanup all email files for this test suite. + prefix = Email.email_prefix(suite=True) + files = os.listdir(Email.TEST_DIR) + for file in files: + if file.startswith(prefix): + os.remove(os.path.join(Email.TEST_DIR, file)) @pytest.fixture(scope="module") @@ -155,20 +149,8 @@ def setup_database(tmp_path_factory: pathlib.Path, worker_id: str) -> None: engine = test_engine() dbname = aurweb.db.name() - if worker_id == "master": # pragma: no cover - # If we're not running tests through multiproc pytest-xdist. - setup_email() - yield _create_database(engine, dbname) - _drop_database(engine, dbname) - return - - def setup(path): - setup_email() - _create_database(engine, dbname) - - tmpdir = tmp_path_factory.getbasetemp().parent - file_lock = FileLock(tmpdir, dbname) - file_lock.lock(on_create=setup) + setup_email() + _create_database(engine, dbname) yield # Run the test function depending on this fixture. _drop_database(engine, dbname) # Cleanup the database. From 1433553c05993b097e812e43496bf140df49144c Mon Sep 17 00:00:00 2001 From: moson Date: Sat, 26 Aug 2023 17:08:36 +0200 Subject: [PATCH 094/178] fix(test): Clear previous prometheus data for test It could happen that test data is already generated by a previous test. (running in the same worker) Make sure we clear everything before performing our checks. Signed-off-by: moson --- test/test_statistics.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/test_statistics.py b/test/test_statistics.py index db262fa3..80223cbd 100644 --- a/test/test_statistics.py +++ b/test/test_statistics.py @@ -1,7 +1,7 @@ import pytest from prometheus_client import REGISTRY, generate_latest -from aurweb import cache, db, time +from aurweb import cache, db, prometheus, time from aurweb.models import Package, PackageBase, PackageRequest from aurweb.models.account_type import TRUSTED_USER_ID, USER_ID from aurweb.models.package_request import ( @@ -140,6 +140,11 @@ def test_get_count_change(stats: Statistics, test_data): def test_update_prometheus_metrics(test_data): + # Make sure any previous data is cleared + prometheus.USERS.clear() + prometheus.PACKAGES.clear() + prometheus.REQUESTS.clear() + metrics = str(generate_latest(REGISTRY)) assert "aur_users{" not in metrics From 0a7b02956feeaaeea4813650b12ead15cfc822af Mon Sep 17 00:00:00 2001 From: moson Date: Sun, 3 Sep 2023 14:17:11 +0200 Subject: [PATCH 095/178] feat: Indicate dependency source Dependencies might reside in the AUR or official repositories. Add "AUR" as superscript letters to indicate if a package/provider is present in the AUR. Signed-off-by: moson --- aurweb/models/package_dependency.py | 7 +++- aurweb/packages/util.py | 8 ++-- .../partials/packages/package_metadata.html | 7 +++- test/test_package_dependency.py | 17 ++++++++ test/test_packages_util.py | 40 +++++++++++++++++++ 5 files changed, 72 insertions(+), 7 deletions(-) diff --git a/aurweb/models/package_dependency.py b/aurweb/models/package_dependency.py index 587ba68d..9cf1eda0 100644 --- a/aurweb/models/package_dependency.py +++ b/aurweb/models/package_dependency.py @@ -57,14 +57,17 @@ class PackageDependency(Base): params=("NULL"), ) - def is_package(self) -> bool: + def is_aur_package(self) -> bool: pkg = db.query(_Package).filter(_Package.Name == self.DepName).exists() + return db.query(pkg).scalar() + + def is_package(self) -> bool: official = ( db.query(_OfficialProvider) .filter(_OfficialProvider.Name == self.DepName) .exists() ) - return db.query(pkg).scalar() or db.query(official).scalar() + return self.is_aur_package() or db.query(official).scalar() def provides(self) -> list[PackageRelation]: from aurweb.models.relation_type import PROVIDES_ID diff --git a/aurweb/packages/util.py b/aurweb/packages/util.py index 78d79508..cfd1e9e9 100644 --- a/aurweb/packages/util.py +++ b/aurweb/packages/util.py @@ -83,9 +83,11 @@ 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] - ) + links = [] + for pkg in provides: + aur = "á´¬áµá´¿" if not pkg.is_official else "" + links.append(f'{pkg.Name}{aur}') + return ", ".join(links) def get_pkg_or_base( diff --git a/templates/partials/packages/package_metadata.html b/templates/partials/packages/package_metadata.html index 50d38b48..c8d583a1 100644 --- a/templates/partials/packages/package_metadata.html +++ b/templates/partials/packages/package_metadata.html @@ -14,12 +14,15 @@ {% endif %} {{ dep.DepName }} - {% if broken %} + {%- if broken %} {% if not provides %} {% endif %} - {% else %} + {% else -%} + {%- if dep.is_aur_package() -%} + á´¬áµá´¿ + {% endif %} {% endif %} {% if provides %} diff --git a/test/test_package_dependency.py b/test/test_package_dependency.py index 9366bb55..1cd2d305 100644 --- a/test/test_package_dependency.py +++ b/test/test_package_dependency.py @@ -4,6 +4,7 @@ from sqlalchemy.exc import IntegrityError from aurweb import db from aurweb.models.account_type import USER_ID from aurweb.models.dependency_type import DEPENDS_ID +from aurweb.models.official_provider import OfficialProvider from aurweb.models.package import Package from aurweb.models.package_base import PackageBase from aurweb.models.package_dependency import PackageDependency @@ -58,6 +59,22 @@ def test_package_dependencies(user: User, package: Package): db.create(Package, PackageBase=base, Name=pkgdep.DepName) assert pkgdep.is_package() + assert pkgdep.is_aur_package() + + # Test with OfficialProvider + with db.begin(): + pkgdep = db.create( + PackageDependency, + Package=package, + DepTypeID=DEPENDS_ID, + DepName="test-repo-pkg", + ) + db.create( + OfficialProvider, Name=pkgdep.DepName, Repo="extra", Provides=pkgdep.DepName + ) + + assert pkgdep.is_package() + assert not pkgdep.is_aur_package() def test_package_dependencies_null_package_raises(): diff --git a/test/test_packages_util.py b/test/test_packages_util.py index bae84614..b429181b 100644 --- a/test/test_packages_util.py +++ b/test/test_packages_util.py @@ -10,8 +10,10 @@ from aurweb.models.package import Package from aurweb.models.package_base import PackageBase from aurweb.models.package_dependency import PackageDependency from aurweb.models.package_notification import PackageNotification +from aurweb.models.package_relation import PackageRelation from aurweb.models.package_source import PackageSource from aurweb.models.package_vote import PackageVote +from aurweb.models.relation_type import PROVIDES_ID from aurweb.models.user import User from aurweb.packages import util @@ -155,3 +157,41 @@ def test_pkg_required(package: Package): # We should have 1 record assert qry.count() == 1 + + +def test_provides_markup(package: Package): + # Create dependency and provider for AUR pkg + with db.begin(): + dep = db.create( + PackageDependency, + Package=package, + DepName="test", + DepTypeID=DEPENDS_ID, + ) + rel_pkg = db.create(Package, PackageBase=package.PackageBase, Name=dep.DepName) + db.create( + PackageRelation, + Package=rel_pkg, + RelName=dep.DepName, + RelTypeID=PROVIDES_ID, + ) + + # AUR provider links should end with á´¬áµá´¿ + link = util.provides_markup(dep.provides()) + assert link.endswith("á´¬áµá´¿") + assert OFFICIAL_BASE not in link + + # Remove AUR provider and add official one + with db.begin(): + db.delete(rel_pkg) + db.create( + OfficialProvider, + Name="official-pkg", + Repo="extra", + Provides=dep.DepName, + ) + + # Repo provider links should not have any suffix + link = util.provides_markup(dep.provides()) + assert link.endswith("") + assert OFFICIAL_BASE in link From 7466e964498cd9d19b93e1f38394ae358a5e6a5f Mon Sep 17 00:00:00 2001 From: moson Date: Tue, 26 Sep 2023 13:47:03 +0200 Subject: [PATCH 096/178] fix(ci): Exclude review-app jobs for renovate MR's Signed-off-by: moson --- .gitlab-ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cf80ab24..fb40d414 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -90,6 +90,8 @@ deploy_review: on_stop: stop_review auto_stop_in: 1 week rules: + - if: $CI_COMMIT_REF_NAME =~ /^renovate\// + when: never - if: $CI_MERGE_REQUEST_ID && $CI_PROJECT_PATH == "archlinux/aurweb" when: manual @@ -141,6 +143,8 @@ provision_review: name: review/$CI_COMMIT_REF_NAME action: access rules: + - if: $CI_COMMIT_REF_NAME =~ /^renovate\// + when: never - if: $CI_MERGE_REQUEST_ID && $CI_PROJECT_PATH == "archlinux/aurweb" stop_review: @@ -155,5 +159,7 @@ stop_review: name: review/$CI_COMMIT_REF_NAME action: stop rules: + - if: $CI_COMMIT_REF_NAME =~ /^renovate\// + when: never - if: $CI_MERGE_REQUEST_ID && $CI_PROJECT_PATH == "archlinux/aurweb" when: manual From 1702075875514de8170b4393d5326cb61e7c5e6e Mon Sep 17 00:00:00 2001 From: moson Date: Fri, 1 Sep 2023 13:25:21 +0200 Subject: [PATCH 097/178] housekeep: TU rename - code changes Renaming of symbols. Functions, variables, values, DB values, etc. Basically everything that is not user-facing. This only covers "Trusted User" things: tests, comments, etc. will covered in a following commit. --- aurweb/auth/__init__.py | 4 +- aurweb/auth/creds.py | 76 ++++++++++--------- aurweb/initdb.py | 4 +- aurweb/models/account_type.py | 12 +-- aurweb/models/user.py | 12 +-- aurweb/pkgbase/actions.py | 2 +- aurweb/routers/__init__.py | 4 +- aurweb/routers/accounts.py | 16 ++-- ...{trusted_user.py => package_maintainer.py} | 59 +++++++------- aurweb/statistics.py | 16 ++-- aurweb/users/validate.py | 2 +- ...d126029_rename_tu_to_package_maintainer.py | 37 +++++++++ schema/gendummydata.py | 28 +++---- templates/addvote.html | 12 +-- templates/partials/archdev-navbar.html | 2 +- .../partials/packages/search_actions.html | 2 +- templates/partials/packages/statistics.html | 2 +- templates/partials/tu/proposals.html | 2 +- templates/tu/index.html | 6 +- test/test_accounts_routes.py | 48 ++++++------ test/test_adduser.py | 4 +- test/test_auth.py | 4 +- test/test_homepage.py | 2 +- test/test_html.py | 10 +-- test/test_notify.py | 4 +- test/test_packages_routes.py | 4 +- test/test_pkgbase_routes.py | 4 +- test/test_requests.py | 4 +- test/test_statistics.py | 14 ++-- test/test_trusted_user_routes.py | 14 ++-- test/test_tu_vote.py | 4 +- test/test_tu_voteinfo.py | 4 +- test/test_tuvotereminder.py | 8 +- test/test_user.py | 42 +++++----- 34 files changed, 265 insertions(+), 203 deletions(-) rename aurweb/routers/{trusted_user.py => package_maintainer.py} (88%) create mode 100644 migrations/versions/6a64dd126029_rename_tu_to_package_maintainer.py diff --git a/aurweb/auth/__init__.py b/aurweb/auth/__init__.py index 83dd424c..e895dcdb 100644 --- a/aurweb/auth/__init__.py +++ b/aurweb/auth/__init__.py @@ -71,7 +71,7 @@ class AnonymousUser: return False @staticmethod - def is_trusted_user(): + def is_package_maintainer(): return False @staticmethod @@ -205,7 +205,7 @@ def account_type_required(one_of: set): @router.get('/some_route') @auth_required(True) - @account_type_required({"Trusted User", "Trusted User & Developer"}) + @account_type_required({"Package Maintainer", "Package Maintainer & Developer"}) async def some_route(request: fastapi.Request): return Response() diff --git a/aurweb/auth/creds.py b/aurweb/auth/creds.py index 17d02a5b..594188ca 100644 --- a/aurweb/auth/creds.py +++ b/aurweb/auth/creds.py @@ -1,7 +1,7 @@ from aurweb.models.account_type import ( DEVELOPER_ID, - TRUSTED_USER_AND_DEV_ID, - TRUSTED_USER_ID, + PACKAGE_MAINTAINER_AND_DEV_ID, + PACKAGE_MAINTAINER_ID, USER_ID, ) from aurweb.models.user import User @@ -30,47 +30,49 @@ PKGBASE_VOTE = 16 PKGREQ_FILE = 23 PKGREQ_CLOSE = 17 PKGREQ_LIST = 18 -TU_ADD_VOTE = 19 -TU_LIST_VOTES = 20 -TU_VOTE = 21 +PM_ADD_VOTE = 19 +PM_LIST_VOTES = 20 +PM_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_package_maintainer = set( + [USER_ID, PACKAGE_MAINTAINER_ID, DEVELOPER_ID, PACKAGE_MAINTAINER_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]) +package_maintainer_or_dev = set( + [PACKAGE_MAINTAINER_ID, DEVELOPER_ID, PACKAGE_MAINTAINER_AND_DEV_ID] +) +developer = set([DEVELOPER_ID, PACKAGE_MAINTAINER_AND_DEV_ID]) +package_maintainer = set([PACKAGE_MAINTAINER_ID, PACKAGE_MAINTAINER_AND_DEV_ID]) cred_filters = { - PKGBASE_FLAG: user_developer_or_trusted_user, - PKGBASE_NOTIFY: user_developer_or_trusted_user, - PKGBASE_VOTE: user_developer_or_trusted_user, - PKGREQ_FILE: user_developer_or_trusted_user, - ACCOUNT_CHANGE_TYPE: trusted_user_or_dev, - ACCOUNT_EDIT: trusted_user_or_dev, - ACCOUNT_LAST_LOGIN: trusted_user_or_dev, - ACCOUNT_LIST_COMMENTS: trusted_user_or_dev, - ACCOUNT_SEARCH: trusted_user_or_dev, - COMMENT_DELETE: trusted_user_or_dev, - COMMENT_UNDELETE: trusted_user_or_dev, - COMMENT_VIEW_DELETED: trusted_user_or_dev, - COMMENT_EDIT: trusted_user_or_dev, - COMMENT_PIN: trusted_user_or_dev, - PKGBASE_ADOPT: trusted_user_or_dev, - PKGBASE_SET_KEYWORDS: trusted_user_or_dev, - PKGBASE_DELETE: trusted_user_or_dev, - PKGBASE_EDIT_COMAINTAINERS: trusted_user_or_dev, - PKGBASE_DISOWN: trusted_user_or_dev, - PKGBASE_LIST_VOTERS: trusted_user_or_dev, - PKGBASE_UNFLAG: trusted_user_or_dev, - PKGREQ_CLOSE: trusted_user_or_dev, - PKGREQ_LIST: trusted_user_or_dev, - TU_ADD_VOTE: trusted_user, - TU_LIST_VOTES: trusted_user_or_dev, - TU_VOTE: trusted_user, + PKGBASE_FLAG: user_developer_or_package_maintainer, + PKGBASE_NOTIFY: user_developer_or_package_maintainer, + PKGBASE_VOTE: user_developer_or_package_maintainer, + PKGREQ_FILE: user_developer_or_package_maintainer, + ACCOUNT_CHANGE_TYPE: package_maintainer_or_dev, + ACCOUNT_EDIT: package_maintainer_or_dev, + ACCOUNT_LAST_LOGIN: package_maintainer_or_dev, + ACCOUNT_LIST_COMMENTS: package_maintainer_or_dev, + ACCOUNT_SEARCH: package_maintainer_or_dev, + COMMENT_DELETE: package_maintainer_or_dev, + COMMENT_UNDELETE: package_maintainer_or_dev, + COMMENT_VIEW_DELETED: package_maintainer_or_dev, + COMMENT_EDIT: package_maintainer_or_dev, + COMMENT_PIN: package_maintainer_or_dev, + PKGBASE_ADOPT: package_maintainer_or_dev, + PKGBASE_SET_KEYWORDS: package_maintainer_or_dev, + PKGBASE_DELETE: package_maintainer_or_dev, + PKGBASE_EDIT_COMAINTAINERS: package_maintainer_or_dev, + PKGBASE_DISOWN: package_maintainer_or_dev, + PKGBASE_LIST_VOTERS: package_maintainer_or_dev, + PKGBASE_UNFLAG: package_maintainer_or_dev, + PKGREQ_CLOSE: package_maintainer_or_dev, + PKGREQ_LIST: package_maintainer_or_dev, + PM_ADD_VOTE: package_maintainer, + PM_LIST_VOTES: package_maintainer_or_dev, + PM_VOTE: package_maintainer, ACCOUNT_EDIT_DEV: developer, - PKGBASE_MERGE: trusted_user_or_dev, + PKGBASE_MERGE: package_maintainer_or_dev, } diff --git a/aurweb/initdb.py b/aurweb/initdb.py index ee59212c..7181ea3e 100644 --- a/aurweb/initdb.py +++ b/aurweb/initdb.py @@ -13,9 +13,9 @@ def feed_initial_data(conn): aurweb.schema.AccountTypes.insert(), [ {"ID": 1, "AccountType": "User"}, - {"ID": 2, "AccountType": "Trusted User"}, + {"ID": 2, "AccountType": "Package Maintainer"}, {"ID": 3, "AccountType": "Developer"}, - {"ID": 4, "AccountType": "Trusted User & Developer"}, + {"ID": 4, "AccountType": "Package Maintainer & Developer"}, ], ) conn.execute( diff --git a/aurweb/models/account_type.py b/aurweb/models/account_type.py index 315800a7..70bfc2c5 100644 --- a/aurweb/models/account_type.py +++ b/aurweb/models/account_type.py @@ -2,21 +2,21 @@ from aurweb import schema from aurweb.models.declarative import Base USER = "User" -TRUSTED_USER = "Trusted User" +PACKAGE_MAINTAINER = "Package Maintainer" DEVELOPER = "Developer" -TRUSTED_USER_AND_DEV = "Trusted User & Developer" +PACKAGE_MAINTAINER_AND_DEV = "Package Maintainer & Developer" USER_ID = 1 -TRUSTED_USER_ID = 2 +PACKAGE_MAINTAINER_ID = 2 DEVELOPER_ID = 3 -TRUSTED_USER_AND_DEV_ID = 4 +PACKAGE_MAINTAINER_AND_DEV_ID = 4 # Map string constants to integer constants. ACCOUNT_TYPE_ID = { USER: USER_ID, - TRUSTED_USER: TRUSTED_USER_ID, + PACKAGE_MAINTAINER: PACKAGE_MAINTAINER_ID, DEVELOPER: DEVELOPER_ID, - TRUSTED_USER_AND_DEV: TRUSTED_USER_AND_DEV_ID, + PACKAGE_MAINTAINER_AND_DEV: PACKAGE_MAINTAINER_AND_DEV_ID, } # Reversed ACCOUNT_TYPE_ID mapping. diff --git a/aurweb/models/user.py b/aurweb/models/user.py index 8612c259..f90d19eb 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -157,25 +157,25 @@ class User(Base): with db.begin(): db.delete(self.session) - def is_trusted_user(self): + def is_package_maintainer(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.PACKAGE_MAINTAINER_ID, + aurweb.models.account_type.PACKAGE_MAINTAINER_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.PACKAGE_MAINTAINER_AND_DEV_ID, } def is_elevated(self): """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.PACKAGE_MAINTAINER_ID, aurweb.models.account_type.DEVELOPER_ID, - aurweb.models.account_type.TRUSTED_USER_AND_DEV_ID, + aurweb.models.account_type.PACKAGE_MAINTAINER_AND_DEV_ID, } def can_edit_user(self, target: "User") -> bool: diff --git a/aurweb/pkgbase/actions.py b/aurweb/pkgbase/actions.py index 00efc1ff..f3688f54 100644 --- a/aurweb/pkgbase/actions.py +++ b/aurweb/pkgbase/actions.py @@ -187,7 +187,7 @@ def pkgbase_merge_instance( # Log this out for accountability purposes. logger.info( - f"Trusted User '{request.user.Username}' merged " + f"Package Maintainer '{request.user.Username}' merged " f"'{pkgbasename}' into '{target.Name}'." ) diff --git a/aurweb/routers/__init__.py b/aurweb/routers/__init__.py index f77bce4f..ccd70662 100644 --- a/aurweb/routers/__init__.py +++ b/aurweb/routers/__init__.py @@ -7,13 +7,13 @@ from . import ( accounts, auth, html, + package_maintainer, packages, pkgbase, requests, rpc, rss, sso, - trusted_user, ) """ @@ -28,7 +28,7 @@ APP_ROUTES = [ packages, pkgbase, requests, - trusted_user, + package_maintainer, rss, rpc, sso, diff --git a/aurweb/routers/accounts.py b/aurweb/routers/accounts.py index 1c81ec1d..a2d167bc 100644 --- a/aurweb/routers/accounts.py +++ b/aurweb/routers/accounts.py @@ -184,9 +184,9 @@ def make_account_form_context( lambda e: request.user.AccountTypeID >= e[0], [ (at.USER_ID, f"Normal {at.USER}"), - (at.TRUSTED_USER_ID, at.TRUSTED_USER), + (at.PACKAGE_MAINTAINER_ID, at.PACKAGE_MAINTAINER), (at.DEVELOPER_ID, at.DEVELOPER), - (at.TRUSTED_USER_AND_DEV_ID, at.TRUSTED_USER_AND_DEV), + (at.PACKAGE_MAINTAINER_AND_DEV_ID, at.PACKAGE_MAINTAINER_AND_DEV), ], ) ) @@ -520,7 +520,9 @@ async def account_comments(request: Request, username: str): @router.get("/accounts") @requires_auth -@account_type_required({at.TRUSTED_USER, at.DEVELOPER, at.TRUSTED_USER_AND_DEV}) +@account_type_required( + {at.PACKAGE_MAINTAINER, at.DEVELOPER, at.PACKAGE_MAINTAINER_AND_DEV} +) async def accounts(request: Request): context = make_context(request, "Accounts") return render_template(request, "account/search.html", context) @@ -529,7 +531,9 @@ 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}) +@account_type_required( + {at.PACKAGE_MAINTAINER, at.DEVELOPER, at.PACKAGE_MAINTAINER_AND_DEV} +) async def accounts_post( request: Request, O: int = Form(default=0), # Offset @@ -564,9 +568,9 @@ async def accounts_post( # Convert parameter T to an AccountType ID. account_types = { "u": at.USER_ID, - "t": at.TRUSTED_USER_ID, + "t": at.PACKAGE_MAINTAINER_ID, "d": at.DEVELOPER_ID, - "td": at.TRUSTED_USER_AND_DEV_ID, + "td": at.PACKAGE_MAINTAINER_AND_DEV_ID, } account_type_id = account_types.get(T, None) diff --git a/aurweb/routers/trusted_user.py b/aurweb/routers/package_maintainer.py similarity index 88% rename from aurweb/routers/trusted_user.py rename to aurweb/routers/package_maintainer.py index 4248347d..c5e70dcf 100644 --- a/aurweb/routers/trusted_user.py +++ b/aurweb/routers/package_maintainer.py @@ -11,7 +11,10 @@ from aurweb import aur_logging, db, l10n, models, time from aurweb.auth import creds, requires_auth from aurweb.exceptions import handle_form_exceptions from aurweb.models import User -from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID +from aurweb.models.account_type import ( + PACKAGE_MAINTAINER_AND_DEV_ID, + PACKAGE_MAINTAINER_ID, +) from aurweb.templates import make_context, make_variable_context, render_template router = APIRouter() @@ -26,32 +29,32 @@ ADDVOTE_SPECIFICS = { # When a proposal is added, duration is added to the current # timestamp. # "addvote_type": (duration, quorum) - "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), + "add_pm": (7 * 24 * 60 * 60, 0.66), + "remove_pm": (7 * 24 * 60 * 60, 0.75), + "remove_inactive_pm": (5 * 24 * 60 * 60, 0.66), "bylaws": (7 * 24 * 60 * 60, 0.75), } -def populate_trusted_user_counts(context: dict[str, Any]) -> None: - tu_query = db.query(User).filter( +def populate_package_maintainer_counts(context: dict[str, Any]) -> None: + pm_query = db.query(User).filter( or_( - User.AccountTypeID == TRUSTED_USER_ID, - User.AccountTypeID == TRUSTED_USER_AND_DEV_ID, + User.AccountTypeID == PACKAGE_MAINTAINER_ID, + User.AccountTypeID == PACKAGE_MAINTAINER_AND_DEV_ID, ) ) - context["trusted_user_count"] = tu_query.count() + context["package_maintainer_count"] = pm_query.count() # In case any records have a None InactivityTS. - active_tu_query = tu_query.filter( + active_pm_query = pm_query.filter( or_(User.InactivityTS.is_(None), User.InactivityTS == 0) ) - context["active_trusted_user_count"] = active_tu_query.count() + context["active_package_maintainer_count"] = active_pm_query.count() @router.get("/tu") @requires_auth -async def trusted_user( +async def package_maintainer( request: Request, coff: int = 0, # current offset cby: str = "desc", # current by @@ -63,7 +66,7 @@ async def trusted_user( if not request.user.has_credential(creds.TU_LIST_VOTES): return RedirectResponse("/", status_code=HTTPStatus.SEE_OTHER) - context = make_context(request, "Trusted User") + context = make_context(request, "Package Maintainer") current_by, past_by = cby, pby current_off, past_off = coff, poff @@ -108,7 +111,7 @@ async def trusted_user( context["past_off"] = past_off last_vote = func.max(models.TUVote.VoteID).label("LastVote") - last_votes_by_tu = ( + last_votes_by_pm = ( db.query(models.TUVote) .join(models.User) .join(models.TUVoteInfo, models.TUVoteInfo.ID == models.TUVote.VoteID) @@ -124,12 +127,12 @@ async def trusted_user( .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["last_votes_by_pm"] = last_votes_by_pm.all() context["current_by_next"] = "asc" if current_by == "desc" else "desc" context["past_by_next"] = "asc" if past_by == "desc" else "desc" - populate_trusted_user_counts(context) + populate_package_maintainer_counts(context) context["q"] = { "coff": current_off, @@ -178,11 +181,11 @@ def render_proposal( @router.get("/tu/{proposal}") @requires_auth -async def trusted_user_proposal(request: Request, proposal: int): +async def package_maintainer_proposal(request: Request, proposal: int): 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") + context = await make_variable_context(request, "Package Maintainer") proposal = int(proposal) voteinfo = ( @@ -221,13 +224,13 @@ async def trusted_user_proposal(request: Request, proposal: int): @router.post("/tu/{proposal}") @handle_form_exceptions @requires_auth -async def trusted_user_proposal_post( +async def package_maintainer_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") + context = await make_variable_context(request, "Package Maintainer") proposal = int(proposal) # Make sure it's an int. voteinfo = ( @@ -285,8 +288,8 @@ async def trusted_user_proposal_post( @router.get("/addvote") @requires_auth -async def trusted_user_addvote( - request: Request, user: str = str(), type: str = "add_tu", agenda: str = str() +async def package_maintainer_addvote( + request: Request, user: str = str(), type: str = "add_pm", agenda: str = str() ): if not request.user.has_credential(creds.TU_ADD_VOTE): return RedirectResponse("/tu", status_code=HTTPStatus.SEE_OTHER) @@ -295,7 +298,7 @@ async def trusted_user_addvote( if type not in ADDVOTE_SPECIFICS: context["error"] = "Invalid type." - type = "add_tu" # Default it. + type = "add_pm" # Default it. context["user"] = user context["type"] = type @@ -308,7 +311,7 @@ async def trusted_user_addvote( @router.post("/addvote") @handle_form_exceptions @requires_auth -async def trusted_user_addvote_post( +async def package_maintainer_addvote_post( request: Request, user: str = Form(default=str()), type: str = Form(default=str()), @@ -352,7 +355,7 @@ async def trusted_user_addvote_post( if type not in ADDVOTE_SPECIFICS: context["error"] = "Invalid type." - context["type"] = type = "add_tu" # Default for rendering. + context["type"] = type = "add_pm" # Default for rendering. return render_addvote(context, HTTPStatus.BAD_REQUEST) if not agenda: @@ -364,11 +367,11 @@ async def trusted_user_addvote_post( timestamp = time.utcnow() # Active TU types we filter for. - types = {TRUSTED_USER_ID, TRUSTED_USER_AND_DEV_ID} + types = {PACKAGE_MAINTAINER_ID, PACKAGE_MAINTAINER_AND_DEV_ID} # Create a new TUVoteInfo (proposal)! with db.begin(): - active_tus = ( + active_pms = ( db.query(User) .filter( and_( @@ -386,7 +389,7 @@ async def trusted_user_addvote_post( Submitted=timestamp, End=(timestamp + duration), Quorum=quorum, - ActiveTUs=active_tus, + ActiveTUs=active_pms, Submitter=request.user, ) diff --git a/aurweb/statistics.py b/aurweb/statistics.py index f301b59c..00a5c151 100644 --- a/aurweb/statistics.py +++ b/aurweb/statistics.py @@ -3,7 +3,11 @@ from sqlalchemy import func from aurweb import config, db, time from aurweb.cache import db_count_cache, db_query_cache from aurweb.models import PackageBase, PackageRequest, RequestType, User -from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID, USER_ID +from aurweb.models.account_type import ( + PACKAGE_MAINTAINER_AND_DEV_ID, + PACKAGE_MAINTAINER_ID, + USER_ID, +) from aurweb.models.package_request import ( ACCEPTED_ID, CLOSED_ID, @@ -22,7 +26,7 @@ HOMEPAGE_COUNTERS = [ "year_old_updated", "never_updated", "user_count", - "trusted_user_count", + "package_maintainer_count", ] REQUEST_COUNTERS = [ "total_requests", @@ -32,7 +36,7 @@ REQUEST_COUNTERS = [ "rejected_requests", ] PROMETHEUS_USER_COUNTERS = [ - ("trusted_user_count", "tu"), + ("package_maintainer_count", "package_maintainer"), ("regular_user_count", "user"), ] PROMETHEUS_PACKAGE_COUNTERS = [ @@ -92,12 +96,12 @@ class Statistics: # Users case "user_count": query = self.user_query - case "trusted_user_count": + case "package_maintainer_count": query = self.user_query.filter( User.AccountTypeID.in_( ( - TRUSTED_USER_ID, - TRUSTED_USER_AND_DEV_ID, + PACKAGE_MAINTAINER_ID, + PACKAGE_MAINTAINER_AND_DEV_ID, ) ) ) diff --git a/aurweb/users/validate.py b/aurweb/users/validate.py index 8fc68864..5f1fcd43 100644 --- a/aurweb/users/validate.py +++ b/aurweb/users/validate.py @@ -220,7 +220,7 @@ def invalid_account_type( raise ValidationError([error]) logger.debug( - f"Trusted User '{request.user.Username}' has " + f"Package Maintainer '{request.user.Username}' has " f"modified '{user.Username}' account's type to" f" {name}." ) diff --git a/migrations/versions/6a64dd126029_rename_tu_to_package_maintainer.py b/migrations/versions/6a64dd126029_rename_tu_to_package_maintainer.py new file mode 100644 index 00000000..005549b0 --- /dev/null +++ b/migrations/versions/6a64dd126029_rename_tu_to_package_maintainer.py @@ -0,0 +1,37 @@ +"""Rename TU to Package Maintainer + +Revision ID: 6a64dd126029 +Revises: c5a6a9b661a0 +Create Date: 2023-09-01 13:48:15.315244 + +""" +from aurweb import db +from aurweb.models import AccountType + +# revision identifiers, used by Alembic. +revision = "6a64dd126029" +down_revision = "c5a6a9b661a0" +branch_labels = None +depends_on = None + +# AccountTypes +# ID 2 -> Trusted User / Package Maintainer +# ID 4 -> Trusted User & Developer / Package Maintainer & Developer + + +def upgrade(): + with db.begin(): + tu = db.query(AccountType).filter(AccountType.ID == 2).first() + tudev = db.query(AccountType).filter(AccountType.ID == 4).first() + + tu.AccountType = "Package Maintainer" + tudev.AccountType = "Package Maintainer & Developer" + + +def downgrade(): + with db.begin(): + pm = db.query(AccountType).filter(AccountType.ID == 2).first() + pmdev = db.query(AccountType).filter(AccountType.ID == 4).first() + + pm.AccountType = "Trusted User" + pmdev.AccountType = "Trusted User & Developer" diff --git a/schema/gendummydata.py b/schema/gendummydata.py index dfc8eee5..25f85c74 100755 --- a/schema/gendummydata.py +++ b/schema/gendummydata.py @@ -156,9 +156,9 @@ contents = None # developer/tu IDs # developers = [] -trustedusers = [] +packagemaintainers = [] has_devs = 0 -has_tus = 0 +has_pms = 0 # Just let python throw the errors if any happen # @@ -170,7 +170,7 @@ out.write("BEGIN;\n") log.debug("Creating SQL statements for users.") for u in user_keys: account_type = 1 # default to normal user - if not has_devs or not has_tus: + if not has_devs or not has_pms: account_type = random.randrange(1, 4) if account_type == 3 and not has_devs: # this will be a dev account @@ -178,12 +178,12 @@ for u in user_keys: developers.append(seen_users[u]) if len(developers) >= MAX_DEVS * MAX_USERS: has_devs = 1 - elif account_type == 2 and not has_tus: + elif account_type == 2 and not has_pms: # this will be a trusted user account # - trustedusers.append(seen_users[u]) - if len(trustedusers) >= MAX_TUS * MAX_USERS: - has_tus = 1 + packagemaintainers.append(seen_users[u]) + if len(packagemaintainers) >= MAX_TUS * MAX_USERS: + has_pms = 1 else: # a normal user account # @@ -205,8 +205,10 @@ for u in user_keys: out.write(s) log.debug("Number of developers: %d" % len(developers)) -log.debug("Number of trusted users: %d" % len(trustedusers)) -log.debug("Number of users: %d" % (MAX_USERS - len(developers) - len(trustedusers))) +log.debug("Number of package maintainers: %d" % len(packagemaintainers)) +log.debug( + "Number of users: %d" % (MAX_USERS - len(developers) - len(packagemaintainers)) +) log.debug("Number of packages: %d" % MAX_PKGS) log.debug("Gathering text from fortune file...") @@ -224,8 +226,8 @@ for p in list(seen_pkgs.keys()): muid = developers[random.randrange(0, len(developers))] puid = developers[random.randrange(0, len(developers))] else: - muid = trustedusers[random.randrange(0, len(trustedusers))] - puid = trustedusers[random.randrange(0, len(trustedusers))] + muid = packagemaintainers[random.randrange(0, len(packagemaintainers))] + puid = packagemaintainers[random.randrange(0, len(packagemaintainers))] if count % 20 == 0: # every so often, there are orphans... muid = "NULL" @@ -339,7 +341,7 @@ for p in seen_pkgs_keys: # Create trusted user proposals # -log.debug("Creating SQL statements for trusted user proposals.") +log.debug("Creating SQL statements for package maintainer proposals.") count = 0 for t in range(0, OPEN_PROPOSALS + CLOSE_PROPOSALS): now = int(time.time()) @@ -353,7 +355,7 @@ for t in range(0, OPEN_PROPOSALS + CLOSE_PROPOSALS): user = "" else: user = user_keys[random.randrange(0, len(user_keys))] - suid = trustedusers[random.randrange(0, len(trustedusers))] + suid = packagemaintainers[random.randrange(0, len(packagemaintainers))] s = ( "INSERT INTO TU_VoteInfo (Agenda, User, Submitted, End," " Quorum, SubmitterID) VALUES ('%s', '%s', %d, %d, 0.0, %d);\n" diff --git a/templates/addvote.html b/templates/addvote.html index 8777cbf3..30b65c0e 100644 --- a/templates/addvote.html +++ b/templates/addvote.html @@ -19,22 +19,22 @@

    - + - +

    diff --git a/templates/addvote.html b/templates/addvote.html index 30b65c0e..cc12f42b 100644 --- a/templates/addvote.html +++ b/templates/addvote.html @@ -24,21 +24,21 @@ selected {% endif %} > - {{ "Addition of a TU" | tr }} + {{ "Addition of a Package Maintainer" | tr }}

  • - {% trans %}Trusted User{% endtrans %} + {% trans %}Package Maintainer{% endtrans %}
  • {% endif %} diff --git a/templates/partials/packages/statistics.html b/templates/partials/packages/statistics.html index 7c3c3ef6..7ce5fba1 100644 --- a/templates/partials/packages/statistics.html +++ b/templates/partials/packages/statistics.html @@ -42,7 +42,7 @@ - {{ "Trusted Users" | tr }} + {{ "Package Maintainers" | tr }} {{ package_maintainer_count }} diff --git a/templates/partials/support.html b/templates/partials/support.html index a2890cc5..b175a040 100644 --- a/templates/partials/support.html +++ b/templates/partials/support.html @@ -10,7 +10,7 @@

    • {% trans %}Orphan Request{% endtrans %}: {% trans %}Request a package to be disowned, e.g. when the maintainer is inactive and the package has been flagged out-of-date for a long time.{% endtrans %}
    • -
    • {% trans %}Deletion Request{% endtrans %}: {%trans %}Request a package to be removed from the Arch User Repository. Please do not use this if a package is broken and can be fixed easily. Instead, contact the package maintainer and file orphan request if necessary.{% endtrans %}
    • +
    • {% trans %}Deletion Request{% endtrans %}: {%trans %}Request a package to be removed from the Arch User Repository. Please do not use this if a package is broken and can be fixed easily. Instead, contact the maintainer and file orphan request if necessary.{% endtrans %}
    • {% trans %}Merge Request{% endtrans %}: {% trans %}Request a package to be merged into another one. Can be used when a package needs to be renamed or replaced by a split package.{% endtrans %}

    @@ -44,7 +44,7 @@

    {% trans %}Discussion{% endtrans %}

    - {{ "General discussion regarding the Arch User Repository (AUR) and Trusted User structure takes place on %saur-general%s. For discussion relating to the development of the AUR web interface, use the %saur-dev%s mailing list." + {{ "General discussion regarding the Arch User Repository (AUR) and Package Maintainer structure takes place on %saur-general%s. For discussion relating to the development of the AUR web interface, use the %saur-dev%s mailing list." | tr | format('', "", '', "") @@ -55,7 +55,7 @@

    {% trans %}Bug Reporting{% endtrans %}

    - {{ "If you find a bug in the AUR web interface, please fill out a bug report on our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface %sonly%s. To report packaging bugs contact the package maintainer or leave a comment on the appropriate package page." + {{ "If you find a bug in the AUR web interface, please fill out a bug report on our %sbug tracker%s. Use the tracker to report bugs in the AUR web interface %sonly%s. To report packaging bugs contact the maintainer or leave a comment on the appropriate package page." | tr | format('', "", "", "") diff --git a/templates/partials/tu/proposal/details.html b/templates/partials/tu/proposal/details.html index 4cbee9ad..c74a5c5e 100644 --- a/templates/partials/tu/proposal/details.html +++ b/templates/partials/tu/proposal/details.html @@ -22,7 +22,7 @@

    - {{ "Active" | tr }} {{ "Trusted Users" | tr }} {{ "assigned" | tr }}: + {{ "Active" | tr }} {{ "Package Maintainers" | tr }} {{ "assigned" | tr }}: {{ voteinfo.ActiveTUs }}
    diff --git a/templates/pkgbase/request.html b/templates/pkgbase/request.html index 61654a49..3ffa2d2d 100644 --- a/templates/pkgbase/request.html +++ b/templates/pkgbase/request.html @@ -69,8 +69,8 @@

    {{ - "By submitting a deletion request, you ask a Trusted " - "User to delete the package base. This type of " + "By submitting a deletion request, you ask a Package " + "Maintainer to delete the package base. This type of " "request should be used for duplicates, software " "abandoned by upstream, as well as illegal and " "irreparably broken packages." | tr @@ -79,8 +79,8 @@