diff --git a/files/helpers/alerts.py b/files/helpers/alerts.py index 8dee5305d..e15139dbd 100644 --- a/files/helpers/alerts.py +++ b/files/helpers/alerts.py @@ -120,7 +120,7 @@ def add_notif(cid, uid, text, pushnotif_url=''): push_notif({uid}, 'New notification', text, pushnotif_url) -def NOTIFY_USERS(text, v, oldtext=None, ghost=False, log_cost=None, followers_ping=True): +def NOTIFY_USERS(text, v, oldtext=None, ghost=False, log_cost=None, followers_ping=True, commenters_ping_post_id=None): # Restrict young accounts from generating notifications if v.age < NOTIFICATION_SPAM_AGE_THRESHOLD: return set() @@ -177,12 +177,17 @@ def NOTIFY_USERS(text, v, oldtext=None, ghost=False, log_cost=None, followers_pi abort(403, f"You can't use !followers in posts!") group = None member_ids = set([x[0] for x in g.db.query(Follow.user_id).filter_by(target_id=v.id)]) + elif i.group(1) == 'commenters': + if not commenters_ping_post_id: + abort(403, "You can only use !commenters in comments made under posts!") + group = None + member_ids = set([x[0] for x in g.db.query(User.id).join(Comment, Comment.author_id == User.id).filter(Comment.parent_post == commenters_ping_post_id)]) - {v.id} else: group = g.db.get(Group, i.group(1)) if not group: continue member_ids = group.member_ids - members = member_ids - notify_users - v.all_twoway_blocks + members = member_ids - notify_users - BOT_IDs - v.all_twoway_blocks notify_users.update(members) diff --git a/files/helpers/sanitize.py b/files/helpers/sanitize.py index 305effc44..8307a0795 100644 --- a/files/helpers/sanitize.py +++ b/files/helpers/sanitize.py @@ -5,6 +5,7 @@ import signal from functools import partial from os import path, listdir from urllib.parse import parse_qs, urlparse, unquote, ParseResult, urlencode, urlunparse +import time from sqlalchemy.sql import func @@ -410,7 +411,7 @@ def handle_youtube_links(url): return html @with_sigalrm_timeout(10) -def sanitize(sanitized, golden=True, limit_pings=0, showmore=False, count_emojis=False, snappy=False, chat=False, blackjack=None, post_mention_notif=False): +def sanitize(sanitized, golden=True, limit_pings=0, showmore=False, count_emojis=False, snappy=False, chat=False, blackjack=None, post_mention_notif=False, commenters_ping_post_id=None): def error(error): if chat: return error, 403 @@ -481,6 +482,8 @@ def sanitize(sanitized, golden=True, limit_pings=0, showmore=False, count_emojis return f'!{name}' elif name == 'jannies': return f'!{name}' + elif name == 'commenters' and commenters_ping_post_id: + return f'!{name}' elif name == 'followers': return f'!{name}' elif g.db.get(Group, name): diff --git a/files/routes/comments.py b/files/routes/comments.py index 08a73966b..4b0bc5fdd 100644 --- a/files/routes/comments.py +++ b/files/routes/comments.py @@ -144,11 +144,14 @@ def comment(v): parent_user = parent if isinstance(parent, User) else parent.author posting_to_post = isinstance(post_target, Post) - - if posting_to_post and not User.can_see(v, parent): abort(403) + if posting_to_post: + commenters_ping_post_id = post_target.id + else: + commenters_ping_post_id = None + if not isinstance(parent, User) and parent.deleted_utc != 0: if isinstance(parent, Post): abort(403, "You can't reply to deleted posts!") @@ -255,7 +258,7 @@ def comment(v): if v.marsify and not v.chud: body_for_sanitize = marsify(body_for_sanitize) if v.sharpen: body_for_sanitize = sharpen(body_for_sanitize) - body_html = sanitize(body_for_sanitize, limit_pings=5, showmore=(not v.marseyawarded), count_emojis=not v.marsify) + body_html = sanitize(body_for_sanitize, limit_pings=5, showmore=(not v.marseyawarded), count_emojis=not v.marsify, commenters_ping_post_id=commenters_ping_post_id) if post_target.id not in ADMIGGER_THREADS and not (v.chud and v.chud_phrase in body.lower()): existing = g.db.query(Comment.id).filter( @@ -349,7 +352,7 @@ def comment(v): execute_zozbot(c, level, post_target, v) if not v.shadowbanned: - notify_users = NOTIFY_USERS(body, v, ghost=c.ghost, log_cost=c) + notify_users = NOTIFY_USERS(body, v, ghost=c.ghost, log_cost=c, commenters_ping_post_id=commenters_ping_post_id) if notify_users == 'everyone': alert_everyone(c.id) @@ -671,7 +674,7 @@ def edit_comment(cid, v): if c.sharpened: body_for_sanitize = sharpen(body_for_sanitize) - body_html = sanitize(body_for_sanitize, golden=False, limit_pings=5, showmore=(not v.marseyawarded)) + body_html = sanitize(body_for_sanitize, golden=False, limit_pings=5, showmore=(not v.marseyawarded), commenters_ping_post_id=c.parent_post) if len(body_html) > COMMENT_BODY_HTML_LENGTH_LIMIT: abort(400) @@ -704,7 +707,7 @@ def edit_comment(cid, v): g.db.add(c) - notify_users = NOTIFY_USERS(body, v, oldtext=oldtext, ghost=c.ghost, log_cost=c) + notify_users = NOTIFY_USERS(body, v, oldtext=oldtext, ghost=c.ghost, log_cost=c, commenters_ping_post_id=c.parent_post) if notify_users == 'everyone': alert_everyone(c.id) @@ -724,3 +727,20 @@ def edit_comment(cid, v): "ping_cost": c.ping_cost, "edited_string": c.edited_string, } + +@app.get("/!commenters//") +@limiter.limit(DEFAULT_RATELIMIT, deduct_when=lambda response: response.status_code < 400) +@limiter.limit(DEFAULT_RATELIMIT, deduct_when=lambda response: response.status_code < 400, key_func=get_ID) +@auth_required +def commenters(v, pid, time): + users = g.db.query(User, Comment.id, Comment.created_utc).distinct(User.id).join( + Comment, Comment.author_id == User.id + ).filter( + Comment.parent_post == pid, + Comment.created_utc < time-1, + User.id.notin_(BOT_IDs), + ).all() + + users = sorted(users, key=lambda x: x[1]) + + return render_template('commenters.html', v=v, users=users) diff --git a/files/routes/groups.py b/files/routes/groups.py index 6734553d0..55c0c5233 100644 --- a/files/routes/groups.py +++ b/files/routes/groups.py @@ -32,7 +32,7 @@ def create_group(v): if not valid_sub_regex.fullmatch(name): abort(400, "Name does not match the required format!") - if name in {'everyone', 'jannies', 'followers'} or g.db.get(Group, name): + if name in {'everyone', 'jannies', 'followers', 'commenters'} or g.db.get(Group, name): abort(400, "This group already exists!") if not v.charge_account('combined', GROUP_COST)[0]: diff --git a/files/templates/commenters.html b/files/templates/commenters.html new file mode 100644 index 000000000..564489545 --- /dev/null +++ b/files/templates/commenters.html @@ -0,0 +1,23 @@ +{% extends "default.html" %} +{% block pagetitle %}!commenters{% endblock %} +{% block content %} +
!commenters
+
+ + + + + + + + +{% for user, comment_id, comment_created_utc in users %} + + + + + +{% endfor %} +
#NameFirst commented on
{{loop.index}}{% include "user_in_table.html" %}
+ +{% endblock %}