Merge branch 'master' into live

This commit is contained in:
Kevin Morris 2022-02-18 17:55:49 -08:00
commit 02149f34cf
No known key found for this signature in database
GPG key ID: F7E46DED420788F3
11 changed files with 111 additions and 40 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.15" AURWEB_VERSION = "v6.0.17"
_parser = None _parser = None

View file

@ -135,6 +135,10 @@ class User(Base):
if last_updated and last_updated < now_ts: if last_updated and last_updated < now_ts:
self.session.SessionID = generate_unique_sid() self.session.SessionID = generate_unique_sid()
self.session.LastUpdateTS = now_ts self.session.LastUpdateTS = now_ts
# Unset InactivityTS, we've logged in!
self.InactivityTS = 0
break break
except IntegrityError as exc_: except IntegrityError as exc_:
exc = exc_ exc = exc_

View file

@ -124,6 +124,7 @@ class PackageSearch:
def _search_by_keywords(self, keywords: Set[str]) -> orm.Query: def _search_by_keywords(self, keywords: Set[str]) -> orm.Query:
self._join_user() self._join_user()
self._join_keywords() self._join_keywords()
keywords = set(k.lower() for k in keywords)
self.query = self.query.filter(PackageKeyword.Keyword.in_(keywords)) self.query = self.query.filter(PackageKeyword.Keyword.in_(keywords))
return self return self

View file

