routers.html: add authenticated dashboard to homepage

Signed-off-by: Kevin Morris <kevr@0cost.org>
This commit is contained in:
Kevin Morris 2021-08-09 23:43:48 -07:00
parent af51b5c460
commit 5a175bd92a
No known key found for this signature in database
GPG key ID: F7E46DED420788F3
6 changed files with 269 additions and 2 deletions

View file

@ -9,11 +9,15 @@ from fastapi.responses import HTMLResponse, RedirectResponse
from sqlalchemy import and_, or_
import aurweb.config
import aurweb.models.package_request
from aurweb import db, util
from aurweb.cache import db_count_cache
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_comaintainer import PackageComaintainer
from aurweb.models.package_request import PackageRequest
from aurweb.models.user import User
from aurweb.packages.util import updated_packages
from aurweb.templates import make_context, render_template
@ -132,6 +136,41 @@ async def index(request: Request):
# Get the 15 most recently updated packages.
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)

54
templates/dashboard.html Normal file
View 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>

View file

@ -3,7 +3,11 @@
{% block pageContent %}
<div id="content-left-wrapper">
<div id="content-left">
{% include 'home.html' %}
{% if request.user.is_authenticated() %}
{% include 'dashboard.html' %}
{% else %}
{% include 'home.html' %}
{% endif %}
</div>
</div>
<div id="content-right">

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

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

View file

@ -13,10 +13,14 @@ from aurweb.asgi import app
from aurweb.models.account_type import USER_ID
from aurweb.models.package import Package
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.redis import redis_connection
from aurweb.testing import setup_test_db
from aurweb.testing.html import parse_root
from aurweb.testing.requests import Request
client = TestClient(app)
@ -26,7 +30,9 @@ def setup():
yield setup_test_db(
User.__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):
pkgname = updates[i].xpath('./td/a').pop(0)
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