mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-23 11:26:56 -08:00
split post creation and editing up into different forms for each type of content #78
This commit is contained in:
parent
db99ea33e9
commit
b8ddf0c481
14 changed files with 1064 additions and 558 deletions
|
@ -85,21 +85,23 @@ class BanUserCommunityForm(FlaskForm):
|
||||||
submit = SubmitField(_l('Ban'))
|
submit = SubmitField(_l('Ban'))
|
||||||
|
|
||||||
|
|
||||||
class CreatePostForm(FlaskForm):
|
class CreateDiscussionForm(FlaskForm):
|
||||||
communities = SelectField(_l('Community'), validators=[DataRequired()], coerce=int)
|
communities = SelectField(_l('Community'), validators=[DataRequired()], coerce=int)
|
||||||
post_type = HiddenField() # https://getbootstrap.com/docs/4.6/components/navs/#tabs
|
discussion_title = StringField(_l('Title'), validators=[DataRequired(), Length(min=3, max=255)])
|
||||||
discussion_title = StringField(_l('Title'), validators=[Optional(), Length(min=3, max=255)])
|
discussion_body = TextAreaField(_l('Body'), validators=[Optional(), Length(min=3, max=5000)])
|
||||||
discussion_body = TextAreaField(_l('Body'), validators=[Optional(), Length(min=3, max=5000)], render_kw={'placeholder': 'Text (optional)'})
|
sticky = BooleanField(_l('Sticky'))
|
||||||
link_title = StringField(_l('Title'), validators=[Optional(), Length(min=3, max=255)])
|
nsfw = BooleanField(_l('NSFW'))
|
||||||
link_body = TextAreaField(_l('Body'), validators=[Optional(), Length(min=3, max=5000)],
|
nsfl = BooleanField(_l('Gore/gross'))
|
||||||
render_kw={'placeholder': 'Text (optional)'})
|
notify_author = BooleanField(_l('Notify about replies'))
|
||||||
link_url = StringField(_l('URL'), validators=[Optional(), Regexp(r'^https?://', message='Submitted links need to start with "http://"" or "https://"')], render_kw={'placeholder': 'https://...'})
|
submit = SubmitField(_l('Save'))
|
||||||
image_title = StringField(_l('Title'), validators=[Optional(), Length(min=3, max=255)])
|
|
||||||
image_alt_text = StringField(_l('Alt text'), validators=[Optional(), Length(min=3, max=255)])
|
|
||||||
image_body = TextAreaField(_l('Body'), validators=[Optional(), Length(min=3, max=5000)],
|
class CreateLinkForm(FlaskForm):
|
||||||
render_kw={'placeholder': 'Text (optional)'})
|
communities = SelectField(_l('Community'), validators=[DataRequired()], coerce=int)
|
||||||
image_file = FileField(_('Image'))
|
link_title = StringField(_l('Title'), validators=[DataRequired(), Length(min=3, max=255)])
|
||||||
# flair = SelectField(_l('Flair'), coerce=int)
|
link_body = TextAreaField(_l('Body'), validators=[Optional(), Length(min=3, max=5000)])
|
||||||
|
link_url = StringField(_l('URL'), validators=[DataRequired(), Regexp(r'^https?://', message='Submitted links need to start with "http://"" or "https://"')],
|
||||||
|
render_kw={'placeholder': 'https://...'})
|
||||||
sticky = BooleanField(_l('Sticky'))
|
sticky = BooleanField(_l('Sticky'))
|
||||||
nsfw = BooleanField(_l('NSFW'))
|
nsfw = BooleanField(_l('NSFW'))
|
||||||
nsfl = BooleanField(_l('Gore/gross'))
|
nsfl = BooleanField(_l('Gore/gross'))
|
||||||
|
@ -107,33 +109,26 @@ class CreatePostForm(FlaskForm):
|
||||||
submit = SubmitField(_l('Save'))
|
submit = SubmitField(_l('Save'))
|
||||||
|
|
||||||
def validate(self, extra_validators=None) -> bool:
|
def validate(self, extra_validators=None) -> bool:
|
||||||
if not super().validate():
|
|
||||||
return False
|
|
||||||
if self.post_type.data is None or self.post_type.data == '':
|
|
||||||
self.post_type.data = 'discussion'
|
|
||||||
|
|
||||||
if self.post_type.data == 'discussion':
|
|
||||||
if self.discussion_title.data == '':
|
|
||||||
self.discussion_title.errors.append(_('Title is required.'))
|
|
||||||
return False
|
|
||||||
elif self.post_type.data == 'link':
|
|
||||||
if self.link_title.data == '':
|
|
||||||
self.link_title.errors.append(_('Title is required.'))
|
|
||||||
return False
|
|
||||||
if self.link_url.data == '':
|
|
||||||
self.link_url.errors.append(_('URL is required.'))
|
|
||||||
return False
|
|
||||||
domain = domain_from_url(self.link_url.data, create=False)
|
domain = domain_from_url(self.link_url.data, create=False)
|
||||||
if domain and domain.banned:
|
if domain and domain.banned:
|
||||||
self.link_url.errors.append(_("Links to %(domain)s are not allowed.", domain=domain.name))
|
self.link_url.errors.append(_("Links to %(domain)s are not allowed.", domain=domain.name))
|
||||||
return False
|
return False
|
||||||
elif self.post_type.data == 'image':
|
return True
|
||||||
if self.image_title.data == '':
|
|
||||||
self.image_title.errors.append(_('Title is required.'))
|
|
||||||
return False
|
class CreateImageForm(FlaskForm):
|
||||||
if self.image_file.data == '':
|
communities = SelectField(_l('Community'), validators=[DataRequired()], coerce=int)
|
||||||
self.image_file.errors.append(_('File is required.'))
|
image_title = StringField(_l('Title'), validators=[DataRequired(), Length(min=3, max=255)])
|
||||||
return False
|
image_alt_text = StringField(_l('Alt text'), validators=[Optional(), Length(min=3, max=255)])
|
||||||
|
image_body = TextAreaField(_l('Body'), validators=[Optional(), Length(min=3, max=5000)])
|
||||||
|
image_file = FileField(_('Image'), validators=[DataRequired()])
|
||||||
|
sticky = BooleanField(_l('Sticky'))
|
||||||
|
nsfw = BooleanField(_l('NSFW'))
|
||||||
|
nsfl = BooleanField(_l('Gore/gross'))
|
||||||
|
notify_author = BooleanField(_l('Notify about replies'))
|
||||||
|
submit = SubmitField(_l('Save'))
|
||||||
|
|
||||||
|
def validate(self, extra_validators=None) -> bool:
|
||||||
uploaded_file = request.files['image_file']
|
uploaded_file = request.files['image_file']
|
||||||
if uploaded_file and uploaded_file.filename != '':
|
if uploaded_file and uploaded_file.filename != '':
|
||||||
Image.MAX_IMAGE_PIXELS = 89478485
|
Image.MAX_IMAGE_PIXELS = 89478485
|
||||||
|
@ -142,8 +137,10 @@ class CreatePostForm(FlaskForm):
|
||||||
image_text = pytesseract.image_to_string(Image.open(BytesIO(uploaded_file.read())).convert('L'))
|
image_text = pytesseract.image_to_string(Image.open(BytesIO(uploaded_file.read())).convert('L'))
|
||||||
except FileNotFoundError as e:
|
except FileNotFoundError as e:
|
||||||
image_text = ''
|
image_text = ''
|
||||||
if 'Anonymous' in image_text and ('No.' in image_text or ' N0' in image_text): # chan posts usually contain the text 'Anonymous' and ' No.12345'
|
if 'Anonymous' in image_text and (
|
||||||
self.image_file.errors.append(f"This image is an invalid file type.") # deliberately misleading error message
|
'No.' in image_text or ' N0' in image_text): # chan posts usually contain the text 'Anonymous' and ' No.12345'
|
||||||
|
self.image_file.errors.append(
|
||||||
|
f"This image is an invalid file type.") # deliberately misleading error message
|
||||||
current_user.reputation -= 1
|
current_user.reputation -= 1
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return False
|
return False
|
||||||
|
@ -151,9 +148,6 @@ class CreatePostForm(FlaskForm):
|
||||||
community = Community.query.get(self.communities.data)
|
community = Community.query.get(self.communities.data)
|
||||||
if community.is_local() and g.site.allow_local_image_posts is False:
|
if community.is_local() and g.site.allow_local_image_posts is False:
|
||||||
self.communities.errors.append(_('Images cannot be posted to local communities.'))
|
self.communities.errors.append(_('Images cannot be posted to local communities.'))
|
||||||
elif self.post_type.data == 'poll':
|
|
||||||
self.discussion_title.errors.append(_('Poll not implemented yet.'))
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ from app import db, constants, cache
|
||||||
from app.activitypub.signature import RsaKeys, post_request
|
from app.activitypub.signature import RsaKeys, post_request
|
||||||
from app.activitypub.util import default_context, notify_about_post, find_actor_or_create, make_image_sizes
|
from app.activitypub.util import default_context, notify_about_post, find_actor_or_create, make_image_sizes
|
||||||
from app.chat.util import send_message
|
from app.chat.util import send_message
|
||||||
from app.community.forms import SearchRemoteCommunity, CreatePostForm, ReportCommunityForm, \
|
from app.community.forms import SearchRemoteCommunity, CreateDiscussionForm, CreateImageForm, CreateLinkForm, ReportCommunityForm, \
|
||||||
DeleteCommunityForm, AddCommunityForm, EditCommunityForm, AddModeratorForm, BanUserCommunityForm, \
|
DeleteCommunityForm, AddCommunityForm, EditCommunityForm, AddModeratorForm, BanUserCommunityForm, \
|
||||||
EscalateReportForm, ResolveReportForm
|
EscalateReportForm, ResolveReportForm
|
||||||
from app.community.util import search_for_community, community_url_exists, actor_to_community, \
|
from app.community.util import search_for_community, community_url_exists, actor_to_community, \
|
||||||
|
@ -444,11 +444,13 @@ def join_then_add(actor):
|
||||||
@bp.route('/<actor>/submit', methods=['GET', 'POST'])
|
@bp.route('/<actor>/submit', methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
@validation_required
|
@validation_required
|
||||||
def add_post(actor):
|
def add_discussion_post(actor):
|
||||||
if current_user.banned:
|
if current_user.banned:
|
||||||
return show_ban_message()
|
return show_ban_message()
|
||||||
community = actor_to_community(actor)
|
community = actor_to_community(actor)
|
||||||
form = CreatePostForm()
|
|
||||||
|
form = CreateDiscussionForm()
|
||||||
|
|
||||||
if g.site.enable_nsfl is False:
|
if g.site.enable_nsfl is False:
|
||||||
form.nsfl.render_kw = {'disabled': True}
|
form.nsfl.render_kw = {'disabled': True}
|
||||||
if community.nsfw:
|
if community.nsfw:
|
||||||
|
@ -470,7 +472,63 @@ def add_post(actor):
|
||||||
if not can_create_post(current_user, community):
|
if not can_create_post(current_user, community):
|
||||||
abort(401)
|
abort(401)
|
||||||
post = Post(user_id=current_user.id, community_id=form.communities.data, instance_id=1)
|
post = Post(user_id=current_user.id, community_id=form.communities.data, instance_id=1)
|
||||||
save_post(form, post)
|
save_post(form, post, 'discussion')
|
||||||
|
community.post_count += 1
|
||||||
|
community.last_active = g.site.last_active = utcnow()
|
||||||
|
db.session.commit()
|
||||||
|
post.ap_id = f"https://{current_app.config['SERVER_NAME']}/post/{post.id}"
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
notify_about_post(post)
|
||||||
|
|
||||||
|
if not community.local_only:
|
||||||
|
federate_post(community, post)
|
||||||
|
|
||||||
|
return redirect(f"/c/{community.link()}")
|
||||||
|
else:
|
||||||
|
form.communities.data = community.id
|
||||||
|
form.notify_author.data = True
|
||||||
|
|
||||||
|
return render_template('community/add_discussion_post.html', title=_('Add post to community'), form=form, community=community,
|
||||||
|
markdown_editor=current_user.markdown_editor, low_bandwidth=False, actor=actor,
|
||||||
|
moderating_communities=moderating_communities(current_user.get_id()),
|
||||||
|
joined_communities=joined_communities(current_user.id),
|
||||||
|
inoculation=inoculation[randint(0, len(inoculation) - 1)]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/<actor>/submit_image', methods=['GET', 'POST'])
|
||||||
|
@login_required
|
||||||
|
@validation_required
|
||||||
|
def add_image_post(actor):
|
||||||
|
if current_user.banned:
|
||||||
|
return show_ban_message()
|
||||||
|
community = actor_to_community(actor)
|
||||||
|
|
||||||
|
form = CreateImageForm()
|
||||||
|
|
||||||
|
if g.site.enable_nsfl is False:
|
||||||
|
form.nsfl.render_kw = {'disabled': True}
|
||||||
|
if community.nsfw:
|
||||||
|
form.nsfw.data = True
|
||||||
|
form.nsfw.render_kw = {'disabled': True}
|
||||||
|
if community.nsfl:
|
||||||
|
form.nsfl.data = True
|
||||||
|
form.nsfw.render_kw = {'disabled': True}
|
||||||
|
if not(community.is_moderator() or community.is_owner() or current_user.is_admin()):
|
||||||
|
form.sticky.render_kw = {'disabled': True}
|
||||||
|
|
||||||
|
form.communities.choices = [(c.id, c.display_name()) for c in current_user.communities()]
|
||||||
|
|
||||||
|
if not can_create_post(current_user, community):
|
||||||
|
abort(401)
|
||||||
|
|
||||||
|
if form.validate_on_submit():
|
||||||
|
community = Community.query.get_or_404(form.communities.data)
|
||||||
|
if not can_create_post(current_user, community):
|
||||||
|
abort(401)
|
||||||
|
post = Post(user_id=current_user.id, community_id=form.communities.data, instance_id=1)
|
||||||
|
save_post(form, post, 'image')
|
||||||
community.post_count += 1
|
community.post_count += 1
|
||||||
community.last_active = g.site.last_active = utcnow()
|
community.last_active = g.site.last_active = utcnow()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -497,6 +555,95 @@ def add_post(actor):
|
||||||
notify_about_post(post)
|
notify_about_post(post)
|
||||||
|
|
||||||
if not community.local_only:
|
if not community.local_only:
|
||||||
|
federate_post(community, post)
|
||||||
|
|
||||||
|
return redirect(f"/c/{community.link()}")
|
||||||
|
else:
|
||||||
|
form.communities.data = community.id
|
||||||
|
form.notify_author.data = True
|
||||||
|
|
||||||
|
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,
|
||||||
|
moderating_communities=moderating_communities(current_user.get_id()),
|
||||||
|
joined_communities=joined_communities(current_user.id),
|
||||||
|
inoculation=inoculation[randint(0, len(inoculation) - 1)]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/<actor>/submit_link', methods=['GET', 'POST'])
|
||||||
|
@login_required
|
||||||
|
@validation_required
|
||||||
|
def add_link_post(actor):
|
||||||
|
if current_user.banned:
|
||||||
|
return show_ban_message()
|
||||||
|
community = actor_to_community(actor)
|
||||||
|
|
||||||
|
form = CreateLinkForm()
|
||||||
|
|
||||||
|
if g.site.enable_nsfl is False:
|
||||||
|
form.nsfl.render_kw = {'disabled': True}
|
||||||
|
if community.nsfw:
|
||||||
|
form.nsfw.data = True
|
||||||
|
form.nsfw.render_kw = {'disabled': True}
|
||||||
|
if community.nsfl:
|
||||||
|
form.nsfl.data = True
|
||||||
|
form.nsfw.render_kw = {'disabled': True}
|
||||||
|
if not(community.is_moderator() or community.is_owner() or current_user.is_admin()):
|
||||||
|
form.sticky.render_kw = {'disabled': True}
|
||||||
|
|
||||||
|
form.communities.choices = [(c.id, c.display_name()) for c in current_user.communities()]
|
||||||
|
|
||||||
|
if not can_create_post(current_user, community):
|
||||||
|
abort(401)
|
||||||
|
|
||||||
|
if form.validate_on_submit():
|
||||||
|
community = Community.query.get_or_404(form.communities.data)
|
||||||
|
if not can_create_post(current_user, community):
|
||||||
|
abort(401)
|
||||||
|
post = Post(user_id=current_user.id, community_id=form.communities.data, instance_id=1)
|
||||||
|
save_post(form, post, 'link')
|
||||||
|
community.post_count += 1
|
||||||
|
community.last_active = g.site.last_active = utcnow()
|
||||||
|
db.session.commit()
|
||||||
|
post.ap_id = f"https://{current_app.config['SERVER_NAME']}/post/{post.id}"
|
||||||
|
db.session.commit()
|
||||||
|
if post.image_id and post.image.file_path is None:
|
||||||
|
make_image_sizes(post.image_id, 150, 512, 'posts') # the 512 sized image is for masonry view
|
||||||
|
|
||||||
|
# Update list of cross posts
|
||||||
|
if post.url:
|
||||||
|
other_posts = Post.query.filter(Post.id != post.id, Post.url == post.url,
|
||||||
|
Post.posted_at > post.posted_at - timedelta(days=6)).all()
|
||||||
|
for op in other_posts:
|
||||||
|
if op.cross_posts is None:
|
||||||
|
op.cross_posts = [post.id]
|
||||||
|
else:
|
||||||
|
op.cross_posts.append(post.id)
|
||||||
|
if post.cross_posts is None:
|
||||||
|
post.cross_posts = [op.id]
|
||||||
|
else:
|
||||||
|
post.cross_posts.append(op.id)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
notify_about_post(post)
|
||||||
|
|
||||||
|
if not community.local_only:
|
||||||
|
federate_post(community, post)
|
||||||
|
|
||||||
|
return redirect(f"/c/{community.link()}")
|
||||||
|
else:
|
||||||
|
form.communities.data = community.id
|
||||||
|
form.notify_author.data = True
|
||||||
|
|
||||||
|
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,
|
||||||
|
moderating_communities=moderating_communities(current_user.get_id()),
|
||||||
|
joined_communities=joined_communities(current_user.id),
|
||||||
|
inoculation=inoculation[randint(0, len(inoculation) - 1)]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def federate_post(community, post):
|
||||||
page = {
|
page = {
|
||||||
'type': 'Page',
|
'type': 'Page',
|
||||||
'id': post.ap_id,
|
'id': post.ap_id,
|
||||||
|
@ -539,15 +686,18 @@ def add_post(actor):
|
||||||
page['attachment'] = [{'href': post.url, 'type': 'Link'}]
|
page['attachment'] = [{'href': post.url, 'type': 'Link'}]
|
||||||
elif post.image_id:
|
elif post.image_id:
|
||||||
if post.image.file_path:
|
if post.image.file_path:
|
||||||
image_url = post.image.file_path.replace('app/static/', f"https://{current_app.config['SERVER_NAME']}/static/")
|
image_url = post.image.file_path.replace('app/static/',
|
||||||
|
f"https://{current_app.config['SERVER_NAME']}/static/")
|
||||||
elif post.image.thumbnail_path:
|
elif post.image.thumbnail_path:
|
||||||
image_url = post.image.thumbnail_path.replace('app/static/', f"https://{current_app.config['SERVER_NAME']}/static/")
|
image_url = post.image.thumbnail_path.replace('app/static/',
|
||||||
|
f"https://{current_app.config['SERVER_NAME']}/static/")
|
||||||
else:
|
else:
|
||||||
image_url = post.image.source_url
|
image_url = post.image.source_url
|
||||||
# NB image is a dict while attachment is a list of dicts (usually just one dict in the list)
|
# NB image is a dict while attachment is a list of dicts (usually just one dict in the list)
|
||||||
page['image'] = {'type': 'Image', 'url': image_url}
|
page['image'] = {'type': 'Image', 'url': image_url}
|
||||||
if post.type == POST_TYPE_IMAGE:
|
if post.type == POST_TYPE_IMAGE:
|
||||||
page['attachment'] = [{'type': 'Link', 'href': post.image.source_url}] # source_url is always a https link, no need for .replace() as done above
|
page['attachment'] = [{'type': 'Link',
|
||||||
|
'href': post.image.source_url}] # source_url is always a https link, no need for .replace() as done above
|
||||||
if not community.is_local(): # this is a remote community - send the post to the instance that hosts it
|
if not community.is_local(): # this is a remote community - send the post to the instance that hosts it
|
||||||
success = post_request(community.ap_inbox_url, create, current_user.private_key,
|
success = post_request(community.ap_inbox_url, create, current_user.private_key,
|
||||||
current_user.ap_profile_id + '#main-key')
|
current_user.ap_profile_id + '#main-key')
|
||||||
|
@ -572,7 +722,8 @@ def add_post(actor):
|
||||||
|
|
||||||
sent_to = 0
|
sent_to = 0
|
||||||
for instance in community.following_instances():
|
for instance in community.following_instances():
|
||||||
if instance.inbox and not current_user.has_blocked_instance(instance.id) and not instance_banned(instance.domain):
|
if instance.inbox and not current_user.has_blocked_instance(instance.id) and not instance_banned(
|
||||||
|
instance.domain):
|
||||||
send_to_remote_instance(instance.id, community.id, announce)
|
send_to_remote_instance(instance.id, community.id, announce)
|
||||||
sent_to += 1
|
sent_to += 1
|
||||||
if sent_to:
|
if sent_to:
|
||||||
|
@ -580,21 +731,6 @@ def add_post(actor):
|
||||||
else:
|
else:
|
||||||
flash(_('Your post to %(name)s has been made.', name=community.title))
|
flash(_('Your post to %(name)s has been made.', name=community.title))
|
||||||
|
|
||||||
return redirect(f"/c/{community.link()}")
|
|
||||||
else:
|
|
||||||
# when request.form has some data in it, it means form validation failed. Set the post_type so the correct tab is shown. See setupPostTypeTabs() in scripts.js
|
|
||||||
if request.form.get('post_type', None):
|
|
||||||
form.post_type.data = request.form.get('post_type')
|
|
||||||
form.communities.data = community.id
|
|
||||||
form.notify_author.data = True
|
|
||||||
|
|
||||||
return render_template('community/add_post.html', title=_('Add post to community'), form=form, community=community,
|
|
||||||
markdown_editor=current_user.markdown_editor, low_bandwidth=False,
|
|
||||||
moderating_communities=moderating_communities(current_user.get_id()),
|
|
||||||
joined_communities=joined_communities(current_user.id),
|
|
||||||
inoculation=inoculation[randint(0, len(inoculation) - 1)]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/community/<int:community_id>/report', methods=['GET', 'POST'])
|
@bp.route('/community/<int:community_id>/report', methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
|
|
|
@ -196,18 +196,18 @@ def url_to_thumbnail_file(filename) -> File:
|
||||||
source_url=filename)
|
source_url=filename)
|
||||||
|
|
||||||
|
|
||||||
def save_post(form, post: Post):
|
def save_post(form, post: Post, type: str):
|
||||||
post.indexable = current_user.indexable
|
post.indexable = current_user.indexable
|
||||||
post.sticky = form.sticky.data
|
post.sticky = form.sticky.data
|
||||||
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
|
||||||
if form.post_type.data == '' or form.post_type.data == '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
|
||||||
post.body_html = markdown_to_html(post.body)
|
post.body_html = markdown_to_html(post.body)
|
||||||
post.type = POST_TYPE_ARTICLE
|
post.type = POST_TYPE_ARTICLE
|
||||||
elif form.post_type.data == 'link':
|
elif type == 'link':
|
||||||
post.title = form.link_title.data
|
post.title = form.link_title.data
|
||||||
post.body = form.link_body.data
|
post.body = form.link_body.data
|
||||||
post.body_html = markdown_to_html(post.body)
|
post.body_html = markdown_to_html(post.body)
|
||||||
|
@ -244,7 +244,7 @@ def save_post(form, post: Post):
|
||||||
post.image = file
|
post.image = file
|
||||||
db.session.add(file)
|
db.session.add(file)
|
||||||
|
|
||||||
elif form.post_type.data == 'image':
|
elif type == 'image':
|
||||||
post.title = form.image_title.data
|
post.title = form.image_title.data
|
||||||
post.body = form.image_body.data
|
post.body = form.image_body.data
|
||||||
post.body_html = markdown_to_html(post.body)
|
post.body_html = markdown_to_html(post.body)
|
||||||
|
@ -304,7 +304,7 @@ def save_post(form, post: Post):
|
||||||
post.image = file
|
post.image = file
|
||||||
db.session.add(file)
|
db.session.add(file)
|
||||||
|
|
||||||
elif form.post_type.data == 'poll':
|
elif type == 'poll':
|
||||||
...
|
...
|
||||||
else:
|
else:
|
||||||
raise Exception('invalid post type')
|
raise Exception('invalid post type')
|
||||||
|
|
|
@ -13,9 +13,9 @@ from app.activitypub.util import default_context
|
||||||
from app.community.util import save_post, send_to_remote_instance
|
from app.community.util import save_post, send_to_remote_instance
|
||||||
from app.inoculation import inoculation
|
from app.inoculation import inoculation
|
||||||
from app.post.forms import NewReplyForm, ReportPostForm, MeaCulpaForm
|
from app.post.forms import NewReplyForm, ReportPostForm, MeaCulpaForm
|
||||||
from app.community.forms import CreatePostForm
|
from app.community.forms import CreateLinkForm, CreateImageForm, CreateDiscussionForm
|
||||||
from app.post.util import post_replies, get_comment_branch, post_reply_count
|
from app.post.util import post_replies, get_comment_branch, post_reply_count
|
||||||
from app.constants import SUBSCRIPTION_MEMBER, POST_TYPE_LINK, POST_TYPE_IMAGE
|
from app.constants import SUBSCRIPTION_MEMBER, POST_TYPE_LINK, POST_TYPE_IMAGE, POST_TYPE_ARTICLE
|
||||||
from app.models import Post, PostReply, \
|
from app.models import Post, PostReply, \
|
||||||
PostReplyVote, PostVote, Notification, utcnow, UserBlock, DomainBlock, InstanceBlock, Report, Site, Community, \
|
PostReplyVote, PostVote, Notification, utcnow, UserBlock, DomainBlock, InstanceBlock, Report, Site, Community, \
|
||||||
Topic, User, Instance
|
Topic, User, Instance
|
||||||
|
@ -654,11 +654,82 @@ def post_reply_options(post_id: int, comment_id: int):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/post/<int:post_id>/edit', methods=['GET', 'POST'])
|
@bp.route('/post/<int:post_id>/edit', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
def post_edit(post_id: int):
|
def post_edit(post_id: int):
|
||||||
post = Post.query.get_or_404(post_id)
|
post = Post.query.get_or_404(post_id)
|
||||||
form = CreatePostForm()
|
if post.type == POST_TYPE_ARTICLE:
|
||||||
|
return redirect(url_for('post.post_edit_discussion_post', post_id=post_id))
|
||||||
|
elif post.type == POST_TYPE_LINK:
|
||||||
|
return redirect(url_for('post.post_edit_link_post', post_id=post_id))
|
||||||
|
elif post.type == POST_TYPE_IMAGE:
|
||||||
|
return redirect(url_for('post.post_edit_image_post', post_id=post_id))
|
||||||
|
else:
|
||||||
|
abort(404)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/post/<int:post_id>/edit_discussion', methods=['GET', 'POST'])
|
||||||
|
@login_required
|
||||||
|
def post_edit_discussion_post(post_id: int):
|
||||||
|
post = Post.query.get_or_404(post_id)
|
||||||
|
form = CreateDiscussionForm()
|
||||||
|
del form.communities
|
||||||
|
|
||||||
|
mods = post.community.moderators()
|
||||||
|
if post.community.private_mods:
|
||||||
|
mod_list = []
|
||||||
|
else:
|
||||||
|
mod_user_ids = [mod.user_id for mod in mods]
|
||||||
|
mod_list = User.query.filter(User.id.in_(mod_user_ids)).all()
|
||||||
|
|
||||||
|
if post.user_id == current_user.id or post.community.is_moderator() or current_user.is_admin():
|
||||||
|
if g.site.enable_nsfl is False:
|
||||||
|
form.nsfl.render_kw = {'disabled': True}
|
||||||
|
if post.community.nsfw:
|
||||||
|
form.nsfw.data = True
|
||||||
|
form.nsfw.render_kw = {'disabled': True}
|
||||||
|
if post.community.nsfl:
|
||||||
|
form.nsfl.data = True
|
||||||
|
form.nsfw.render_kw = {'disabled': True}
|
||||||
|
|
||||||
|
if form.validate_on_submit():
|
||||||
|
save_post(form, post, 'discussion')
|
||||||
|
post.community.last_active = utcnow()
|
||||||
|
post.edited_at = utcnow()
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
post.flush_cache()
|
||||||
|
flash(_('Your changes have been saved.'), 'success')
|
||||||
|
|
||||||
|
# federate edit
|
||||||
|
if not post.community.local_only:
|
||||||
|
federate_post_update(post)
|
||||||
|
|
||||||
|
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
||||||
|
else:
|
||||||
|
form.discussion_title.data = post.title
|
||||||
|
form.discussion_body.data = post.body
|
||||||
|
form.notify_author.data = post.notify_author
|
||||||
|
form.nsfw.data = post.nsfw
|
||||||
|
form.nsfl.data = post.nsfl
|
||||||
|
form.sticky.data = post.sticky
|
||||||
|
if not (post.community.is_moderator() or post.community.is_owner() or current_user.is_admin()):
|
||||||
|
form.sticky.render_kw = {'disabled': True}
|
||||||
|
return render_template('post/post_edit_discussion.html', title=_('Edit post'), form=form, post=post,
|
||||||
|
markdown_editor=current_user.markdown_editor, mods=mod_list,
|
||||||
|
moderating_communities=moderating_communities(current_user.get_id()),
|
||||||
|
joined_communities=joined_communities(current_user.get_id()),
|
||||||
|
inoculation=inoculation[randint(0, len(inoculation) - 1)]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
abort(401)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/post/<int:post_id>/edit_image', methods=['GET', 'POST'])
|
||||||
|
@login_required
|
||||||
|
def post_edit_image_post(post_id: int):
|
||||||
|
post = Post.query.get_or_404(post_id)
|
||||||
|
form = CreateImageForm()
|
||||||
del form.communities
|
del form.communities
|
||||||
|
|
||||||
mods = post.community.moderators()
|
mods = post.community.moderators()
|
||||||
|
@ -678,11 +749,10 @@ def post_edit(post_id: int):
|
||||||
form.nsfl.data = True
|
form.nsfl.data = True
|
||||||
form.nsfw.render_kw = {'disabled': True}
|
form.nsfw.render_kw = {'disabled': True}
|
||||||
|
|
||||||
#form.communities.choices = [(c.id, c.display_name()) for c in current_user.communities()]
|
|
||||||
old_url = post.url
|
old_url = post.url
|
||||||
|
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
save_post(form, post)
|
save_post(form, post, 'image')
|
||||||
post.community.last_active = utcnow()
|
post.community.last_active = utcnow()
|
||||||
post.edited_at = utcnow()
|
post.edited_at = utcnow()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -714,6 +784,112 @@ def post_edit(post_id: int):
|
||||||
# federate edit
|
# federate edit
|
||||||
|
|
||||||
if not post.community.local_only:
|
if not post.community.local_only:
|
||||||
|
federate_post_update(post)
|
||||||
|
|
||||||
|
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
||||||
|
else:
|
||||||
|
form.image_title.data = post.title
|
||||||
|
form.image_body.data = post.body
|
||||||
|
form.image_alt_text.data = post.image.alt_text
|
||||||
|
form.notify_author.data = post.notify_author
|
||||||
|
form.nsfw.data = post.nsfw
|
||||||
|
form.nsfl.data = post.nsfl
|
||||||
|
form.sticky.data = post.sticky
|
||||||
|
if not (post.community.is_moderator() or post.community.is_owner() or current_user.is_admin()):
|
||||||
|
form.sticky.render_kw = {'disabled': True}
|
||||||
|
return render_template('post/post_edit_image.html', title=_('Edit post'), form=form, post=post,
|
||||||
|
markdown_editor=current_user.markdown_editor, mods=mod_list,
|
||||||
|
moderating_communities=moderating_communities(current_user.get_id()),
|
||||||
|
joined_communities=joined_communities(current_user.get_id()),
|
||||||
|
inoculation=inoculation[randint(0, len(inoculation) - 1)]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
abort(401)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/post/<int:post_id>/edit_link', methods=['GET', 'POST'])
|
||||||
|
@login_required
|
||||||
|
def post_edit_link_post(post_id: int):
|
||||||
|
post = Post.query.get_or_404(post_id)
|
||||||
|
form = CreateLinkForm()
|
||||||
|
del form.communities
|
||||||
|
|
||||||
|
mods = post.community.moderators()
|
||||||
|
if post.community.private_mods:
|
||||||
|
mod_list = []
|
||||||
|
else:
|
||||||
|
mod_user_ids = [mod.user_id for mod in mods]
|
||||||
|
mod_list = User.query.filter(User.id.in_(mod_user_ids)).all()
|
||||||
|
|
||||||
|
if post.user_id == current_user.id or post.community.is_moderator() or current_user.is_admin():
|
||||||
|
if g.site.enable_nsfl is False:
|
||||||
|
form.nsfl.render_kw = {'disabled': True}
|
||||||
|
if post.community.nsfw:
|
||||||
|
form.nsfw.data = True
|
||||||
|
form.nsfw.render_kw = {'disabled': True}
|
||||||
|
if post.community.nsfl:
|
||||||
|
form.nsfl.data = True
|
||||||
|
form.nsfw.render_kw = {'disabled': True}
|
||||||
|
|
||||||
|
old_url = post.url
|
||||||
|
|
||||||
|
if form.validate_on_submit():
|
||||||
|
save_post(form, post, 'link')
|
||||||
|
post.community.last_active = utcnow()
|
||||||
|
post.edited_at = utcnow()
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
if post.url != old_url:
|
||||||
|
if 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)
|
||||||
|
|
||||||
|
new_cross_posts = Post.query.filter(Post.id != post.id, Post.url == post.url,
|
||||||
|
Post.posted_at > post.edited_at - timedelta(days=6)).all()
|
||||||
|
for ncp in new_cross_posts:
|
||||||
|
if ncp.cross_posts is None:
|
||||||
|
ncp.cross_posts = [post.id]
|
||||||
|
else:
|
||||||
|
ncp.cross_posts.append(post.id)
|
||||||
|
if post.cross_posts is None:
|
||||||
|
post.cross_posts = [ncp.id]
|
||||||
|
else:
|
||||||
|
post.cross_posts.append(ncp.id)
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
post.flush_cache()
|
||||||
|
flash(_('Your changes have been saved.'), 'success')
|
||||||
|
# federate edit
|
||||||
|
|
||||||
|
if not post.community.local_only:
|
||||||
|
federate_post_update(post)
|
||||||
|
|
||||||
|
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
||||||
|
else:
|
||||||
|
form.link_title.data = post.title
|
||||||
|
form.link_body.data = post.body
|
||||||
|
form.link_url.data = post.url
|
||||||
|
form.notify_author.data = post.notify_author
|
||||||
|
form.nsfw.data = post.nsfw
|
||||||
|
form.nsfl.data = post.nsfl
|
||||||
|
form.sticky.data = post.sticky
|
||||||
|
if not (post.community.is_moderator() or post.community.is_owner() or current_user.is_admin()):
|
||||||
|
form.sticky.render_kw = {'disabled': True}
|
||||||
|
return render_template('post/post_edit_link.html', title=_('Edit post'), form=form, post=post,
|
||||||
|
markdown_editor=current_user.markdown_editor, mods=mod_list,
|
||||||
|
moderating_communities=moderating_communities(current_user.get_id()),
|
||||||
|
joined_communities=joined_communities(current_user.get_id()),
|
||||||
|
inoculation=inoculation[randint(0, len(inoculation) - 1)]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
abort(401)
|
||||||
|
|
||||||
|
|
||||||
|
def federate_post_update(post):
|
||||||
page_json = {
|
page_json = {
|
||||||
'type': 'Page',
|
'type': 'Page',
|
||||||
'id': post.ap_id,
|
'id': post.ap_id,
|
||||||
|
@ -755,16 +931,18 @@ def post_edit(post_id: int):
|
||||||
page_json['attachment'] = [{'href': post.url, 'type': 'Link'}]
|
page_json['attachment'] = [{'href': post.url, 'type': 'Link'}]
|
||||||
elif post.image_id:
|
elif post.image_id:
|
||||||
if post.image.file_path:
|
if post.image.file_path:
|
||||||
image_url = post.image.file_path.replace('app/static/', f"https://{current_app.config['SERVER_NAME']}/static/")
|
image_url = post.image.file_path.replace('app/static/',
|
||||||
|
f"https://{current_app.config['SERVER_NAME']}/static/")
|
||||||
elif post.image.thumbnail_path:
|
elif post.image.thumbnail_path:
|
||||||
image_url = post.image.thumbnail_path.replace('app/static/', f"https://{current_app.config['SERVER_NAME']}/static/")
|
image_url = post.image.thumbnail_path.replace('app/static/',
|
||||||
|
f"https://{current_app.config['SERVER_NAME']}/static/")
|
||||||
else:
|
else:
|
||||||
image_url = post.image.source_url
|
image_url = post.image.source_url
|
||||||
# NB image is a dict while attachment is a list of dicts (usually just one dict in the list)
|
# NB image is a dict while attachment is a list of dicts (usually just one dict in the list)
|
||||||
page_json['image'] = {'type': 'Image', 'url': image_url}
|
page_json['image'] = {'type': 'Image', 'url': image_url}
|
||||||
if post.type == POST_TYPE_IMAGE:
|
if post.type == POST_TYPE_IMAGE:
|
||||||
page_json['attachment'] = [{'type': 'Link', 'href': post.image.source_url}] # source_url is always a https link, no need for .replace() as done above
|
page_json['attachment'] = [{'type': 'Link',
|
||||||
|
'href': post.image.source_url}] # source_url is always a https link, no need for .replace() as done above
|
||||||
if not post.community.is_local(): # this is a remote community, send it to the instance that hosts it
|
if not post.community.is_local(): # this is a remote community, send it to the instance that hosts it
|
||||||
success = post_request(post.community.ap_inbox_url, update_json, current_user.private_key,
|
success = post_request(post.community.ap_inbox_url, update_json, current_user.private_key,
|
||||||
current_user.ap_profile_id + '#main-key')
|
current_user.ap_profile_id + '#main-key')
|
||||||
|
@ -786,40 +964,10 @@ def post_edit(post_id: int):
|
||||||
}
|
}
|
||||||
|
|
||||||
for instance in post.community.following_instances():
|
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):
|
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)
|
send_to_remote_instance(instance.id, post.community.id, announce)
|
||||||
|
|
||||||
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
|
||||||
else:
|
|
||||||
if post.type == constants.POST_TYPE_ARTICLE:
|
|
||||||
form.post_type.data = 'discussion'
|
|
||||||
form.discussion_title.data = post.title
|
|
||||||
form.discussion_body.data = post.body
|
|
||||||
elif post.type == constants.POST_TYPE_LINK:
|
|
||||||
form.post_type.data = 'link'
|
|
||||||
form.link_title.data = post.title
|
|
||||||
form.link_body.data = post.body
|
|
||||||
form.link_url.data = post.url
|
|
||||||
elif post.type == constants.POST_TYPE_IMAGE:
|
|
||||||
form.post_type.data = 'image'
|
|
||||||
form.image_title.data = post.title
|
|
||||||
form.image_body.data = post.body
|
|
||||||
form.image_alt_text.data = post.image.alt_text
|
|
||||||
form.notify_author.data = post.notify_author
|
|
||||||
form.nsfw.data = post.nsfw
|
|
||||||
form.nsfl.data = post.nsfl
|
|
||||||
form.sticky.data = post.sticky
|
|
||||||
if not (post.community.is_moderator() or post.community.is_owner() or current_user.is_admin()):
|
|
||||||
form.sticky.render_kw = {'disabled': True}
|
|
||||||
return render_template('post/post_edit.html', title=_('Edit post'), form=form, post=post,
|
|
||||||
markdown_editor=current_user.markdown_editor, mods=mod_list,
|
|
||||||
moderating_communities=moderating_communities(current_user.get_id()),
|
|
||||||
joined_communities=joined_communities(current_user.get_id()),
|
|
||||||
inoculation=inoculation[randint(0, len(inoculation) - 1)]
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
abort(401)
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/post/<int:post_id>/delete', methods=['GET', 'POST'])
|
@bp.route('/post/<int:post_id>/delete', methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
|
|
|
@ -501,6 +501,14 @@ fieldset legend {
|
||||||
.form-group {
|
.form-group {
|
||||||
margin-bottom: 1.1rem;
|
margin-bottom: 1.1rem;
|
||||||
}
|
}
|
||||||
|
.form-group.required label:after {
|
||||||
|
content: "*";
|
||||||
|
color: red;
|
||||||
|
margin-left: 2px;
|
||||||
|
font-size: 80%;
|
||||||
|
position: relative;
|
||||||
|
top: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
max-width: 350px;
|
max-width: 350px;
|
||||||
|
|
|
@ -65,6 +65,19 @@ html {
|
||||||
|
|
||||||
.form-group {
|
.form-group {
|
||||||
margin-bottom: 1.1rem;
|
margin-bottom: 1.1rem;
|
||||||
|
|
||||||
|
&.required {
|
||||||
|
label {
|
||||||
|
&:after {
|
||||||
|
content: '*';
|
||||||
|
color: red;
|
||||||
|
margin-left: 2px;
|
||||||
|
font-size: 80%;
|
||||||
|
position: relative;
|
||||||
|
top: -1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
|
|
95
app/templates/community/add_discussion_post.html
Normal file
95
app/templates/community/add_discussion_post.html
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
{% if theme() and file_exists('app/templates/themes/' + theme() + '/base.html') %}
|
||||||
|
{% extends 'themes/' + theme() + '/base.html' %}
|
||||||
|
{% else %}
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% endif %} %}
|
||||||
|
{% from 'bootstrap/form.html' import render_field %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-md-8 position-relative main_pane">
|
||||||
|
<h1>{{ _('Create post') }}</h1>
|
||||||
|
<form method="post" enctype="multipart/form-data" role="form">
|
||||||
|
{{ form.csrf_token() }}
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-control-label" for="type_of_post">
|
||||||
|
{{ _('Type of post') }}
|
||||||
|
</label>
|
||||||
|
<div id="type_of_post" class="btn-group flex-wrap" role="navigation">
|
||||||
|
<a href="{{ url_for('community.add_discussion_post', actor=actor) }}" class="btn btn-primary" aria-label="{{ _('Start a discussion') }}">{{ _('Discussion') }}</a>
|
||||||
|
<a href="{{ url_for('community.add_link_post', actor=actor) }}" class="btn btn-outline-secondary" aria-label="{{ _('Share a link') }}">{{ _('Link') }}</a>
|
||||||
|
<a href="{{ url_for('community.add_image_post', actor=actor) }}" class="btn btn-outline-secondary" aria-label="{{ _('Share an image') }}">{{ _('Image') }}</a>
|
||||||
|
<!-- <a href="#" class="btn" aria-label="{{ _('Create a poll') }}">{{ _('Poll') }}</a>
|
||||||
|
<a href="#" class="btn" aria-label="{{ _('Create an event') }}">{{ _('Event') }}</a> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ render_field(form.communities) }}
|
||||||
|
{{ render_field(form.discussion_title) }}
|
||||||
|
{{ render_field(form.discussion_body) }}
|
||||||
|
{% if not low_bandwidth %}
|
||||||
|
{% if markdown_editor %}
|
||||||
|
<script nonce="{{ session['nonce'] }}">
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
var downarea = new DownArea({
|
||||||
|
elem: document.querySelector('#discussion_body'),
|
||||||
|
resize: DownArea.RESIZE_VERTICAL,
|
||||||
|
hide: ['heading', 'bold-italic'],
|
||||||
|
});
|
||||||
|
setupAutoResize('discussion_body');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% else %}
|
||||||
|
<a href="#" aria-hidden="true" class="markdown_editor_enabler create_post_markdown_editor_enabler" data-id="discussion_body">{{ _('Enable markdown editor') }}</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="row mt-4">
|
||||||
|
<div class="col-md-3">
|
||||||
|
{{ render_field(form.notify_author) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1">
|
||||||
|
{{ render_field(form.sticky) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1">
|
||||||
|
{{ render_field(form.nsfw) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1">
|
||||||
|
{{ render_field(form.nsfl) }}
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ render_field(form.submit) }}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<aside id="side_pane" class="col-12 col-md-4 side_pane" role="complementary">
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2>{{ community.title }}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>{{ community.description_html|safe if community.description_html else '' }}</p>
|
||||||
|
<p>{{ community.rules_html|safe if community.rules_html else '' }}</p>
|
||||||
|
{% if len(mods) > 0 and not community.private_mods %}
|
||||||
|
<h3>Moderators</h3>
|
||||||
|
<ul class="moderator_list">
|
||||||
|
{% for mod in mods %}
|
||||||
|
<li>{{ render_username(mod) }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% if rss_feed %}
|
||||||
|
<p class="mt-4">
|
||||||
|
<a class="no-underline" href="{{ rss_feed }}" rel="nofollow"><span class="fe fe-rss"></span> RSS feed</a>
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% include "_inoculation_links.html" %}
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
97
app/templates/community/add_image_post.html
Normal file
97
app/templates/community/add_image_post.html
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
{% if theme() and file_exists('app/templates/themes/' + theme() + '/base.html') %}
|
||||||
|
{% extends 'themes/' + theme() + '/base.html' %}
|
||||||
|
{% else %}
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% endif %} %}
|
||||||
|
{% from 'bootstrap/form.html' import render_field %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-md-8 position-relative main_pane">
|
||||||
|
<h1>{{ _('Create post') }}</h1>
|
||||||
|
<form method="post" enctype="multipart/form-data" role="form">
|
||||||
|
{{ form.csrf_token() }}
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-control-label" for="type_of_post">
|
||||||
|
{{ _('Type of post') }}
|
||||||
|
</label>
|
||||||
|
<div id="type_of_post" class="btn-group flex-wrap" role="navigation">
|
||||||
|
<a href="{{ url_for('community.add_discussion_post', actor=actor) }}" class="btn btn-outline-secondary" aria-label="{{ _('Start a discussion') }}">{{ _('Discussion') }}</a>
|
||||||
|
<a href="{{ url_for('community.add_link_post', actor=actor) }}" class="btn btn-outline-secondary" aria-label="{{ _('Share a link') }}">{{ _('Link') }}</a>
|
||||||
|
<a href="{{ url_for('community.add_image_post', actor=actor) }}" class="btn btn-primary" aria-label="{{ _('Share an image') }}">{{ _('Image') }}</a>
|
||||||
|
<!-- <a href="#" class="btn" aria-label="{{ _('Create a poll') }}">{{ _('Poll') }}</a>
|
||||||
|
<a href="#" class="btn" aria-label="{{ _('Create an event') }}">{{ _('Event') }}</a> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ render_field(form.communities) }}
|
||||||
|
{{ render_field(form.image_title) }}
|
||||||
|
{{ render_field(form.image_file) }}
|
||||||
|
{{ render_field(form.image_alt_text) }}
|
||||||
|
<small class="field_hint">{{ _('Describe the image, to help visually impaired people.') }}</small>
|
||||||
|
{{ render_field(form.image_body) }}
|
||||||
|
{% if not low_bandwidth %}
|
||||||
|
{% if markdown_editor %}
|
||||||
|
<script nonce="{{ session['nonce'] }}">
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
var downarea = new DownArea({
|
||||||
|
elem: document.querySelector('#image_body'),
|
||||||
|
resize: DownArea.RESIZE_VERTICAL,
|
||||||
|
hide: ['heading', 'bold-italic'],
|
||||||
|
});
|
||||||
|
setupAutoResize('image_body');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% else %}
|
||||||
|
<a href="#" aria-hidden="true" class="markdown_editor_enabler create_post_markdown_editor_enabler" data-id="image_body">{{ _('Enable markdown editor') }}</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="row mt-4">
|
||||||
|
<div class="col-md-3">
|
||||||
|
{{ render_field(form.notify_author) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1">
|
||||||
|
{{ render_field(form.sticky) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1">
|
||||||
|
{{ render_field(form.nsfw) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1">
|
||||||
|
{{ render_field(form.nsfl) }}
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ render_field(form.submit) }}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<aside id="side_pane" class="col-12 col-md-4 side_pane" role="complementary">
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2>{{ community.title }}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>{{ community.description_html|safe if community.description_html else '' }}</p>
|
||||||
|
<p>{{ community.rules_html|safe if community.rules_html else '' }}</p>
|
||||||
|
{% if len(mods) > 0 and not community.private_mods %}
|
||||||
|
<h3>Moderators</h3>
|
||||||
|
<ul class="moderator_list">
|
||||||
|
{% for mod in mods %}
|
||||||
|
<li>{{ render_username(mod) }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% if rss_feed %}
|
||||||
|
<p class="mt-4">
|
||||||
|
<a class="no-underline" href="{{ rss_feed }}" rel="nofollow"><span class="fe fe-rss"></span> RSS feed</a>
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% include "_inoculation_links.html" %}
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
96
app/templates/community/add_link_post.html
Normal file
96
app/templates/community/add_link_post.html
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
{% if theme() and file_exists('app/templates/themes/' + theme() + '/base.html') %}
|
||||||
|
{% extends 'themes/' + theme() + '/base.html' %}
|
||||||
|
{% else %}
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% endif %} %}
|
||||||
|
{% from 'bootstrap/form.html' import render_field %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-md-8 position-relative main_pane">
|
||||||
|
<h1>{{ _('Create post') }}</h1>
|
||||||
|
<form method="post" enctype="multipart/form-data" role="form">
|
||||||
|
{{ form.csrf_token() }}
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-control-label" for="type_of_post">
|
||||||
|
{{ _('Type of post') }}
|
||||||
|
</label>
|
||||||
|
<div id="type_of_post" class="btn-group flex-wrap" role="navigation">
|
||||||
|
<a href="{{ url_for('community.add_discussion_post', actor=actor) }}" class="btn btn-outline-secondary" aria-label="{{ _('Start a discussion') }}">{{ _('Discussion') }}</a>
|
||||||
|
<a href="{{ url_for('community.add_link_post', actor=actor) }}" class="btn btn-primary" aria-label="{{ _('Share a link') }}">{{ _('Link') }}</a>
|
||||||
|
<a href="{{ url_for('community.add_image_post', actor=actor) }}" class="btn btn-outline-secondary" aria-label="{{ _('Share an image') }}">{{ _('Image') }}</a>
|
||||||
|
<!-- <a href="#" class="btn" aria-label="{{ _('Create a poll') }}">{{ _('Poll') }}</a>
|
||||||
|
<a href="#" class="btn" aria-label="{{ _('Create an event') }}">{{ _('Event') }}</a> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ render_field(form.communities) }}
|
||||||
|
|
||||||
|
{{ render_field(form.link_title) }}
|
||||||
|
{{ render_field(form.link_url) }}
|
||||||
|
{{ render_field(form.link_body) }}
|
||||||
|
{% if not low_bandwidth %}
|
||||||
|
{% if markdown_editor %}
|
||||||
|
<script nonce="{{ session['nonce'] }}">
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
var downarea = new DownArea({
|
||||||
|
elem: document.querySelector('#link_body'),
|
||||||
|
resize: DownArea.RESIZE_VERTICAL,
|
||||||
|
hide: ['heading', 'bold-italic'],
|
||||||
|
});
|
||||||
|
setupAutoResize('link_body');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% else %}
|
||||||
|
<a href="#" aria-hidden="true" class="markdown_editor_enabler create_post_markdown_editor_enabler" data-id="link_body">{{ _('Enable markdown editor') }}</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="row mt-4">
|
||||||
|
<div class="col-md-3">
|
||||||
|
{{ render_field(form.notify_author) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1">
|
||||||
|
{{ render_field(form.sticky) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1">
|
||||||
|
{{ render_field(form.nsfw) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1">
|
||||||
|
{{ render_field(form.nsfl) }}
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ render_field(form.submit) }}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<aside id="side_pane" class="col-12 col-md-4 side_pane" role="complementary">
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2>{{ community.title }}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>{{ community.description_html|safe if community.description_html else '' }}</p>
|
||||||
|
<p>{{ community.rules_html|safe if community.rules_html else '' }}</p>
|
||||||
|
{% if len(mods) > 0 and not community.private_mods %}
|
||||||
|
<h3>Moderators</h3>
|
||||||
|
<ul class="moderator_list">
|
||||||
|
{% for mod in mods %}
|
||||||
|
<li>{{ render_username(mod) }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% if rss_feed %}
|
||||||
|
<p class="mt-4">
|
||||||
|
<a class="no-underline" href="{{ rss_feed }}" rel="nofollow"><span class="fe fe-rss"></span> RSS feed</a>
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% include "_inoculation_links.html" %}
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -1,145 +0,0 @@
|
||||||
{% if theme() and file_exists('app/templates/themes/' + theme() + '/base.html') %}
|
|
||||||
{% extends 'themes/' + theme() + '/base.html' %}
|
|
||||||
{% else %}
|
|
||||||
{% extends "base.html" %}
|
|
||||||
{% endif %} %}
|
|
||||||
{% from 'bootstrap/form.html' import render_field %}
|
|
||||||
|
|
||||||
{% block app_content %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-12 col-md-8 position-relative main_pane">
|
|
||||||
<h1>{{ _('Create post') }}</h1>
|
|
||||||
<form method="post" enctype="multipart/form-data" role="form">
|
|
||||||
{{ form.csrf_token() }}
|
|
||||||
{{ render_field(form.communities) }}
|
|
||||||
<nav id="post_type_chooser">
|
|
||||||
<div class="nav nav-tabs nav-justified" id="typeTab" role="tablist">
|
|
||||||
<button class="nav-link active" id="discussion-tab" data-bs-toggle="tab" data-bs-target="#discussion-tab-pane"
|
|
||||||
type="button" role="tab" aria-controls="discussion-tab-pane" aria-selected="true">Discussion</button>
|
|
||||||
<button class="nav-link" id="link-tab" data-bs-toggle="tab" data-bs-target="#link-tab-pane"
|
|
||||||
type="button" role="tab" aria-controls="link-tab-pane" aria-selected="false">Link</button>
|
|
||||||
<button class="nav-link" id="image-tab" data-bs-toggle="tab" data-bs-target="#image-tab-pane"
|
|
||||||
type="button" role="tab" aria-controls="image-tab-pane" aria-selected="false">Image</button>
|
|
||||||
<button class="nav-link" id="poll-tab" data-bs-toggle="tab" data-bs-target="#poll-tab-pane"
|
|
||||||
type="button" role="tab" aria-controls="poll-tab-pane" aria-selected="false" disabled>Poll</button>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<div class="tab-content" id="myTabContent">
|
|
||||||
<div class="tab-pane fade show active" id="discussion-tab-pane" role="tabpanel" aria-labelledby="home-tab" tabindex="0">
|
|
||||||
{{ render_field(form.discussion_title) }}
|
|
||||||
{{ render_field(form.discussion_body) }}
|
|
||||||
{% if not low_bandwidth %}
|
|
||||||
{% if markdown_editor %}
|
|
||||||
<script nonce="{{ session['nonce'] }}">
|
|
||||||
window.addEventListener("load", function () {
|
|
||||||
var downarea = new DownArea({
|
|
||||||
elem: document.querySelector('#discussion_body'),
|
|
||||||
resize: DownArea.RESIZE_VERTICAL,
|
|
||||||
hide: ['heading', 'bold-italic'],
|
|
||||||
});
|
|
||||||
setupAutoResize('discussion_body');
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% else %}
|
|
||||||
<a href="#" aria-hidden="true" class="markdown_editor_enabler create_post_markdown_editor_enabler" data-id="discussion_body">{{ _('Enable markdown editor') }}</a>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="tab-pane fade" id="link-tab-pane" role="tabpanel" aria-labelledby="profile-tab" tabindex="0">
|
|
||||||
{{ render_field(form.link_title) }}
|
|
||||||
{{ render_field(form.link_url) }}
|
|
||||||
{{ render_field(form.link_body) }}
|
|
||||||
{% if not low_bandwidth %}
|
|
||||||
{% if markdown_editor %}
|
|
||||||
<script nonce="{{ session['nonce'] }}">
|
|
||||||
window.addEventListener("load", function () {
|
|
||||||
var downarea = new DownArea({
|
|
||||||
elem: document.querySelector('#link_body'),
|
|
||||||
resize: DownArea.RESIZE_VERTICAL,
|
|
||||||
hide: ['heading', 'bold-italic'],
|
|
||||||
});
|
|
||||||
setupAutoResize('link_body');
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% else %}
|
|
||||||
<a href="#" aria-hidden="true" class="markdown_editor_enabler create_post_markdown_editor_enabler" data-id="link_body">{{ _('Enable markdown editor') }}</a>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="tab-pane fade" id="image-tab-pane" role="tabpanel" aria-labelledby="contact-tab" tabindex="0">
|
|
||||||
{{ render_field(form.image_title) }}
|
|
||||||
{{ render_field(form.image_file) }}
|
|
||||||
{{ render_field(form.image_alt_text) }}
|
|
||||||
<small class="field_hint">{{ _('Describe the image, to help visually impaired people.') }}</small>
|
|
||||||
{{ render_field(form.image_body) }}
|
|
||||||
{% if not low_bandwidth %}
|
|
||||||
{% if markdown_editor %}
|
|
||||||
<script nonce="{{ session['nonce'] }}">
|
|
||||||
window.addEventListener("load", function () {
|
|
||||||
var downarea = new DownArea({
|
|
||||||
elem: document.querySelector('#image_body'),
|
|
||||||
resize: DownArea.RESIZE_VERTICAL,
|
|
||||||
hide: ['heading', 'bold-italic'],
|
|
||||||
});
|
|
||||||
setupAutoResize('image_body');
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% else %}
|
|
||||||
<a href="#" aria-hidden="true" class="markdown_editor_enabler create_post_markdown_editor_enabler" data-id="image_body">{{ _('Enable markdown editor') }}</a>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="tab-pane fade" id="poll-tab-pane" role="tabpanel" aria-labelledby="disabled-tab" tabindex="0">
|
|
||||||
Poll
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{ render_field(form.post_type) }}
|
|
||||||
<div class="row mt-4">
|
|
||||||
<div class="col-md-3">
|
|
||||||
{{ render_field(form.notify_author) }}
|
|
||||||
</div>
|
|
||||||
<div class="col-md-1">
|
|
||||||
{{ render_field(form.sticky) }}
|
|
||||||
</div>
|
|
||||||
<div class="col-md-1">
|
|
||||||
{{ render_field(form.nsfw) }}
|
|
||||||
</div>
|
|
||||||
<div class="col-md-1">
|
|
||||||
{{ render_field(form.nsfl) }}
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{ render_field(form.submit) }}
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<aside id="side_pane" class="col-12 col-md-4 side_pane" role="complementary">
|
|
||||||
<div class="card mb-3">
|
|
||||||
<div class="card-header">
|
|
||||||
<h2>{{ community.title }}</h2>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<p>{{ community.description_html|safe if community.description_html else '' }}</p>
|
|
||||||
<p>{{ community.rules_html|safe if community.rules_html else '' }}</p>
|
|
||||||
{% if len(mods) > 0 and not community.private_mods %}
|
|
||||||
<h3>Moderators</h3>
|
|
||||||
<ul class="moderator_list">
|
|
||||||
{% for mod in mods %}
|
|
||||||
<li>{{ render_username(mod) }}</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
{% if rss_feed %}
|
|
||||||
<p class="mt-4">
|
|
||||||
<a class="no-underline" href="{{ rss_feed }}" rel="nofollow"><span class="fe fe-rss"></span> RSS feed</a>
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% include "_inoculation_links.html" %}
|
|
||||||
</aside>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
|
@ -1,164 +0,0 @@
|
||||||
{% if theme() and file_exists('app/templates/themes/' + theme() + '/base.html') %}
|
|
||||||
{% extends 'themes/' + theme() + '/base.html' %}
|
|
||||||
{% else %}
|
|
||||||
{% extends "base.html" %}
|
|
||||||
{% endif %} %}
|
|
||||||
{% from 'bootstrap/form.html' import render_form, render_field %}
|
|
||||||
|
|
||||||
{% block app_content %}
|
|
||||||
<script nonce="{{ session['nonce'] }}" type="text/javascript">
|
|
||||||
window.addEventListener("load", function () {
|
|
||||||
var type = document.forms[0].elements['type'].value;
|
|
||||||
var toClick = undefined;
|
|
||||||
switch(type) {
|
|
||||||
case '':
|
|
||||||
case 'discussion':
|
|
||||||
toClick = document.getElementById('discussion-tab');
|
|
||||||
break;
|
|
||||||
case 'link':
|
|
||||||
toClick = document.getElementById('link-tab');
|
|
||||||
break;
|
|
||||||
case 'image':
|
|
||||||
toClick = document.getElementById('image-tab');
|
|
||||||
break;
|
|
||||||
case 'poll':
|
|
||||||
toClick = document.getElementById('poll-tab');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(toClick) {
|
|
||||||
toClick.click();
|
|
||||||
}
|
|
||||||
|
|
||||||
var downarea = new DownArea({
|
|
||||||
elem: document.querySelector('#discussion_body'),
|
|
||||||
resize: DownArea.RESIZE_VERTICAL,
|
|
||||||
hide: ['heading', 'bold-italic'],
|
|
||||||
value: {{ form.discussion_body.data | tojson | safe }}
|
|
||||||
});
|
|
||||||
setupAutoResize('discussion_body');
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-12 col-md-8 position-relative main_pane">
|
|
||||||
<h1>{{ _('Edit post') }}</h1>
|
|
||||||
<form method="post" enctype="multipart/form-data" role="form">
|
|
||||||
{{ form.csrf_token() }}
|
|
||||||
<nav id="post_type_chooser">
|
|
||||||
<div class="nav nav-tabs nav-justified" id="typeTab" role="tablist">
|
|
||||||
<button class="nav-link active" id="discussion-tab" data-bs-toggle="tab" data-bs-target="#discussion-tab-pane"
|
|
||||||
type="button" role="tab" aria-controls="discussion-tab-pane" aria-selected="true">Discussion</button>
|
|
||||||
<button class="nav-link" id="link-tab" data-bs-toggle="tab" data-bs-target="#link-tab-pane"
|
|
||||||
type="button" role="tab" aria-controls="link-tab-pane" aria-selected="false">Link</button>
|
|
||||||
<button class="nav-link" id="image-tab" data-bs-toggle="tab" data-bs-target="#image-tab-pane"
|
|
||||||
type="button" role="tab" aria-controls="image-tab-pane" aria-selected="false">Image</button>
|
|
||||||
<button class="nav-link" id="poll-tab" data-bs-toggle="tab" data-bs-target="#poll-tab-pane"
|
|
||||||
type="button" role="tab" aria-controls="poll-tab-pane" aria-selected="false" disabled>Poll</button>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<div class="tab-content" id="myTabContent">
|
|
||||||
<div class="tab-pane fade show active" id="discussion-tab-pane" role="tabpanel" aria-labelledby="home-tab" tabindex="0">
|
|
||||||
{{ render_field(form.discussion_title) }}
|
|
||||||
{{ render_field(form.discussion_body) }}
|
|
||||||
{% if markdown_editor %}
|
|
||||||
<script nonce="{{ session['nonce'] }}">
|
|
||||||
window.addEventListener("load", function () {
|
|
||||||
var downarea = new DownArea({
|
|
||||||
elem: document.querySelector('#discussion_body'),
|
|
||||||
resize: DownArea.RESIZE_VERTICAL,
|
|
||||||
hide: ['heading', 'bold-italic'],
|
|
||||||
value: {{ form.discussion_body.data | tojson | safe }},
|
|
||||||
});
|
|
||||||
setupAutoResize('discussion_body');
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="tab-pane fade" id="link-tab-pane" role="tabpanel" aria-labelledby="profile-tab" tabindex="0">
|
|
||||||
{{ render_field(form.link_title) }}
|
|
||||||
{{ render_field(form.link_url) }}
|
|
||||||
{{ render_field(form.link_body) }}
|
|
||||||
{% if markdown_editor %}
|
|
||||||
<script nonce="{{ session['nonce'] }}">
|
|
||||||
window.addEventListener("load", function () {
|
|
||||||
var downarea = new DownArea({
|
|
||||||
elem: document.querySelector('#link_body'),
|
|
||||||
resize: DownArea.RESIZE_VERTICAL,
|
|
||||||
hide: ['heading', 'bold-italic'],
|
|
||||||
value: {{ form.link_body.data | tojson | safe }},
|
|
||||||
});
|
|
||||||
setupAutoResize('link_body');
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="tab-pane fade" id="image-tab-pane" role="tabpanel" aria-labelledby="contact-tab" tabindex="0">
|
|
||||||
{{ render_field(form.image_title) }}
|
|
||||||
{{ render_field(form.image_file) }}
|
|
||||||
{{ render_field(form.image_alt_text) }}
|
|
||||||
<small class="field_hint">{{ _('Describe the image, to help visually impaired people.') }}</small>
|
|
||||||
{{ render_field(form.image_body) }}
|
|
||||||
{% if markdown_editor %}
|
|
||||||
<script nonce="{{ session['nonce'] }}">
|
|
||||||
window.addEventListener("load", function () {
|
|
||||||
var downarea = new DownArea({
|
|
||||||
elem: document.querySelector('#image_body'),
|
|
||||||
resize: DownArea.RESIZE_VERTICAL,
|
|
||||||
hide: ['heading', 'bold-italic'],
|
|
||||||
value: {{ form.image_body.data | tojson | safe }},
|
|
||||||
});
|
|
||||||
setupAutoResize('image_body');
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="tab-pane fade" id="poll-tab-pane" role="tabpanel" aria-labelledby="disabled-tab" tabindex="0">
|
|
||||||
Poll
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{ render_field(form.post_type) }}
|
|
||||||
<div class="row mt-4">
|
|
||||||
<div class="col-md-3">
|
|
||||||
{{ render_field(form.notify_author) }}
|
|
||||||
</div>
|
|
||||||
<div class="col-md-1">
|
|
||||||
{{ render_field(form.sticky) }}
|
|
||||||
</div>
|
|
||||||
<div class="col-md-1">
|
|
||||||
{{ render_field(form.nsfw) }}
|
|
||||||
</div>
|
|
||||||
<div class="col-md-1">
|
|
||||||
{{ render_field(form.nsfl) }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{ render_field(form.submit) }}
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<aside id="side_pane" class="col-12 col-md-4 side_pane" role="complementary">
|
|
||||||
<div class="card mt-3">
|
|
||||||
<div class="card-header">
|
|
||||||
<h2>{{ post.community.title }}</h2>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<p>{{ post.community.description_html|safe if post.community.description_html else '' }}</p>
|
|
||||||
<p>{{ post.community.rules_html|safe if post.community.rules_html else '' }}</p>
|
|
||||||
{% if len(mods) > 0 and not post.community.private_mods %}
|
|
||||||
<h3>Moderators</h3>
|
|
||||||
<ul class="moderator_list">
|
|
||||||
{% for mod in mods %}
|
|
||||||
<li><a href="/u/{{ mod.link() }}">{{ mod.display_name() }}</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% include "_inoculation_links.html" %}
|
|
||||||
</aside>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
75
app/templates/post/post_edit_discussion.html
Normal file
75
app/templates/post/post_edit_discussion.html
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
{% if theme() and file_exists('app/templates/themes/' + theme() + '/base.html') %}
|
||||||
|
{% extends 'themes/' + theme() + '/base.html' %}
|
||||||
|
{% else %}
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% endif %} %}
|
||||||
|
{% from 'bootstrap/form.html' import render_form, render_field %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-md-8 position-relative main_pane">
|
||||||
|
<h1>{{ _('Edit post') }}</h1>
|
||||||
|
<form method="post" role="form">
|
||||||
|
{{ form.csrf_token() }}
|
||||||
|
{{ render_field(form.discussion_title) }}
|
||||||
|
{{ render_field(form.discussion_body) }}
|
||||||
|
{% if markdown_editor %}
|
||||||
|
<script nonce="{{ session['nonce'] }}">
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
var downarea = new DownArea({
|
||||||
|
elem: document.querySelector('#discussion_body'),
|
||||||
|
resize: DownArea.RESIZE_VERTICAL,
|
||||||
|
hide: ['heading', 'bold-italic'],
|
||||||
|
value: {{ form.discussion_body.data | tojson | safe }},
|
||||||
|
});
|
||||||
|
setupAutoResize('discussion_body');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="row mt-4">
|
||||||
|
<div class="col-md-3">
|
||||||
|
{{ render_field(form.notify_author) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1">
|
||||||
|
{{ render_field(form.sticky) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1">
|
||||||
|
{{ render_field(form.nsfw) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1">
|
||||||
|
{{ render_field(form.nsfl) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ render_field(form.submit) }}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<aside id="side_pane" class="col-12 col-md-4 side_pane" role="complementary">
|
||||||
|
<div class="card mt-3">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2>{{ post.community.title }}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>{{ post.community.description_html|safe if post.community.description_html else '' }}</p>
|
||||||
|
<p>{{ post.community.rules_html|safe if post.community.rules_html else '' }}</p>
|
||||||
|
{% if len(mods) > 0 and not post.community.private_mods %}
|
||||||
|
<h3>Moderators</h3>
|
||||||
|
<ul class="moderator_list">
|
||||||
|
{% for mod in mods %}
|
||||||
|
<li><a href="/u/{{ mod.link() }}">{{ mod.display_name() }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% include "_inoculation_links.html" %}
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
78
app/templates/post/post_edit_image.html
Normal file
78
app/templates/post/post_edit_image.html
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
{% if theme() and file_exists('app/templates/themes/' + theme() + '/base.html') %}
|
||||||
|
{% extends 'themes/' + theme() + '/base.html' %}
|
||||||
|
{% else %}
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% endif %} %}
|
||||||
|
{% from 'bootstrap/form.html' import render_form, render_field %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-md-8 position-relative main_pane">
|
||||||
|
<h1>{{ _('Edit post') }}</h1>
|
||||||
|
<form method="post" enctype="multipart/form-data" role="form">
|
||||||
|
{{ form.csrf_token() }}
|
||||||
|
{{ render_field(form.image_title) }}
|
||||||
|
{{ render_field(form.image_file) }}
|
||||||
|
{{ render_field(form.image_alt_text) }}
|
||||||
|
<small class="field_hint">{{ _('Describe the image, to help visually impaired people.') }}</small>
|
||||||
|
{{ render_field(form.image_body) }}
|
||||||
|
{% if markdown_editor %}
|
||||||
|
<script nonce="{{ session['nonce'] }}">
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
var downarea = new DownArea({
|
||||||
|
elem: document.querySelector('#image_body'),
|
||||||
|
resize: DownArea.RESIZE_VERTICAL,
|
||||||
|
hide: ['heading', 'bold-italic'],
|
||||||
|
value: {{ form.image_body.data | tojson | safe }},
|
||||||
|
});
|
||||||
|
setupAutoResize('image_body');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="row mt-4">
|
||||||
|
<div class="col-md-3">
|
||||||
|
{{ render_field(form.notify_author) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1">
|
||||||
|
{{ render_field(form.sticky) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1">
|
||||||
|
{{ render_field(form.nsfw) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1">
|
||||||
|
{{ render_field(form.nsfl) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ render_field(form.submit) }}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<aside id="side_pane" class="col-12 col-md-4 side_pane" role="complementary">
|
||||||
|
<div class="card mt-3">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2>{{ post.community.title }}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>{{ post.community.description_html|safe if post.community.description_html else '' }}</p>
|
||||||
|
<p>{{ post.community.rules_html|safe if post.community.rules_html else '' }}</p>
|
||||||
|
{% if len(mods) > 0 and not post.community.private_mods %}
|
||||||
|
<h3>Moderators</h3>
|
||||||
|
<ul class="moderator_list">
|
||||||
|
{% for mod in mods %}
|
||||||
|
<li><a href="/u/{{ mod.link() }}">{{ mod.display_name() }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% include "_inoculation_links.html" %}
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
75
app/templates/post/post_edit_link.html
Normal file
75
app/templates/post/post_edit_link.html
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
{% if theme() and file_exists('app/templates/themes/' + theme() + '/base.html') %}
|
||||||
|
{% extends 'themes/' + theme() + '/base.html' %}
|
||||||
|
{% else %}
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% endif %} %}
|
||||||
|
{% from 'bootstrap/form.html' import render_form, render_field %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-md-8 position-relative main_pane">
|
||||||
|
<h1>{{ _('Edit post') }}</h1>
|
||||||
|
<form method="post" enctype="multipart/form-data" role="form">
|
||||||
|
{{ form.csrf_token() }}
|
||||||
|
{{ render_field(form.link_title) }}
|
||||||
|
{{ render_field(form.link_url) }}
|
||||||
|
{{ render_field(form.link_body) }}
|
||||||
|
{% if markdown_editor %}
|
||||||
|
<script nonce="{{ session['nonce'] }}">
|
||||||
|
window.addEventListener("load", function () {
|
||||||
|
var downarea = new DownArea({
|
||||||
|
elem: document.querySelector('#link_body'),
|
||||||
|
resize: DownArea.RESIZE_VERTICAL,
|
||||||
|
hide: ['heading', 'bold-italic'],
|
||||||
|
value: {{ form.link_body.data | tojson | safe }},
|
||||||
|
});
|
||||||
|
setupAutoResize('link_body');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
|
<div class="row mt-4">
|
||||||
|
<div class="col-md-3">
|
||||||
|
{{ render_field(form.notify_author) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1">
|
||||||
|
{{ render_field(form.sticky) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1">
|
||||||
|
{{ render_field(form.nsfw) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1">
|
||||||
|
{{ render_field(form.nsfl) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ render_field(form.submit) }}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<aside id="side_pane" class="col-12 col-md-4 side_pane" role="complementary">
|
||||||
|
<div class="card mt-3">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2>{{ post.community.title }}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>{{ post.community.description_html|safe if post.community.description_html else '' }}</p>
|
||||||
|
<p>{{ post.community.rules_html|safe if post.community.rules_html else '' }}</p>
|
||||||
|
{% if len(mods) > 0 and not post.community.private_mods %}
|
||||||
|
<h3>Moderators</h3>
|
||||||
|
<ul class="moderator_list">
|
||||||
|
{% for mod in mods %}
|
||||||
|
<li><a href="/u/{{ mod.link() }}">{{ mod.display_name() }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% include "_inoculation_links.html" %}
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
Loading…
Reference in a new issue