__filename__ = "webapp_create_post.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
__version__ = "1.4.0"
__maintainer__ = "Bob Mottram"
__email__ = "bob@libreserver.org"
__status__ = "Production"
__module_group__ = "Web Interface"
import os
from utils import remove_html
from utils import get_content_from_post
from utils import has_object_dict
from utils import load_json
from utils import locate_post
from utils import get_new_post_endpoints
from utils import is_public_post_from_url
from utils import get_nickname_from_actor
from utils import get_domain_from_actor
from utils import get_media_formats
from utils import get_config_param
from utils import acct_dir
from utils import get_currencies
from utils import get_category_types
from utils import get_account_timezone
from utils import get_supported_languages
from utils import text_in_file
from webapp_utils import edit_check_box
from webapp_utils import get_buy_links
from webapp_utils import html_following_data_list
from webapp_utils import html_common_emoji
from webapp_utils import begin_edit_section
from webapp_utils import end_edit_section
from webapp_utils import get_banner_file
from webapp_utils import html_header_with_external_style
from webapp_utils import html_footer
from webapp_utils import edit_text_field
from webapp_utils import edit_number_field
from webapp_utils import edit_currency_field
from webapp_post import individual_post_as_html
from maps import get_map_preferences_url
from maps import get_map_preferences_coords
from maps import get_location_from_post
def _html_new_post_drop_down(scope_icon: str, scope_description: str,
reply_str: str,
translate: {},
show_public_on_dropdown: bool,
default_timeline: str,
path_base: str,
dropdown_new_post_suffix: str,
dropdown_new_blog_suffix: str,
dropdown_unlisted_suffix: str,
dropdown_followers_suffix: str,
dropdown_dm_suffix: str,
dropdown_reminder_suffix: str,
dropdown_report_suffix: str,
no_drop_down: bool,
access_keys: {},
account_dir: str) -> str:
"""Returns the html for a drop down list of new post types
"""
drop_down_content = '\n'
return drop_down_content
drop_down_content += '
\n'
if show_public_on_dropdown:
drop_down_content += \
'
\n'
drop_down_content += '\n'
return drop_down_content
def _get_date_from_tags(tags: []) -> (str, str):
"""Returns the date from the tags list
"""
for tag_item in tags:
if not tag_item.get('type'):
continue
if tag_item['type'] != 'Event':
continue
if not tag_item.get('startTime'):
continue
if not isinstance(tag_item['startTime'], str):
continue
if 'T' not in tag_item['startTime']:
continue
start_time = tag_item['startTime']
if not tag_item.get('endTime'):
return start_time, ''
if not isinstance(tag_item['endTime'], str):
return start_time, ''
if 'T' not in tag_item['endTime']:
return start_time, ''
end_time = tag_item['endTime']
return start_time, end_time
return '', ''
def _remove_initial_mentions_from_content(content: str) -> str:
""" Removes initial @mentions from content
This happens when a the html content is converted back to plain text
"""
if not content.startswith('@'):
return content
words = content.split(' ')
new_content = ''
for wrd in words:
if wrd.startswith('@'):
continue
if new_content:
new_content += ' ' + wrd
else:
new_content += wrd
return new_content
def html_new_post(edit_post_params: {},
media_instance: bool, translate: {},
base_dir: str, http_prefix: str,
path: str, in_reply_to: str,
mentions: [],
share_description: str,
report_url: str, page_number: int,
category: str,
nickname: str, domain: str,
domain_full: str,
default_timeline: str, newswire: {},
theme: str, no_drop_down: bool,
access_keys: {}, custom_submit_text: str,
conversation_id: str,
recent_posts_cache: {}, max_recent_posts: int,
session, cached_webfingers: {},
person_cache: {}, port: int,
post_json_object: {},
project_version: str,
yt_replace_domain: str,
twitter_replacement_domain: str,
show_published_date_only: bool,
peertube_instances: [],
allow_local_network_access: bool,
system_language: str,
languages_understood: [],
max_like_count: int, signing_priv_key_pem: str,
cw_lists: {}, lists_enabled: str,
box_name: str,
reply_is_chat: bool, bold_reading: bool,
dogwhistles: {},
min_images_for_accounts: [],
default_month: int, default_year: int,
default_post_language: str,
buy_sites: {},
default_buy_site: str) -> str:
"""New post screen
"""
# get the json if this is an edited post
edited_post_json = None
edited_published = ''
if edit_post_params:
if edit_post_params.get('post_url'):
edited_post_filename = \
locate_post(base_dir, nickname,
domain, edit_post_params['post_url'])
if edited_post_filename:
edited_post_json = load_json(edited_post_filename)
if not has_object_dict(edited_post_json):
return ''
if not edited_post_json:
return ''
buy_links = \
get_buy_links(edited_post_json, translate, buy_sites)
if buy_links:
for _, buy_url in buy_links.items():
default_buy_site = buy_url
break
if edited_post_json['object'].get('conversation'):
conversation_id = edited_post_json['object']['conversation']
elif edited_post_json['object'].get('context'):
conversation_id = edited_post_json['object']['context']
if edit_post_params.get('replyTo'):
in_reply_to = edit_post_params['replyTo']
if edit_post_params['scope'] == 'dm':
mentions = edited_post_json['object']['to']
edited_published = \
edited_post_json['object']['published']
# default subject line or content warning
default_subject = ''
if share_description:
default_subject = share_description
default_location = ''
default_start_time = ''
default_end_time = ''
if default_month and default_year:
default_month_str = str(default_month)
if default_month < 10:
default_month_str = '0' + default_month_str
default_start_time = \
str(default_year) + '-' + default_month_str + '-01T09:00:00'
if edited_post_json:
# if this is an edited post then get the subject line or
# content warning
summary_str = get_content_from_post(edited_post_json, system_language,
languages_understood, "summary")
if summary_str:
default_subject = remove_html(summary_str)
if edited_post_json['object'].get('tag'):
# if this is an edited post then get the location
location_str = get_location_from_post(edited_post_json)
if location_str:
default_location = location_str
# if this is an edited post then get the start and end time
default_start_time, default_end_time = \
_get_date_from_tags(edited_post_json['object']['tag'])
reply_str = ''
is_new_reminder = False
if path.endswith('/newreminder'):
is_new_reminder = True
# the date and time
date_and_time_str = '
\n'
if not is_new_reminder:
date_and_time_str += \
'\n'
# select a date and time for this post
date_and_time_str += '\n'
date_default = ''
time_default = ''
if default_start_time:
date_default = ' value="' + default_start_time.split('T')[0] + '"'
time_default = ' value="' + default_start_time.split('T')[1] + '"'
end_time_default = ''
if default_end_time:
end_time_default = ' value="' + default_end_time.split('T')[1] + '"'
date_and_time_str += \
'\n'
date_and_time_str += '\n \n'
date_and_time_str += '\n
\n'
show_public_on_dropdown = True
message_box_height = 400
image_description_height = 150
transcript_height = 1000
# filename of the banner shown at the top
banner_file, _ = \
get_banner_file(base_dir, nickname, domain, theme)
if not path.endswith('/newshare') and not path.endswith('/newwanted'):
if not path.endswith('/newreport'):
if not in_reply_to or is_new_reminder:
new_post_text = '
' + \
translate['Write your post text below.'] + '
\n'
if post_json_object:
timezone = \
get_account_timezone(base_dir, nickname, domain)
minimize_all_images = False
if nickname in min_images_for_accounts:
minimize_all_images = True
new_post_text += \
individual_post_as_html(signing_priv_key_pem,
True, recent_posts_cache,
max_recent_posts,
translate, None,
base_dir, session,
cached_webfingers,
person_cache,
nickname, domain, port,
post_json_object,
None, True, False,
http_prefix,
project_version,
box_name,
yt_replace_domain,
twitter_replacement_domain,
show_published_date_only,
peertube_instances,
allow_local_network_access,
theme, system_language,
max_like_count,
False, False, False,
False, False, False,
cw_lists, lists_enabled,
timezone, False,
bold_reading, dogwhistles,
minimize_all_images, None,
buy_sites)
reply_str = '\n'
# if replying to a non-public post then also make
# this post non-public
if not is_public_post_from_url(base_dir, nickname, domain,
in_reply_to):
new_post_path = path
if '?' in new_post_path:
new_post_path = new_post_path.split('?')[0]
if new_post_path.endswith('/newpost'):
path = path.replace('/newpost', '/newfollowers')
show_public_on_dropdown = False
else:
new_post_text = \
'
' + translate['Write your report below.'] + '
\n'
# custom report header with any additional instructions
if os.path.isfile(base_dir + '/accounts/report.txt'):
with open(base_dir + '/accounts/report.txt', 'r',
encoding='utf-8') as file:
custom_report_text = file.read()
if '' not in custom_report_text:
custom_report_text = \
'
', rep_str)
new_post_text += custom_report_text
idx = 'This message only goes to moderators, even if it ' + \
'mentions other fediverse addresses.'
new_post_text += \
'
\n'
citations_separator = '#####'
with open(citations_filename, 'r', encoding='utf-8') as cit_file:
citations = cit_file.readlines()
for line in citations:
if citations_separator not in line:
continue
sections = line.strip().split(citations_separator)
if len(sections) != 3:
continue
title = sections[1]
link = sections[2]
citations_str += \
'
\n'
replies_section = ''
date_and_location = ''
if endpoint not in ('newshare', 'newwanted', 'newreport', 'newquestion'):
if not is_new_reminder:
replies_section = \
'