diff --git a/files/classes/__init__.py b/files/classes/__init__.py index d17d699fe..25ccf8afd 100644 --- a/files/classes/__init__.py +++ b/files/classes/__init__.py @@ -11,6 +11,7 @@ from .reports import * from .user import * from .badges import * from .userblock import * +from .usermute import * from .post import * from .votes import * from .domains import * diff --git a/files/classes/user.py b/files/classes/user.py index 9f614cdd1..f609b43f5 100644 --- a/files/classes/user.py +++ b/files/classes/user.py @@ -36,6 +36,7 @@ from .sub_relationship import * from .sub_logs import * from .subscriptions import * from .userblock import * +from .usermute import * if SITE == 'devrama.net': DEFAULT_ADMIN_LEVEL = 3 @@ -561,6 +562,10 @@ class User(Base): def has_blocked(self, target): return g.db.query(UserBlock).filter_by(user_id=self.id, target_id=target.id).one_or_none() + @lazy + def has_muted(self, target): + return g.db.query(UserMute).filter_by(user_id=self.id, target_id=target.id).one_or_none() + @property @lazy def all_twoway_blocks(self): @@ -1023,6 +1028,12 @@ class User(Base): def userblocks(self): return [x[0] for x in g.db.query(UserBlock.target_id).filter_by(user_id=self.id)] + @property + @lazy + def muters(self): + return set([x[0] for x in g.db.query(UserMute.user_id).filter_by(target_id=self.id)]) + + def get_relationship_count(self, relationship_cls): # TODO: deduplicate (see routes/users.py) if relationship_cls in {SaveRelationship, Subscription}: diff --git a/files/classes/usermute.py b/files/classes/usermute.py new file mode 100644 index 000000000..5f572fa73 --- /dev/null +++ b/files/classes/usermute.py @@ -0,0 +1,19 @@ +import time + +from sqlalchemy import Column, ForeignKey +from sqlalchemy.sql.sqltypes import * + +from files.classes import Base + +class UserMute(Base): + __tablename__ = "usermutes" + user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) + target_id = Column(Integer, ForeignKey("users.id"), primary_key=True) + created_utc = Column(Integer) + + def __init__(self, *args, **kwargs): + if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time()) + super().__init__(*args, **kwargs) + + def __repr__(self): + return f"<{self.__class__.__name__}(user={self.user_id}, target={self.target_id})>" diff --git a/files/helpers/alerts.py b/files/helpers/alerts.py index e15139dbd..5378bdfc3 100644 --- a/files/helpers/alerts.py +++ b/files/helpers/alerts.py @@ -187,7 +187,7 @@ def NOTIFY_USERS(text, v, oldtext=None, ghost=False, log_cost=None, followers_pi if not group: continue member_ids = group.member_ids - members = member_ids - notify_users - BOT_IDs - v.all_twoway_blocks + members = member_ids - notify_users - BOT_IDs - v.all_twoway_blocks - v.muters notify_users.update(members) @@ -210,13 +210,10 @@ def NOTIFY_USERS(text, v, oldtext=None, ghost=False, log_cost=None, followers_pi if coin_receivers: g.db.query(User).options(load_only(User.id)).filter(User.id.in_(coin_receivers)).update({ User.coins: User.coins + 10 }) - if SITE == 'rdrama.net' and v.id in {256, 9287, 10489, 18701}: - notify_users.discard(AEVANN_ID) - if len(notify_users) > 400 and v.admin_level < PERMS['POST_COMMENT_INFINITE_PINGS']: abort(403, "You can only notify a maximum of 400 users.") - return notify_users - BOT_IDs - {v.id, 0} - v.all_twoway_blocks + return notify_users - BOT_IDs - {v.id, 0} - v.all_twoway_blocks - v.muters def push_notif(uids, title, body, url_or_comment): diff --git a/files/routes/comments.py b/files/routes/comments.py index 2d6591b81..83ef9de16 100644 --- a/files/routes/comments.py +++ b/files/routes/comments.py @@ -178,7 +178,7 @@ def comment(v): if not body and not request.files.get('file'): abort(400, "You need to actually write something!") - if parent_user.has_blocked(v): + if parent_user.has_blocked(v) or parent_user.has_muted(v): notify_op = False if request.files.get("file") and not g.is_tor: diff --git a/files/routes/notifications.py b/files/routes/notifications.py index 1a31da1a5..1eee22bcf 100644 --- a/files/routes/notifications.py +++ b/files/routes/notifications.py @@ -346,6 +346,7 @@ def notifications(v): if n.created_utc > 1620391248: c.notif_utc = n.created_utc if not n.read: c.unread = True + c.is_notif = True if c.parent_post or c.wall_user_id: all_items.append(c) diff --git a/files/routes/users.py b/files/routes/users.py index 66e8a6d4a..fbd46b759 100644 --- a/files/routes/users.py +++ b/files/routes/users.py @@ -623,6 +623,9 @@ def message2(v, username=None, id=None): if v.admin_level <= PERMS['MESSAGE_BLOCKED_USERS'] and hasattr(user, 'is_blocked') and user.is_blocked: abort(403, f"@{user.username} is blocking you!") + if user.has_muted(v): + abort(403, f"@{user.username} is muting notifications from you, so messaging them is pointless!") + body = request.values.get("message", "") body = body[:COMMENT_BODY_LENGTH_LIMIT].strip() @@ -708,6 +711,9 @@ def messagereply(v): and hasattr(user, 'is_blocked') and user.is_blocked): abort(403, f"You're blocked by @{user.username}") + if user.has_muted(v): + abort(403, f"@{user.username} is muting notifications from you, so messaging them is pointless!") + if not g.is_tor and get_setting("dm_media"): body = process_files(request.files, v, body, is_dm=True, dm_user=user) body = body[:COMMENT_BODY_LENGTH_LIMIT].strip() #process_files potentially adds characters to the post @@ -1511,3 +1517,47 @@ def users_list(v): page=page, user_cards_title="Users Feed", ) + +@app.post("/mute_notifs/") +@limiter.limit('1/second', scope=rpath) +@limiter.limit('1/second', scope=rpath, key_func=get_ID) +@limiter.limit("20/day", deduct_when=lambda response: response.status_code < 400) +@limiter.limit("20/day", deduct_when=lambda response: response.status_code < 400, key_func=get_ID) +@auth_required +def mute_notifs(v, uid): + user = get_account(uid) + + if user.id == v.id: + abort(400, "You can't mute notifications from yourself!") + if user.id == AUTOJANNY_ID: + abort(403, f"You can't mute notifications from @{user.username}") + if v.has_muted(user): + abort(409, f"You have already muted notifications from @{user.username}") + + new_mute = UserMute(user_id=v.id, target_id=user.id) + g.db.add(new_mute) + + send_notification(user.id, f"@{v.username} has muted notifications from you!") + + return {"message": f"You have muted notifications from @{user.username} successfully!"} + + +@app.post("/unmute_notifs/") +@limiter.limit('1/second', scope=rpath) +@limiter.limit('1/second', scope=rpath, key_func=get_ID) +@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 unmute_notifs(v, uid): + user = get_account(uid) + + x = v.has_muted(user) + + if not x: + abort(409, "You can't unmute notifications from someone you haven't muted notifications from!") + + g.db.delete(x) + + send_notification(user.id, f"@{v.username} has unmuted notifications from you!") + + return {"message": f"You have unmuted notifications from @{user.username} successfully!"} diff --git a/files/templates/comments.html b/files/templates/comments.html index 1f1aa7f6b..307e96e95 100644 --- a/files/templates/comments.html +++ b/files/templates/comments.html @@ -116,7 +116,7 @@
-