__filename__ = "webapp_create_post.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
__version__ = "1.5.0"
__maintainer__ = "Bob Mottram"
__email__ = "bob@libreserver.org"
__status__ = "Production"
__module_group__ = "Web Interface"
import os
from flags import is_public_post_from_url
from flags import is_premium_account
from utils import data_dir
from utils import dangerous_markup
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 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 utils import get_attributed_to
from utils import get_full_domain
from webapp_utils import open_content_warning
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
from cache import get_person_from_cache
from person import get_person_notes
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,
premium: bool) -> 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, convthread_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,
auto_cw_cache: {},
searchable_by_default: str,
mitm_servers: []) -> 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
# Due to lack of AP specification maintenance, a conversation can also
# be referred to as a thread or (confusingly) "context"
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 edited_post_json['object'].get('thread'):
convthread_id = edited_post_json['object']['thread']
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)
banner_path = '/users/' + nickname + '/' + banner_file
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.'] + '
' + summary
else:
summary = \
'' + \
person_notes + \
''
if summary:
if not dangerous_markup(summary,
False, []):
reply_to_description = \
summary
else:
reply_to_description = \
remove_html(summary)
about_author_str = \
translate['About the author']
new_post_text += \
'
\n' + \
'
\n' + \
' ' + about_author_str + \
'\n
\n' + \
' ' + reply_to_description + \
'\n
\n'
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
dir_str = data_dir(base_dir)
if os.path.isfile(dir_str + '/report.txt'):
try:
with open(dir_str + '/report.txt', 'r',
encoding='utf-8') as fp_report:
custom_report_text = fp_report.read()
if '' not in custom_report_text:
custom_report_text = \
'
\n'
citations_separator = '#####'
citations = []
try:
with open(citations_filename, 'r',
encoding='utf-8') as fp_cit:
citations = fp_cit.readlines()
except OSError as exc:
print('EX: html_new_post unable to read ' +
citations_filename + ' ' + str(exc))
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', 'newreadingstatus'):
if not is_new_reminder:
replies_section = \
'
\n'
if category != 'accommodation':
replies_section += \
'\n'
if endpoint == 'newpost':
replies_section += \
'\n'
else:
replies_section += \
'\n'
# Language used dropdown
supported_languages = get_supported_languages(base_dir)
languages_dropdown = ' '
languages_dropdown = \
languages_dropdown.replace('
\n'
date_and_location = \
begin_edit_section('ποΈ ' + translate['Set a place and time'])
if not in_reply_to:
date_and_location += \
'\n'
date_and_location += date_and_time_str
maps_url = get_map_preferences_url(base_dir, nickname, domain)
if not maps_url:
maps_url = 'https://www.openstreetmap.org'
if '://' not in maps_url:
maps_url = 'https://' + maps_url
maps_latitude, maps_longitude, maps_zoom = \
get_map_preferences_coords(base_dir, nickname, domain)
if maps_latitude and maps_longitude and maps_zoom:
if 'openstreetmap.org' in maps_url:
maps_url = \
'https://www.openstreetmap.org/#map=' + \
str(maps_zoom) + '/' + \
str(maps_latitude) + '/' + \
str(maps_longitude)
elif '.google.co' in maps_url:
maps_url = \
'https://www.google.com/maps/@' + \
str(maps_latitude) + ',' + \
str(maps_longitude) + ',' + \
str(maps_zoom) + 'z'
elif '.bing.co' in maps_url:
maps_url = \
'https://www.bing.com/maps?cp=' + \
str(maps_latitude) + '~' + \
str(maps_longitude) + '&lvl=' + \
str(maps_zoom)
elif '.waze.co' in maps_url:
maps_url = \
'https://ul.waze.com/ul?ll=' + \
str(maps_latitude) + '%2C' + \
str(maps_longitude) + '&zoom=' + \
str(maps_zoom)
elif 'wego.here.co' in maps_url:
maps_url = \
'https://wego.here.com/?x=ep&map=' + \
str(maps_latitude) + ',' + \
str(maps_longitude) + ',' + \
str(maps_zoom) + ',normal'
location_label_with_link = \
'πΊοΈ ' + \
translate['Location'] + ''
date_and_location += '