diff --git a/aurweb/routers/packages.py b/aurweb/routers/packages.py index c74a5ba3..0ce4f60f 100644 --- a/aurweb/routers/packages.py +++ b/aurweb/routers/packages.py @@ -867,11 +867,7 @@ async def pkgbase_notify(request: Request, name: str): status_code=HTTPStatus.SEE_OTHER) -@router.post("/pkgbase/{name}/unnotify") -@auth_required(True, redirect="/pkgbase/{name}") -async def pkgbase_unnotify(request: Request, name: str): - pkgbase = get_pkg_or_base(name, models.PackageBase) - +def pkgbase_unnotify_instance(request: Request, pkgbase: models.PackageBase): notif = pkgbase.notifications.filter( models.PackageNotification.UserID == request.user.ID ).first() @@ -880,6 +876,12 @@ async def pkgbase_unnotify(request: Request, name: str): with db.begin(): db.session.delete(notif) + +@router.post("/pkgbase/{name}/unnotify") +@auth_required(True, redirect="/pkgbase/{name}") +async def pkgbase_unnotify(request: Request, name: str): + pkgbase = get_pkg_or_base(name, models.PackageBase) + pkgbase_unnotify_instance(request, pkgbase) return RedirectResponse(f"/pkgbase/{name}", status_code=HTTPStatus.SEE_OTHER) @@ -1111,12 +1113,51 @@ async def packages_notify(request: Request, package_ids: List[int] = [], # TODO: This message does not yet have a translation. return (True, ["The selected packages' notifications have been enabled."]) + +async def packages_unnotify(request: Request, package_ids: List[int] = [], + **kwargs): + if not package_ids: + # TODO: This error does not yet have a translation. + return (False, + ["You did not select any packages for notification removal."]) + + # TODO: This error does not yet have a translation. + error_tuple = ( + False, + ["A package you selected does not have notifications enabled."] + ) + + bases = set() + package_ids = set(package_ids) + packages = db.query(models.Package).filter( + models.Package.ID.in_(package_ids)).all() + + for pkg in packages: + if pkg.PackageBase not in bases: + bases.update({pkg.PackageBase}) + + # Perform some checks on what the user selected for notify. + for pkgbase in bases: + notif = db.query(pkgbase.notifications.filter( + models.PackageNotification.UserID == request.user.ID + ).exists()).scalar() + if not notif: + return error_tuple + + for pkgbase in bases: + pkgbase_unnotify_instance(request, pkgbase) + + # TODO: This message does not yet have a translation. + return (True, ["The selected packages' notifications have been removed."]) + + # A mapping of action string -> callback functions used within the # `packages_post` route below. We expect any action callback to # return a tuple in the format: (succeeded: bool, message: List[str]). PACKAGE_ACTIONS = { "unflag": packages_unflag, "notify": packages_notify, + "unnotify": packages_unnotify, } diff --git a/po/aurweb.pot b/po/aurweb.pot index 699a6aef..05505e8b 100644 --- a/po/aurweb.pot +++ b/po/aurweb.pot @@ -966,6 +966,18 @@ msgstr "" msgid "The selected packages' notifications have been enabled." msgstr "" +#: aurweb/routers/packages.py +msgid "You did not select any packages for notification removal." +msgstr "" + +#: aurweb/routers/packages.py +msgid "A package you selected does not have notifications enabled." +msgstr "" + +#: aurweb/routers/packages.py +msgid "The selected packages' notifications have been removed." +msgstr "" + #: lib/pkgbasefuncs.inc.php msgid "You must be logged in before you can flag packages." msgstr "" diff --git a/test/test_packages_routes.py b/test/test_packages_routes.py index f86bb805..f663da49 100644 --- a/test/test_packages_routes.py +++ b/test/test_packages_routes.py @@ -2154,3 +2154,52 @@ def test_packages_post_notify(client: TestClient, user: User, package: Package): errors = get_errors(resp.text) expected = "You did not select any packages to be notified about." assert errors[0].text.strip() == expected + + +def test_packages_post_unnotify(client: TestClient, user: User, + package: Package): + # Create a notification record. + with db.begin(): + notif = db.create(PackageNotification, + PackageBase=package.PackageBase, + User=user) + assert notif is not None + + # Request removal of the notification without any IDs. + cookies = {"AURSID": user.login(Request(), "testPassword")} + with client as request: + resp = request.post("/packages", data={ + "action": "unnotify" + }, cookies=cookies) + assert resp.status_code == int(HTTPStatus.BAD_REQUEST) + errors = get_errors(resp.text) + expected = "You did not select any packages for notification removal." + assert errors[0].text.strip() == expected + + # Request removal of the notification; really. + with client as request: + resp = request.post("/packages", data={ + "action": "unnotify", + "IDs": [package.ID] + }, cookies=cookies) + assert resp.status_code == int(HTTPStatus.OK) + successes = get_successes(resp.text) + expected = "The selected packages' notifications have been removed." + assert successes[0].text.strip() == expected + + # Let's ensure the record got removed. + notif = package.PackageBase.notifications.filter( + PackageNotification.UserID == user.ID + ).first() + assert notif is None + + # Try it again. The notif no longer exists. + with client as request: + resp = request.post("/packages", data={ + "action": "unnotify", + "IDs": [package.ID] + }, cookies=cookies) + assert resp.status_code == int(HTTPStatus.BAD_REQUEST) + errors = get_errors(resp.text) + expected = "A package you selected does not have notifications enabled." + assert errors[0].text.strip() == expected