mirror of
https://gitlab.archlinux.org/archlinux/aurweb.git
synced 2025-02-03 10:43:03 +01:00
Problem is that we join with PackageBase, thus we are missing requests for packages that were deleted. Fixes: #483 Signed-off-by: moson <moson@archlinux.org>
166 lines
5.4 KiB
Python
166 lines
5.4 KiB
Python
from http import HTTPStatus
|
|
|
|
from fastapi import APIRouter, Form, Query, Request
|
|
from fastapi.responses import RedirectResponse
|
|
from sqlalchemy import case, orm
|
|
|
|
from aurweb import db, defaults, time, util
|
|
from aurweb.auth import creds, requires_auth
|
|
from aurweb.exceptions import handle_form_exceptions
|
|
from aurweb.models import PackageBase, PackageRequest, User
|
|
from aurweb.models.package_request import (
|
|
ACCEPTED_ID,
|
|
CLOSED_ID,
|
|
PENDING_ID,
|
|
REJECTED_ID,
|
|
)
|
|
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 = {
|
|
"filter_pending",
|
|
"filter_closed",
|
|
"filter_accepted",
|
|
"filter_rejected",
|
|
"filter_maintainers_requests",
|
|
}
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/requests")
|
|
@requires_auth
|
|
async def requests( # noqa: C901
|
|
request: Request,
|
|
O: int = Query(default=defaults.O),
|
|
PP: int = Query(default=defaults.PP),
|
|
filter_pending: bool = False,
|
|
filter_closed: bool = False,
|
|
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
|
|
context["PP"] = PP
|
|
context["filter_pending"] = filter_pending
|
|
context["filter_closed"] = filter_closed
|
|
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
|
|
query = (
|
|
db.query(PackageRequest)
|
|
.join(PackageBase)
|
|
.join(User, PackageRequest.UsersID == User.ID, isouter=True)
|
|
.join(Maintainer, PackageBase.MaintainerUID == Maintainer.ID, isouter=True)
|
|
)
|
|
|
|
# Requests statistics
|
|
counts = get_request_counts()
|
|
for k in counts:
|
|
context[k] = counts[k]
|
|
|
|
# Apply status filters
|
|
in_filters = []
|
|
if filter_pending:
|
|
in_filters.append(PENDING_ID)
|
|
if filter_closed:
|
|
in_filters.append(CLOSED_ID)
|
|
if filter_accepted:
|
|
in_filters.append(ACCEPTED_ID)
|
|
if filter_rejected:
|
|
in_filters.append(REJECTED_ID)
|
|
filtered = query.filter(PackageRequest.Status.in_(in_filters))
|
|
|
|
# Name filter (contains)
|
|
if 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:
|
|
filtered = filtered.filter(PackageRequest.UsersID == PackageBase.MaintainerUID)
|
|
# If the request user is not elevated (TU or Dev), then
|
|
# filter PackageRequests which are owned by the request user.
|
|
if not request.user.is_elevated():
|
|
filtered = filtered.filter(PackageRequest.UsersID == request.user.ID)
|
|
|
|
context["total"] = filtered.count()
|
|
context["results"] = (
|
|
filtered.order_by(
|
|
# Order primarily by the Status column being PENDING_ID,
|
|
# and secondarily by RequestTS; both in descending order.
|
|
case([(PackageRequest.Status == PENDING_ID, 1)], else_=0).desc(),
|
|
PackageRequest.RequestTS.desc(),
|
|
)
|
|
.limit(PP)
|
|
.offset(O)
|
|
.all()
|
|
)
|
|
return render_template(request, "requests.html", context)
|
|
|
|
|
|
@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 '/'.
|
|
return RedirectResponse("/", status_code=HTTPStatus.SEE_OTHER)
|
|
|
|
context = make_context(request, "Close Request")
|
|
context["pkgreq"] = pkgreq
|
|
return render_template(request, "requests/close.html", context)
|
|
|
|
|
|
@db.async_retry_deadlock
|
|
@router.post("/requests/{id}/close")
|
|
@handle_form_exceptions
|
|
@requires_auth
|
|
async def request_close_post(
|
|
request: Request, id: int, comments: str = Form(default=str())
|
|
):
|
|
pkgreq = get_pkgreq_by_id(id)
|
|
|
|
# `pkgreq`.User can close their own request.
|
|
approved = [pkgreq.User]
|
|
if not request.user.has_credential(creds.PKGREQ_CLOSE, approved=approved):
|
|
# Request user doesn't have permission here: redirect to '/'.
|
|
return RedirectResponse("/", status_code=HTTPStatus.SEE_OTHER)
|
|
|
|
context = make_context(request, "Close Request")
|
|
context["pkgreq"] = pkgreq
|
|
|
|
now = time.utcnow()
|
|
with db.begin():
|
|
pkgreq.Closer = request.user
|
|
pkgreq.ClosureComment = comments
|
|
pkgreq.ClosedTS = now
|
|
pkgreq.Status = REJECTED_ID
|
|
|
|
notify_ = notify.RequestCloseNotification(
|
|
request.user.ID, pkgreq.ID, pkgreq.status_display()
|
|
)
|
|
notify_.send()
|
|
|
|
return RedirectResponse("/requests", status_code=HTTPStatus.SEE_OTHER)
|