mirror of
https://gitlab.archlinux.org/archlinux/aurweb.git
synced 2025-02-03 10:43:03 +01:00
feat: Limit comment length
Limit the amount of characters that can be entered for a comment. Signed-off-by: moson <moson@archlinux.org>
This commit is contained in:
parent
d050b626db
commit
21a23c9abe
14 changed files with 128 additions and 14 deletions
|
@ -1,6 +1,9 @@
|
|||
from http import HTTPStatus
|
||||
from typing import Any
|
||||
|
||||
from aurweb import db
|
||||
from fastapi import HTTPException
|
||||
|
||||
from aurweb import config, db
|
||||
from aurweb.exceptions import ValidationError
|
||||
from aurweb.models import PackageBase
|
||||
|
||||
|
@ -12,8 +15,8 @@ def request(
|
|||
merge_into: str,
|
||||
context: dict[str, Any],
|
||||
) -> None:
|
||||
if not comments:
|
||||
raise ValidationError(["The comment field must not be empty."])
|
||||
# validate comment
|
||||
comment(comments)
|
||||
|
||||
if type == "merge":
|
||||
# Perform merge-related checks.
|
||||
|
@ -32,3 +35,21 @@ def request(
|
|||
if target.ID == pkgbase.ID:
|
||||
# TODO: This error needs to be translated.
|
||||
raise ValidationError(["You cannot merge a package base into itself."])
|
||||
|
||||
|
||||
def comment(comment: str):
|
||||
if not comment:
|
||||
raise ValidationError(["The comment field must not be empty."])
|
||||
|
||||
if len(comment) > config.getint("options", "max_chars_comment", 5000):
|
||||
raise ValidationError(["Maximum number of characters for comment exceeded."])
|
||||
|
||||
|
||||
def comment_raise_http_ex(comments: str):
|
||||
try:
|
||||
comment(comments)
|
||||
except ValidationError as err:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST,
|
||||
detail=err.data[0],
|
||||
)
|
||||
|
|
|
@ -159,6 +159,8 @@ async def pkgbase_flag_post(
|
|||
request, "pkgbase/flag.html", context, status_code=HTTPStatus.BAD_REQUEST
|
||||
)
|
||||
|
||||
validate.comment_raise_http_ex(comments)
|
||||
|
||||
has_cred = request.user.has_credential(creds.PKGBASE_FLAG)
|
||||
if has_cred and not pkgbase.OutOfDateTS:
|
||||
now = time.utcnow()
|
||||
|
@ -185,8 +187,7 @@ async def pkgbase_comments_post(
|
|||
"""Add a new comment via POST request."""
|
||||
pkgbase = get_pkg_or_base(name, PackageBase)
|
||||
|
||||
if not comment:
|
||||
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST)
|
||||
validate.comment_raise_http_ex(comment)
|
||||
|
||||
# If the provided comment is different than the record's version,
|
||||
# update the db record.
|
||||
|
@ -304,9 +305,9 @@ async def pkgbase_comment_post(
|
|||
pkgbase = get_pkg_or_base(name, PackageBase)
|
||||
db_comment = get_pkgbase_comment(pkgbase, id)
|
||||
|
||||
if not comment:
|
||||
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST)
|
||||
elif request.user.ID != db_comment.UsersID:
|
||||
validate.comment_raise_http_ex(comment)
|
||||
|
||||
if request.user.ID != db_comment.UsersID:
|
||||
raise HTTPException(status_code=HTTPStatus.UNAUTHORIZED)
|
||||
|
||||
# If the provided comment is different than the record's version,
|
||||
|
@ -602,6 +603,9 @@ async def pkgbase_disown_post(
|
|||
):
|
||||
pkgbase = get_pkg_or_base(name, PackageBase)
|
||||
|
||||
if comments:
|
||||
validate.comment_raise_http_ex(comments)
|
||||
|
||||
comaints = {c.User for c in pkgbase.comaintainers}
|
||||
approved = [pkgbase.Maintainer] + list(comaints)
|
||||
has_cred = request.user.has_credential(creds.PKGBASE_DISOWN, approved=approved)
|
||||
|
@ -873,6 +877,7 @@ async def pkgbase_delete_post(
|
|||
)
|
||||
|
||||
if comments:
|
||||
validate.comment_raise_http_ex(comments)
|
||||
# Update any existing deletion requests' ClosureComment.
|
||||
with db.begin():
|
||||
requests = pkgbase.requests.filter(
|
||||
|
@ -966,6 +971,9 @@ async def pkgbase_merge_post(
|
|||
request, "pkgbase/merge.html", context, status_code=HTTPStatus.BAD_REQUEST
|
||||
)
|
||||
|
||||
if comments:
|
||||
validate.comment_raise_http_ex(comments)
|
||||
|
||||
with db.begin():
|
||||
update_closure_comment(pkgbase, MERGE_ID, comments, target=target)
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ def make_context(request: Request, title: str, next: str = None):
|
|||
|
||||
commit_url = aurweb.config.get_with_fallback("devel", "commit_url", None)
|
||||
commit_hash = aurweb.config.get_with_fallback("devel", "commit_hash", None)
|
||||
max_chars_comment = aurweb.config.getint("options", "max_chars_comment", 5000)
|
||||
if commit_hash:
|
||||
# Shorten commit_hash to a short Git hash.
|
||||
commit_hash = commit_hash[:7]
|
||||
|
@ -92,6 +93,7 @@ def make_context(request: Request, title: str, next: str = None):
|
|||
"creds": aurweb.auth.creds,
|
||||
"next": next if next else request.url.path,
|
||||
"version": os.environ.get("COMMIT_HASH", aurweb.config.AURWEB_VERSION),
|
||||
"max_chars_comment": max_chars_comment,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -49,6 +49,8 @@ salt_rounds = 12
|
|||
redis_address = redis://localhost
|
||||
; Toggles traceback display in templates/errors/500.html.
|
||||
traceback = 0
|
||||
; Maximum number of characters for a comment
|
||||
max_chars_comment = 5000
|
||||
|
||||
[ratelimit]
|
||||
request_limit = 4000
|
||||
|
|
|
@ -2371,3 +2371,7 @@ msgid "Note that if you hide your email address, it'll "
|
|||
"receive an email. However, replies are typically sent to the "
|
||||
"mailing-list and would then be visible in the archive."
|
||||
msgstr ""
|
||||
|
||||
#: templates/partials/packages/comment_form.html
|
||||
msgid "Maximum number of characters"
|
||||
msgstr ""
|
||||
|
|
|
@ -21,12 +21,15 @@ Routes:
|
|||
| format('<a href="https://daringfireball.net/projects/markdown/syntax">',
|
||||
"</a>")
|
||||
| safe }}
|
||||
<br/>
|
||||
{{ "Maximum number of characters" | tr }}: {{ max_chars_comment }}.
|
||||
</p>
|
||||
<p>
|
||||
<textarea id="id_comment"
|
||||
name="comment"
|
||||
cols="80"
|
||||
rows="10"
|
||||
maxlength="{{ max_chars_comment }}"
|
||||
>{% if comment %}{{ comment.Comments or '' }}{% endif %}</textarea>
|
||||
</p>
|
||||
<p>
|
||||
|
|
|
@ -24,13 +24,17 @@
|
|||
"</a>"
|
||||
) | safe
|
||||
}}
|
||||
<br/>
|
||||
{{ "Maximum number of characters" | tr }}: {{ max_chars_comment }}.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<textarea id="id_comment"
|
||||
name="comment"
|
||||
cols="80"
|
||||
rows="10">{{ comment.Comments }}</textarea>
|
||||
rows="10"
|
||||
maxlength="{{ max_chars_comment }}"
|
||||
>{{ comment.Comments }}</textarea>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
<p>
|
||||
<label for="id_comments">{{ "Comments" | tr }}:</label>
|
||||
<textarea id="id_comments" name="comments"
|
||||
rows="5" cols="50"
|
||||
rows="5" cols="50" maxlength="{{ max_chars_comment }}"
|
||||
placeholder="Related package request closure comments..."
|
||||
></textarea>
|
||||
</p>
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
<textarea id="id_comments"
|
||||
name="comments"
|
||||
rows="5" cols="50"
|
||||
maxlength="{{ max_chars_comment }}"
|
||||
placeholder="Related package request closure comments..."
|
||||
></textarea>
|
||||
</p>
|
||||
|
|
|
@ -60,7 +60,8 @@
|
|||
<textarea id="id_comments"
|
||||
name="comments"
|
||||
rows="5"
|
||||
cols="50"></textarea>
|
||||
cols="50"
|
||||
maxlength="{{ max_chars_comment }}"></textarea>
|
||||
</p>
|
||||
<p>
|
||||
<input class="button" type="submit" value="{{ 'Flag' | tr }}" />
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
<textarea id="id_comments"
|
||||
name="comments"
|
||||
rows="5" cols="50"
|
||||
maxlength="{{ max_chars_comment }}"
|
||||
placeholder="Related package request closure comments..."
|
||||
></textarea>
|
||||
</p>
|
||||
|
|
|
@ -64,7 +64,10 @@
|
|||
<p>
|
||||
<label for="id_comments">{{ "Comments" | tr }}:</label>
|
||||
<textarea id="id_comments" name="comments"
|
||||
rows="5" cols="50">{{ comments or '' }}</textarea>
|
||||
rows="5" cols="50"
|
||||
maxlength="{{ max_chars_comment }}"
|
||||
>{{ comments or '' }}
|
||||
</textarea>
|
||||
</p>
|
||||
|
||||
<p id="deletion_hint">
|
||||
|
|
|
@ -26,7 +26,8 @@
|
|||
<p>
|
||||
<label for="id_comments">{{ "Comments" | tr }}:</label>
|
||||
<textarea id="id_comments" name="comments"
|
||||
rows="5" cols="50"></textarea>
|
||||
rows="5" cols="50" maxlength="{{ max_chars_comment }}"
|
||||
></textarea>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
|
@ -6,7 +6,7 @@ import pytest
|
|||
from fastapi.testclient import TestClient
|
||||
from sqlalchemy import and_
|
||||
|
||||
from aurweb import asgi, db, time
|
||||
from aurweb import asgi, config, db, time
|
||||
from aurweb.models.account_type import USER_ID, AccountType
|
||||
from aurweb.models.dependency_type import DependencyType
|
||||
from aurweb.models.package import Package
|
||||
|
@ -25,6 +25,8 @@ from aurweb.testing.email import Email
|
|||
from aurweb.testing.html import get_errors, get_successes, parse_root
|
||||
from aurweb.testing.requests import Request
|
||||
|
||||
max_chars_comment = config.getint("options", "max_chars_comment", 5000)
|
||||
|
||||
|
||||
def package_endpoint(package: Package) -> str:
|
||||
return f"/packages/{package.Name}"
|
||||
|
@ -572,6 +574,38 @@ def test_pkgbase_comments(
|
|||
assert "form" in data
|
||||
|
||||
|
||||
def test_pkgbase_comment_exceed_character_limit(
|
||||
client: TestClient,
|
||||
user: User,
|
||||
package: Package,
|
||||
comment: PackageComment,
|
||||
):
|
||||
# Post new comment
|
||||
cookies = {"AURSID": user.login(Request(), "testPassword")}
|
||||
pkgbasename = package.PackageBase.Name
|
||||
endpoint = f"/pkgbase/{pkgbasename}/comments"
|
||||
|
||||
with client as request:
|
||||
request.cookies = cookies
|
||||
resp = request.post(
|
||||
endpoint,
|
||||
data={"comment": "x" * (max_chars_comment + 1)},
|
||||
)
|
||||
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
|
||||
assert "Maximum number of characters for comment exceeded." in resp.text
|
||||
# Edit existing
|
||||
cookies = {"AURSID": user.login(Request(), "testPassword")}
|
||||
with client as request:
|
||||
request.cookies = cookies
|
||||
endp = f"/pkgbase/{pkgbasename}/comments/{comment.ID}"
|
||||
response = request.post(
|
||||
endp,
|
||||
data={"comment": "x" * (max_chars_comment + 1)},
|
||||
)
|
||||
assert response.status_code == HTTPStatus.BAD_REQUEST
|
||||
assert "Maximum number of characters for comment exceeded." in resp.text
|
||||
|
||||
|
||||
def test_pkgbase_comment_edit_unauthorized(
|
||||
client: TestClient,
|
||||
user: User,
|
||||
|
@ -935,6 +969,28 @@ def test_pkgbase_request_post_no_comment_error(
|
|||
assert error.text.strip() == expected
|
||||
|
||||
|
||||
def test_pkgbase_request_post_comment_exceed_character_limit(
|
||||
client: TestClient, user: User, package: Package
|
||||
):
|
||||
endpoint = f"/pkgbase/{package.PackageBase.Name}/request"
|
||||
cookies = {"AURSID": user.login(Request(), "testPassword")}
|
||||
with client as request:
|
||||
request.cookies = cookies
|
||||
resp = request.post(
|
||||
endpoint,
|
||||
data={
|
||||
"type": "deletion",
|
||||
"comments": "x" * (max_chars_comment + 1),
|
||||
},
|
||||
)
|
||||
assert resp.status_code == int(HTTPStatus.OK)
|
||||
|
||||
root = parse_root(resp.text)
|
||||
error = root.xpath('//ul[@class="errorlist"]/li')[0]
|
||||
expected = "Maximum number of characters for comment exceeded."
|
||||
assert error.text.strip() == expected
|
||||
|
||||
|
||||
def test_pkgbase_request_post_merge_not_found_error(
|
||||
client: TestClient, user: User, package: Package
|
||||
):
|
||||
|
@ -1087,6 +1143,13 @@ def test_pkgbase_flag(
|
|||
assert resp.status_code == int(HTTPStatus.SEE_OTHER)
|
||||
assert pkgbase.Flagger is None
|
||||
|
||||
# Try flagging with a comment that exceeds our character limit.
|
||||
with client as request:
|
||||
request.cookies = cookies
|
||||
data = {"comments": "x" * (max_chars_comment + 1)}
|
||||
resp = request.post(f"/pkgbase/{pkgbase.Name}/flag", data=data)
|
||||
assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
|
||||
|
||||
# Flag it again.
|
||||
with client as request:
|
||||
request.cookies = cookies
|
||||
|
|
Loading…
Add table
Reference in a new issue