diff --git a/app/activitypub/routes.py b/app/activitypub/routes.py index dd751e08..1bfe6ae5 100644 --- a/app/activitypub/routes.py +++ b/app/activitypub/routes.py @@ -24,12 +24,12 @@ from app.activitypub.util import public_key, users_total, active_half_year, acti user_removed_from_remote_server, create_post, create_post_reply, update_post_reply_from_activity, \ update_post_from_activity, undo_vote, undo_downvote, post_to_page, get_redis_connection, find_reported_object, \ process_report, ensure_domains_match, can_edit, can_delete, remove_data_from_banned_user, resolve_remote_post, \ - inform_followers_of_post_update, comment_model_to_json, restore_post_or_comment, ban_local_user, unban_local_user, \ - lock_post, log_incoming_ap, find_community_ap_id, site_ban_remove_data, community_ban_remove_data + inform_followers_of_post_update, comment_model_to_json, restore_post_or_comment, ban_user, unban_user, \ + log_incoming_ap, find_community_ap_id, site_ban_remove_data, community_ban_remove_data from app.utils import gibberish, get_setting, render_template, \ community_membership, ap_datetime, ip_address, can_downvote, \ can_upvote, can_create_post, awaken_dormant_instance, shorten_string, can_create_post_reply, sha256_digest, \ - community_moderators, markdown_to_html, html_to_text + community_moderators, markdown_to_html, html_to_text, add_to_modlog_activitypub @bp.route('/testredis') @@ -1094,10 +1094,14 @@ def process_inbox_request(request_json, store_ap_json): mod = user post_id = request_json['object']['object'] post = Post.query.filter_by(ap_id=post_id).first() + reason = request_json['object']['summary'] if 'summary' in request_json['object'] else '' if post: if post.community.is_moderator(mod) or post.community.is_instance_admin(mod): post.comments_enabled = False db.session.commit() + add_to_modlog_activitypub('lock_post', mod, community_id=post.community.id, + link_text=shorten_string(post.title), link=f'post/{post.id}', + reason=reason) log_incoming_ap(id, APLOG_LOCK, APLOG_SUCCESS, request_json if store_ap_json else None) else: log_incoming_ap(id, APLOG_LOCK, APLOG_FAILURE, request_json if store_ap_json else None, 'Lock: Does not have permission') @@ -1181,8 +1185,7 @@ def process_inbox_request(request_json, store_ap_json): else: log_incoming_ap(id, APLOG_USERBAN, APLOG_IGNORED, request_json if store_ap_json else None, 'Banned, but content retained') - if blocked.is_local(): - ban_local_user(blocker, blocked, community, request_json) + ban_user(blocker, blocked, community, request_json) return if request_json['object']['type'] == 'Undo': @@ -1217,10 +1220,14 @@ def process_inbox_request(request_json, store_ap_json): mod = user post_id = request_json['object']['object']['object'] post = Post.query.filter_by(ap_id=post_id).first() + reason = request_json['object']['summary'] if 'summary' in request_json['object'] else '' if post: if post.community.is_moderator(mod) or post.community.is_instance_admin(mod): post.comments_enabled = True db.session.commit() + add_to_modlog_activitypub('unlock_post', mod, community_id=post.community.id, + link_text=shorten_string(post.title), link=f'post/{post.id}', + reason=reason) log_incoming_ap(id, APLOG_LOCK, APLOG_SUCCESS, request_json if store_ap_json else None) else: log_incoming_ap(id, APLOG_LOCK, APLOG_FAILURE, request_json if store_ap_json else None, 'Lock: Does not have permission') @@ -1240,8 +1247,7 @@ def process_inbox_request(request_json, store_ap_json): log_incoming_ap(id, APLOG_USERBAN, APLOG_FAILURE, request_json if store_ap_json else None, 'Does not have permission') return - if blocked.is_local(): - unban_local_user(blocker, blocked, community, request_json) + unban_user(blocker, blocked, community, request_json) log_incoming_ap(id, APLOG_USERBAN, APLOG_SUCCESS, request_json if store_ap_json else None) return diff --git a/app/activitypub/util.py b/app/activitypub/util.py index 745a1612..6f4a0449 100644 --- a/app/activitypub/util.py +++ b/app/activitypub/util.py @@ -1343,6 +1343,7 @@ def is_activitypub_request(): def delete_post_or_comment(deletor, to_delete, store_ap_json, request_json): id = request_json['id'] community = to_delete.community + reason = request_json['object']['summary'] if 'summary' in request_json['object'] else '' if to_delete.user_id == deletor.id or deletor.is_admin() or community.is_moderator(deletor) or community.is_instance_admin(deletor): if isinstance(to_delete, Post): to_delete.deleted = True @@ -1358,7 +1359,8 @@ def delete_post_or_comment(deletor, to_delete, store_ap_json, request_json): db.session.commit() if to_delete.author.id != deletor.id: add_to_modlog_activitypub('delete_post', deletor, community_id=community.id, - link_text=shorten_string(to_delete.title), link=f'post/{to_delete.id}') + link_text=shorten_string(to_delete.title), link=f'post/{to_delete.id}', + reason=reason) elif isinstance(to_delete, PostReply): to_delete.deleted = True to_delete.deleted_by = deletor.id @@ -1370,7 +1372,8 @@ def delete_post_or_comment(deletor, to_delete, store_ap_json, request_json): if to_delete.author.id != deletor.id: add_to_modlog_activitypub('delete_post_reply', deletor, community_id=community.id, link_text=f'comment on {shorten_string(to_delete.post.title)}', - link=f'post/{to_delete.post.id}#comment_{to_delete.id}') + link=f'post/{to_delete.post.id}#comment_{to_delete.id}', + reason=reason) log_incoming_ap(id, APLOG_DELETE, APLOG_SUCCESS, request_json if store_ap_json else None) else: log_incoming_ap(id, APLOG_DELETE, APLOG_FAILURE, request_json if store_ap_json else None, 'Deletor did not have permisson') @@ -1379,6 +1382,7 @@ def delete_post_or_comment(deletor, to_delete, store_ap_json, request_json): def restore_post_or_comment(restorer, to_restore, store_ap_json, request_json): id = request_json['id'] community = to_restore.community + reason = request_json['object']['summary'] if 'summary' in request_json['object'] else '' if to_restore.user_id == restorer.id or restorer.is_admin() or community.is_moderator(restorer) or community.is_instance_admin(restorer): if isinstance(to_restore, Post): to_restore.deleted = False @@ -1400,7 +1404,8 @@ def restore_post_or_comment(restorer, to_restore, store_ap_json, request_json): db.session.commit() if to_restore.author.id != restorer.id: add_to_modlog_activitypub('restore_post', restorer, community_id=community.id, - link_text=shorten_string(to_restore.title), link=f'post/{to_restore.id}') + link_text=shorten_string(to_restore.title), link=f'post/{to_restore.id}', + reason=reason) elif isinstance(to_restore, PostReply): to_restore.deleted = False @@ -1412,7 +1417,8 @@ def restore_post_or_comment(restorer, to_restore, store_ap_json, request_json): if to_restore.author.id != restorer.id: add_to_modlog_activitypub('restore_post_reply', restorer, community_id=community.id, link_text=f'comment on {shorten_string(to_restore.post.title)}', - link=f'post/{to_restore.post_id}#comment_{to_restore.id}') + link=f'post/{to_restore.post_id}#comment_{to_restore.id}', + reason=reason) log_incoming_ap(id, APLOG_UNDO_DELETE, APLOG_SUCCESS, request_json if store_ap_json else None) else: log_incoming_ap(id, APLOG_UNDO_DELETE, APLOG_FAILURE, request_json if store_ap_json else None, 'Restorer did not have permisson') @@ -1539,82 +1545,73 @@ def community_ban_remove_data(blocker_id, community_id, blocked): db.session.commit() -def ban_local_user(blocker, blocked, community, request_json): +def ban_user(blocker, blocked, community, request_json): existing = CommunityBan.query.filter_by(community_id=community.id, user_id=blocked.id).first() if not existing: new_ban = CommunityBan(community_id=community.id, user_id=blocked.id, banned_by=blocker.id) - if 'summary' in request_json: + if 'summary' in request_json['object']: new_ban.reason=request_json['object']['summary'] + reason = request_json['object']['summary'] + else: + reason = '' if 'expires' in request_json and datetime.fromisoformat(request_json['object']['expires']) > datetime.now(timezone.utc): new_ban.ban_until = datetime.fromisoformat(request_json['object']['expires']) elif 'endTime' in request_json and datetime.fromisoformat(request_json['object']['endTime']) > datetime.now(timezone.utc): new_ban.ban_until = datetime.fromisoformat(request_json['object']['endTime']) db.session.add(new_ban) - db.session.commit() - db.session.query(CommunityJoinRequest).filter(CommunityJoinRequest.community_id == community.id, CommunityJoinRequest.user_id == blocked.id).delete() community_membership_record = CommunityMember.query.filter_by(community_id=community.id, user_id=blocked.id).first() if community_membership_record: community_membership_record.is_banned = True + db.session.commit() - # Notify banned person - notify = Notification(title=shorten_string('You have been banned from ' + community.title), - url=f'/notifications', user_id=blocked.id, - author_id=blocker.id) + if blocked.is_local(): + db.session.query(CommunityJoinRequest).filter(CommunityJoinRequest.community_id == community.id, CommunityJoinRequest.user_id == blocked.id).delete() + + # Notify banned person + notify = Notification(title=shorten_string('You have been banned from ' + community.title), + url=f'/notifications', user_id=blocked.id, + author_id=blocker.id) + db.session.add(notify) + if not current_app.debug: # user.unread_notifications += 1 hangs app if 'user' is the same person + blocked.unread_notifications += 1 # who pressed 'Re-submit this activity'. + + # Remove their notification subscription, if any + db.session.query(NotificationSubscription).filter(NotificationSubscription.entity_id == community.id, + NotificationSubscription.user_id == blocked.id, + NotificationSubscription.type == NOTIF_COMMUNITY).delete() + db.session.commit() + + cache.delete_memoized(communities_banned_from, blocked.id) + cache.delete_memoized(joined_communities, blocked.id) + cache.delete_memoized(moderating_communities, blocked.id) + + add_to_modlog_activitypub('ban_user', blocker, community_id=community.id, link_text=blocked.display_name(), link=f'u/{blocked.link()}', reason=reason) + + +def unban_user(blocker, blocked, community, request_json): + reason = request_json['object']['summary'] if 'summary' in request_json['object'] else '' + db.session.query(CommunityBan).filter(CommunityBan.community_id == community.id, CommunityBan.user_id == blocked.id).delete() + community_membership_record = CommunityMember.query.filter_by(community_id=community.id, user_id=blocked.id).first() + if community_membership_record: + community_membership_record.is_banned = False + db.session.commit() + + if blocked.is_local(): + # Notify unbanned person + notify = Notification(title=shorten_string('You have been unbanned from ' + community.title), + url=f'/notifications', user_id=blocked.id, author_id=blocker.id) db.session.add(notify) if not current_app.debug: # user.unread_notifications += 1 hangs app if 'user' is the same person blocked.unread_notifications += 1 # who pressed 'Re-submit this activity'. - # Remove their notification subscription, if any - db.session.query(NotificationSubscription).filter(NotificationSubscription.entity_id == community.id, - NotificationSubscription.user_id == blocked.id, - NotificationSubscription.type == NOTIF_COMMUNITY).delete() db.session.commit() cache.delete_memoized(communities_banned_from, blocked.id) cache.delete_memoized(joined_communities, blocked.id) cache.delete_memoized(moderating_communities, blocked.id) - add_to_modlog_activitypub('ban_user', blocker, community_id=community.id, link_text=blocked.display_name(), link=blocked.link()) - - -def unban_local_user(blocker, blocked, community, request_json): - db.session.query(CommunityBan).filter(CommunityBan.community_id == community.id, CommunityBan.user_id == blocked.id).delete() - community_membership_record = CommunityMember.query.filter_by(community_id=community.id, user_id=blocked.id).first() - if community_membership_record: - community_membership_record.is_banned = False - - # Notify unbanned person - notify = Notification(title=shorten_string('You have been unbanned from ' + community.title), - url=f'/notifications', user_id=blocked.id, author_id=blocker.id) - db.session.add(notify) - if not current_app.debug: # user.unread_notifications += 1 hangs app if 'user' is the same person - blocked.unread_notifications += 1 # who pressed 'Re-submit this activity'. - - db.session.commit() - - cache.delete_memoized(communities_banned_from, blocked.id) - cache.delete_memoized(joined_communities, blocked.id) - cache.delete_memoized(moderating_communities, blocked.id) - - add_to_modlog_activitypub('unban_user', blocker, community_id=community.id, link_text=blocked.display_name(), link=blocked.link()) - - -def lock_post(mod_ap_id, post_id, comments_enabled): - if current_app.debug: - lock_post_task(mod_ap_id, post_id, comments_enabled) - else: - lock_post_task.delay(mod_ap_id, post_id, comments_enabled) - - -@celery.task -def lock_post_task(mod_ap_id, post_id, comments_enabled): - mod = find_actor_or_create(mod_ap_id, create_if_not_found=False) - post = Post.query.filter_by(ap_id=post_id).first() - if mod and post: - if post.community.is_moderator(mod) or post.community.is_instance_admin(mod): - post.comments_enabled = comments_enabled - db.session.commit() + add_to_modlog_activitypub('unban_user', blocker, community_id=community.id, link_text=blocked.display_name(), link=f'u/{blocked.link()}', reason=reason) def create_post_reply(store_ap_json, community: Community, in_reply_to, request_json: dict, user: User, announce_id=None) -> Union[PostReply, None]: diff --git a/app/models.py b/app/models.py index e19e2a28..0e0a410d 100644 --- a/app/models.py +++ b/app/models.py @@ -630,6 +630,7 @@ class Community(db.Model): db.session.query(CommunityJoinRequest).filter(CommunityJoinRequest.community_id == self.id).delete() db.session.query(CommunityMember).filter(CommunityMember.community_id == self.id).delete() db.session.query(Report).filter(Report.suspect_community_id == self.id).delete() + db.session.query(ModLog).filter(ModLog.community_id == self.id).delete() user_role = db.Table('user_role', @@ -1020,6 +1021,7 @@ class User(UserMixin, db.Model): db.session.query(PollChoiceVote).filter(PollChoiceVote.user_id == self.id).delete() db.session.query(PostBookmark).filter(PostBookmark.user_id == self.id).delete() db.session.query(PostReplyBookmark).filter(PostReplyBookmark.user_id == self.id).delete() + db.session.query(ModLog).filter(ModLog.user_id == self.id).delete() def purge_content(self, soft=True): files = File.query.join(Post).filter(Post.user_id == self.id).all() @@ -2285,6 +2287,8 @@ class ModLog(db.Model): 'undelete_user': _l('Restored account'), 'ban_user': _l('Banned account'), 'unban_user': _l('Un-banned account'), + 'lock_post': _l('Lock post'), + 'unlock_post': _l('Un-lock post'), } def action_to_str(self): diff --git a/app/templates/modlog.html b/app/templates/modlog.html index f3290900..7c905546 100644 --- a/app/templates/modlog.html +++ b/app/templates/modlog.html @@ -29,12 +29,12 @@ {% elif modlog_entry.link_text -%} {{ modlog_entry.link_text }} {% endif -%} - {% if modlog_entry.reason -%} -
{{ _('Reason:') }} {{ modlog_entry.reason }} - {% endif -%} {% if modlog_entry.community_id -%} {{ _(' in %(community_name)s', community_name='' + modlog_entry.community.display_name()) }} {% endif -%} + {% if modlog_entry.reason -%} +
{{ _('Reason:') }} {{ modlog_entry.reason }} + {% endif -%} {% endfor %}