@ -138,6 +138,7 @@ def updated_packages(limit: int = 0,
# If we already have a cache, deserialize it and return. # If we already have a cache, deserialize it and return.
return orjson.loads(packages) return orjson.loads(packages)
with db.begin():
query = db.query(models.Package).join(models.PackageBase).filter( query = db.query(models.Package).join(models.PackageBase).filter(
models.PackageBase.PackagerUID.isnot(None) models.PackageBase.PackagerUID.isnot(None)
).order_by( ).order_by(
@ -151,7 +152,6 @@ def updated_packages(limit: int = 0,
for pkg in query: for pkg in query:
# For each Package returned by the query, append a dict # For each Package returned by the query, append a dict
# containing Package columns we're interested in. # containing Package columns we're interested in.
db.refresh(pkg)
packages.append({ packages.append({
"Name": pkg.Name, "Name": pkg.Name,
"Version": pkg.Version, "Version": pkg.Version,

View file

@ -46,13 +46,19 @@ async def login_post(request: Request,
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, raise HTTPException(status_code=HTTPStatus.BAD_REQUEST,
detail=_("Bad Referer header.")) detail=_("Bad Referer header."))
with db.begin():
user = db.query(User).filter( user = db.query(User).filter(
or_(User.Username == user, User.Email == user) or_(User.Username == user, User.Email == user)
).first() ).first()
if not user: if not user:
return await login_template(request, next, return await login_template(request, next,
errors=["Bad username or password."]) errors=["Bad username or password."])
if user.Suspended:
return await login_template(request, next,
errors=["Account Suspended"])
cookie_timeout = cookies.timeout(remember_me) cookie_timeout = cookies.timeout(remember_me)
sid = user.login(request, passwd, cookie_timeout) sid = user.login(request, passwd, cookie_timeout)
if not sid: if not sid:

View file

@ -95,24 +95,28 @@ async def pkgbase_flag_comment(request: Request, name: str):
async def pkgbase_keywords(request: Request, name: str, async def pkgbase_keywords(request: Request, name: str,
keywords: str = Form(default=str())): keywords: str = Form(default=str())):
pkgbase = get_pkg_or_base(name, PackageBase) pkgbase = get_pkg_or_base(name, PackageBase)
keywords = set(keywords.split(" "))
# Lowercase all keywords. Our database table is case insensitive,
# and providing CI duplicates of keywords is erroneous.
keywords = set(k.lower() for k in keywords.split(" "))
# Delete all keywords which are not supplied by the user. # Delete all keywords which are not supplied by the user.
with db.begin():
other_keywords = pkgbase.keywords.filter( other_keywords = pkgbase.keywords.filter(
~PackageKeyword.Keyword.in_(keywords)) ~PackageKeyword.Keyword.in_(keywords))
other_keyword_strings = [kwd.Keyword for kwd in other_keywords] other_keyword_strings = set(
kwd.Keyword.lower() for kwd in other_keywords)
existing_keywords = set( existing_keywords = set(
kwd.Keyword for kwd in kwd.Keyword.lower() for kwd in
pkgbase.keywords.filter( pkgbase.keywords.filter(
~PackageKeyword.Keyword.in_(other_keyword_strings)) ~PackageKeyword.Keyword.in_(other_keyword_strings))
) )
with db.begin():
db.delete_all(other_keywords) db.delete_all(other_keywords)
for keyword in keywords.difference(existing_keywords): new_keywords = keywords.difference(existing_keywords)
db.create(PackageKeyword, for keyword in new_keywords:
PackageBase=pkgbase, db.create(PackageKeyword, PackageBase=pkgbase, Keyword=keyword)
Keyword=keyword)
return RedirectResponse(f"/pkgbase/{name}", return RedirectResponse(f"/pkgbase/{name}",
status_code=HTTPStatus.SEE_OTHER) status_code=HTTPStatus.SEE_OTHER)

View file

@ -269,7 +269,7 @@ PackageVotes = Table(
'PackageVotes', metadata, 'PackageVotes', metadata,
Column('UsersID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False), Column('UsersID', ForeignKey('Users.ID', ondelete='CASCADE'), nullable=False),
Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), nullable=False), Column('PackageBaseID', ForeignKey('PackageBases.ID', ondelete='CASCADE'), nullable=False),
Column('VoteTS', BIGINT(unsigned=True)), Column('VoteTS', BIGINT(unsigned=True), nullable=False),
Index('VoteUsersIDPackageID', 'UsersID', 'PackageBaseID', unique=True), Index('VoteUsersIDPackageID', 'UsersID', 'PackageBaseID', unique=True),
Index('VotesPackageBaseID', 'PackageBaseID'), Index('VotesPackageBaseID', 'PackageBaseID'),
Index('VotesUsersID', 'UsersID'), Index('VotesUsersID', 'UsersID'),

View file

@ -0,0 +1,37 @@
"""fix pkgvote votets
Revision ID: d64e5571bc8d
Revises: be7adae47ac3
Create Date: 2022-02-18 12:47:05.322766
"""
from datetime import datetime
import sqlalchemy as sa
from alembic import op
from aurweb import db
from aurweb.models import PackageVote
# revision identifiers, used by Alembic.
revision = 'd64e5571bc8d'
down_revision = 'be7adae47ac3'
branch_labels = None
depends_on = None
table = PackageVote.__tablename__
column = 'VoteTS'
epoch = datetime(1970, 1, 1)
def upgrade():
with db.begin():
records = db.query(PackageVote).filter(PackageVote.VoteTS.is_(None))
for record in records:
record.VoteTS = epoch.timestamp()
op.alter_column(table, column, existing_type=sa.BIGINT(), nullable=False)
def downgrade():
op.alter_column(table, column, existing_type=sa.BIGINT(), nullable=True)

View file

@ -8,7 +8,7 @@
# #
[tool.poetry] [tool.poetry]
name = "aurweb" name = "aurweb"
version = "v6.0.15" version = "v6.0.17"
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

@ -16,6 +16,8 @@ import random
import sys import sys
import time import time
from datetime import datetime
import bcrypt import bcrypt
LOG_LEVEL = logging.DEBUG # logging level. set to logging.INFO to reduce output LOG_LEVEL = logging.DEBUG # logging level. set to logging.INFO to reduce output
@ -251,7 +253,8 @@ for p in list(seen_pkgs.keys()):
out.write(s) out.write(s)
# Cast votes # Cast votes
# utcnow = int(datetime.utcnow().timestamp())
track_votes = {} track_votes = {}
log.debug("Casting votes for packages.") log.debug("Casting votes for packages.")
for u in user_keys: for u in user_keys:
@ -261,9 +264,9 @@ for u in user_keys:
for v in range(num_votes): for v in range(num_votes):
pkg = random.randrange(1, len(seen_pkgs) + 1) pkg = random.randrange(1, len(seen_pkgs) + 1)
if pkg not in pkgvote: if pkg not in pkgvote:
s = ("INSERT INTO PackageVotes (UsersID, PackageBaseID)" s = ("INSERT INTO PackageVotes (UsersID, PackageBaseID, VoteTS)"
" VALUES (%d, %d);\n") " VALUES (%d, %d, %d);\n")
s = s % (seen_users[u], pkg) s = s % (seen_users[u], pkg, utcnow)
pkgvote[pkg] = 1 pkgvote[pkg] = 1
if pkg not in track_votes: if pkg not in track_votes:
track_votes[pkg] = 0 track_votes[pkg] = 0

View file

@ -14,6 +14,7 @@ from aurweb.asgi import app
from aurweb.models.account_type import USER_ID from aurweb.models.account_type import USER_ID
from aurweb.models.session import Session from aurweb.models.session import Session
from aurweb.models.user import User from aurweb.models.user import User
from aurweb.testing.html import get_errors
# Some test global constants. # Some test global constants.
TEST_USERNAME = "test" TEST_USERNAME = "test"
@ -79,6 +80,21 @@ def test_login_logout(client: TestClient, user: User):
assert "AURSID" not in response.cookies assert "AURSID" not in response.cookies
def test_login_suspended(client: TestClient, user: User):
with db.begin():
user.Suspended = 1
data = {
"user": user.Username,
"passwd": "testPassword",
"next": "/"
}
with client as request:
resp = request.post("/login", data=data)
errors = get_errors(resp.text)
assert errors[0].text.strip() == "Account Suspended"
def test_login_email(client: TestClient, user: user): def test_login_email(client: TestClient, user: user):
post_data = { post_data = {
"user": user.Email, "user": user.Email,