mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-23 19:36:56 -08:00
add language choices to UI #51
This commit is contained in:
parent
29c2a05d38
commit
af4dee7ea3
24 changed files with 287 additions and 59 deletions
|
@ -21,11 +21,11 @@ from app.activitypub.util import public_key, users_total, active_half_year, acti
|
||||||
upvote_post, delete_post_or_comment, community_members, \
|
upvote_post, delete_post_or_comment, community_members, \
|
||||||
user_removed_from_remote_server, create_post, create_post_reply, update_post_reply_from_activity, \
|
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, \
|
update_post_from_activity, undo_vote, undo_downvote, post_to_page, get_redis_connection, find_reported_object, \
|
||||||
process_report, ensure_domains_match
|
process_report, ensure_domains_match, can_edit, can_delete
|
||||||
from app.utils import gibberish, get_setting, is_image_url, allowlist_html, render_template, \
|
from app.utils import gibberish, get_setting, is_image_url, allowlist_html, render_template, \
|
||||||
domain_from_url, markdown_to_html, community_membership, ap_datetime, ip_address, can_downvote, \
|
domain_from_url, markdown_to_html, community_membership, ap_datetime, ip_address, can_downvote, \
|
||||||
can_upvote, can_create_post, awaken_dormant_instance, shorten_string, can_create_post_reply, sha256_digest, \
|
can_upvote, can_create_post, awaken_dormant_instance, shorten_string, can_create_post_reply, sha256_digest, \
|
||||||
community_moderators, blocked_users
|
community_moderators
|
||||||
import werkzeug.exceptions
|
import werkzeug.exceptions
|
||||||
|
|
||||||
|
|
||||||
|
@ -933,17 +933,23 @@ def process_inbox_request(request_json, activitypublog_id, ip_address):
|
||||||
if request_json['object']['type'] == 'Page': # Editing a post
|
if request_json['object']['type'] == 'Page': # Editing a post
|
||||||
post = Post.query.filter_by(ap_id=request_json['object']['id']).first()
|
post = Post.query.filter_by(ap_id=request_json['object']['id']).first()
|
||||||
if post:
|
if post:
|
||||||
|
if can_edit(request_json['actor'], post):
|
||||||
update_post_from_activity(post, request_json)
|
update_post_from_activity(post, request_json)
|
||||||
announce_activity_to_followers(post.community, post.author, request_json)
|
announce_activity_to_followers(post.community, post.author, request_json)
|
||||||
activity_log.result = 'success'
|
activity_log.result = 'success'
|
||||||
|
else:
|
||||||
|
activity_log.exception_message = 'Edit attempt denied'
|
||||||
else:
|
else:
|
||||||
activity_log.exception_message = 'Post not found'
|
activity_log.exception_message = 'Post not found'
|
||||||
elif request_json['object']['type'] == 'Note': # Editing a reply
|
elif request_json['object']['type'] == 'Note': # Editing a reply
|
||||||
reply = PostReply.query.filter_by(ap_id=request_json['object']['id']).first()
|
reply = PostReply.query.filter_by(ap_id=request_json['object']['id']).first()
|
||||||
if reply:
|
if reply:
|
||||||
|
if can_edit(request_json['actor'], reply):
|
||||||
update_post_reply_from_activity(reply, request_json)
|
update_post_reply_from_activity(reply, request_json)
|
||||||
announce_activity_to_followers(reply.community, reply.author, request_json)
|
announce_activity_to_followers(reply.community, reply.author, request_json)
|
||||||
activity_log.result = 'success'
|
activity_log.result = 'success'
|
||||||
|
else:
|
||||||
|
activity_log.exception_message = 'Edit attempt denied'
|
||||||
else:
|
else:
|
||||||
activity_log.exception_message = 'PostReply not found'
|
activity_log.exception_message = 'PostReply not found'
|
||||||
elif request_json['type'] == 'Delete':
|
elif request_json['type'] == 'Delete':
|
||||||
|
@ -954,6 +960,7 @@ def process_inbox_request(request_json, activitypublog_id, ip_address):
|
||||||
post = Post.query.filter_by(ap_id=ap_id).first()
|
post = Post.query.filter_by(ap_id=ap_id).first()
|
||||||
# Delete post
|
# Delete post
|
||||||
if post:
|
if post:
|
||||||
|
if can_delete(request_json['actor'], post):
|
||||||
if post.url and post.cross_posts is not None:
|
if post.url and post.cross_posts is not None:
|
||||||
old_cross_posts = Post.query.filter(Post.id.in_(post.cross_posts)).all()
|
old_cross_posts = Post.query.filter(Post.id.in_(post.cross_posts)).all()
|
||||||
post.cross_posts.clear()
|
post.cross_posts.clear()
|
||||||
|
@ -966,16 +973,21 @@ def process_inbox_request(request_json, activitypublog_id, ip_address):
|
||||||
db.session.delete(post)
|
db.session.delete(post)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
activity_log.result = 'success'
|
activity_log.result = 'success'
|
||||||
|
else:
|
||||||
|
activity_log.exception_message = 'Delete attempt denied'
|
||||||
else:
|
else:
|
||||||
# Delete PostReply
|
# Delete PostReply
|
||||||
reply = PostReply.query.filter_by(ap_id=ap_id).first()
|
reply = PostReply.query.filter_by(ap_id=ap_id).first()
|
||||||
if reply:
|
if reply:
|
||||||
|
if can_delete(request_json['actor'], reply):
|
||||||
reply.body_html = '<p><em>deleted</em></p>'
|
reply.body_html = '<p><em>deleted</em></p>'
|
||||||
reply.body = 'deleted'
|
reply.body = 'deleted'
|
||||||
reply.post.reply_count -= 1
|
reply.post.reply_count -= 1
|
||||||
announce_activity_to_followers(reply.community, reply.author, request_json)
|
announce_activity_to_followers(reply.community, reply.author, request_json)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
activity_log.result = 'success'
|
activity_log.result = 'success'
|
||||||
|
else:
|
||||||
|
activity_log.exception_message = 'Delete attempt denied'
|
||||||
else:
|
else:
|
||||||
# Delete User
|
# Delete User
|
||||||
user = find_actor_or_create(ap_id, create_if_not_found=False)
|
user = find_actor_or_create(ap_id, create_if_not_found=False)
|
||||||
|
@ -1399,7 +1411,11 @@ def comment_ap(comment_id):
|
||||||
'mediaType': 'text/html',
|
'mediaType': 'text/html',
|
||||||
'published': ap_datetime(reply.created_at),
|
'published': ap_datetime(reply.created_at),
|
||||||
'distinguished': False,
|
'distinguished': False,
|
||||||
'audience': reply.community.profile_id()
|
'audience': reply.community.profile_id(),
|
||||||
|
'language': {
|
||||||
|
'identifier': reply.language_code(),
|
||||||
|
'name': reply.language_name()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if reply.edited_at:
|
if reply.edited_at:
|
||||||
reply_data['updated'] = ap_datetime(reply.edited_at)
|
reply_data['updated'] = ap_datetime(reply.edited_at)
|
||||||
|
|
|
@ -156,7 +156,11 @@ def post_to_activity(post: Post, community: Community):
|
||||||
"sensitive": post.nsfw or post.nsfl,
|
"sensitive": post.nsfw or post.nsfl,
|
||||||
"published": ap_datetime(post.created_at),
|
"published": ap_datetime(post.created_at),
|
||||||
"stickied": post.sticky,
|
"stickied": post.sticky,
|
||||||
"audience": f"https://{current_app.config['SERVER_NAME']}/c/{community.name}"
|
"audience": f"https://{current_app.config['SERVER_NAME']}/c/{community.name}",
|
||||||
|
'language': {
|
||||||
|
'identifier': post.language_code(),
|
||||||
|
'name': post.language_name()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"cc": [
|
"cc": [
|
||||||
f"https://{current_app.config['SERVER_NAME']}/c/{community.name}"
|
f"https://{current_app.config['SERVER_NAME']}/c/{community.name}"
|
||||||
|
@ -756,6 +760,11 @@ def post_json_to_model(activity_log, post_json, user, community) -> Post:
|
||||||
domain.post_count += 1
|
domain.post_count += 1
|
||||||
post.domain = domain
|
post.domain = domain
|
||||||
|
|
||||||
|
if 'language' in post_json:
|
||||||
|
language = find_language_or_create(post_json['language']['identifier'], post_json['language']['name'])
|
||||||
|
if language:
|
||||||
|
post.language_id = language.id
|
||||||
|
|
||||||
if post is not None:
|
if post is not None:
|
||||||
if 'image' in post_json and post.image is None:
|
if 'image' in post_json and post.image is None:
|
||||||
image = File(source_url=post_json['image']['url'])
|
image = File(source_url=post_json['image']['url'])
|
||||||
|
@ -1312,6 +1321,11 @@ def create_post_reply(activity_log: ActivityPubLog, community: Community, in_rep
|
||||||
elif 'content' in request_json['object']: # Kbin
|
elif 'content' in request_json['object']: # Kbin
|
||||||
post_reply.body_html = allowlist_html(request_json['object']['content'])
|
post_reply.body_html = allowlist_html(request_json['object']['content'])
|
||||||
post_reply.body = ''
|
post_reply.body = ''
|
||||||
|
if 'language' in request_json['object'] and isinstance(request_json['object']['language'], dict):
|
||||||
|
language = find_language_or_create(request_json['object']['language']['identifier'],
|
||||||
|
request_json['object']['language']['name'])
|
||||||
|
post_reply.language_id = language.id
|
||||||
|
|
||||||
if post_id is not None:
|
if post_id is not None:
|
||||||
# Discard post_reply if it contains certain phrases. Good for stopping spam floods.
|
# Discard post_reply if it contains certain phrases. Good for stopping spam floods.
|
||||||
if post_reply.body:
|
if post_reply.body:
|
||||||
|
@ -1579,6 +1593,10 @@ def update_post_reply_from_activity(reply: PostReply, request_json: dict):
|
||||||
elif 'content' in request_json['object']:
|
elif 'content' in request_json['object']:
|
||||||
reply.body_html = allowlist_html(request_json['object']['content'])
|
reply.body_html = allowlist_html(request_json['object']['content'])
|
||||||
reply.body = ''
|
reply.body = ''
|
||||||
|
# Language
|
||||||
|
if 'language' in request_json['object'] and isinstance(request_json['object']['language'], dict):
|
||||||
|
language = find_language_or_create(request_json['object']['language']['identifier'], request_json['object']['language']['name'])
|
||||||
|
reply.language_id = language.id
|
||||||
reply.edited_at = utcnow()
|
reply.edited_at = utcnow()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
@ -1636,7 +1654,7 @@ def update_post_from_activity(post: Post, request_json: dict):
|
||||||
db.session.add(image)
|
db.session.add(image)
|
||||||
post.image = image
|
post.image = image
|
||||||
elif is_video_url(post.url):
|
elif is_video_url(post.url):
|
||||||
post.type == POST_TYPE_VIDEO
|
post.type = POST_TYPE_VIDEO
|
||||||
image = File(source_url=post.url)
|
image = File(source_url=post.url)
|
||||||
db.session.add(image)
|
db.session.add(image)
|
||||||
post.image = image
|
post.image = image
|
||||||
|
@ -2049,3 +2067,16 @@ def ensure_domains_match(activity: dict) -> bool:
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def can_edit(user_ap_id, post):
|
||||||
|
user = find_actor_or_create(user_ap_id, create_if_not_found=False)
|
||||||
|
if user:
|
||||||
|
if post.user_id == user.id:
|
||||||
|
return True
|
||||||
|
if post.community.is_moderator(user) or post.community.is_owner(user) or post.community.is_instance_admin(user):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def can_delete(user_ap_id, post):
|
||||||
|
return can_edit(user_ap_id, post)
|
||||||
|
|
|
@ -87,6 +87,7 @@ def register(app):
|
||||||
db.session.add(Settings(name='allow_remote_image_posts', value=json.dumps(True)))
|
db.session.add(Settings(name='allow_remote_image_posts', value=json.dumps(True)))
|
||||||
db.session.add(Settings(name='federation', value=json.dumps(True)))
|
db.session.add(Settings(name='federation', value=json.dumps(True)))
|
||||||
db.session.add(Language(name='Undetermined', code='und'))
|
db.session.add(Language(name='Undetermined', code='und'))
|
||||||
|
db.session.add(Language(name='English', code='en'))
|
||||||
banned_instances = ['anonib.al','lemmygrad.ml', 'gab.com', 'rqd2.net', 'exploding-heads.com', 'hexbear.net',
|
banned_instances = ['anonib.al','lemmygrad.ml', 'gab.com', 'rqd2.net', 'exploding-heads.com', 'hexbear.net',
|
||||||
'threads.net', 'noauthority.social', 'pieville.net', 'links.hackliberty.org',
|
'threads.net', 'noauthority.social', 'pieville.net', 'links.hackliberty.org',
|
||||||
'poa.st', 'freespeechextremist.com', 'bae.st', 'nicecrew.digital', 'detroitriotcity.com',
|
'poa.st', 'freespeechextremist.com', 'bae.st', 'nicecrew.digital', 'detroitriotcity.com',
|
||||||
|
|
|
@ -100,6 +100,7 @@ class CreateDiscussionForm(FlaskForm):
|
||||||
nsfw = BooleanField(_l('NSFW'))
|
nsfw = BooleanField(_l('NSFW'))
|
||||||
nsfl = BooleanField(_l('Gore/gross'))
|
nsfl = BooleanField(_l('Gore/gross'))
|
||||||
notify_author = BooleanField(_l('Notify about replies'))
|
notify_author = BooleanField(_l('Notify about replies'))
|
||||||
|
language_id = SelectField(_l('Language'), validators=[DataRequired()], coerce=int, render_kw={'class': 'form-select'})
|
||||||
submit = SubmitField(_l('Save'))
|
submit = SubmitField(_l('Save'))
|
||||||
|
|
||||||
|
|
||||||
|
@ -113,6 +114,7 @@ class CreateLinkForm(FlaskForm):
|
||||||
nsfw = BooleanField(_l('NSFW'))
|
nsfw = BooleanField(_l('NSFW'))
|
||||||
nsfl = BooleanField(_l('Gore/gross'))
|
nsfl = BooleanField(_l('Gore/gross'))
|
||||||
notify_author = BooleanField(_l('Notify about replies'))
|
notify_author = BooleanField(_l('Notify about replies'))
|
||||||
|
language_id = SelectField(_l('Language'), validators=[DataRequired()], coerce=int, render_kw={'class': 'form-select'})
|
||||||
submit = SubmitField(_l('Save'))
|
submit = SubmitField(_l('Save'))
|
||||||
|
|
||||||
def validate(self, extra_validators=None) -> bool:
|
def validate(self, extra_validators=None) -> bool:
|
||||||
|
@ -133,6 +135,7 @@ class CreateVideoForm(FlaskForm):
|
||||||
nsfw = BooleanField(_l('NSFW'))
|
nsfw = BooleanField(_l('NSFW'))
|
||||||
nsfl = BooleanField(_l('Gore/gross'))
|
nsfl = BooleanField(_l('Gore/gross'))
|
||||||
notify_author = BooleanField(_l('Notify about replies'))
|
notify_author = BooleanField(_l('Notify about replies'))
|
||||||
|
language_id = SelectField(_l('Language'), validators=[DataRequired()], coerce=int, render_kw={'class': 'form-select'})
|
||||||
submit = SubmitField(_l('Save'))
|
submit = SubmitField(_l('Save'))
|
||||||
|
|
||||||
def validate(self, extra_validators=None) -> bool:
|
def validate(self, extra_validators=None) -> bool:
|
||||||
|
@ -153,6 +156,7 @@ class CreateImageForm(FlaskForm):
|
||||||
nsfw = BooleanField(_l('NSFW'))
|
nsfw = BooleanField(_l('NSFW'))
|
||||||
nsfl = BooleanField(_l('Gore/gross'))
|
nsfl = BooleanField(_l('Gore/gross'))
|
||||||
notify_author = BooleanField(_l('Notify about replies'))
|
notify_author = BooleanField(_l('Notify about replies'))
|
||||||
|
language_id = SelectField(_l('Language'), validators=[DataRequired()], coerce=int, render_kw={'class': 'form-select'})
|
||||||
submit = SubmitField(_l('Save'))
|
submit = SubmitField(_l('Save'))
|
||||||
|
|
||||||
def validate(self, extra_validators=None) -> bool:
|
def validate(self, extra_validators=None) -> bool:
|
||||||
|
|
|
@ -33,7 +33,7 @@ from app.utils import get_setting, render_template, allowlist_html, markdown_to_
|
||||||
request_etag_matches, return_304, instance_banned, can_create_post, can_upvote, can_downvote, user_filters_posts, \
|
request_etag_matches, return_304, instance_banned, can_create_post, can_upvote, can_downvote, user_filters_posts, \
|
||||||
joined_communities, moderating_communities, blocked_domains, mimetype_from_url, blocked_instances, \
|
joined_communities, moderating_communities, blocked_domains, mimetype_from_url, blocked_instances, \
|
||||||
community_moderators, communities_banned_from, show_ban_message, recently_upvoted_posts, recently_downvoted_posts, \
|
community_moderators, communities_banned_from, show_ban_message, recently_upvoted_posts, recently_downvoted_posts, \
|
||||||
blocked_users, post_ranking, languages_for_form
|
blocked_users, post_ranking, languages_for_form, english_language_id
|
||||||
from feedgen.feed import FeedGenerator
|
from feedgen.feed import FeedGenerator
|
||||||
from datetime import timezone, timedelta
|
from datetime import timezone, timedelta
|
||||||
|
|
||||||
|
@ -488,6 +488,8 @@ def add_discussion_post(actor):
|
||||||
if not community_in_list(community.id, form.communities.choices):
|
if not community_in_list(community.id, form.communities.choices):
|
||||||
form.communities.choices.append((community.id, community.display_name()))
|
form.communities.choices.append((community.id, community.display_name()))
|
||||||
|
|
||||||
|
form.language_id.choices = languages_for_form()
|
||||||
|
|
||||||
if not can_create_post(current_user, community):
|
if not can_create_post(current_user, community):
|
||||||
abort(401)
|
abort(401)
|
||||||
|
|
||||||
|
@ -515,6 +517,7 @@ def add_discussion_post(actor):
|
||||||
else:
|
else:
|
||||||
form.communities.data = community.id
|
form.communities.data = community.id
|
||||||
form.notify_author.data = True
|
form.notify_author.data = True
|
||||||
|
form.language_id.data = current_user.language_id if current_user.language_id else english_language_id()
|
||||||
if community.posting_warning:
|
if community.posting_warning:
|
||||||
flash(community.posting_warning)
|
flash(community.posting_warning)
|
||||||
|
|
||||||
|
@ -551,6 +554,8 @@ def add_image_post(actor):
|
||||||
if not community_in_list(community.id, form.communities.choices):
|
if not community_in_list(community.id, form.communities.choices):
|
||||||
form.communities.choices.append((community.id, community.display_name()))
|
form.communities.choices.append((community.id, community.display_name()))
|
||||||
|
|
||||||
|
form.language_id.choices = languages_for_form()
|
||||||
|
|
||||||
if not can_create_post(current_user, community):
|
if not can_create_post(current_user, community):
|
||||||
abort(401)
|
abort(401)
|
||||||
|
|
||||||
|
@ -594,6 +599,7 @@ def add_image_post(actor):
|
||||||
else:
|
else:
|
||||||
form.communities.data = community.id
|
form.communities.data = community.id
|
||||||
form.notify_author.data = True
|
form.notify_author.data = True
|
||||||
|
form.language_id.data = current_user.language_id if current_user.language_id else english_language_id()
|
||||||
|
|
||||||
return render_template('community/add_image_post.html', title=_('Add post to community'), form=form, community=community,
|
return render_template('community/add_image_post.html', title=_('Add post to community'), form=form, community=community,
|
||||||
markdown_editor=current_user.markdown_editor, low_bandwidth=False, actor=actor,
|
markdown_editor=current_user.markdown_editor, low_bandwidth=False, actor=actor,
|
||||||
|
@ -628,6 +634,8 @@ def add_link_post(actor):
|
||||||
if not community_in_list(community.id, form.communities.choices):
|
if not community_in_list(community.id, form.communities.choices):
|
||||||
form.communities.choices.append((community.id, community.display_name()))
|
form.communities.choices.append((community.id, community.display_name()))
|
||||||
|
|
||||||
|
form.language_id.choices = languages_for_form()
|
||||||
|
|
||||||
if not can_create_post(current_user, community):
|
if not can_create_post(current_user, community):
|
||||||
abort(401)
|
abort(401)
|
||||||
|
|
||||||
|
@ -671,6 +679,7 @@ def add_link_post(actor):
|
||||||
else:
|
else:
|
||||||
form.communities.data = community.id
|
form.communities.data = community.id
|
||||||
form.notify_author.data = True
|
form.notify_author.data = True
|
||||||
|
form.language_id.data = current_user.language_id if current_user.language_id else english_language_id()
|
||||||
|
|
||||||
return render_template('community/add_link_post.html', title=_('Add post to community'), form=form, community=community,
|
return render_template('community/add_link_post.html', title=_('Add post to community'), form=form, community=community,
|
||||||
markdown_editor=current_user.markdown_editor, low_bandwidth=False, actor=actor,
|
markdown_editor=current_user.markdown_editor, low_bandwidth=False, actor=actor,
|
||||||
|
@ -705,6 +714,8 @@ def add_video_post(actor):
|
||||||
if not community_in_list(community.id, form.communities.choices):
|
if not community_in_list(community.id, form.communities.choices):
|
||||||
form.communities.choices.append((community.id, community.display_name()))
|
form.communities.choices.append((community.id, community.display_name()))
|
||||||
|
|
||||||
|
form.language_id.choices = languages_for_form()
|
||||||
|
|
||||||
if not can_create_post(current_user, community):
|
if not can_create_post(current_user, community):
|
||||||
abort(401)
|
abort(401)
|
||||||
|
|
||||||
|
@ -748,6 +759,7 @@ def add_video_post(actor):
|
||||||
else:
|
else:
|
||||||
form.communities.data = community.id
|
form.communities.data = community.id
|
||||||
form.notify_author.data = True
|
form.notify_author.data = True
|
||||||
|
form.language_id.data = current_user.language_id if current_user.language_id else english_language_id()
|
||||||
|
|
||||||
return render_template('community/add_video_post.html', title=_('Add post to community'), form=form, community=community,
|
return render_template('community/add_video_post.html', title=_('Add post to community'), form=form, community=community,
|
||||||
markdown_editor=current_user.markdown_editor, low_bandwidth=False, actor=actor,
|
markdown_editor=current_user.markdown_editor, low_bandwidth=False, actor=actor,
|
||||||
|
@ -780,7 +792,11 @@ def federate_post(community, post):
|
||||||
'nsfl': post.nsfl,
|
'nsfl': post.nsfl,
|
||||||
'stickied': post.sticky,
|
'stickied': post.sticky,
|
||||||
'published': ap_datetime(utcnow()),
|
'published': ap_datetime(utcnow()),
|
||||||
'audience': community.ap_profile_id
|
'audience': community.ap_profile_id,
|
||||||
|
'language': {
|
||||||
|
'identifier': post.language_code(),
|
||||||
|
'name': post.language_name()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
create = {
|
create = {
|
||||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/create/{gibberish(15)}",
|
"id": f"https://{current_app.config['SERVER_NAME']}/activities/create/{gibberish(15)}",
|
||||||
|
@ -870,7 +886,11 @@ def federate_post_to_user_followers(post):
|
||||||
'sensitive': post.nsfw,
|
'sensitive': post.nsfw,
|
||||||
'nsfl': post.nsfl,
|
'nsfl': post.nsfl,
|
||||||
'stickied': post.sticky,
|
'stickied': post.sticky,
|
||||||
'published': ap_datetime(utcnow())
|
'published': ap_datetime(utcnow()),
|
||||||
|
'language': {
|
||||||
|
'identifier': post.language_code(),
|
||||||
|
'name': post.language_name()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
create = {
|
create = {
|
||||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/create/{gibberish(15)}",
|
"id": f"https://{current_app.config['SERVER_NAME']}/activities/create/{gibberish(15)}",
|
||||||
|
|
|
@ -216,6 +216,8 @@ def save_post(form, post: Post, type: str):
|
||||||
post.nsfw = form.nsfw.data
|
post.nsfw = form.nsfw.data
|
||||||
post.nsfl = form.nsfl.data
|
post.nsfl = form.nsfl.data
|
||||||
post.notify_author = form.notify_author.data
|
post.notify_author = form.notify_author.data
|
||||||
|
post.language_id = form.language_id.data
|
||||||
|
current_user.language_id = form.language_id.data
|
||||||
if type == '' or type == 'discussion':
|
if type == '' or type == 'discussion':
|
||||||
post.title = form.discussion_title.data
|
post.title = form.discussion_title.data
|
||||||
post.body = form.discussion_body.data
|
post.body = form.discussion_body.data
|
||||||
|
|
|
@ -944,10 +944,9 @@ class Post(db.Model):
|
||||||
up_votes = db.Column(db.Integer, default=0)
|
up_votes = db.Column(db.Integer, default=0)
|
||||||
down_votes = db.Column(db.Integer, default=0)
|
down_votes = db.Column(db.Integer, default=0)
|
||||||
ranking = db.Column(db.Integer, default=0, index=True) # used for 'hot' ranking
|
ranking = db.Column(db.Integer, default=0, index=True) # used for 'hot' ranking
|
||||||
language = db.Column(db.String(10))
|
|
||||||
edited_at = db.Column(db.DateTime)
|
edited_at = db.Column(db.DateTime)
|
||||||
reports = db.Column(db.Integer, default=0) # how many times this post has been reported. Set to -1 to ignore reports
|
reports = db.Column(db.Integer, default=0) # how many times this post has been reported. Set to -1 to ignore reports
|
||||||
language_id = db.Column(db.Integer, index=True)
|
language_id = db.Column(db.Integer, db.ForeignKey('language.id'), index=True)
|
||||||
cross_posts = db.Column(MutableList.as_mutable(ARRAY(db.Integer)))
|
cross_posts = db.Column(MutableList.as_mutable(ARRAY(db.Integer)))
|
||||||
tags = db.relationship('Tag', lazy='dynamic', secondary=post_tag, backref=db.backref('posts', lazy='dynamic'))
|
tags = db.relationship('Tag', lazy='dynamic', secondary=post_tag, backref=db.backref('posts', lazy='dynamic'))
|
||||||
|
|
||||||
|
@ -962,6 +961,7 @@ class Post(db.Model):
|
||||||
author = db.relationship('User', lazy='joined', overlaps='posts', foreign_keys=[user_id])
|
author = db.relationship('User', lazy='joined', overlaps='posts', foreign_keys=[user_id])
|
||||||
community = db.relationship('Community', lazy='joined', overlaps='posts', foreign_keys=[community_id])
|
community = db.relationship('Community', lazy='joined', overlaps='posts', foreign_keys=[community_id])
|
||||||
replies = db.relationship('PostReply', lazy='dynamic', backref='post')
|
replies = db.relationship('PostReply', lazy='dynamic', backref='post')
|
||||||
|
language = db.relationship('Language', foreign_keys=[language_id])
|
||||||
|
|
||||||
def is_local(self):
|
def is_local(self):
|
||||||
return self.ap_id is None or self.ap_id.startswith('https://' + current_app.config['SERVER_NAME'])
|
return self.ap_id is None or self.ap_id.startswith('https://' + current_app.config['SERVER_NAME'])
|
||||||
|
@ -1006,6 +1006,18 @@ class Post(db.Model):
|
||||||
NotificationSubscription.type == NOTIF_POST).first()
|
NotificationSubscription.type == NOTIF_POST).first()
|
||||||
return existing_notification is not None
|
return existing_notification is not None
|
||||||
|
|
||||||
|
def language_code(self):
|
||||||
|
if self.language_id:
|
||||||
|
return self.language.code
|
||||||
|
else:
|
||||||
|
return 'en'
|
||||||
|
|
||||||
|
def language_name(self):
|
||||||
|
if self.language_id:
|
||||||
|
return self.language.name
|
||||||
|
else:
|
||||||
|
return 'English'
|
||||||
|
|
||||||
|
|
||||||
class PostReply(db.Model):
|
class PostReply(db.Model):
|
||||||
query_class = FullTextSearchQuery
|
query_class = FullTextSearchQuery
|
||||||
|
@ -1033,7 +1045,7 @@ class PostReply(db.Model):
|
||||||
up_votes = db.Column(db.Integer, default=0)
|
up_votes = db.Column(db.Integer, default=0)
|
||||||
down_votes = db.Column(db.Integer, default=0)
|
down_votes = db.Column(db.Integer, default=0)
|
||||||
ranking = db.Column(db.Float, default=0.0, index=True) # used for 'hot' sorting
|
ranking = db.Column(db.Float, default=0.0, index=True) # used for 'hot' sorting
|
||||||
language = db.Column(db.String(10))
|
language_id = db.Column(db.Integer, db.ForeignKey('language.id'), index=True)
|
||||||
edited_at = db.Column(db.DateTime)
|
edited_at = db.Column(db.DateTime)
|
||||||
reports = db.Column(db.Integer, default=0) # how many times this post has been reported. Set to -1 to ignore reports
|
reports = db.Column(db.Integer, default=0) # how many times this post has been reported. Set to -1 to ignore reports
|
||||||
|
|
||||||
|
@ -1045,6 +1057,19 @@ class PostReply(db.Model):
|
||||||
|
|
||||||
author = db.relationship('User', lazy='joined', foreign_keys=[user_id], single_parent=True, overlaps="post_replies")
|
author = db.relationship('User', lazy='joined', foreign_keys=[user_id], single_parent=True, overlaps="post_replies")
|
||||||
community = db.relationship('Community', lazy='joined', overlaps='replies', foreign_keys=[community_id])
|
community = db.relationship('Community', lazy='joined', overlaps='replies', foreign_keys=[community_id])
|
||||||
|
language = db.relationship('Language', foreign_keys=[language_id])
|
||||||
|
|
||||||
|
def language_code(self):
|
||||||
|
if self.language_id:
|
||||||
|
return self.language.code
|
||||||
|
else:
|
||||||
|
return 'en'
|
||||||
|
|
||||||
|
def language_name(self):
|
||||||
|
if self.language_id:
|
||||||
|
return self.language.name
|
||||||
|
else:
|
||||||
|
return 'English'
|
||||||
|
|
||||||
def is_local(self):
|
def is_local(self):
|
||||||
return self.ap_id is None or self.ap_id.startswith('https://' + current_app.config['SERVER_NAME'])
|
return self.ap_id is None or self.ap_id.startswith('https://' + current_app.config['SERVER_NAME'])
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from wtforms import TextAreaField, SubmitField, BooleanField, StringField
|
from wtforms import TextAreaField, SubmitField, BooleanField, StringField
|
||||||
|
from wtforms.fields.choices import SelectField
|
||||||
from wtforms.validators import DataRequired, Length, ValidationError
|
from wtforms.validators import DataRequired, Length, ValidationError
|
||||||
from flask_babel import _, lazy_gettext as _l
|
from flask_babel import _, lazy_gettext as _l
|
||||||
|
|
||||||
|
@ -9,6 +10,7 @@ from app.utils import MultiCheckboxField
|
||||||
class NewReplyForm(FlaskForm):
|
class NewReplyForm(FlaskForm):
|
||||||
body = TextAreaField(_l('Body'), render_kw={'placeholder': 'What are your thoughts?', 'rows': 5}, validators={DataRequired(), Length(min=1, max=5000)})
|
body = TextAreaField(_l('Body'), render_kw={'placeholder': 'What are your thoughts?', 'rows': 5}, validators={DataRequired(), Length(min=1, max=5000)})
|
||||||
notify_author = BooleanField(_l('Notify about replies'))
|
notify_author = BooleanField(_l('Notify about replies'))
|
||||||
|
language_id = SelectField(_l('Language'), validators=[DataRequired()], coerce=int, render_kw={'class': 'form-select language-float-right'})
|
||||||
submit = SubmitField(_l('Comment'))
|
submit = SubmitField(_l('Comment'))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,8 @@ from app.utils import get_setting, render_template, allowlist_html, markdown_to_
|
||||||
request_etag_matches, ip_address, user_ip_banned, instance_banned, can_downvote, can_upvote, post_ranking, \
|
request_etag_matches, ip_address, user_ip_banned, instance_banned, can_downvote, can_upvote, post_ranking, \
|
||||||
reply_already_exists, reply_is_just_link_to_gif_reaction, confidence, moderating_communities, joined_communities, \
|
reply_already_exists, reply_is_just_link_to_gif_reaction, confidence, moderating_communities, joined_communities, \
|
||||||
blocked_instances, blocked_domains, community_moderators, blocked_phrases, show_ban_message, recently_upvoted_posts, \
|
blocked_instances, blocked_domains, community_moderators, blocked_phrases, show_ban_message, recently_upvoted_posts, \
|
||||||
recently_downvoted_posts, recently_upvoted_post_replies, recently_downvoted_post_replies, reply_is_stupid
|
recently_downvoted_posts, recently_upvoted_post_replies, recently_downvoted_post_replies, reply_is_stupid, \
|
||||||
|
languages_for_form, english_language_id
|
||||||
|
|
||||||
|
|
||||||
def show_post(post_id: int):
|
def show_post(post_id: int):
|
||||||
|
@ -58,6 +59,7 @@ def show_post(post_id: int):
|
||||||
|
|
||||||
# handle top-level comments/replies
|
# handle top-level comments/replies
|
||||||
form = NewReplyForm()
|
form = NewReplyForm()
|
||||||
|
form.language_id.choices = languages_for_form()
|
||||||
if current_user.is_authenticated and current_user.verified and form.validate_on_submit():
|
if current_user.is_authenticated and current_user.verified and form.validate_on_submit():
|
||||||
|
|
||||||
if not post.comments_enabled:
|
if not post.comments_enabled:
|
||||||
|
@ -98,11 +100,12 @@ def show_post(post_id: int):
|
||||||
reply = PostReply(user_id=current_user.id, post_id=post.id, community_id=community.id, body=form.body.data,
|
reply = PostReply(user_id=current_user.id, post_id=post.id, community_id=community.id, body=form.body.data,
|
||||||
body_html=markdown_to_html(form.body.data), body_html_safe=True,
|
body_html=markdown_to_html(form.body.data), body_html_safe=True,
|
||||||
from_bot=current_user.bot, nsfw=post.nsfw, nsfl=post.nsfl,
|
from_bot=current_user.bot, nsfw=post.nsfw, nsfl=post.nsfl,
|
||||||
notify_author=form.notify_author.data, instance_id=1)
|
notify_author=form.notify_author.data, language_id=form.language_id.data, instance_id=1)
|
||||||
|
|
||||||
post.last_active = community.last_active = utcnow()
|
post.last_active = community.last_active = utcnow()
|
||||||
post.reply_count += 1
|
post.reply_count += 1
|
||||||
community.post_reply_count += 1
|
community.post_reply_count += 1
|
||||||
|
current_user.language_id = form.language_id.data
|
||||||
|
|
||||||
db.session.add(reply)
|
db.session.add(reply)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -163,7 +166,11 @@ def show_post(post_id: int):
|
||||||
'href': post.author.public_url(),
|
'href': post.author.public_url(),
|
||||||
'name': post.author.mention_tag(),
|
'name': post.author.mention_tag(),
|
||||||
'type': 'Mention'
|
'type': 'Mention'
|
||||||
}]
|
}],
|
||||||
|
'language': {
|
||||||
|
'identifier': reply.language_code(),
|
||||||
|
'name': reply.language_name()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
create_json = {
|
create_json = {
|
||||||
'type': 'Create',
|
'type': 'Create',
|
||||||
|
@ -222,6 +229,7 @@ def show_post(post_id: int):
|
||||||
else:
|
else:
|
||||||
replies = post_replies(post.id, sort)
|
replies = post_replies(post.id, sort)
|
||||||
form.notify_author.data = True
|
form.notify_author.data = True
|
||||||
|
form.language_id.data = current_user.language_id if current_user.language_id else english_language_id()
|
||||||
|
|
||||||
og_image = post.image.source_url if post.image_id else None
|
og_image = post.image.source_url if post.image_id else None
|
||||||
description = shorten_string(markdown_to_text(post.body), 150) if post.body else None
|
description = shorten_string(markdown_to_text(post.body), 150) if post.body else None
|
||||||
|
@ -588,6 +596,7 @@ def add_reply(post_id: int, comment_id: int):
|
||||||
return redirect(url_for('activitypub.post_ap', post_id=post_id))
|
return redirect(url_for('activitypub.post_ap', post_id=post_id))
|
||||||
|
|
||||||
form = NewReplyForm()
|
form = NewReplyForm()
|
||||||
|
form.language_id.choices = languages_for_form()
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
if reply_already_exists(user_id=current_user.id, post_id=post.id, parent_id=in_reply_to.id, body=form.body.data):
|
if reply_already_exists(user_id=current_user.id, post_id=post.id, parent_id=in_reply_to.id, body=form.body.data):
|
||||||
if in_reply_to.depth <= constants.THREAD_CUTOFF_DEPTH:
|
if in_reply_to.depth <= constants.THREAD_CUTOFF_DEPTH:
|
||||||
|
@ -617,11 +626,12 @@ def add_reply(post_id: int, comment_id: int):
|
||||||
|
|
||||||
current_user.last_seen = utcnow()
|
current_user.last_seen = utcnow()
|
||||||
current_user.ip_address = ip_address()
|
current_user.ip_address = ip_address()
|
||||||
|
current_user.language_id = form.language_id.data
|
||||||
reply = PostReply(user_id=current_user.id, post_id=post.id, parent_id=in_reply_to.id, depth=in_reply_to.depth + 1,
|
reply = PostReply(user_id=current_user.id, post_id=post.id, parent_id=in_reply_to.id, depth=in_reply_to.depth + 1,
|
||||||
community_id=post.community.id, body=form.body.data,
|
community_id=post.community.id, body=form.body.data,
|
||||||
body_html=markdown_to_html(form.body.data), body_html_safe=True,
|
body_html=markdown_to_html(form.body.data), body_html_safe=True,
|
||||||
from_bot=current_user.bot, nsfw=post.nsfw, nsfl=post.nsfl,
|
from_bot=current_user.bot, nsfw=post.nsfw, nsfl=post.nsfl,
|
||||||
notify_author=form.notify_author.data, instance_id=1)
|
notify_author=form.notify_author.data, instance_id=1, language_id=form.language_id.data)
|
||||||
if reply.body:
|
if reply.body:
|
||||||
for blocked_phrase in blocked_phrases():
|
for blocked_phrase in blocked_phrases():
|
||||||
if blocked_phrase in reply.body:
|
if blocked_phrase in reply.body:
|
||||||
|
@ -761,6 +771,7 @@ def add_reply(post_id: int, comment_id: int):
|
||||||
return redirect(url_for('post.continue_discussion', post_id=post_id, comment_id=reply.parent_id))
|
return redirect(url_for('post.continue_discussion', post_id=post_id, comment_id=reply.parent_id))
|
||||||
else:
|
else:
|
||||||
form.notify_author.data = True
|
form.notify_author.data = True
|
||||||
|
form.language_id.data = current_user.language_id if current_user.language_id else english_language_id()
|
||||||
|
|
||||||
return render_template('post/add_reply.html', title=_('Discussing %(title)s', title=post.title), post=post,
|
return render_template('post/add_reply.html', title=_('Discussing %(title)s', title=post.title), post=post,
|
||||||
is_moderator=is_moderator, form=form, comment=in_reply_to, markdown_editor=current_user.is_authenticated and current_user.markdown_editor,
|
is_moderator=is_moderator, form=form, comment=in_reply_to, markdown_editor=current_user.is_authenticated and current_user.markdown_editor,
|
||||||
|
@ -828,6 +839,8 @@ def post_edit_discussion_post(post_id: int):
|
||||||
form.nsfl.data = True
|
form.nsfl.data = True
|
||||||
form.nsfw.render_kw = {'disabled': True}
|
form.nsfw.render_kw = {'disabled': True}
|
||||||
|
|
||||||
|
form.language_id.choices = languages_for_form()
|
||||||
|
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
save_post(form, post, 'discussion')
|
save_post(form, post, 'discussion')
|
||||||
post.community.last_active = utcnow()
|
post.community.last_active = utcnow()
|
||||||
|
@ -848,6 +861,7 @@ def post_edit_discussion_post(post_id: int):
|
||||||
form.nsfw.data = post.nsfw
|
form.nsfw.data = post.nsfw
|
||||||
form.nsfl.data = post.nsfl
|
form.nsfl.data = post.nsfl
|
||||||
form.sticky.data = post.sticky
|
form.sticky.data = post.sticky
|
||||||
|
form.language_id.data = post.language_id
|
||||||
if not (post.community.is_moderator() or post.community.is_owner() or current_user.is_admin()):
|
if not (post.community.is_moderator() or post.community.is_owner() or current_user.is_admin()):
|
||||||
form.sticky.render_kw = {'disabled': True}
|
form.sticky.render_kw = {'disabled': True}
|
||||||
return render_template('post/post_edit_discussion.html', title=_('Edit post'), form=form, post=post,
|
return render_template('post/post_edit_discussion.html', title=_('Edit post'), form=form, post=post,
|
||||||
|
@ -886,6 +900,8 @@ def post_edit_image_post(post_id: int):
|
||||||
|
|
||||||
old_url = post.url
|
old_url = post.url
|
||||||
|
|
||||||
|
form.language_id.choices = languages_for_form()
|
||||||
|
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
save_post(form, post, 'image')
|
save_post(form, post, 'image')
|
||||||
post.community.last_active = utcnow()
|
post.community.last_active = utcnow()
|
||||||
|
@ -929,6 +945,7 @@ def post_edit_image_post(post_id: int):
|
||||||
form.nsfw.data = post.nsfw
|
form.nsfw.data = post.nsfw
|
||||||
form.nsfl.data = post.nsfl
|
form.nsfl.data = post.nsfl
|
||||||
form.sticky.data = post.sticky
|
form.sticky.data = post.sticky
|
||||||
|
form.language_id.data = post.language_id
|
||||||
if not (post.community.is_moderator() or post.community.is_owner() or current_user.is_admin()):
|
if not (post.community.is_moderator() or post.community.is_owner() or current_user.is_admin()):
|
||||||
form.sticky.render_kw = {'disabled': True}
|
form.sticky.render_kw = {'disabled': True}
|
||||||
return render_template('post/post_edit_image.html', title=_('Edit post'), form=form, post=post,
|
return render_template('post/post_edit_image.html', title=_('Edit post'), form=form, post=post,
|
||||||
|
@ -967,6 +984,8 @@ def post_edit_link_post(post_id: int):
|
||||||
|
|
||||||
old_url = post.url
|
old_url = post.url
|
||||||
|
|
||||||
|
form.language_id.choices = languages_for_form()
|
||||||
|
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
save_post(form, post, 'link')
|
save_post(form, post, 'link')
|
||||||
post.community.last_active = utcnow()
|
post.community.last_active = utcnow()
|
||||||
|
@ -1010,6 +1029,7 @@ def post_edit_link_post(post_id: int):
|
||||||
form.nsfw.data = post.nsfw
|
form.nsfw.data = post.nsfw
|
||||||
form.nsfl.data = post.nsfl
|
form.nsfl.data = post.nsfl
|
||||||
form.sticky.data = post.sticky
|
form.sticky.data = post.sticky
|
||||||
|
form.language_id.data = post.language_id
|
||||||
if not (post.community.is_moderator() or post.community.is_owner() or current_user.is_admin()):
|
if not (post.community.is_moderator() or post.community.is_owner() or current_user.is_admin()):
|
||||||
form.sticky.render_kw = {'disabled': True}
|
form.sticky.render_kw = {'disabled': True}
|
||||||
return render_template('post/post_edit_link.html', title=_('Edit post'), form=form, post=post,
|
return render_template('post/post_edit_link.html', title=_('Edit post'), form=form, post=post,
|
||||||
|
@ -1048,6 +1068,8 @@ def post_edit_video_post(post_id: int):
|
||||||
|
|
||||||
old_url = post.url
|
old_url = post.url
|
||||||
|
|
||||||
|
form.language_id.choices = languages_for_form()
|
||||||
|
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
save_post(form, post, 'video')
|
save_post(form, post, 'video')
|
||||||
post.community.last_active = utcnow()
|
post.community.last_active = utcnow()
|
||||||
|
@ -1091,6 +1113,7 @@ def post_edit_video_post(post_id: int):
|
||||||
form.nsfw.data = post.nsfw
|
form.nsfw.data = post.nsfw
|
||||||
form.nsfl.data = post.nsfl
|
form.nsfl.data = post.nsfl
|
||||||
form.sticky.data = post.sticky
|
form.sticky.data = post.sticky
|
||||||
|
form.language_id.data = post.language_id
|
||||||
if not (post.community.is_moderator() or post.community.is_owner() or current_user.is_admin()):
|
if not (post.community.is_moderator() or post.community.is_owner() or current_user.is_admin()):
|
||||||
form.sticky.render_kw = {'disabled': True}
|
form.sticky.render_kw = {'disabled': True}
|
||||||
return render_template('post/post_edit_video.html', title=_('Edit post'), form=form, post=post,
|
return render_template('post/post_edit_video.html', title=_('Edit post'), form=form, post=post,
|
||||||
|
@ -1126,7 +1149,11 @@ def federate_post_update(post):
|
||||||
'stickied': post.sticky,
|
'stickied': post.sticky,
|
||||||
'published': ap_datetime(post.posted_at),
|
'published': ap_datetime(post.posted_at),
|
||||||
'updated': ap_datetime(post.edited_at),
|
'updated': ap_datetime(post.edited_at),
|
||||||
'audience': post.community.ap_profile_id
|
'audience': post.community.ap_profile_id,
|
||||||
|
'language': {
|
||||||
|
'identifier': post.language_code(),
|
||||||
|
'name': post.language_name()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
update_json = {
|
update_json = {
|
||||||
'id': f"https://{current_app.config['SERVER_NAME']}/activities/update/{gibberish(15)}",
|
'id': f"https://{current_app.config['SERVER_NAME']}/activities/update/{gibberish(15)}",
|
||||||
|
@ -1487,6 +1514,7 @@ def post_reply_edit(post_id: int, comment_id: int):
|
||||||
else:
|
else:
|
||||||
comment = None
|
comment = None
|
||||||
form = NewReplyForm()
|
form = NewReplyForm()
|
||||||
|
form.language_id.choices = languages_for_form()
|
||||||
if post_reply.user_id == current_user.id or post.community.is_moderator():
|
if post_reply.user_id == current_user.id or post.community.is_moderator():
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
post_reply.body = form.body.data
|
post_reply.body = form.body.data
|
||||||
|
@ -1494,6 +1522,7 @@ def post_reply_edit(post_id: int, comment_id: int):
|
||||||
post_reply.notify_author = form.notify_author.data
|
post_reply.notify_author = form.notify_author.data
|
||||||
post.community.last_active = utcnow()
|
post.community.last_active = utcnow()
|
||||||
post_reply.edited_at = utcnow()
|
post_reply.edited_at = utcnow()
|
||||||
|
post_reply.language_id = form.language_id.data
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash(_('Your changes have been saved.'), 'success')
|
flash(_('Your changes have been saved.'), 'success')
|
||||||
|
|
||||||
|
@ -1528,6 +1557,10 @@ def post_reply_edit(post_id: int, comment_id: int):
|
||||||
'audience': post.community.public_url(),
|
'audience': post.community.public_url(),
|
||||||
'contentMap': {
|
'contentMap': {
|
||||||
'en': post_reply.body_html
|
'en': post_reply.body_html
|
||||||
|
},
|
||||||
|
'language': {
|
||||||
|
'identifier': post_reply.language_code(),
|
||||||
|
'name': post_reply.language_name()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
update_json = {
|
update_json = {
|
||||||
|
@ -1599,6 +1632,7 @@ def post_reply_edit(post_id: int, comment_id: int):
|
||||||
else:
|
else:
|
||||||
form.body.data = post_reply.body
|
form.body.data = post_reply.body
|
||||||
form.notify_author.data = post_reply.notify_author
|
form.notify_author.data = post_reply.notify_author
|
||||||
|
form.language_id.data = post_reply.language_id
|
||||||
return render_template('post/post_reply_edit.html', title=_('Edit comment'), form=form, post=post, post_reply=post_reply,
|
return render_template('post/post_reply_edit.html', title=_('Edit comment'), form=form, post=post, post_reply=post_reply,
|
||||||
comment=comment, markdown_editor=current_user.markdown_editor, moderating_communities=moderating_communities(current_user.get_id()),
|
comment=comment, markdown_editor=current_user.markdown_editor, moderating_communities=moderating_communities(current_user.get_id()),
|
||||||
joined_communities=joined_communities(current_user.get_id()), community=post.community,
|
joined_communities=joined_communities(current_user.get_id()), community=post.community,
|
||||||
|
|
|
@ -1376,4 +1376,22 @@ h1 .warning_badge {
|
||||||
max-height: 90vh;
|
max-height: 90vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.post_language_chooser label {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.post_language_chooser select {
|
||||||
|
max-width: 150px;
|
||||||
|
float: right;
|
||||||
|
margin-top: -5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.language-float-right {
|
||||||
|
max-width: 150px;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*# sourceMappingURL=structure.css.map */
|
/*# sourceMappingURL=structure.css.map */
|
||||||
|
|
|
@ -1051,3 +1051,23 @@ h1 .warning_badge {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
max-height: 90vh;
|
max-height: 90vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.post_language_chooser {
|
||||||
|
@include breakpoint(phablet) {
|
||||||
|
label {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
max-width: 150px;
|
||||||
|
float: right;
|
||||||
|
margin-top: -5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.language-float-right {
|
||||||
|
@include breakpoint(phablet) {
|
||||||
|
max-width: 150px;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
|
@ -58,8 +58,8 @@
|
||||||
<div class="col-md-1">
|
<div class="col-md-1">
|
||||||
{{ render_field(form.nsfl) }}
|
{{ render_field(form.nsfl) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col post_language_chooser">
|
||||||
|
{{ render_field(form.language_id) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -60,8 +60,8 @@
|
||||||
<div class="col-md-1">
|
<div class="col-md-1">
|
||||||
{{ render_field(form.nsfl) }}
|
{{ render_field(form.nsfl) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col post_language_chooser">
|
||||||
|
{{ render_field(form.language_id) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -59,8 +59,8 @@
|
||||||
<div class="col-md-1">
|
<div class="col-md-1">
|
||||||
{{ render_field(form.nsfl) }}
|
{{ render_field(form.nsfl) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col post_language_chooser">
|
||||||
|
{{ render_field(form.language_id) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -60,8 +60,8 @@
|
||||||
<div class="col-md-1">
|
<div class="col-md-1">
|
||||||
{{ render_field(form.nsfl) }}
|
{{ render_field(form.nsfl) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col post_language_chooser">
|
||||||
|
{{ render_field(form.language_id) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="#" aria-hidden="true" id="post_reply_markdown_editor_enabler" class="markdown_editor_enabler" data-id="body">{{ _('Enable markdown editor') }}</a>
|
<!-- <a href="#" aria-hidden="true" id="post_reply_markdown_editor_enabler" class="markdown_editor_enabler" data-id="body">{{ _('Enable markdown editor') }}</a> -->
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -41,8 +41,8 @@
|
||||||
{{ render_field(form.nsfl) }}
|
{{ render_field(form.nsfl) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col">
|
<div class="col post_language_chooser">
|
||||||
|
{{ render_field(form.language_id) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -44,8 +44,8 @@
|
||||||
{{ render_field(form.nsfl) }}
|
{{ render_field(form.nsfl) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col">
|
<div class="col post_language_chooser">
|
||||||
|
{{ render_field(form.language_id) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,8 @@
|
||||||
{{ render_field(form.nsfl) }}
|
{{ render_field(form.nsfl) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col">
|
<div class="col post_language_chooser">
|
||||||
|
{{ render_field(form.language_id) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,8 @@
|
||||||
{{ render_field(form.nsfl) }}
|
{{ render_field(form.nsfl) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col">
|
<div class="col post_language_chooser">
|
||||||
|
{{ render_field(form.language_id) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,11 @@
|
||||||
<div class="card-title">{{ _('Options for "%(post_title)s"', post_title=post.title) }}</div>
|
<div class="card-title">{{ _('Options for "%(post_title)s"', post_title=post.title) }}</div>
|
||||||
<ul class="option_list">
|
<ul class="option_list">
|
||||||
{% if current_user.is_authenticated %}
|
{% if current_user.is_authenticated %}
|
||||||
{% if post.user_id == current_user.id or post.community.is_moderator() or current_user.is_admin() %}
|
{% if post.user_id == current_user.id %}
|
||||||
<li><a href="{{ url_for('post.post_edit', post_id=post.id) }}" class="no-underline" rel="nofollow"><span class="fe fe-edit"></span>
|
<li><a href="{{ url_for('post.post_edit', post_id=post.id) }}" class="no-underline" rel="nofollow"><span class="fe fe-edit"></span>
|
||||||
{{ _('Edit') }}</a></li>
|
{{ _('Edit') }}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if post.user_id == current_user.id or post.community.is_moderator() or post.community.is_owner() or current_user.is_admin() %}
|
||||||
<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>
|
<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>
|
{{ _('Delete') }}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -13,9 +13,11 @@
|
||||||
<div class="card-title">{{ _('Options for comment on "%(post_title)s"', post_title=post.title) }}</div>
|
<div class="card-title">{{ _('Options for comment on "%(post_title)s"', post_title=post.title) }}</div>
|
||||||
<ul class="option_list">
|
<ul class="option_list">
|
||||||
{% if current_user.is_authenticated %}
|
{% if current_user.is_authenticated %}
|
||||||
{% if post_reply.user_id == current_user.id or post.community.is_moderator() or current_user.is_admin() %}
|
{% if post_reply.user_id == current_user.id %}
|
||||||
<li><a href="{{ url_for('post.post_reply_edit', post_id=post.id, comment_id=post_reply.id) }}" class="no-underline" rel="nofollow"><span class="fe fe-edit"></span>
|
<li><a href="{{ url_for('post.post_reply_edit', post_id=post.id, comment_id=post_reply.id) }}" class="no-underline" rel="nofollow"><span class="fe fe-edit"></span>
|
||||||
{{ _('Edit') }}</a></li>
|
{{ _('Edit') }}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if post_reply.user_id == current_user.id or post.community.is_moderator() or post.community.is_owner() or current_user.is_admin() %}
|
||||||
<li><a href="{{ url_for('post.post_reply_delete', post_id=post.id, comment_id=post_reply.id) }}" class="no-underline confirm_first" rel="nofollow"><span class="fe fe-delete"></span>
|
<li><a href="{{ url_for('post.post_reply_delete', post_id=post.id, comment_id=post_reply.id) }}" class="no-underline confirm_first" rel="nofollow"><span class="fe fe-delete"></span>
|
||||||
{{ _('Delete') }}</a></li>
|
{{ _('Delete') }}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -984,3 +984,8 @@ def languages_for_form():
|
||||||
if language.code != 'und':
|
if language.code != 'und':
|
||||||
result.append((language.id, language.name))
|
result.append((language.id, language.name))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def english_language_id():
|
||||||
|
english = Language.query.filter(Language.code == 'en').first()
|
||||||
|
return english.id if english else None
|
||||||
|
|
46
migrations/versions/9ad372b72d7c_post_reply_language.py
Normal file
46
migrations/versions/9ad372b72d7c_post_reply_language.py
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
"""post_reply language
|
||||||
|
|
||||||
|
Revision ID: 9ad372b72d7c
|
||||||
|
Revises: e73996747d7e
|
||||||
|
Create Date: 2024-05-09 14:26:48.888908
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '9ad372b72d7c'
|
||||||
|
down_revision = 'e73996747d7e'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('post', schema=None) as batch_op:
|
||||||
|
batch_op.create_foreign_key(None, 'language', ['language_id'], ['id'])
|
||||||
|
batch_op.drop_column('language')
|
||||||
|
|
||||||
|
with op.batch_alter_table('post_reply', schema=None) as batch_op:
|
||||||
|
batch_op.add_column(sa.Column('language_id', sa.Integer(), nullable=True))
|
||||||
|
batch_op.create_index(batch_op.f('ix_post_reply_language_id'), ['language_id'], unique=False)
|
||||||
|
batch_op.create_foreign_key(None, 'language', ['language_id'], ['id'])
|
||||||
|
batch_op.drop_column('language')
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('post_reply', schema=None) as batch_op:
|
||||||
|
batch_op.add_column(sa.Column('language', sa.VARCHAR(length=10), autoincrement=False, nullable=True))
|
||||||
|
batch_op.drop_constraint(None, type_='foreignkey')
|
||||||
|
batch_op.drop_index(batch_op.f('ix_post_reply_language_id'))
|
||||||
|
batch_op.drop_column('language_id')
|
||||||
|
|
||||||
|
with op.batch_alter_table('post', schema=None) as batch_op:
|
||||||
|
batch_op.add_column(sa.Column('language', sa.VARCHAR(length=10), autoincrement=False, nullable=True))
|
||||||
|
batch_op.drop_constraint(None, type_='foreignkey')
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
Loading…
Add table
Reference in a new issue