mirror of
https://gitlab.archlinux.org/archlinux/aurweb.git
synced 2025-02-03 10:43:03 +01:00
feat: allow users to hide deleted comments
Closes: #435 Signed-off-by: Leonidas Spyropoulos <artafinde@archlinux.org>
This commit is contained in:
parent
174af5f025
commit
6ede837b4f
9 changed files with 132 additions and 5 deletions
|
@ -209,6 +209,7 @@ def make_account_form_context(
|
||||||
context["cn"] = args.get("CN", user.CommentNotify)
|
context["cn"] = args.get("CN", user.CommentNotify)
|
||||||
context["un"] = args.get("UN", user.UpdateNotify)
|
context["un"] = args.get("UN", user.UpdateNotify)
|
||||||
context["on"] = args.get("ON", user.OwnershipNotify)
|
context["on"] = args.get("ON", user.OwnershipNotify)
|
||||||
|
context["hdc"] = args.get("HDC", user.HideDeletedComments)
|
||||||
context["inactive"] = args.get("J", user.InactivityTS != 0)
|
context["inactive"] = args.get("J", user.InactivityTS != 0)
|
||||||
else:
|
else:
|
||||||
context["username"] = args.get("U", str())
|
context["username"] = args.get("U", str())
|
||||||
|
@ -227,6 +228,7 @@ def make_account_form_context(
|
||||||
context["cn"] = args.get("CN", True)
|
context["cn"] = args.get("CN", True)
|
||||||
context["un"] = args.get("UN", False)
|
context["un"] = args.get("UN", False)
|
||||||
context["on"] = args.get("ON", True)
|
context["on"] = args.get("ON", True)
|
||||||
|
context["hdc"] = args.get("HDC", False)
|
||||||
context["inactive"] = args.get("J", False)
|
context["inactive"] = args.get("J", False)
|
||||||
|
|
||||||
context["password"] = args.get("P", str())
|
context["password"] = args.get("P", str())
|
||||||
|
@ -253,6 +255,7 @@ async def account_register(
|
||||||
CN: bool = Form(default=False), # Comment Notify
|
CN: bool = Form(default=False), # Comment Notify
|
||||||
CU: bool = Form(default=False), # Update Notify
|
CU: bool = Form(default=False), # Update Notify
|
||||||
CO: bool = Form(default=False), # Owner Notify
|
CO: bool = Form(default=False), # Owner Notify
|
||||||
|
HDC: bool = Form(default=False), # Hide Deleted Comments
|
||||||
captcha: str = Form(default=str()),
|
captcha: str = Form(default=str()),
|
||||||
):
|
):
|
||||||
context = await make_variable_context(request, "Register")
|
context = await make_variable_context(request, "Register")
|
||||||
|
@ -281,6 +284,7 @@ async def account_register_post(
|
||||||
CN: bool = Form(default=False),
|
CN: bool = Form(default=False),
|
||||||
UN: bool = Form(default=False),
|
UN: bool = Form(default=False),
|
||||||
ON: bool = Form(default=False),
|
ON: bool = Form(default=False),
|
||||||
|
HDC: bool = Form(default=False),
|
||||||
captcha: str = Form(default=None),
|
captcha: str = Form(default=None),
|
||||||
captcha_salt: str = Form(...),
|
captcha_salt: str = Form(...),
|
||||||
):
|
):
|
||||||
|
@ -334,6 +338,7 @@ async def account_register_post(
|
||||||
CommentNotify=CN,
|
CommentNotify=CN,
|
||||||
UpdateNotify=UN,
|
UpdateNotify=UN,
|
||||||
OwnershipNotify=ON,
|
OwnershipNotify=ON,
|
||||||
|
HideDeletedComments=HDC,
|
||||||
ResetKey=resetkey,
|
ResetKey=resetkey,
|
||||||
AccountType=atype,
|
AccountType=atype,
|
||||||
)
|
)
|
||||||
|
@ -417,6 +422,7 @@ async def account_edit_post(
|
||||||
CN: bool = Form(default=False), # Comment Notify
|
CN: bool = Form(default=False), # Comment Notify
|
||||||
UN: bool = Form(default=False), # Update Notify
|
UN: bool = Form(default=False), # Update Notify
|
||||||
ON: bool = Form(default=False), # Owner Notify
|
ON: bool = Form(default=False), # Owner Notify
|
||||||
|
HDC: bool = Form(default=False), # Hide Deleted Comments
|
||||||
T: int = Form(default=None),
|
T: int = Form(default=None),
|
||||||
passwd: str = Form(default=str()),
|
passwd: str = Form(default=str()),
|
||||||
):
|
):
|
||||||
|
|
|
@ -108,6 +108,12 @@ Users = Table(
|
||||||
Column("OwnershipNotify", TINYINT(1), nullable=False, server_default=text("1")),
|
Column("OwnershipNotify", TINYINT(1), nullable=False, server_default=text("1")),
|
||||||
Column("SSOAccountID", String(255), nullable=True, unique=True),
|
Column("SSOAccountID", String(255), nullable=True, unique=True),
|
||||||
Index("UsersAccountTypeID", "AccountTypeID"),
|
Index("UsersAccountTypeID", "AccountTypeID"),
|
||||||
|
Column(
|
||||||
|
"HideDeletedComments",
|
||||||
|
TINYINT(unsigned=True),
|
||||||
|
nullable=False,
|
||||||
|
server_default=text("0"),
|
||||||
|
),
|
||||||
mysql_engine="InnoDB",
|
mysql_engine="InnoDB",
|
||||||
mysql_charset="utf8mb4",
|
mysql_charset="utf8mb4",
|
||||||
mysql_collate="utf8mb4_general_ci",
|
mysql_collate="utf8mb4_general_ci",
|
||||||
|
|
|
@ -22,6 +22,7 @@ def simple(
|
||||||
CN: bool = False,
|
CN: bool = False,
|
||||||
UN: bool = False,
|
UN: bool = False,
|
||||||
ON: bool = False,
|
ON: bool = False,
|
||||||
|
HDC: bool = False,
|
||||||
S: bool = False,
|
S: bool = False,
|
||||||
user: models.User = None,
|
user: models.User = None,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
|
@ -41,6 +42,7 @@ def simple(
|
||||||
user.CommentNotify = strtobool(CN)
|
user.CommentNotify = strtobool(CN)
|
||||||
user.UpdateNotify = strtobool(UN)
|
user.UpdateNotify = strtobool(UN)
|
||||||
user.OwnershipNotify = strtobool(ON)
|
user.OwnershipNotify = strtobool(ON)
|
||||||
|
user.HideDeletedComments = strtobool(HDC)
|
||||||
|
|
||||||
|
|
||||||
@db.retry_deadlock
|
@db.retry_deadlock
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
"""Add HideDeletedComments to User
|
||||||
|
|
||||||
|
Revision ID: e4e49ffce091
|
||||||
|
Revises: 9e3158957fd7
|
||||||
|
Create Date: 2023-04-19 23:24:25.854874
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
from sqlalchemy.exc import OperationalError
|
||||||
|
|
||||||
|
from aurweb.models.user import User
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = "e4e49ffce091"
|
||||||
|
down_revision = "9e3158957fd7"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
table = User.__table__
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
try:
|
||||||
|
op.add_column(table.name, table.c.HideDeletedComments)
|
||||||
|
except OperationalError:
|
||||||
|
print(
|
||||||
|
f"Column HideDeletedComments already exists in '{table.name}',"
|
||||||
|
f" skipping migration."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.drop_column(table.name, "HideDeletedComments")
|
|
@ -1402,6 +1402,10 @@ msgstr ""
|
||||||
msgid "Specify multiple SSH Keys separated by new line, empty lines are ignored."
|
msgid "Specify multiple SSH Keys separated by new line, empty lines are ignored."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/partials/account_form.html
|
||||||
|
msgid "Hide deleted comments"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: template/account_edit_form.php
|
#: template/account_edit_form.php
|
||||||
msgid "SSH Public Key"
|
msgid "SSH Public Key"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if not comment.Deleter or request.user.has_credential(creds.COMMENT_VIEW_DELETED, approved=[comment.Deleter]) %}
|
{% if not comment.Deleter or request.user.has_credential(creds.COMMENT_VIEW_DELETED, approved=[comment.Deleter]) %}
|
||||||
|
{% if not (request.user.HideDeletedComments and comment.DelTS) %}
|
||||||
{% set commented_at = comment.CommentTS | dt | as_timezone(timezone) %}
|
{% set commented_at = comment.CommentTS | dt | as_timezone(timezone) %}
|
||||||
<h4 id="comment-{{ comment.ID }}" class="{{ header_cls }}">
|
<h4 id="comment-{{ comment.ID }}" class="{{ header_cls }}">
|
||||||
{{
|
{{
|
||||||
|
@ -38,3 +38,4 @@
|
||||||
|
|
||||||
{% include "partials/comment_content.html" %}
|
{% include "partials/comment_content.html" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
|
@ -182,7 +182,7 @@
|
||||||
maxlength="50" name="K" value="{{ pgp }}">
|
maxlength="50" name="K" value="{{ pgp }}">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- Homepage -->
|
<!-- Language -->
|
||||||
<p>
|
<p>
|
||||||
<label for="id_language">
|
<label for="id_language">
|
||||||
{% trans %}Language{% endtrans %}:
|
{% trans %}Language{% endtrans %}:
|
||||||
|
@ -202,10 +202,10 @@
|
||||||
</select>
|
</select>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- Homepage -->
|
<!-- Timezone -->
|
||||||
<p>
|
<p>
|
||||||
<label for="id_timezone">
|
<label for="id_timezone">
|
||||||
{% trans %}Timezone{% endtrans %}
|
{% trans %}Timezone{% endtrans %}:
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<select id="id_timezone" name="TZ">
|
<select id="id_timezone" name="TZ">
|
||||||
|
@ -219,6 +219,19 @@
|
||||||
</select>
|
</select>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<!-- Hide Deleted Comments -->
|
||||||
|
<p>
|
||||||
|
<label for="id_hidedeletedcomments">
|
||||||
|
{% trans %}Hide deleted comments{% endtrans %}:
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<input id="id_hidedeletedcomments" type="checkbox" name="HDC"
|
||||||
|
{% if hdc %}
|
||||||
|
checked="checked"
|
||||||
|
{% endif %}
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
{% if form_type == "UpdateAccount" %}
|
{% if form_type == "UpdateAccount" %}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if not comment.Deleter or request.user.has_credential(creds.COMMENT_VIEW_DELETED, approved=[comment.Deleter]) %}
|
{% if not comment.Deleter or request.user.has_credential(creds.COMMENT_VIEW_DELETED, approved=[comment.Deleter]) %}
|
||||||
|
{% if not (request.user.HideDeletedComments and comment.DelTS) %}
|
||||||
<h4 id="comment-{{ comment.ID }}" class="{{ header_cls }}">
|
<h4 id="comment-{{ comment.ID }}" class="{{ header_cls }}">
|
||||||
{% set commented_at = comment.CommentTS | dt | as_timezone(timezone) %}
|
{% set commented_at = comment.CommentTS | dt | as_timezone(timezone) %}
|
||||||
{% set view_account_info = 'View account information for %s' | tr | format(comment.User.Username) %}
|
{% set view_account_info = 'View account information for %s' | tr | format(comment.User.Username) %}
|
||||||
|
@ -41,3 +42,4 @@
|
||||||
|
|
||||||
{% include "partials/comment_content.html" %}
|
{% include "partials/comment_content.html" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
|
@ -122,6 +122,22 @@ def tu_user():
|
||||||
yield tu_user
|
yield tu_user
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def user_who_hates_grey_comments() -> User:
|
||||||
|
"""Yield a specific User who doesn't like grey comments."""
|
||||||
|
account_type = db.query(AccountType, AccountType.ID == USER_ID).first()
|
||||||
|
with db.begin():
|
||||||
|
user_who_hates_grey_comments = db.create(
|
||||||
|
User,
|
||||||
|
Username="test_hater",
|
||||||
|
Email="test_hater@example.org",
|
||||||
|
Passwd="testPassword",
|
||||||
|
AccountType=account_type,
|
||||||
|
HideDeletedComments=True,
|
||||||
|
)
|
||||||
|
yield user_who_hates_grey_comments
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def package(maintainer: User) -> Package:
|
def package(maintainer: User) -> Package:
|
||||||
"""Yield a Package created by user."""
|
"""Yield a Package created by user."""
|
||||||
|
@ -193,6 +209,23 @@ def comment(user: User, package: Package) -> PackageComment:
|
||||||
yield comment
|
yield comment
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def deleted_comment(user: User, package: Package) -> PackageComment:
|
||||||
|
pkgbase = package.PackageBase
|
||||||
|
now = time.utcnow()
|
||||||
|
with db.begin():
|
||||||
|
comment = db.create(
|
||||||
|
PackageComment,
|
||||||
|
User=user,
|
||||||
|
PackageBase=pkgbase,
|
||||||
|
Comments="Test comment.",
|
||||||
|
RenderedComment=str(),
|
||||||
|
CommentTS=now,
|
||||||
|
DelTS=now,
|
||||||
|
)
|
||||||
|
yield comment
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def packages(maintainer: User) -> list[Package]:
|
def packages(maintainer: User) -> list[Package]:
|
||||||
"""Yield 55 packages named pkg_0 .. pkg_54."""
|
"""Yield 55 packages named pkg_0 .. pkg_54."""
|
||||||
|
@ -409,7 +442,9 @@ def test_paged_depends_required(client: TestClient, package: Package):
|
||||||
assert "Show 6 more" not in resp.text
|
assert "Show 6 more" not in resp.text
|
||||||
|
|
||||||
|
|
||||||
def test_package_comments(client: TestClient, user: User, package: Package):
|
def test_package_comments(
|
||||||
|
client: TestClient, user: User, user_who_hates_grey_comments: User, package: Package
|
||||||
|
):
|
||||||
now = time.utcnow()
|
now = time.utcnow()
|
||||||
with db.begin():
|
with db.begin():
|
||||||
comment = db.create(
|
comment = db.create(
|
||||||
|
@ -419,6 +454,14 @@ def test_package_comments(client: TestClient, user: User, package: Package):
|
||||||
Comments="Test comment",
|
Comments="Test comment",
|
||||||
CommentTS=now,
|
CommentTS=now,
|
||||||
)
|
)
|
||||||
|
deleted_comment = db.create(
|
||||||
|
PackageComment,
|
||||||
|
PackageBase=package.PackageBase,
|
||||||
|
User=user,
|
||||||
|
Comments="Deleted Test comment",
|
||||||
|
CommentTS=now,
|
||||||
|
DelTS=now - 1,
|
||||||
|
)
|
||||||
|
|
||||||
cookies = {"AURSID": user.login(Request(), "testPassword")}
|
cookies = {"AURSID": user.login(Request(), "testPassword")}
|
||||||
with client as request:
|
with client as request:
|
||||||
|
@ -426,12 +469,29 @@ def test_package_comments(client: TestClient, user: User, package: Package):
|
||||||
resp = request.get(package_endpoint(package))
|
resp = request.get(package_endpoint(package))
|
||||||
assert resp.status_code == int(HTTPStatus.OK)
|
assert resp.status_code == int(HTTPStatus.OK)
|
||||||
|
|
||||||
|
root = parse_root(resp.text)
|
||||||
|
expected = [comment.Comments, deleted_comment.Comments]
|
||||||
|
comments = root.xpath(
|
||||||
|
'.//div[contains(@class, "package-comments")]'
|
||||||
|
'/div[@class="article-content"]/div/text()'
|
||||||
|
)
|
||||||
|
assert len(comments) == 2
|
||||||
|
for i, row in enumerate(expected):
|
||||||
|
assert comments[i].strip() == row
|
||||||
|
|
||||||
|
cookies = {"AURSID": user_who_hates_grey_comments.login(Request(), "testPassword")}
|
||||||
|
with client as request:
|
||||||
|
request.cookies = cookies
|
||||||
|
resp = request.get(package_endpoint(package))
|
||||||
|
assert resp.status_code == int(HTTPStatus.OK)
|
||||||
|
|
||||||
root = parse_root(resp.text)
|
root = parse_root(resp.text)
|
||||||
expected = [comment.Comments]
|
expected = [comment.Comments]
|
||||||
comments = root.xpath(
|
comments = root.xpath(
|
||||||
'.//div[contains(@class, "package-comments")]'
|
'.//div[contains(@class, "package-comments")]'
|
||||||
'/div[@class="article-content"]/div/text()'
|
'/div[@class="article-content"]/div/text()'
|
||||||
)
|
)
|
||||||
|
assert len(comments) == 1 # Deleted comment is hidden
|
||||||
for i, row in enumerate(expected):
|
for i, row in enumerate(expected):
|
||||||
assert comments[i].strip() == row
|
assert comments[i].strip() == row
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue