mirror of
https://gitlab.archlinux.org/archlinux/aurweb.git
synced 2025-02-03 10:43:03 +01:00
routers.html: add authenticated dashboard to homepage
Signed-off-by: Kevin Morris <kevr@0cost.org>
This commit is contained in:
parent
af51b5c460
commit
5a175bd92a
6 changed files with 269 additions and 2 deletions
|
@ -9,11 +9,15 @@ from fastapi.responses import HTMLResponse, RedirectResponse
|
||||||
from sqlalchemy import and_, or_
|
from sqlalchemy import and_, or_
|
||||||
|
|
||||||
import aurweb.config
|
import aurweb.config
|
||||||
|
import aurweb.models.package_request
|
||||||
|
|
||||||
from aurweb import db, util
|
from aurweb import db, util
|
||||||
from aurweb.cache import db_count_cache
|
from aurweb.cache import db_count_cache
|
||||||
from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID
|
from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID
|
||||||
|
from aurweb.models.package import Package
|
||||||
from aurweb.models.package_base import PackageBase
|
from aurweb.models.package_base import PackageBase
|
||||||
|
from aurweb.models.package_comaintainer import PackageComaintainer
|
||||||
|
from aurweb.models.package_request import PackageRequest
|
||||||
from aurweb.models.user import User
|
from aurweb.models.user import User
|
||||||
from aurweb.packages.util import updated_packages
|
from aurweb.packages.util import updated_packages
|
||||||
from aurweb.templates import make_context, render_template
|
from aurweb.templates import make_context, render_template
|
||||||
|
@ -132,6 +136,41 @@ async def index(request: Request):
|
||||||
# Get the 15 most recently updated packages.
|
# Get the 15 most recently updated packages.
|
||||||
context["package_updates"] = updated_packages(15, updates_expire)
|
context["package_updates"] = updated_packages(15, updates_expire)
|
||||||
|
|
||||||
|
if request.user.is_authenticated():
|
||||||
|
# Authenticated users get a few extra pieces of data for
|
||||||
|
# the dashboard display.
|
||||||
|
packages = db.query(Package).join(PackageBase)
|
||||||
|
|
||||||
|
maintained = packages.join(
|
||||||
|
User, PackageBase.MaintainerUID == User.ID
|
||||||
|
).filter(
|
||||||
|
PackageBase.MaintainerUID == request.user.ID
|
||||||
|
)
|
||||||
|
|
||||||
|
context["flagged_packages"] = maintained.filter(
|
||||||
|
PackageBase.OutOfDateTS.isnot(None)
|
||||||
|
).order_by(
|
||||||
|
PackageBase.ModifiedTS.desc(), Package.Name.asc()
|
||||||
|
).limit(50).all()
|
||||||
|
|
||||||
|
archive_time = aurweb.config.getint('options', 'request_archive_time')
|
||||||
|
start = now - archive_time
|
||||||
|
context["package_requests"] = request.user.package_requests.filter(
|
||||||
|
PackageRequest.RequestTS >= start
|
||||||
|
).limit(50).all()
|
||||||
|
|
||||||
|
# Packages that the request user maintains or comaintains.
|
||||||
|
context["packages"] = maintained.order_by(
|
||||||
|
PackageBase.ModifiedTS.desc(), Package.Name.desc()
|
||||||
|
).limit(50).all()
|
||||||
|
|
||||||
|
# Any packages that the request user comaintains.
|
||||||
|
context["comaintained"] = packages.join(
|
||||||
|
PackageComaintainer).filter(
|
||||||
|
PackageComaintainer.UsersID == request.user.ID).order_by(
|
||||||
|
PackageBase.ModifiedTS.desc(), Package.Name.desc()
|
||||||
|
).limit(50).all()
|
||||||
|
|
||||||
return render_template(request, "index.html", context)
|
return render_template(request, "index.html", context)
|
||||||
|
|
||||||
|
|
||||||
|
|
54
templates/dashboard.html
Normal file
54
templates/dashboard.html
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
<div id="intro" class="box">
|
||||||
|
<h2>{{ "Dashboard" | tr }}</h2>
|
||||||
|
|
||||||
|
<h3>{{ "My Flagged Packages" | tr }}</h3>
|
||||||
|
{% if not flagged_packages %}
|
||||||
|
<p>{{ "No packages matched your search criteria." | tr }}</p>
|
||||||
|
{% else %}
|
||||||
|
{% with table_id = "flagged-packages", packages = flagged_packages %}
|
||||||
|
{% include 'partials/packages/results.html' %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<h3>{{ "My Requests" | tr }}</h3>
|
||||||
|
{% if not package_requests %}
|
||||||
|
<p>{{ "No requests matched your search criteria." | tr }}</p>
|
||||||
|
{% else %}
|
||||||
|
{% with requests = package_requests %}
|
||||||
|
{% include 'partials/packages/requests.html' %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="intro" class="box">
|
||||||
|
<h2>{{ "My Packages" | tr }}</h2>
|
||||||
|
<p>
|
||||||
|
<a href="/packages/?SeB=m&K={{ request.user.Username }}">
|
||||||
|
{{ "Search for packages I maintain" | tr }}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
{% if not packages %}
|
||||||
|
<p>{{ "No packages matched your search criteria." | tr }}</p>
|
||||||
|
{% else %}
|
||||||
|
{% with table_id = "my-packages" %}
|
||||||
|
{% include 'partials/packages/results.html' %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="intro" class="box">
|
||||||
|
<h2>{{ "Co-Maintained Packages" | tr }}</h2>
|
||||||
|
<p>
|
||||||
|
<a href="/packages/?SeB=c&K={{ request.user.Username }}">
|
||||||
|
{{ "Search for packages I co-maintain" | tr }}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
{% if not comaintained %}
|
||||||
|
<p>{{ "No packages matched your search criteria." | tr }}</p>
|
||||||
|
{% else %}
|
||||||
|
{% with table_id = "comaintained-packages", packages = comaintained %}
|
||||||
|
{% include 'partials/packages/results.html' %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
|
@ -3,7 +3,11 @@
|
||||||
{% block pageContent %}
|
{% block pageContent %}
|
||||||
<div id="content-left-wrapper">
|
<div id="content-left-wrapper">
|
||||||
<div id="content-left">
|
<div id="content-left">
|
||||||
|
{% if request.user.is_authenticated() %}
|
||||||
|
{% include 'dashboard.html' %}
|
||||||
|
{% else %}
|
||||||
{% include 'home.html' %}
|
{% include 'home.html' %}
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="content-right">
|
<div id="content-right">
|
||||||
|
|
38
templates/partials/packages/requests.html
Normal file
38
templates/partials/packages/requests.html
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<table id="pkgreq-results" class="results">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ "Package" | tr }}</th>
|
||||||
|
<th>{{ "Type" | tr }}</th>
|
||||||
|
<th>{{ "Comments" | tr }}</th>
|
||||||
|
<th>{{ "Filed by" | tr }}</th>
|
||||||
|
<th>{{ "Date" | tr }}</th>
|
||||||
|
<th>{{ "Status" | tr }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
{% for request in requests %}
|
||||||
|
{% set requested = request.RequestTS | dt | as_timezone(timezone) %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/pkgbase/{{ request.PackageBase.Name }}">
|
||||||
|
{{ request.PackageBase.Name }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>{{ request.RequestType.name_display() | tr }}</td>
|
||||||
|
<td class="wrap">{{ request.Comments }}</td>
|
||||||
|
<td>
|
||||||
|
<a href="/account/{{ request.User.Username }}"
|
||||||
|
title="{{ 'View account information for %s' | tr | format(request.User.Username) }}">
|
||||||
|
{{ request.User.Username }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>{{ requested.strftime("%Y-%m-%d %H:%M") }}</td>
|
||||||
|
<td>{{ request.status_display() | tr }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
|
||||||
|
</table>
|
55
templates/partials/packages/results.html
Normal file
55
templates/partials/packages/results.html
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
|
||||||
|
<table {% if table_id %}id="{{ table_id }}"{% endif %} class="results">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ "Name" | tr }}</th>
|
||||||
|
<th>{{ "Version" | tr }}</th>
|
||||||
|
<th>{{ "Votes" | tr }}</th>
|
||||||
|
<th>{{ "Popularity" | tr }}</th>
|
||||||
|
<th>{{ "Voted" | tr }}</th>
|
||||||
|
<th>{{ "Notify" | tr }}</th>
|
||||||
|
<th>{{ "Description" | tr }}</th>
|
||||||
|
<th>{{ "Maintainer" | tr }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for pkg in packages %}
|
||||||
|
{% set flagged = pkg.PackageBase.OutOfDateTS %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/packages/{{ pkg.Name }}">
|
||||||
|
{{ pkg.Name }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
{% if flagged %}
|
||||||
|
<td class="flagged">{{ pkg.Version }}</td>
|
||||||
|
{% else %}
|
||||||
|
<td>{{ pkg.Version }}</td>
|
||||||
|
{% endif %}
|
||||||
|
<td>{{ pkg.PackageBase.NumVotes }}</td>
|
||||||
|
<td>
|
||||||
|
{{ pkg.PackageBase.Popularity | number_format(2) }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<!-- If I voted, display "Yes". -->
|
||||||
|
{% if request.user.voted_for(pkg) %}
|
||||||
|
{{ "Yes" | tr }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<!-- If I'm being notified, display "Yes". -->
|
||||||
|
{% if request.user.notified(pkg) %}
|
||||||
|
{{ "Yes" | tr }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td class="wrap">{{ pkg.Description or '' }}</td>
|
||||||
|
<td>
|
||||||
|
{% set maintainer = pkg.PackageBase.Maintainer %}
|
||||||
|
<a href="/account/{{ maintainer.Username }}">
|
||||||
|
{{ maintainer.Username }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
|
@ -13,10 +13,14 @@ from aurweb.asgi import app
|
||||||
from aurweb.models.account_type import USER_ID
|
from aurweb.models.account_type import USER_ID
|
||||||
from aurweb.models.package import Package
|
from aurweb.models.package import Package
|
||||||
from aurweb.models.package_base import PackageBase
|
from aurweb.models.package_base import PackageBase
|
||||||
|
from aurweb.models.package_comaintainer import PackageComaintainer
|
||||||
|
from aurweb.models.package_request import PackageRequest
|
||||||
|
from aurweb.models.request_type import DELETION_ID, RequestType
|
||||||
from aurweb.models.user import User
|
from aurweb.models.user import User
|
||||||
from aurweb.redis import redis_connection
|
from aurweb.redis import redis_connection
|
||||||
from aurweb.testing import setup_test_db
|
from aurweb.testing import setup_test_db
|
||||||
from aurweb.testing.html import parse_root
|
from aurweb.testing.html import parse_root
|
||||||
|
from aurweb.testing.requests import Request
|
||||||
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
|
|
||||||
|
@ -26,7 +30,9 @@ def setup():
|
||||||
yield setup_test_db(
|
yield setup_test_db(
|
||||||
User.__tablename__,
|
User.__tablename__,
|
||||||
Package.__tablename__,
|
Package.__tablename__,
|
||||||
PackageBase.__tablename__
|
PackageBase.__tablename__,
|
||||||
|
PackageComaintainer.__tablename__,
|
||||||
|
PackageRequest.__tablename__
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -149,3 +155,74 @@ def test_homepage_updates(redis, packages):
|
||||||
for i, expected in enumerate(expectations):
|
for i, expected in enumerate(expectations):
|
||||||
pkgname = updates[i].xpath('./td/a').pop(0)
|
pkgname = updates[i].xpath('./td/a').pop(0)
|
||||||
assert pkgname.text.strip() == expected
|
assert pkgname.text.strip() == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_homepage_dashboard(redis, packages, user):
|
||||||
|
# Create Comaintainer records for all of the packages.
|
||||||
|
for pkg in packages:
|
||||||
|
db.create(PackageComaintainer, PackageBase=pkg.PackageBase,
|
||||||
|
User=user, Priority=1, autocommit=False)
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
cookies = {"AURSID": user.login(Request(), "testPassword")}
|
||||||
|
with client as request:
|
||||||
|
response = request.get("/", cookies=cookies)
|
||||||
|
assert response.status_code == int(HTTPStatus.OK)
|
||||||
|
|
||||||
|
root = parse_root(response.text)
|
||||||
|
|
||||||
|
# Assert some expectations that we end up getting all fifty
|
||||||
|
# packages in the "My Packages" table.
|
||||||
|
expectations = [f"pkg_{i}" for i in range(50 - 1, 0, -1)]
|
||||||
|
my_packages = root.xpath('//table[@id="my-packages"]/tbody/tr')
|
||||||
|
for i, expected in enumerate(expectations):
|
||||||
|
name, version, votes, pop, voted, notify, desc, maint \
|
||||||
|
= my_packages[i].xpath('./td')
|
||||||
|
assert name.xpath('./a').pop(0).text.strip() == expected
|
||||||
|
|
||||||
|
# Do the same for the Comaintained Packages table.
|
||||||
|
my_packages = root.xpath('//table[@id="comaintained-packages"]/tbody/tr')
|
||||||
|
for i, expected in enumerate(expectations):
|
||||||
|
name, version, votes, pop, voted, notify, desc, maint \
|
||||||
|
= my_packages[i].xpath('./td')
|
||||||
|
assert name.xpath('./a').pop(0).text.strip() == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_homepage_dashboard_requests(redis, packages, user):
|
||||||
|
now = int(datetime.utcnow().timestamp())
|
||||||
|
|
||||||
|
pkg = packages[0]
|
||||||
|
reqtype = db.query(RequestType, RequestType.ID == DELETION_ID).first()
|
||||||
|
pkgreq = db.create(PackageRequest, PackageBase=pkg.PackageBase,
|
||||||
|
PackageBaseName=pkg.PackageBase.Name,
|
||||||
|
User=user, Comments=str(),
|
||||||
|
ClosureComment=str(), RequestTS=now,
|
||||||
|
RequestType=reqtype)
|
||||||
|
|
||||||
|
cookies = {"AURSID": user.login(Request(), "testPassword")}
|
||||||
|
with client as request:
|
||||||
|
response = request.get("/", cookies=cookies)
|
||||||
|
assert response.status_code == int(HTTPStatus.OK)
|
||||||
|
|
||||||
|
root = parse_root(response.text)
|
||||||
|
request = root.xpath('//table[@id="pkgreq-results"]/tbody/tr').pop(0)
|
||||||
|
pkgname = request.xpath('./td/a').pop(0)
|
||||||
|
assert pkgname.text.strip() == pkgreq.PackageBaseName
|
||||||
|
|
||||||
|
|
||||||
|
def test_homepage_dashboard_flagged_packages(redis, packages, user):
|
||||||
|
# Set the first Package flagged by setting its OutOfDateTS column.
|
||||||
|
pkg = packages[0]
|
||||||
|
pkg.PackageBase.OutOfDateTS = int(datetime.utcnow().timestamp())
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
cookies = {"AURSID": user.login(Request(), "testPassword")}
|
||||||
|
with client as request:
|
||||||
|
response = request.get("/", cookies=cookies)
|
||||||
|
assert response.status_code == int(HTTPStatus.OK)
|
||||||
|
|
||||||
|
# Check to see that the package showed up in the Flagged Packages table.
|
||||||
|
root = parse_root(response.text)
|
||||||
|
flagged_pkg = root.xpath('//table[@id="flagged-packages"]/tbody/tr').pop(0)
|
||||||
|
flagged_name = flagged_pkg.xpath('./td/a').pop(0)
|
||||||
|
assert flagged_name.text.strip() == pkg.Name
|
||||||
|
|
Loading…
Add table
Reference in a new issue