mirror of
https://gitlab.archlinux.org/archlinux/aurweb.git
synced 2025-02-03 10:43:03 +01:00
Merge branch 'master' into live
This commit is contained in:
commit
02149f34cf
11 changed files with 111 additions and 40 deletions
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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_
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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'),
|
||||||
|
|
37
migrations/versions/d64e5571bc8d_fix_pkgvote_votets.py
Normal file
37
migrations/versions/d64e5571bc8d_fix_pkgvote_votets.py
Normal 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)
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
@ -203,7 +205,7 @@ for u in user_keys:
|
||||||
|
|
||||||
log.debug("Number of developers: %d" % len(developers))
|
log.debug("Number of developers: %d" % len(developers))
|
||||||
log.debug("Number of trusted users: %d" % len(trustedusers))
|
log.debug("Number of trusted users: %d" % len(trustedusers))
|
||||||
log.debug("Number of users: %d" % (MAX_USERS-len(developers)-len(trustedusers)))
|
log.debug("Number of users: %d" % (MAX_USERS - len(developers) - len(trustedusers)))
|
||||||
log.debug("Number of packages: %d" % MAX_PKGS)
|
log.debug("Number of packages: %d" % MAX_PKGS)
|
||||||
|
|
||||||
log.debug("Gathering text from fortune file...")
|
log.debug("Gathering text from fortune file...")
|
||||||
|
@ -244,26 +246,27 @@ for p in list(seen_pkgs.keys()):
|
||||||
#
|
#
|
||||||
num_comments = random.randrange(PKG_CMNTS[0], PKG_CMNTS[1])
|
num_comments = random.randrange(PKG_CMNTS[0], PKG_CMNTS[1])
|
||||||
for i in range(0, num_comments):
|
for i in range(0, num_comments):
|
||||||
now = NOW + random.randrange(400, 86400*3)
|
now = NOW + random.randrange(400, 86400 * 3)
|
||||||
s = ("INSERT INTO PackageComments (PackageBaseID, UsersID,"
|
s = ("INSERT INTO PackageComments (PackageBaseID, UsersID,"
|
||||||
" Comments, RenderedComment, CommentTS) VALUES (%d, %d, '%s', '', %d);\n")
|
" Comments, RenderedComment, CommentTS) VALUES (%d, %d, '%s', '', %d);\n")
|
||||||
s = s % (seen_pkgs[p], genUID(), genFortune(), now)
|
s = s % (seen_pkgs[p], genUID(), genFortune(), now)
|
||||||
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:
|
||||||
num_votes = random.randrange(int(len(seen_pkgs)*VOTING[0]),
|
num_votes = random.randrange(int(len(seen_pkgs) * VOTING[0]),
|
||||||
int(len(seen_pkgs)*VOTING[1]))
|
int(len(seen_pkgs) * VOTING[1]))
|
||||||
pkgvote = {}
|
pkgvote = {}
|
||||||
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
|
||||||
|
@ -318,14 +321,14 @@ for p in seen_pkgs_keys:
|
||||||
#
|
#
|
||||||
log.debug("Creating SQL statements for trusted user proposals.")
|
log.debug("Creating SQL statements for trusted user proposals.")
|
||||||
count = 0
|
count = 0
|
||||||
for t in range(0, OPEN_PROPOSALS+CLOSE_PROPOSALS):
|
for t in range(0, OPEN_PROPOSALS + CLOSE_PROPOSALS):
|
||||||
now = int(time.time())
|
now = int(time.time())
|
||||||
if count < CLOSE_PROPOSALS:
|
if count < CLOSE_PROPOSALS:
|
||||||
start = now - random.randrange(3600*24*7, 3600*24*21)
|
start = now - random.randrange(3600 * 24 * 7, 3600 * 24 * 21)
|
||||||
end = now - random.randrange(0, 3600*24*7)
|
end = now - random.randrange(0, 3600 * 24 * 7)
|
||||||
else:
|
else:
|
||||||
start = now
|
start = now
|
||||||
end = now + random.randrange(3600*24, 3600*24*7)
|
end = now + random.randrange(3600 * 24, 3600 * 24 * 7)
|
||||||
if count % 5 == 0: # Don't make the vote about anyone once in a while
|
if count % 5 == 0: # Don't make the vote about anyone once in a while
|
||||||
user = ""
|
user = ""
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Add table
Reference in a new issue