mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-23 19:36:56 -08:00
Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
bcbb9f83e9
24 changed files with 348 additions and 188 deletions
|
@ -206,17 +206,18 @@ def lemmy_federated_instances():
|
|||
linked = []
|
||||
allowed = []
|
||||
blocked = []
|
||||
for instance in AllowedInstances.query.all():
|
||||
allowed.append({"id": instance.id, "domain": instance.domain, "published": utcnow(), "updated": utcnow()})
|
||||
for instance in BannedInstances.query.all():
|
||||
blocked.append({"id": instance.id, "domain": instance.domain, "published": utcnow(), "updated": utcnow()})
|
||||
for instance in instances:
|
||||
instance_data = {"id": instance.id, "domain": instance.domain, "published": instance.created_at.isoformat(), "updated": instance.updated_at.isoformat()}
|
||||
if instance.software:
|
||||
instance_data['software'] = instance.software
|
||||
if instance.version:
|
||||
instance_data['version'] = instance.version
|
||||
linked.append(instance_data)
|
||||
for instance in AllowedInstances.query.all():
|
||||
allowed.append({"id": instance.id, "domain": instance.domain, "published": utcnow(), "updated": utcnow()})
|
||||
for instance in BannedInstances.query.all():
|
||||
blocked.append({"id": instance.id, "domain": instance.domain, "published": utcnow(), "updated": utcnow()})
|
||||
if not any(blocked_instance.get('domain') == instance.domain for blocked_instance in blocked):
|
||||
linked.append(instance_data)
|
||||
return jsonify({
|
||||
"federated_instances": {
|
||||
"linked": linked,
|
||||
|
@ -619,6 +620,7 @@ def process_inbox_request(request_json, activitypublog_id, ip_address):
|
|||
post = create_post(activity_log, community, request_json, user)
|
||||
if post:
|
||||
announce_activity_to_followers(community, user, request_json)
|
||||
activity_log.result = 'success'
|
||||
except TypeError as e:
|
||||
activity_log.exception_message = 'TypeError. See log file.'
|
||||
current_app.logger.error('TypeError: ' + str(request_json))
|
||||
|
@ -1081,17 +1083,16 @@ def process_inbox_request(request_json, activitypublog_id, ip_address):
|
|||
activity_log.result = 'success'
|
||||
elif request_json['object']['type'] == 'Delete': # undoing a delete
|
||||
activity_log.activity_type = 'Restore'
|
||||
reply = PostReply.query.filter_by(ap_id=request_json['object']['object']).first()
|
||||
if reply:
|
||||
post = Post.query.filter_by(ap_id=request_json['object']['object']).first()
|
||||
if post:
|
||||
deletor = find_actor_or_create(request_json['object']['actor'], create_if_not_found=False)
|
||||
if deletor:
|
||||
if reply.author.id == deletor.id or reply.community.is_moderator(deletor) or reply.community.is_instance_admin(deletor):
|
||||
reply.deleted = False
|
||||
reply.deleted_by = None
|
||||
if not reply.author.bot:
|
||||
reply.post.reply_count += 1
|
||||
reply.author.post_reply_count += 1
|
||||
announce_activity_to_followers(reply.community, reply.author, request_json)
|
||||
if post.author.id == deletor.id or post.community.is_moderator(deletor) or post.community.is_instance_admin(deletor):
|
||||
post.deleted = False
|
||||
post.deleted_by = None
|
||||
post.author.post_count += 1
|
||||
post.community.post_count += 1
|
||||
announce_activity_to_followers(post.community, post.author, request_json)
|
||||
db.session.commit()
|
||||
activity_log.result = 'success'
|
||||
else:
|
||||
|
@ -1099,7 +1100,25 @@ def process_inbox_request(request_json, activitypublog_id, ip_address):
|
|||
else:
|
||||
activity_log.exception_message = 'Restorer did not already exist'
|
||||
else:
|
||||
activity_log.exception_message = 'Reply not found, or object was not a reply'
|
||||
reply = PostReply.query.filter_by(ap_id=request_json['object']['object']).first()
|
||||
if reply:
|
||||
deletor = find_actor_or_create(request_json['object']['actor'], create_if_not_found=False)
|
||||
if deletor:
|
||||
if reply.author.id == deletor.id or reply.community.is_moderator(deletor) or reply.community.is_instance_admin(deletor):
|
||||
reply.deleted = False
|
||||
reply.deleted_by = None
|
||||
if not reply.author.bot:
|
||||
reply.post.reply_count += 1
|
||||
reply.author.post_reply_count += 1
|
||||
announce_activity_to_followers(reply.community, reply.author, request_json)
|
||||
db.session.commit()
|
||||
activity_log.result = 'success'
|
||||
else:
|
||||
activity_log.exception_message = 'Restore attempt denied'
|
||||
else:
|
||||
activity_log.exception_message = 'Restorer did not already exist'
|
||||
else:
|
||||
activity_log.exception_message = 'Object not found, or object was not a post or a reply'
|
||||
elif request_json['type'] == 'Delete':
|
||||
if isinstance(request_json['object'], str):
|
||||
ap_id = request_json['object'] # lemmy
|
||||
|
@ -1108,21 +1127,26 @@ def process_inbox_request(request_json, activitypublog_id, ip_address):
|
|||
post = Post.query.filter_by(ap_id=ap_id).first()
|
||||
# Delete post
|
||||
if post:
|
||||
if can_delete(request_json['actor'], post):
|
||||
if post.url and post.cross_posts is not None:
|
||||
old_cross_posts = Post.query.filter(Post.id.in_(post.cross_posts)).all()
|
||||
post.cross_posts.clear()
|
||||
for ocp in old_cross_posts:
|
||||
if ocp.cross_posts is not None:
|
||||
ocp.cross_posts.remove(post.id)
|
||||
post.delete_dependencies()
|
||||
announce_activity_to_followers(post.community, post.author, request_json)
|
||||
post.deleted = True
|
||||
post.author.post_count -= 1
|
||||
db.session.commit()
|
||||
activity_log.result = 'success'
|
||||
deletor = find_actor_or_create(request_json['actor'], create_if_not_found=False)
|
||||
if deletor:
|
||||
if post.author.id == deletor.id or post.community.is_moderator(deletor) or post.community.is_instance_admin(deletor):
|
||||
post.deleted = True
|
||||
post.delted_by = deletor.id
|
||||
post.author.post_count -= 1
|
||||
post.community.post_count -= 1
|
||||
if post.url and post.cross_posts is not None:
|
||||
old_cross_posts = Post.query.filter(Post.id.in_(post.cross_posts)).all()
|
||||
post.cross_posts.clear()
|
||||
for ocp in old_cross_posts:
|
||||
if ocp.cross_posts is not None:
|
||||
ocp.cross_posts.remove(post.id)
|
||||
announce_activity_to_followers(post.community, post.author, request_json)
|
||||
db.session.commit()
|
||||
activity_log.result = 'success'
|
||||
else:
|
||||
activity_log.exception_message = 'Delete attempt denied'
|
||||
else:
|
||||
activity_log.exception_message = 'Delete attempt denied'
|
||||
activity_log.exception_message = 'Deletor did not already exist'
|
||||
else:
|
||||
# Delete PostReply
|
||||
reply = PostReply.query.filter_by(ap_id=ap_id).first()
|
||||
|
|
|
@ -1323,24 +1323,22 @@ def delete_post_or_comment_task(user_ap_id, community_ap_id, to_be_deleted_ap_id
|
|||
return
|
||||
|
||||
if deletor and community and to_delete:
|
||||
if deletor.is_admin() or community.is_moderator(deletor) or community.is_instance_admin(deletor) or to_delete.author.id == deletor.id:
|
||||
if to_delete.author.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.delete_dependencies()
|
||||
to_delete.deleted = True
|
||||
to_delete.deleted_by = deletor.id
|
||||
community.post_count -= 1
|
||||
to_delete.author.post_count -= 1
|
||||
to_delete.deleted_by = deletor.id
|
||||
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}')
|
||||
elif isinstance(to_delete, PostReply):
|
||||
if not to_delete.author.bot:
|
||||
to_delete.post.reply_count -= 1
|
||||
to_delete.deleted = True
|
||||
to_delete.deleted_by = deletor.id
|
||||
to_delete.author.post_reply_count -= 1
|
||||
to_delete.deleted_by = deletor.id
|
||||
if not to_delete.author.bot:
|
||||
to_delete.post.reply_count -= 1
|
||||
db.session.commit()
|
||||
if to_delete.author.id != deletor.id:
|
||||
add_to_modlog_activitypub('delete_post_reply', deletor, community_id=community.id,
|
||||
|
@ -1383,7 +1381,6 @@ def restore_post_or_comment_task(object_json, aplog_id):
|
|||
if restorer and community and to_restore:
|
||||
if to_restore.author.id == restorer.id or restorer.is_admin() or community.is_moderator(restorer) or community.is_instance_admin(restorer):
|
||||
if isinstance(to_restore, Post):
|
||||
# TODO: restore_dependencies()
|
||||
to_restore.deleted = False
|
||||
to_restore.deleted_by = None
|
||||
community.post_count += 1
|
||||
|
|
|
@ -2,7 +2,7 @@ from app.api.alpha import bp
|
|||
from app.api.alpha.utils import get_site, post_site_block, \
|
||||
get_search, \
|
||||
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_user, post_user_block
|
||||
from app.shared.auth import log_user_in
|
||||
|
@ -242,6 +242,18 @@ def post_alpha_comment_delete():
|
|||
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
|
||||
@bp.route('/api/alpha/user', methods=['GET'])
|
||||
def get_alpha_user():
|
||||
|
@ -325,7 +337,6 @@ def alpha_post():
|
|||
@bp.route('/api/alpha/comment/remove', 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/report', methods=['POST'])
|
||||
@bp.route('/api/alpha/comment/report/resolve', methods=['PUT'])
|
||||
@bp.route('/api/alpha/comment/report/list', methods=['GET'])
|
||||
def alpha_reply():
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
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.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.user import get_user, post_user_block
|
||||
|
||||
|
|
|
@ -17,15 +17,11 @@ def cached_community_list(type, user_id):
|
|||
else:
|
||||
communities = Community.query.filter_by(banned=False)
|
||||
|
||||
print(len(communities.all()))
|
||||
|
||||
if user_id is not None:
|
||||
blocked_instance_ids = blocked_instances(user_id)
|
||||
if blocked_instance_ids:
|
||||
communities = communities.filter(Community.instance_id.not_in(blocked_instance_ids))
|
||||
|
||||
print(len(communities.all()))
|
||||
|
||||
return communities.all()
|
||||
|
||||
|
||||
|
|
|
@ -98,10 +98,7 @@ def get_post(auth, data):
|
|||
user_id = authorise_api_user(auth) if auth else None
|
||||
|
||||
post_json = post_view(post=id, variant=3, user_id=user_id)
|
||||
if post_json:
|
||||
return post_json
|
||||
else:
|
||||
raise Exception('post_not_found')
|
||||
return post_json
|
||||
|
||||
|
||||
# would be in app/constants.py
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
from app import cache
|
||||
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.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 sqlalchemy import desc
|
||||
|
@ -131,9 +131,7 @@ def post_reply(auth, data):
|
|||
language_id = 2 # FIXME: use site language
|
||||
|
||||
input = {'body': body, 'notify_author': True, 'language_id': language_id}
|
||||
post = Post.query.get(post_id)
|
||||
if not post:
|
||||
raise Exception('parent_not_found')
|
||||
post = Post.query.filter_by(id=post_id).one()
|
||||
|
||||
user_id, reply = make_reply(input, post, parent_id, SRC_API, auth)
|
||||
|
||||
|
@ -153,12 +151,8 @@ def put_reply(auth, data):
|
|||
language_id = 2 # FIXME: use site language
|
||||
|
||||
input = {'body': body, 'notify_author': True, 'language_id': language_id}
|
||||
reply = PostReply.query.get(reply_id)
|
||||
if not reply:
|
||||
raise Exception('reply_not_found')
|
||||
post = Post.query.get(reply.post_id)
|
||||
if not post:
|
||||
raise Exception('post_not_found')
|
||||
reply = PostReply.query.filter_by(id=reply_id).one()
|
||||
post = Post.query.filter_by(id=reply.post_id).one()
|
||||
|
||||
user_id, reply = edit_reply(input, reply, post, SRC_API, auth)
|
||||
|
||||
|
@ -182,4 +176,18 @@ def post_reply_delete(auth, data):
|
|||
reply_json = reply_view(reply=reply, variant=4, user_id=user_id)
|
||||
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
|
||||
|
||||
|
|
|
@ -12,9 +12,7 @@ from sqlalchemy import text
|
|||
|
||||
def post_view(post: Post | int, variant, stub=False, user_id=None, my_vote=0):
|
||||
if isinstance(post, int):
|
||||
post = Post.query.get(post)
|
||||
if not post or post.deleted:
|
||||
raise Exception('post_not_found')
|
||||
post = Post.query.filter_by(id=post, deleted=False).one()
|
||||
|
||||
# Variant 1 - models/post/post.dart
|
||||
if variant == 1:
|
||||
|
@ -133,9 +131,7 @@ def cached_user_view_variant_1(user: User, stub=False):
|
|||
# 'user' param can be anyone (including the logged in user), 'user_id' param belongs to the user making the request
|
||||
def user_view(user: User | int, variant, stub=False, user_id=None):
|
||||
if isinstance(user, int):
|
||||
user = User.query.get(user)
|
||||
if not user:
|
||||
raise Exception('user_not_found')
|
||||
user = User.query.filter_by(id=user).one()
|
||||
|
||||
# Variant 1 - models/person/person.dart
|
||||
if variant == 1:
|
||||
|
@ -190,12 +186,10 @@ def cached_community_view_variant_1(community: Community, stub=False):
|
|||
|
||||
def community_view(community: Community | int | str, variant, stub=False, user_id=None):
|
||||
if isinstance(community, int):
|
||||
community = Community.query.get(community)
|
||||
community = Community.query.filter_by(id=community).one()
|
||||
elif isinstance(community, str):
|
||||
name, ap_domain = community.split('@')
|
||||
community = Community.query.filter_by(name=name, ap_domain=ap_domain).first()
|
||||
if not community:
|
||||
raise Exception('community_not_found')
|
||||
community = Community.query.filter_by(name=name, ap_domain=ap_domain).one()
|
||||
|
||||
# Variant 1 - models/community/community.dart
|
||||
if variant == 1:
|
||||
|
@ -269,9 +263,7 @@ def calculate_if_has_children(reply): # result used as True / False
|
|||
|
||||
def reply_view(reply: PostReply | int, variant, user_id=None, my_vote=0):
|
||||
if isinstance(reply, int):
|
||||
reply = PostReply.query.get(reply)
|
||||
if not reply:
|
||||
raise Exception('reply_not_found')
|
||||
reply = PostReply.query.filter_by(id=reply).one()
|
||||
|
||||
# Variant 1 - models/comment/comment.dart
|
||||
if variant == 1:
|
||||
|
@ -338,6 +330,48 @@ def reply_view(reply: PostReply | int, variant, user_id=None, my_vote=0):
|
|||
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):
|
||||
v1 = {
|
||||
'type_': type,
|
||||
|
@ -351,9 +385,7 @@ def search_view(type):
|
|||
|
||||
def instance_view(instance: Instance | int, variant):
|
||||
if isinstance(instance, int):
|
||||
instance = Instance.query.get(instance)
|
||||
if not instance:
|
||||
raise Exception('instance_not_found')
|
||||
instance = Instance.query.filter_by(id=instance).one()
|
||||
|
||||
if variant == 1:
|
||||
include = ['id', 'domain', 'software', 'version']
|
||||
|
|
|
@ -527,8 +527,8 @@ def delete_post_from_community(post_id):
|
|||
def delete_post_from_community_task(post_id):
|
||||
post = Post.query.get(post_id)
|
||||
community = post.community
|
||||
post.delete_dependencies()
|
||||
post.deleted = True
|
||||
post.deleted_by = current_user.id
|
||||
db.session.commit()
|
||||
|
||||
if not community.local_only:
|
||||
|
|
|
@ -1041,11 +1041,8 @@ class User(UserMixin, db.Model):
|
|||
{'user_id': self.id, 'type': NOTIF_USER}).scalars())
|
||||
|
||||
def encode_jwt_token(self):
|
||||
try:
|
||||
payload = {'sub': str(self.id), 'iss': current_app.config['SERVER_NAME'], 'iat': int(time())}
|
||||
return jwt.encode(payload, current_app.config['SECRET_KEY'], algorithm='HS256')
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
payload = {'sub': str(self.id), 'iss': current_app.config['SERVER_NAME'], 'iat': int(time())}
|
||||
return jwt.encode(payload, current_app.config['SECRET_KEY'], algorithm='HS256')
|
||||
|
||||
# mark a post as 'read' for this user
|
||||
def mark_post_as_read(self, post):
|
||||
|
@ -1377,10 +1374,19 @@ class Post(db.Model):
|
|||
db.session.query(PollChoice).filter(PollChoice.post_id == self.id).delete()
|
||||
db.session.query(Poll).filter(Poll.post_id == self.id).delete()
|
||||
db.session.query(Report).filter(Report.suspect_post_id == self.id).delete()
|
||||
db.session.execute(text('DELETE FROM "post_reply_vote" WHERE post_reply_id IN (SELECT id FROM post_reply WHERE post_id = :post_id)'),
|
||||
{'post_id': self.id})
|
||||
db.session.execute(text('DELETE FROM "post_reply" WHERE post_id = :post_id'), {'post_id': self.id})
|
||||
db.session.execute(text('DELETE FROM "post_vote" WHERE post_id = :post_id'), {'post_id': self.id})
|
||||
|
||||
reply_ids = db.session.execute(text('SELECT id FROM "post_reply" WHERE post_id = :post_id'), {'post_id': self.id}).scalars()
|
||||
reply_ids = tuple(reply_ids)
|
||||
if reply_ids:
|
||||
db.session.execute(text('DELETE FROM "post_reply_vote" WHERE post_reply_id IN :reply_ids'), {'reply_ids': reply_ids})
|
||||
db.session.execute(text('DELETE FROM "post_reply_bookmark" WHERE post_reply_id IN :reply_ids'), {'reply_ids': reply_ids})
|
||||
db.session.execute(text('DELETE FROM "report" WHERE suspect_post_reply_id IN :reply_ids'), {'reply_ids': reply_ids})
|
||||
db.session.execute(text('DELETE FROM "post_reply" WHERE post_id = :post_id'), {'post_id': self.id})
|
||||
|
||||
self.community.post_reply_count = db.session.execute(text('SELECT COUNT(id) as c FROM "post_reply" WHERE community_id = :community_id AND deleted = false'),
|
||||
{'community_id': self.community_id}).scalar()
|
||||
|
||||
if self.image_id:
|
||||
file = File.query.get(self.image_id)
|
||||
file.delete_from_disk()
|
||||
|
|
|
@ -670,14 +670,18 @@ def add_reply(post_id: int, comment_id: int):
|
|||
@bp.route('/post/<int:post_id>/options', methods=['GET'])
|
||||
def post_options(post_id: int):
|
||||
post = Post.query.get_or_404(post_id)
|
||||
if current_user.is_anonymous or not current_user.is_admin():
|
||||
if post.deleted:
|
||||
if post.deleted:
|
||||
if current_user.is_anonymous:
|
||||
abort(404)
|
||||
if (not post.community.is_moderator() and
|
||||
not current_user.is_admin() and
|
||||
(post.deleted_by is not None and post.deleted_by != current_user.id)):
|
||||
abort(401)
|
||||
|
||||
existing_bookmark = []
|
||||
if current_user.is_authenticated:
|
||||
existing_bookmark = PostBookmark.query.filter(PostBookmark.post_id == post_id, PostBookmark.user_id == current_user.id).first()
|
||||
|
||||
|
||||
return render_template('post/post_options.html', post=post, existing_bookmark=existing_bookmark,
|
||||
moderating_communities=moderating_communities(current_user.get_id()),
|
||||
joined_communities=joined_communities(current_user.get_id()),
|
||||
|
@ -1025,7 +1029,6 @@ def post_delete_post(community: Community, post: Post, user_id: int, federate_al
|
|||
for ocp in old_cross_posts:
|
||||
if ocp.cross_posts is not None and post.id in ocp.cross_posts:
|
||||
ocp.cross_posts.remove(post.id)
|
||||
post.delete_dependencies()
|
||||
post.deleted = True
|
||||
post.deleted_by = user_id
|
||||
post.author.post_count -= 1
|
||||
|
@ -1093,14 +1096,19 @@ def post_delete_post(community: Community, post: Post, user_id: int, federate_al
|
|||
@login_required
|
||||
def post_restore(post_id: int):
|
||||
post = Post.query.get_or_404(post_id)
|
||||
if post.community.is_moderator() or post.community.is_owner() or current_user.is_admin():
|
||||
if post.user_id == current_user.id or post.community.is_moderator() or post.community.is_owner() or current_user.is_admin():
|
||||
if post.deleted_by == post.user_id:
|
||||
was_mod_deletion = False
|
||||
else:
|
||||
was_mod_deletion = True
|
||||
post.deleted = False
|
||||
post.deleted_by = None
|
||||
post.author.post_count += 1
|
||||
post.community.post_count += 1
|
||||
db.session.commit()
|
||||
|
||||
# Federate un-delete
|
||||
if post.is_local():
|
||||
if not post.community.local_only:
|
||||
delete_json = {
|
||||
"actor": current_user.public_url(),
|
||||
"to": ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
|
@ -1116,31 +1124,40 @@ def post_restore(post_id: int):
|
|||
],
|
||||
'object': post.ap_id,
|
||||
'uri': post.ap_id,
|
||||
"summary": "bad post",
|
||||
},
|
||||
"cc": [post.community.public_url()],
|
||||
"audience": post.author.public_url(),
|
||||
"audience": post.community.public_url(),
|
||||
"type": "Undo",
|
||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/undo/{gibberish(15)}"
|
||||
}
|
||||
if was_mod_deletion:
|
||||
delete_json['object']['summary'] = "Deleted by mod"
|
||||
|
||||
announce = {
|
||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/announce/{gibberish(15)}",
|
||||
"type": 'Announce',
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"actor": post.community.public_url(),
|
||||
"cc": [
|
||||
post.community.ap_followers_url
|
||||
],
|
||||
'@context': default_context(),
|
||||
'object': delete_json
|
||||
}
|
||||
if not post.community.is_local(): # this is a remote community, send it to the instance that hosts it
|
||||
if not was_mod_deletion or (was_mod_deletion and post.community.is_moderator(current_user)):
|
||||
success = post_request(post.community.ap_inbox_url, delete_json, current_user.private_key,
|
||||
current_user.public_url() + '#main-key')
|
||||
if success is False or isinstance(success, str):
|
||||
flash('Failed to send delete to remote server', 'error')
|
||||
|
||||
for instance in post.community.following_instances():
|
||||
if instance.inbox and not current_user.has_blocked_instance(instance.id) and not instance_banned(instance.domain):
|
||||
send_to_remote_instance(instance.id, post.community.id, announce)
|
||||
else: # local community - send it to followers on remote instances
|
||||
announce = {
|
||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/announce/{gibberish(15)}",
|
||||
"type": 'Announce',
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"actor": post.community.public_url(),
|
||||
"cc": [
|
||||
post.community.ap_followers_url
|
||||
],
|
||||
'@context': default_context(),
|
||||
'object': delete_json
|
||||
}
|
||||
|
||||
for instance in post.community.following_instances():
|
||||
if instance.inbox and not current_user.has_blocked_instance(instance.id) and not instance_banned(instance.domain):
|
||||
send_to_remote_instance(instance.id, post.community.id, announce)
|
||||
|
||||
if post.user_id != current_user.id:
|
||||
add_to_modlog('restore_post', community_id=post.community.id, link_text=shorten_string(post.title),
|
||||
|
@ -1150,6 +1167,23 @@ def post_restore(post_id: int):
|
|||
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
||||
|
||||
|
||||
@bp.route('/post/<int:post_id>/purge', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def post_purge(post_id: int):
|
||||
post = Post.query.get_or_404(post_id)
|
||||
if not post.deleted:
|
||||
abort(404)
|
||||
if post.deleted_by == current_user.id or post.community.is_moderator() or current_user.is_admin():
|
||||
post.delete_dependencies()
|
||||
db.session.delete(post)
|
||||
db.session.commit()
|
||||
flash(_('Post purged.'))
|
||||
else:
|
||||
abort(401)
|
||||
|
||||
return redirect(url_for('user.show_profile_by_id', user_id=post.user_id))
|
||||
|
||||
|
||||
@bp.route('/post/<int:post_id>/bookmark', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def post_bookmark(post_id: int):
|
||||
|
@ -1750,9 +1784,7 @@ def post_reply_purge(post_id: int, comment_id: int):
|
|||
post_reply = PostReply.query.get_or_404(comment_id)
|
||||
if not post_reply.deleted:
|
||||
abort(404)
|
||||
if post_reply.user_id == current_user.id and (post_reply.deleted_by is None or post_reply.deleted_by != post_reply.user_id):
|
||||
abort(401)
|
||||
if post_reply.user_id == current_user.id or post.community.is_moderator() or current_user.is_admin():
|
||||
if post_reply.deleted_by == current_user.id or post.community.is_moderator() or current_user.is_admin():
|
||||
if not post_reply.has_replies():
|
||||
post_reply.delete_dependencies()
|
||||
db.session.delete(post_reply)
|
||||
|
|
|
@ -21,23 +21,21 @@ def log_user_in(input, src):
|
|||
if src == SRC_WEB:
|
||||
username = input.user_name.data
|
||||
password = input.password.data
|
||||
user = User.query.filter_by(user_name=username, ap_id=None).first()
|
||||
elif src == SRC_API:
|
||||
required(["username_or_email", "password"], input)
|
||||
string_expected(["username_or_email", "password"], input)
|
||||
|
||||
username = input['username_or_email']
|
||||
password = input['password']
|
||||
user = User.query.filter_by(user_name=username, ap_id=None, deleted=False).one()
|
||||
else:
|
||||
return None
|
||||
|
||||
user = User.query.filter_by(user_name=username, ap_id=None).first()
|
||||
|
||||
if user is None or user.deleted:
|
||||
if src == SRC_WEB:
|
||||
if src == SRC_WEB:
|
||||
if user is None or user.deleted:
|
||||
flash(_('No account exists with that user name.'), 'error')
|
||||
return redirect(url_for('auth.login'))
|
||||
elif src == SRC_API:
|
||||
raise Exception('incorrect_login')
|
||||
|
||||
if not user.check_password(password):
|
||||
if src == SRC_WEB:
|
||||
|
@ -96,13 +94,9 @@ def log_user_in(input, src):
|
|||
response.set_cookie('low_bandwidth', '0', expires=datetime(year=2099, month=12, day=30))
|
||||
return response
|
||||
elif src == SRC_API:
|
||||
token = user.encode_jwt_token()
|
||||
if token:
|
||||
login_json = {
|
||||
"jwt": token,
|
||||
"registration_created": user.verified,
|
||||
"verify_email_sent": True
|
||||
}
|
||||
return login_json
|
||||
else:
|
||||
raise Exception('could_not_generate_token')
|
||||
login_json = {
|
||||
'jwt': user.encode_jwt_token(),
|
||||
'registration_created': user.verified,
|
||||
'verify_email_sent': True
|
||||
}
|
||||
return login_json
|
||||
|
|
|
@ -17,9 +17,7 @@ SRC_API = 3
|
|||
# call from admin.federation not tested
|
||||
def join_community(community_id: int, src, auth=None, user_id=None, main_user_name=True):
|
||||
if src == SRC_API:
|
||||
community = Community.query.get(community_id)
|
||||
if not community:
|
||||
raise Exception('community_not_found')
|
||||
community = Community.query.filter_by(id=community_id).one()
|
||||
user = authorise_api_user(auth, return_type='model')
|
||||
else:
|
||||
community = Community.query.get_or_404(community_id)
|
||||
|
@ -112,9 +110,7 @@ def join_community(community_id: int, src, auth=None, user_id=None, main_user_na
|
|||
# function can be shared between WEB and API (only API calls it for now)
|
||||
def leave_community(community_id: int, src, auth=None):
|
||||
if src == SRC_API:
|
||||
community = Community.query.get(community_id)
|
||||
if not community:
|
||||
raise Exception('community_not_found')
|
||||
community = Community.query.filter_by(id=community_id).one()
|
||||
user = authorise_api_user(auth, return_type='model')
|
||||
else:
|
||||
community = Community.query.get_or_404(community_id)
|
||||
|
|
|
@ -20,9 +20,7 @@ SRC_API = 3
|
|||
|
||||
def vote_for_post(post_id: int, vote_direction, src, auth=None):
|
||||
if src == SRC_API:
|
||||
post = Post.query.get(post_id)
|
||||
if not post:
|
||||
raise Exception('post_not_found')
|
||||
post = Post.query.filter_by(id=post_id).one()
|
||||
user = authorise_api_user(auth, return_type='model')
|
||||
else:
|
||||
post = Post.query.get_or_404(post_id)
|
||||
|
@ -97,9 +95,7 @@ def vote_for_post(post_id: int, vote_direction, src, auth=None):
|
|||
# post_bookmark in app/post/routes would just need to do 'return bookmark_the_post(post_id, SRC_WEB)'
|
||||
def bookmark_the_post(post_id: int, src, auth=None):
|
||||
if src == SRC_API:
|
||||
post = Post.query.get(post_id)
|
||||
if not post or post.deleted:
|
||||
raise Exception('post_not_found')
|
||||
post = Post.query.filter_by(id=post_id, deleted=False).one()
|
||||
user_id = authorise_api_user(auth)
|
||||
else:
|
||||
post = Post.query.get_or_404(post_id)
|
||||
|
@ -127,9 +123,7 @@ def bookmark_the_post(post_id: int, src, auth=None):
|
|||
# post_remove_bookmark in app/post/routes would just need to do 'return remove_the_bookmark_from_post(post_id, SRC_WEB)'
|
||||
def remove_the_bookmark_from_post(post_id: int, src, auth=None):
|
||||
if src == SRC_API:
|
||||
post = Post.query.get(post_id)
|
||||
if not post or post.deleted:
|
||||
raise Exception('post_not_found')
|
||||
post = Post.query.filter_by(id=post_id, deleted=False).one()
|
||||
user_id = authorise_api_user(auth)
|
||||
else:
|
||||
post = Post.query.get_or_404(post_id)
|
||||
|
@ -156,9 +150,7 @@ def remove_the_bookmark_from_post(post_id: int, src, auth=None):
|
|||
def toggle_post_notification(post_id: int, src, auth=None):
|
||||
# Toggle whether the current user is subscribed to notifications about top-level replies to this post or not
|
||||
if src == SRC_API:
|
||||
post = Post.query.get(post_id)
|
||||
if not post or post.deleted:
|
||||
raise Exception('post_not_found')
|
||||
post = Post.query.filter_by(id=post_id, deleted=False).one()
|
||||
user_id = authorise_api_user(auth)
|
||||
else:
|
||||
post = Post.query.get_or_404(post_id)
|
||||
|
@ -173,10 +165,8 @@ def toggle_post_notification(post_id: int, src, auth=None):
|
|||
db.session.delete(existing_notification)
|
||||
db.session.commit()
|
||||
else: # no subscription yet, so make one
|
||||
new_notification = NotificationSubscription(name=shorten_string(_('Replies to my post %(post_title)s',
|
||||
post_title=post.title)),
|
||||
user_id=user_id, entity_id=post.id,
|
||||
type=NOTIF_POST)
|
||||
new_notification = NotificationSubscription(name=shorten_string(_('Replies to my post %(post_title)s', post_title=post.title)),
|
||||
user_id=user_id, entity_id=post.id, type=NOTIF_POST)
|
||||
db.session.add(new_notification)
|
||||
db.session.commit()
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ from app import cache, db
|
|||
from app.activitypub.signature import default_context, post_request_in_background, post_request
|
||||
from app.community.util import send_to_remote_instance
|
||||
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, \
|
||||
piefed_markdown_to_lemmy_markdown, markdown_to_html, ap_datetime
|
||||
|
||||
|
@ -21,9 +21,7 @@ SRC_API = 3
|
|||
|
||||
def vote_for_reply(reply_id: int, vote_direction, src, auth=None):
|
||||
if src == SRC_API:
|
||||
reply = PostReply.query.get(reply_id)
|
||||
if not reply:
|
||||
raise Exception('reply_not_found')
|
||||
reply = PostReply.query.filter_by(id=reply_id).one()
|
||||
user = authorise_api_user(auth, return_type='model')
|
||||
else:
|
||||
reply = PostReply.query.get_or_404(reply_id)
|
||||
|
@ -98,9 +96,7 @@ def vote_for_reply(reply_id: int, vote_direction, src, auth=None):
|
|||
# post_reply_bookmark in app/post/routes would just need to do 'return bookmark_the_post_reply(comment_id, SRC_WEB)'
|
||||
def bookmark_the_post_reply(comment_id: int, src, auth=None):
|
||||
if src == SRC_API:
|
||||
post_reply = PostReply.query.get(comment_id)
|
||||
if not post_reply or post_reply.deleted:
|
||||
raise Exception('comment_not_found')
|
||||
post_reply = PostReply.query.filter_by(id=comment_id, deleted=False).one()
|
||||
user_id = authorise_api_user(auth)
|
||||
else:
|
||||
post_reply = PostReply.query.get_or_404(comment_id)
|
||||
|
@ -129,9 +125,7 @@ def bookmark_the_post_reply(comment_id: int, src, auth=None):
|
|||
# post_reply_remove_bookmark in app/post/routes would just need to do 'return remove_the_bookmark_from_post_reply(comment_id, SRC_WEB)'
|
||||
def remove_the_bookmark_from_post_reply(comment_id: int, src, auth=None):
|
||||
if src == SRC_API:
|
||||
post_reply = PostReply.query.get(comment_id)
|
||||
if not post_reply or post_reply.deleted:
|
||||
raise Exception('comment_not_found')
|
||||
post_reply = PostReply.query.filter_by(id=comment_id, deleted=False).one()
|
||||
user_id = authorise_api_user(auth)
|
||||
else:
|
||||
post_reply = PostReply.query.get_or_404(comment_id)
|
||||
|
@ -158,9 +152,7 @@ def remove_the_bookmark_from_post_reply(comment_id: int, src, auth=None):
|
|||
def toggle_post_reply_notification(post_reply_id: int, src, auth=None):
|
||||
# Toggle whether the current user is subscribed to notifications about replies to this reply or not
|
||||
if src == SRC_API:
|
||||
post_reply = PostReply.query.get(post_reply_id)
|
||||
if not post_reply or post_reply.deleted:
|
||||
raise Exception('comment_not_found')
|
||||
post_reply = PostReply.query.filter_by(id=post_reply_id, deleted=False).one()
|
||||
user_id = authorise_api_user(auth)
|
||||
else:
|
||||
post_reply = PostReply.query.get_or_404(post_reply_id)
|
||||
|
@ -226,9 +218,7 @@ def make_reply(input, post, parent_id, src, auth=None):
|
|||
language_id = input.language_id.data
|
||||
|
||||
if parent_id:
|
||||
parent_reply = PostReply.query.get(parent_id)
|
||||
if not parent_reply:
|
||||
raise Exception('parent_reply_not_found')
|
||||
parent_reply = PostReply.query.filter_by(id=parent_id).one()
|
||||
else:
|
||||
parent_reply = None
|
||||
|
||||
|
@ -375,7 +365,7 @@ def edit_reply(input, reply, post, src, auth=None):
|
|||
flash(_('Your changes have been saved.'), 'success')
|
||||
|
||||
if reply.parent_id:
|
||||
in_reply_to = PostReply.query.get(reply.parent_id)
|
||||
in_reply_to = PostReply.query.filter_by(id=reply.parent_id).one()
|
||||
else:
|
||||
in_reply_to = post
|
||||
|
||||
|
@ -642,3 +632,77 @@ def restore_reply(reply_id, src, auth):
|
|||
return user.id, reply
|
||||
else:
|
||||
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
|
||||
|
|
|
@ -14,7 +14,11 @@
|
|||
{% if teaser -%}
|
||||
<div class="row">
|
||||
<div class="col-12 hidable">
|
||||
reply to: <a href="{{ url_for('activitypub.post_ap', post_id=post_reply.post.id, _anchor='comment_' + str(post_reply.id)) }}">{{ post_reply.post.title | truncate(80, True) }}</a>
|
||||
{% if post_reply.post.deleted: -%}
|
||||
reply to: [deleted post]
|
||||
{% else -%}
|
||||
reply to: <a href="{{ url_for('activitypub.post_ap', post_id=post_reply.post.id, _anchor='comment_' + str(post_reply.id)) }}">{{ post_reply.post.title | truncate(80, True) }}</a>
|
||||
{% endif -%}
|
||||
<span class="comment_community">in {{ render_communityname(post_reply.post.community) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -53,7 +57,11 @@
|
|||
</div>
|
||||
<div class="comment_actions hidable">
|
||||
{% if post_reply.post.comments_enabled -%}
|
||||
<a href="{{ url_for('post.add_reply', post_id=post_reply.post.id, comment_id=post_reply.id) }}" class="" rel="nofollow noindex"><span class="fe fe-reply"></span> reply</a>
|
||||
{% if not post_reply.post.deleted and not post_reply.deleted -%}
|
||||
<a href="{{ url_for('post.add_reply', post_id=post_reply.post.id, comment_id=post_reply.id) }}" class="" rel="nofollow noindex"><span class="fe fe-reply"></span> reply</a>
|
||||
{% else -%}
|
||||
<span class="fe fe-reply"></span> reply
|
||||
{% endif -%}
|
||||
{% endif -%}
|
||||
<div class="voting_buttons_new">
|
||||
{% with comment=post_reply, community=post_reply.post.community -%}
|
||||
|
@ -74,7 +82,9 @@
|
|||
{% endwith -%}
|
||||
{% endif -%}
|
||||
</div>
|
||||
<a href="{{ url_for('post.post_reply_options', post_id=post_reply.post.id, comment_id=post_reply.id) }}" class="comment_actions_link" rel="nofollow noindex" aria-label="{{ _('Comment options') }}"><span class="fe fe-options" title="Options"> </span></a>
|
||||
{% if not post_reply.post.deleted -%}
|
||||
<a href="{{ url_for('post.post_reply_options', post_id=post_reply.post.id, comment_id=post_reply.id) }}" class="comment_actions_link" rel="nofollow noindex" aria-label="{{ _('Comment options') }}"><span class="fe fe-options" title="Options"> </span></a>
|
||||
{% endif -%}
|
||||
</div>
|
||||
{% if not post_reply.author.indexable -%}<!--googleon all-->{% endif -%}
|
||||
{% if collapsed -%}
|
||||
|
|
|
@ -19,8 +19,10 @@
|
|||
{% endif -%}
|
||||
{% if post.user_id == current_user.id or post.community.is_moderator() or post.community.is_owner() or current_user.is_admin() -%}
|
||||
{% if post.deleted -%}
|
||||
<li><a href="{{ url_for('post.post_restore', post_id=post.id) }}" class="no-underline confirm_first" rel="nofollow"><span class="fe fe-delete"></span>
|
||||
<li><a href="{{ url_for('post.post_restore', post_id=post.id) }}" class="no-underline confirm_first" rel="nofollow"><span class="fe fe-arrow-up"></span>
|
||||
{{ _('Restore') }}</a></li>
|
||||
<li><a href="{{ url_for('post.post_purge', post_id=post.id) }}" class="no-underline confirm_first" rel="nofollow"><span class="fe fe-delete red"></span>
|
||||
{{ _('Purge') }}</a></li>
|
||||
{% else -%}
|
||||
<li><a href="{{ url_for('post.post_delete', post_id=post.id) }}" class="no-underline confirm_first" rel="nofollow"><span class="fe fe-delete"></span>
|
||||
{{ _('Delete') }}</a></li>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
<span class="red fe fe-report" title="{{ _('Reported. Check post for issues.') }}"></span>
|
||||
{% endif -%}
|
||||
{% if post.sticky -%}<span class="fe fe-sticky-right"></span>{% endif -%}
|
||||
{% if post.deleted -%}<span class="red fe fe-delete" title="{{ _('Post deleted') }}"></span>{% endif -%}
|
||||
</h3>
|
||||
<span class="author small">{% if show_post_community -%}<a href="/c/{{ post.community.link() }}" aria-label="{{ _('Go to community %(name)s', name=post.community.name) }}">
|
||||
{% if post.community.icon_id and not low_bandwidth %}<img class="community_icon_small rounded-circle" src="{{ post.community.icon_image('tiny') }}" alt="Community icon" />{% endif -%}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
<span class="red fe fe-report" title="{{ _('Reported. Check post for issues.') }}"></span>
|
||||
{% endif -%}
|
||||
{% if post.sticky -%}<span class="fe fe-sticky-right"></span>{% endif -%}
|
||||
{% if post.deleted -%}<span class="red fe fe-delete" title="{{ _('Post deleted') }}"></span>{% endif -%}
|
||||
</h3>
|
||||
<span class="author small">{% if show_post_community -%}<a href="/c/{{ post.community.link() }}" aria-label="{{ _('Go to community %(name)s', name=post.community.name) }}">
|
||||
{% if post.community.icon_id and not low_bandwidth %}<img class="community_icon_small rounded-circle" src="{{ post.community.icon_image('tiny') }}" alt="Community icon" />{% endif -%}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
<span class="red fe fe-report" title="{{ _('Reported. Check post for issues.') }}"></span>
|
||||
{% endif -%}
|
||||
{% if post.sticky -%}<span class="fe fe-sticky-right"></span>{% endif -%}
|
||||
{% if post.deleted -%}<span class="red fe fe-delete" title="{{ _('Post deleted') }}"></span>{% endif -%}
|
||||
</h3>
|
||||
<span class="author small">{% if show_post_community -%}<a href="/c/{{ post.community.link() }}" aria-label="{{ _('Go to community %(name)s', name=post.community.name) }}">
|
||||
{% if post.community.icon_id and not low_bandwidth %}<img class="community_icon_small rounded-circle" src="{{ post.community.icon_image('tiny') }}" alt="Community icon" />{% endif -%}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
<span class="red fe fe-report" title="{{ _('Reported. Check post for issues.') }}"></span>
|
||||
{% endif -%}
|
||||
{% if post.sticky -%}<span class="fe fe-sticky-right"></span>{% endif -%}
|
||||
{% if post.deleted -%}<span class="red fe fe-delete" title="{{ _('Post deleted') }}"></span>{% endif -%}
|
||||
</h3>
|
||||
<span class="author small">{% if show_post_community -%}<a href="/c/{{ post.community.link() }}" aria-label="{{ _('Go to community %(name)s', name=post.community.name) }}">
|
||||
{% if post.community.icon_id and not low_bandwidth %}<img class="community_icon_small rounded-circle" src="{{ post.community.icon_image('tiny') }}" alt="Community icon" />{% endif -%}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
<span class="red fe fe-report" title="{{ _('Reported. Check post for issues.') }}"></span>
|
||||
{% endif -%}
|
||||
{% if post.sticky -%}<span class="fe fe-sticky-right"></span>{% endif -%}
|
||||
{% if post.deleted -%}<span class="red fe fe-delete" title="{{ _('Post deleted') }}"></span>{% endif -%}
|
||||
</h3>
|
||||
<span class="author small">{% if show_post_community -%}<a href="/c/{{ post.community.link() }}" aria-label="{{ _('Go to community %(name)s', name=post.community.name) }}">
|
||||
{% if post.community.icon_id and not low_bandwidth %}<img class="community_icon_small rounded-circle" src="{{ post.community.icon_image('tiny') }}" alt="Community icon" />{% endif -%}
|
||||
|
|
|
@ -55,7 +55,6 @@ def show_profile(user):
|
|||
post_page = request.args.get('post_page', 1, type=int)
|
||||
replies_page = request.args.get('replies_page', 1, type=int)
|
||||
|
||||
posts = Post.query.filter_by(user_id=user.id).filter(Post.deleted == False).order_by(desc(Post.posted_at)).paginate(page=post_page, per_page=50, error_out=False)
|
||||
moderates = Community.query.filter_by(banned=False).join(CommunityMember).filter(CommunityMember.user_id == user.id)\
|
||||
.filter(or_(CommunityMember.is_moderator, CommunityMember.is_owner))
|
||||
if current_user.is_authenticated and (user.id == current_user.get_id() or current_user.is_admin()):
|
||||
|
@ -65,10 +64,13 @@ def show_profile(user):
|
|||
subscribed = Community.query.filter_by(banned=False).join(CommunityMember).filter(CommunityMember.user_id == user.id).all()
|
||||
if current_user.is_anonymous or (user.id != current_user.id and not current_user.is_admin()):
|
||||
moderates = moderates.filter(Community.private_mods == False)
|
||||
posts = Post.query.filter_by(user_id=user.id).filter(Post.deleted == False).order_by(desc(Post.posted_at)).paginate(page=post_page, per_page=50, error_out=False)
|
||||
post_replies = PostReply.query.filter_by(user_id=user.id, deleted=False).order_by(desc(PostReply.posted_at)).paginate(page=replies_page, per_page=50, error_out=False)
|
||||
elif current_user.is_admin():
|
||||
posts = Post.query.filter_by(user_id=user.id).order_by(desc(Post.posted_at)).paginate(page=post_page, per_page=50, error_out=False)
|
||||
post_replies = PostReply.query.filter_by(user_id=user.id).order_by(desc(PostReply.posted_at)).paginate(page=replies_page, per_page=50, error_out=False)
|
||||
elif current_user.id == user.id:
|
||||
posts = Post.query.filter_by(user_id=user.id).filter(or_(Post.deleted == False, Post.deleted_by == user.id)).order_by(desc(Post.posted_at)).paginate(page=post_page, per_page=50, error_out=False)
|
||||
post_replies = PostReply.query.filter_by(user_id=user.id).filter(or_(PostReply.deleted == False, PostReply.deleted_by == user.id)).order_by(desc(PostReply.posted_at)).paginate(page=replies_page, per_page=50, error_out=False)
|
||||
|
||||
# profile info
|
||||
|
|
28
app/utils.py
28
app/utils.py
|
@ -1250,23 +1250,17 @@ def authorise_api_user(auth, return_type=None, id_match=None):
|
|||
raise Exception('incorrect_login')
|
||||
token = auth[7:] # remove 'Bearer '
|
||||
|
||||
try:
|
||||
decoded = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=["HS256"])
|
||||
if decoded:
|
||||
user_id = decoded['sub']
|
||||
issued_at = decoded['iat'] # use to check against blacklisted JWTs
|
||||
user = User.query.filter_by(id=user_id, ap_id=None, verified=True, banned=False, deleted=False).scalar()
|
||||
if user:
|
||||
if id_match and user.id != id_match:
|
||||
raise Exception('incorrect_login')
|
||||
if return_type and return_type == 'model':
|
||||
return user
|
||||
else:
|
||||
return user.id
|
||||
else:
|
||||
raise Exception('incorrect_login')
|
||||
except jwt.InvalidTokenError:
|
||||
raise Exception('invalid_token')
|
||||
decoded = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=["HS256"])
|
||||
if decoded:
|
||||
user_id = decoded['sub']
|
||||
issued_at = decoded['iat'] # use to check against blacklisted JWTs
|
||||
user = User.query.filter_by(id=user_id, ap_id=None, verified=True, banned=False, deleted=False).one()
|
||||
if id_match and user.id != id_match:
|
||||
raise Exception('incorrect_login')
|
||||
if return_type and return_type == 'model':
|
||||
return user
|
||||
else:
|
||||
return user.id
|
||||
|
||||
|
||||
@cache.memoize(timeout=86400)
|
||||
|
|
Loading…
Reference in a new issue