Merge branch 'master' into live

This commit is contained in:
Kevin Morris 2022-03-08 20:36:09 -08:00
commit 0c1e40a437
No known key found for this signature in database
GPG key ID: F7E46DED420788F3
8 changed files with 109 additions and 2 deletions

View file

@ -6,7 +6,7 @@ from typing import Any
# Publicly visible version of aurweb. This is used to display # Publicly visible version of aurweb. This is used to display
# aurweb versioning in the footer and must be maintained. # aurweb versioning in the footer and must be maintained.
# Todo: Make this dynamic/automated. # Todo: Make this dynamic/automated.
AURWEB_VERSION = "v6.0.24" AURWEB_VERSION = "v6.0.25"
_parser = None _parser = None

View file

@ -2,6 +2,7 @@ import html
import typing import typing
from http import HTTPStatus from http import HTTPStatus
from typing import Any, Dict
from fastapi import APIRouter, Form, HTTPException, Request from fastapi import APIRouter, Form, HTTPException, Request
from fastapi.responses import RedirectResponse, Response from fastapi.responses import RedirectResponse, Response
@ -33,6 +34,21 @@ ADDVOTE_SPECIFICS = {
} }
def populate_trusted_user_counts(context: Dict[str, Any]) -> None:
tu_query = db.query(User).filter(
or_(User.AccountTypeID == TRUSTED_USER_ID,
User.AccountTypeID == TRUSTED_USER_AND_DEV_ID)
)
context["trusted_user_count"] = tu_query.count()
# In case any records have a None InactivityTS.
active_tu_query = tu_query.filter(
or_(User.InactivityTS.is_(None),
User.InactivityTS == 0)
)
context["active_trusted_user_count"] = active_tu_query.count()
@router.get("/tu") @router.get("/tu")
@requires_auth @requires_auth
async def trusted_user(request: Request, async def trusted_user(request: Request,
@ -40,6 +56,8 @@ async def trusted_user(request: Request,
cby: str = "desc", # current by cby: str = "desc", # current by
poff: int = 0, # past offset poff: int = 0, # past offset
pby: str = "desc"): # past by pby: str = "desc"): # past by
""" Proposal listings. """
if not request.user.has_credential(creds.TU_LIST_VOTES): if not request.user.has_credential(creds.TU_LIST_VOTES):
return RedirectResponse("/", status_code=HTTPStatus.SEE_OTHER) return RedirectResponse("/", status_code=HTTPStatus.SEE_OTHER)
@ -102,6 +120,8 @@ async def trusted_user(request: Request,
context["current_by_next"] = "asc" if current_by == "desc" else "desc" context["current_by_next"] = "asc" if current_by == "desc" else "desc"
context["past_by_next"] = "asc" if past_by == "desc" else "desc" context["past_by_next"] = "asc" if past_by == "desc" else "desc"
populate_trusted_user_counts(context)
context["q"] = { context["q"] = {
"coff": current_off, "coff": current_off,
"cby": current_by, "cby": current_by,

View file

@ -2334,3 +2334,7 @@ msgid "This action will close any pending package requests "
"related to it. If %sComments%s are omitted, a closure " "related to it. If %sComments%s are omitted, a closure "
"comment will be autogenerated." "comment will be autogenerated."
msgstr "" msgstr ""
#: templates/partials/tu/proposal/details.html
msgid "assigned"
msgstr ""

View file

@ -8,7 +8,7 @@
# #
[tool.poetry] [tool.poetry]
name = "aurweb" name = "aurweb"
version = "v6.0.24" version = "v6.0.25"
license = "GPL-2.0-only" license = "GPL-2.0-only"
description = "Source code for the Arch User Repository's website" description = "Source code for the Arch User Repository's website"
homepage = "https://aur.archlinux.org" homepage = "https://aur.archlinux.org"

View file

@ -21,6 +21,11 @@
</strong> </strong>
</div> </div>
<div class="field">
{{ "Active" | tr }} {{ "Trusted Users" | tr }} {{ "assigned" | tr }}:
{{ voteinfo.ActiveTUs }}
</div>
{% set submitter = voteinfo.Submitter.Username %} {% set submitter = voteinfo.Submitter.Username %}
{% set submitter_uri = "/account/%s" | format(submitter) %} {% set submitter_uri = "/account/%s" | format(submitter) %}
{% set submitter = '<a href="%s">%s</a>' | format(submitter_uri, submitter) %} {% set submitter = '<a href="%s">%s</a>' | format(submitter_uri, submitter) %}

View file

@ -1,6 +1,22 @@
{% extends "partials/layout.html" %} {% extends "partials/layout.html" %}
{% block pageContent %} {% block pageContent %}
<div class="box">
<h2>{{ "Statistics" | tr }}</h2>
<table class="no-width">
<tbody>
<tr>
<td class="text-right">{{ "Total" | tr }} {{ "Trusted Users" | tr }}:</td>
<td>{{ trusted_user_count }}</td>
</tr>
<tr>
<td class="text-right">{{ "Active" | tr }} {{ "Trusted Users" | tr }}:</td>
<td>{{ active_trusted_user_count }}</td>
</tr>
</tbody>
</table>
</div>
{% {%
with table_class = "current-votes", with table_class = "current-votes",
total_votes = current_votes_count, total_votes = current_votes_count,

View file

@ -267,6 +267,48 @@ def test_tu_index(client, tu_user):
assert int(vote_id.text.strip()) == vote_records[1].ID assert int(vote_id.text.strip()) == vote_records[1].ID
def test_tu_stats(client: TestClient, tu_user: User):
cookies = {"AURSID": tu_user.login(Request(), "testPassword")}
with client as request:
response = request.get("/tu", cookies=cookies, allow_redirects=False)
assert response.status_code == HTTPStatus.OK
root = parse_root(response.text)
stats = root.xpath('//table[@class="no-width"]')[0]
rows = stats.xpath("./tbody/tr")
# We have one trusted user.
total = rows[0]
label, count = total.xpath("./td")
assert int(count.text.strip()) == 1
# And we have one active TU.
active = rows[1]
label, count = active.xpath("./td")
assert int(count.text.strip()) == 1
with db.begin():
tu_user.InactivityTS = time.utcnow()
with client as request:
response = request.get("/tu", cookies=cookies, allow_redirects=False)
assert response.status_code == HTTPStatus.OK
root = parse_root(response.text)
stats = root.xpath('//table[@class="no-width"]')[0]
rows = stats.xpath("./tbody/tr")
# We have one trusted user.
total = rows[0]
label, count = total.xpath("./td")
assert int(count.text.strip()) == 1
# But we have no more active TUs.
active = rows[1]
label, count = active.xpath("./td")
assert int(count.text.strip()) == 0
def test_tu_index_table_paging(client, tu_user): def test_tu_index_table_paging(client, tu_user):
ts = time.utcnow() ts = time.utcnow()
@ -515,6 +557,8 @@ def test_tu_proposal_unauthorized(client: TestClient, user: User,
def test_tu_running_proposal(client: TestClient, def test_tu_running_proposal(client: TestClient,
proposal: Tuple[User, User, TUVoteInfo]): proposal: Tuple[User, User, TUVoteInfo]):
tu_user, user, voteinfo = proposal tu_user, user, voteinfo = proposal
with db.begin():
voteinfo.ActiveTUs = 1
# Initiate an authenticated GET request to /tu/{proposal_id}. # Initiate an authenticated GET request to /tu/{proposal_id}.
proposal_id = voteinfo.ID proposal_id = voteinfo.ID
@ -536,6 +580,11 @@ def test_tu_running_proposal(client: TestClient,
'./div[contains(@class, "user")]/strong/a/text()')[0] './div[contains(@class, "user")]/strong/a/text()')[0]
assert username.strip() == user.Username assert username.strip() == user.Username
active = details.xpath('./div[contains(@class, "field")]')[1]
content = active.text.strip()
assert "Active Trusted Users assigned:" in content
assert "1" in content
submitted = details.xpath( submitted = details.xpath(
'./div[contains(@class, "submitted")]/text()')[0] './div[contains(@class, "submitted")]/text()')[0]
assert re.match(r'^Submitted: \d{4}-\d{2}-\d{2} \d{2}:\d{2} \(.+\) by$', assert re.match(r'^Submitted: \d{4}-\d{2}-\d{2} \d{2}:\d{2} \(.+\) by$',

View file

@ -282,3 +282,16 @@ pre.traceback {
white-space: -o-pre-wrap; white-space: -o-pre-wrap;
word-wrap: break-all; word-wrap: break-all;
} }
/* A text aligning alias. */
.text-right {
text-align: right;
}
/* 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;
}