mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-23 19:36:56 -08:00
API: support /comment/report
This commit is contained in:
parent
d738850fc7
commit
308f29ba38
5 changed files with 148 additions and 7 deletions
|
@ -2,7 +2,7 @@ from app.api.alpha import bp
|
||||||
from app.api.alpha.utils import get_site, post_site_block, \
|
from app.api.alpha.utils import get_site, post_site_block, \
|
||||||
get_search, \
|
get_search, \
|
||||||
get_post_list, get_post, post_post_like, put_post_save, put_post_subscribe, \
|
get_post_list, get_post, post_post_like, put_post_save, put_post_subscribe, \
|
||||||
get_reply_list, post_reply_like, put_reply_save, put_reply_subscribe, post_reply, put_reply, post_reply_delete, \
|
get_reply_list, post_reply_like, put_reply_save, put_reply_subscribe, post_reply, put_reply, post_reply_delete, post_reply_report, \
|
||||||
get_community_list, get_community, post_community_follow, post_community_block, \
|
get_community_list, get_community, post_community_follow, post_community_block, \
|
||||||
get_user, post_user_block
|
get_user, post_user_block
|
||||||
from app.shared.auth import log_user_in
|
from app.shared.auth import log_user_in
|
||||||
|
@ -242,6 +242,18 @@ def post_alpha_comment_delete():
|
||||||
return jsonify({"error": str(ex)}), 400
|
return jsonify({"error": str(ex)}), 400
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/api/alpha/comment/report', methods=['POST'])
|
||||||
|
def post_alpha_comment_report():
|
||||||
|
if not current_app.debug:
|
||||||
|
return jsonify({'error': 'alpha api routes only available in debug mode'})
|
||||||
|
try:
|
||||||
|
auth = request.headers.get('Authorization')
|
||||||
|
data = request.get_json(force=True) or {}
|
||||||
|
return jsonify(post_reply_report(auth, data))
|
||||||
|
except Exception as ex:
|
||||||
|
return jsonify({"error": str(ex)}), 400
|
||||||
|
|
||||||
|
|
||||||
# User
|
# User
|
||||||
@bp.route('/api/alpha/user', methods=['GET'])
|
@bp.route('/api/alpha/user', methods=['GET'])
|
||||||
def get_alpha_user():
|
def get_alpha_user():
|
||||||
|
@ -325,7 +337,6 @@ def alpha_post():
|
||||||
@bp.route('/api/alpha/comment/remove', methods=['POST'])
|
@bp.route('/api/alpha/comment/remove', methods=['POST'])
|
||||||
@bp.route('/api/alpha/comment/mark_as_read', methods=['POST'])
|
@bp.route('/api/alpha/comment/mark_as_read', methods=['POST'])
|
||||||
@bp.route('/api/alpha/comment/distinguish', methods=['POST'])
|
@bp.route('/api/alpha/comment/distinguish', methods=['POST'])
|
||||||
@bp.route('/api/alpha/comment/report', methods=['POST'])
|
|
||||||
@bp.route('/api/alpha/comment/report/resolve', methods=['PUT'])
|
@bp.route('/api/alpha/comment/report/resolve', methods=['PUT'])
|
||||||
@bp.route('/api/alpha/comment/report/list', methods=['GET'])
|
@bp.route('/api/alpha/comment/report/list', methods=['GET'])
|
||||||
def alpha_reply():
|
def alpha_reply():
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from app.api.alpha.utils.site import get_site, post_site_block
|
from app.api.alpha.utils.site import get_site, post_site_block
|
||||||
from app.api.alpha.utils.misc import get_search
|
from app.api.alpha.utils.misc import get_search
|
||||||
from app.api.alpha.utils.post import get_post_list, get_post, post_post_like, put_post_save, put_post_subscribe
|
from app.api.alpha.utils.post import get_post_list, get_post, post_post_like, put_post_save, put_post_subscribe
|
||||||
from app.api.alpha.utils.reply import get_reply_list, post_reply_like, put_reply_save, put_reply_subscribe, post_reply, put_reply, post_reply_delete
|
from app.api.alpha.utils.reply import get_reply_list, post_reply_like, put_reply_save, put_reply_subscribe, post_reply, put_reply, post_reply_delete, post_reply_report
|
||||||
from app.api.alpha.utils.community import get_community, get_community_list, post_community_follow, post_community_block
|
from app.api.alpha.utils.community import get_community, get_community_list, post_community_follow, post_community_block
|
||||||
from app.api.alpha.utils.user import get_user, post_user_block
|
from app.api.alpha.utils.user import get_user, post_user_block
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
from app import cache
|
from app import cache
|
||||||
from app.api.alpha.utils.validators import required, integer_expected, boolean_expected, string_expected
|
from app.api.alpha.utils.validators import required, integer_expected, boolean_expected, string_expected
|
||||||
from app.api.alpha.views import reply_view
|
from app.api.alpha.views import reply_view, reply_report_view
|
||||||
from app.models import PostReply, Post
|
from app.models import PostReply, Post
|
||||||
from app.shared.reply import vote_for_reply, bookmark_the_post_reply, remove_the_bookmark_from_post_reply, toggle_post_reply_notification, make_reply, edit_reply, \
|
from app.shared.reply import vote_for_reply, bookmark_the_post_reply, remove_the_bookmark_from_post_reply, toggle_post_reply_notification, make_reply, edit_reply, \
|
||||||
delete_reply, restore_reply
|
delete_reply, restore_reply, report_reply
|
||||||
from app.utils import authorise_api_user, blocked_users, blocked_instances
|
from app.utils import authorise_api_user, blocked_users, blocked_instances
|
||||||
|
|
||||||
from sqlalchemy import desc
|
from sqlalchemy import desc
|
||||||
|
@ -182,4 +182,18 @@ def post_reply_delete(auth, data):
|
||||||
reply_json = reply_view(reply=reply, variant=4, user_id=user_id)
|
reply_json = reply_view(reply=reply, variant=4, user_id=user_id)
|
||||||
return reply_json
|
return reply_json
|
||||||
|
|
||||||
return {}
|
|
||||||
|
def post_reply_report(auth, data):
|
||||||
|
required(['comment_id', 'reason'], data)
|
||||||
|
integer_expected(['comment_id'], data)
|
||||||
|
string_expected(['reason'], data)
|
||||||
|
|
||||||
|
reply_id = data['comment_id']
|
||||||
|
reason = data['reason']
|
||||||
|
input = {'reason': reason, 'description': '', 'report_remote': True}
|
||||||
|
|
||||||
|
user_id, report = report_reply(reply_id, input, SRC_API, auth)
|
||||||
|
|
||||||
|
reply_json = reply_report_view(report=report, reply_id=reply_id, user_id=user_id)
|
||||||
|
return reply_json
|
||||||
|
|
||||||
|
|
|
@ -338,6 +338,48 @@ def reply_view(reply: PostReply | int, variant, user_id=None, my_vote=0):
|
||||||
return v4
|
return v4
|
||||||
|
|
||||||
|
|
||||||
|
def reply_report_view(report, reply_id, user_id):
|
||||||
|
# views/comment_report_view.dart - /comment/report api endpoint
|
||||||
|
reply_json = reply_view(reply=reply_id, variant=2, user_id=user_id)
|
||||||
|
post_json = post_view(post=reply_json['comment']['post_id'], variant=1, stub=True)
|
||||||
|
community_json = community_view(community=post_json['community_id'], variant=1, stub=True)
|
||||||
|
|
||||||
|
banned = db.session.execute(text('SELECT user_id FROM "community_ban" WHERE user_id = :user_id and community_id = :community_id'), {'user_id': report.reporter_id, 'community_id': community_json['id']}).scalar()
|
||||||
|
moderator = db.session.execute(text('SELECT is_moderator FROM "community_member" WHERE user_id = :user_id and community_id = :community_id'), {'user_id': report.reporter_id, 'community_id': community_json['id']}).scalar()
|
||||||
|
admin = db.session.execute(text('SELECT user_id FROM "user_role" WHERE user_id = :user_id and role_id = 4'), {'user_id': report.reporter_id}).scalar()
|
||||||
|
|
||||||
|
creator_banned_from_community = True if banned else False
|
||||||
|
creator_is_moderator = True if moderator else False
|
||||||
|
creator_is_admin = True if admin else False
|
||||||
|
|
||||||
|
v1 = {
|
||||||
|
'comment_report_view': {
|
||||||
|
'comment_report': {
|
||||||
|
'id': report.id,
|
||||||
|
'creator_id': report.reporter_id,
|
||||||
|
'comment_id': report.suspect_post_reply_id,
|
||||||
|
'original_comment_text': reply_json['comment']['body'],
|
||||||
|
'reason': report.reasons,
|
||||||
|
'resolved': report.status == 3,
|
||||||
|
'published': report.created_at.isoformat() + 'Z'
|
||||||
|
},
|
||||||
|
'comment': reply_json['comment'],
|
||||||
|
'post': post_json,
|
||||||
|
'community': community_json,
|
||||||
|
'creator': user_view(user=user_id, variant=1, stub=True),
|
||||||
|
'comment_creator': user_view(user=report.suspect_user_id, variant=1, stub=True),
|
||||||
|
'counts': reply_json['counts'],
|
||||||
|
'creator_banned_from_community': creator_banned_from_community,
|
||||||
|
'creator_is_moderator': creator_is_moderator,
|
||||||
|
'creator_is_admin': creator_is_admin,
|
||||||
|
'creator_blocked': False,
|
||||||
|
'subscribed': reply_json['subscribed'],
|
||||||
|
'saved': reply_json['saved']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v1
|
||||||
|
|
||||||
|
|
||||||
def search_view(type):
|
def search_view(type):
|
||||||
v1 = {
|
v1 = {
|
||||||
'type_': type,
|
'type_': type,
|
||||||
|
|
|
@ -2,7 +2,7 @@ from app import cache, db
|
||||||
from app.activitypub.signature import default_context, post_request_in_background, post_request
|
from app.activitypub.signature import default_context, post_request_in_background, post_request
|
||||||
from app.community.util import send_to_remote_instance
|
from app.community.util import send_to_remote_instance
|
||||||
from app.constants import *
|
from app.constants import *
|
||||||
from app.models import NotificationSubscription, Post, PostReply, PostReplyBookmark, User, utcnow
|
from app.models import Instance, Notification, NotificationSubscription, Post, PostReply, PostReplyBookmark, Report, Site, User, utcnow
|
||||||
from app.utils import gibberish, instance_banned, render_template, authorise_api_user, recently_upvoted_post_replies, recently_downvoted_post_replies, shorten_string, \
|
from app.utils import gibberish, instance_banned, render_template, authorise_api_user, recently_upvoted_post_replies, recently_downvoted_post_replies, shorten_string, \
|
||||||
piefed_markdown_to_lemmy_markdown, markdown_to_html, ap_datetime
|
piefed_markdown_to_lemmy_markdown, markdown_to_html, ap_datetime
|
||||||
|
|
||||||
|
@ -642,3 +642,77 @@ def restore_reply(reply_id, src, auth):
|
||||||
return user.id, reply
|
return user.id, reply
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def report_reply(reply_id, input, src, auth=None):
|
||||||
|
if src == SRC_API:
|
||||||
|
reply = PostReply.query.filter_by(id=reply_id).one()
|
||||||
|
user = authorise_api_user(auth, return_type='model')
|
||||||
|
reason = input['reason']
|
||||||
|
description = input['description']
|
||||||
|
report_remote = input['report_remote']
|
||||||
|
else:
|
||||||
|
reply = PostReply.query.get_or_404(reply_id)
|
||||||
|
user = current_user
|
||||||
|
reason = input.reasons_to_string(input.reasons.data)
|
||||||
|
description = input.description.data
|
||||||
|
report_remote = input.report_remote.data
|
||||||
|
|
||||||
|
if reply.reports == -1: # When a mod decides to ignore future reports, reply.reports is set to -1
|
||||||
|
if src == SRC_API:
|
||||||
|
raise Exception('already_reported')
|
||||||
|
else:
|
||||||
|
flash(_('Comment has already been reported, thank you!'))
|
||||||
|
return
|
||||||
|
|
||||||
|
report = Report(reasons=reason, description=description, type=2, reporter_id=user.id, suspect_post_id=reply.post.id, suspect_community_id=reply.community.id,
|
||||||
|
suspect_user_id=reply.author.id, suspect_post_reply_id=reply.id, in_community_id=reply.community.id, source_instance_id=1)
|
||||||
|
db.session.add(report)
|
||||||
|
|
||||||
|
# Notify moderators
|
||||||
|
already_notified = set()
|
||||||
|
for mod in reply.community.moderators():
|
||||||
|
moderator = User.query.get(mod.user_id)
|
||||||
|
if moderator and moderator.is_local():
|
||||||
|
notification = Notification(user_id=mod.user_id, title=_('A comment has been reported'),
|
||||||
|
url=f"https://{current_app.config['SERVER_NAME']}/comment/{reply.id}",
|
||||||
|
author_id=user.id)
|
||||||
|
db.session.add(notification)
|
||||||
|
already_notified.add(mod.user_id)
|
||||||
|
reply.reports += 1
|
||||||
|
# todo: only notify admins for certain types of report
|
||||||
|
for admin in Site.admins():
|
||||||
|
if admin.id not in already_notified:
|
||||||
|
notify = Notification(title='Suspicious content', url='/admin/reports', user_id=admin.id, author_id=user.id)
|
||||||
|
db.session.add(notify)
|
||||||
|
admin.unread_notifications += 1
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
# federate report to originating instance
|
||||||
|
if not reply.community.is_local() and report_remote:
|
||||||
|
summary = reason
|
||||||
|
if description:
|
||||||
|
summary += ' - ' + description
|
||||||
|
report_json = {
|
||||||
|
'actor': user.public_url(),
|
||||||
|
'audience': reply.community.public_url(),
|
||||||
|
'content': None,
|
||||||
|
'id': f"https://{current_app.config['SERVER_NAME']}/activities/flag/{gibberish(15)}",
|
||||||
|
'object': reply.ap_id,
|
||||||
|
'summary': summary,
|
||||||
|
'to': [
|
||||||
|
reply.community.public_url()
|
||||||
|
],
|
||||||
|
'type': 'Flag'
|
||||||
|
}
|
||||||
|
instance = Instance.query.get(reply.community.instance_id)
|
||||||
|
if reply.community.ap_inbox_url and not user.has_blocked_instance(instance.id) and not instance_banned(instance.domain):
|
||||||
|
success = post_request(reply.community.ap_inbox_url, report_json, user.private_key, user.public_url() + '#main-key')
|
||||||
|
if success is False or isinstance(success, str):
|
||||||
|
if src == SRC_WEB:
|
||||||
|
flash('Failed to send report to remote server', 'error')
|
||||||
|
|
||||||
|
if src == SRC_API:
|
||||||
|
return user.id, report
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
Loading…
Add table
Reference in a new issue