mirror of
https://gitlab.com/tildes/tildes.git
synced 2026-04-17 14:59:11 +02:00
Add a delay to comment back-and-forths
This commit is contained in:
@@ -101,6 +101,7 @@
|
||||
// Status message (errors) should be on their own line as well
|
||||
> .text-status-message {
|
||||
min-width: 100%;
|
||||
margin: 0.4rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
"""Web API endpoints related to comments."""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from marshmallow.fields import Boolean
|
||||
from pyramid.httpexceptions import HTTPUnprocessableEntity
|
||||
from pyramid.request import Request
|
||||
@@ -20,6 +22,7 @@ from tildes.models.comment import (
|
||||
CommentVote,
|
||||
)
|
||||
from tildes.models.log import LogComment
|
||||
from tildes.models.user import User
|
||||
from tildes.schemas.comment import CommentLabelSchema, CommentSchema
|
||||
from tildes.views import IC_NOOP
|
||||
from tildes.views.decorators import ic_view_config, rate_limit_view
|
||||
@@ -88,6 +91,13 @@ def post_toplevel_comment(request: Request, markdown: str) -> dict:
|
||||
def post_comment_reply(request: Request, markdown: str) -> dict:
|
||||
"""Post a reply to a comment with Intercooler."""
|
||||
parent_comment = request.context
|
||||
|
||||
wait_mins = _reply_wait_minutes(request, request.user, parent_comment.user)
|
||||
if wait_mins:
|
||||
raise HTTPUnprocessableEntity(
|
||||
f"You can't reply to this user yet. Please wait {wait_mins} minutes."
|
||||
)
|
||||
|
||||
new_comment = Comment(
|
||||
topic=parent_comment.topic,
|
||||
author=request.user,
|
||||
@@ -138,6 +148,12 @@ def get_comment_contents(request: Request) -> dict:
|
||||
)
|
||||
def get_comment_reply(request: Request) -> dict:
|
||||
"""Get the reply form for a comment with Intercooler."""
|
||||
wait_mins = _reply_wait_minutes(request, request.user, request.context.user)
|
||||
if wait_mins:
|
||||
raise HTTPUnprocessableEntity(
|
||||
f"You can't reply to this user yet. Please wait {wait_mins} minutes."
|
||||
)
|
||||
|
||||
return {"parent_comment": request.context}
|
||||
|
||||
|
||||
@@ -451,3 +467,45 @@ def delete_comment_bookmark(request: Request) -> dict:
|
||||
def get_comment_markdown_source(request: Request) -> dict:
|
||||
"""Get the Markdown source for a comment with Intercooler."""
|
||||
return {"post": request.context}
|
||||
|
||||
|
||||
def _reply_wait_minutes(
|
||||
request: Request, replying_user: User, replying_to_user: User
|
||||
) -> Optional[int]:
|
||||
"""Return how many mins replying_user needs to wait to respond to replying_to_user.
|
||||
|
||||
`replying_user` is the one that wants to be able to post a new reply. They can't do
|
||||
so if there exists a back-and-forth between them and `replying_to_user` where the
|
||||
most recent comment is within the time threshold.
|
||||
|
||||
That is, call the user trying to reply "A", and the user they're replying to "B".
|
||||
If a sequence of comments exists that are written by users (B, A, B) and the last
|
||||
comment is "too recent", this will return how many minutes they need to wait. If
|
||||
there isn't any recent sequence like that, it will return None.
|
||||
"""
|
||||
threshold_minutes = 30
|
||||
|
||||
# if a "too recent" exchange exists, this will return a single value for how many
|
||||
# minutes ago the final comment in the back-and-forth was posted
|
||||
result = request.db_session.execute(
|
||||
"""
|
||||
select ceil(extract(epoch from now() - main.created_time) / 60)
|
||||
from comments as main
|
||||
inner join comments as parent on parent.comment_id = main.parent_comment_id
|
||||
inner join comments as grandparent
|
||||
on grandparent.comment_id = parent.parent_comment_id
|
||||
where main.user_id = :replying_to_user_id
|
||||
and parent.user_id = :replying_user_id
|
||||
and grandparent.user_id = :replying_to_user_id
|
||||
and main.created_time > now() - interval ':threshold_minutes minutes'""",
|
||||
{
|
||||
"replying_to_user_id": replying_to_user.user_id,
|
||||
"replying_user_id": replying_user.user_id,
|
||||
"threshold_minutes": threshold_minutes,
|
||||
},
|
||||
).fetchone()
|
||||
|
||||
if not result:
|
||||
return None
|
||||
|
||||
return threshold_minutes - int(result[0])
|
||||
|
||||
Reference in New Issue
Block a user