Initial code for edit button

merge-requests/30/head
Bob Mottram 2022-11-15 19:22:00 +00:00
parent e7a981e07f
commit 3bffa02c76
4 changed files with 301 additions and 21 deletions

105
daemon.py
View File

@ -3341,7 +3341,7 @@ class PubServer(BaseHTTPRequestHandler):
bold_reading = True bold_reading = True
msg = \ msg = \
html_new_post(False, self.server.translate, html_new_post({}, False, self.server.translate,
base_dir, base_dir,
http_prefix, http_prefix,
report_path, None, report_path, None,
@ -3370,6 +3370,7 @@ class PubServer(BaseHTTPRequestHandler):
self.server.peertube_instances, self.server.peertube_instances,
self.server.allow_local_network_access, self.server.allow_local_network_access,
self.server.system_language, self.server.system_language,
self.server.languages_understood,
self.server.max_like_count, self.server.max_like_count,
self.server.signing_priv_key_pem, self.server.signing_priv_key_pem,
self.server.cw_lists, self.server.cw_lists,
@ -3488,7 +3489,7 @@ class PubServer(BaseHTTPRequestHandler):
bold_reading = True bold_reading = True
msg = \ msg = \
html_new_post(False, self.server.translate, html_new_post({}, False, self.server.translate,
base_dir, base_dir,
http_prefix, http_prefix,
report_path, None, [], report_path, None, [],
@ -3516,6 +3517,7 @@ class PubServer(BaseHTTPRequestHandler):
self.server.peertube_instances, self.server.peertube_instances,
self.server.allow_local_network_access, self.server.allow_local_network_access,
self.server.system_language, self.server.system_language,
self.server.languages_understood,
self.server.max_like_count, self.server.max_like_count,
self.server.signing_priv_key_pem, self.server.signing_priv_key_pem,
self.server.cw_lists, self.server.cw_lists,
@ -15047,7 +15049,8 @@ class PubServer(BaseHTTPRequestHandler):
self._write(msg) self._write(msg)
return True return True
def _show_new_post(self, calling_domain: str, path: str, def _show_new_post(self, edit_post_params: {},
calling_domain: str, path: str,
media_instance: bool, translate: {}, media_instance: bool, translate: {},
base_dir: str, http_prefix: str, base_dir: str, http_prefix: str,
in_reply_to_url: str, reply_to_list: [], in_reply_to_url: str, reply_to_list: [],
@ -15103,7 +15106,7 @@ class PubServer(BaseHTTPRequestHandler):
bold_reading = True bold_reading = True
msg = \ msg = \
html_new_post(media_instance, html_new_post(edit_post_params, media_instance,
translate, translate,
base_dir, base_dir,
http_prefix, http_prefix,
@ -15134,6 +15137,7 @@ class PubServer(BaseHTTPRequestHandler):
self.server.peertube_instances, self.server.peertube_instances,
self.server.allow_local_network_access, self.server.allow_local_network_access,
self.server.system_language, self.server.system_language,
self.server.languages_understood,
self.server.max_like_count, self.server.max_like_count,
self.server.signing_priv_key_pem, self.server.signing_priv_key_pem,
self.server.cw_lists, self.server.cw_lists,
@ -18210,6 +18214,46 @@ class PubServer(BaseHTTPRequestHandler):
self.server.getreq_busy = False self.server.getreq_busy = False
return return
# Edit a post
edit_post_params = {}
if authorized and \
'/users/' in self.path and \
'/editpost?scope=' in self.path and \
';postid=' in self.path and \
';actor=' in self.path:
post_scope = self.path.split('?scope=')[1]
if ';' in post_scope:
post_scope = post_scope.split(';')[0]
edit_post_params['scope'] = post_scope
message_id = self.path.split(';postid=')[1]
if ';' in message_id:
message_id = message_id.split(';')[0]
edit_post_params['postid'] = message_id
actor = self.path.split(';actor=')[1]
if ';' in actor:
actor = actor.split(';')[0]
edit_post_params['actor'] = actor
nickname = get_nickname_from_actor(self.path.split('?')[0])
edit_post_params['nickname'] = nickname
if not nickname:
self._404()
self.server.getreq_busy = False
return
if nickname != actor:
self._404()
self.server.getreq_busy = False
return
post_url = \
local_actor_url(self.server.http_prefix, nickname,
self.server.domain_full) + \
'/statuses/' + message_id
edit_post_params['post_url'] = post_url
# use the new post functions, but using edit_post_params
new_post_scope = post_scope
if post_scope == 'public':
new_post_scope = 'post'
self.path = '/users/' + nickname + '/new' + new_post_scope
# list of known crawlers accessing nodeinfo or masto API # list of known crawlers accessing nodeinfo or masto API
if self._show_known_crawlers(calling_domain, self.path, if self._show_known_crawlers(calling_domain, self.path,
self.server.base_dir, self.server.base_dir,
@ -18263,7 +18307,8 @@ class PubServer(BaseHTTPRequestHandler):
self.server.getreq_busy = False self.server.getreq_busy = False
return return
if self._show_new_post(calling_domain, self.path, if self._show_new_post(edit_post_params,
calling_domain, self.path,
self.server.media_instance, self.server.media_instance,
self.server.translate, self.server.translate,
self.server.base_dir, self.server.base_dir,
@ -19155,6 +19200,13 @@ class PubServer(BaseHTTPRequestHandler):
print('WARN: no nickname found when receiving ' + post_type + print('WARN: no nickname found when receiving ' + post_type +
' path ' + path) ' path ' + path)
return -1 return -1
# get the message id of an edited post
edited_postid = None
if '?editid=' in path:
edited_postid = path.split('?editid=')[1]
if '?' in edited_postid:
edited_postid = edited_postid.split('?')[0]
length = int(headers['Content-Length']) length = int(headers['Content-Length'])
if length > self.server.max_post_length: if length > self.server.max_post_length:
print('POST size too large') print('POST size too large')
@ -19357,6 +19409,16 @@ class PubServer(BaseHTTPRequestHandler):
languages_understood, languages_understood,
self.server.translate) self.server.translate)
if message_json: if message_json:
if edited_postid:
message_json['id'] = \
edited_postid + '/activity'
message_json['object']['id'] = \
edited_postid
message_json['object']['url'] = \
edited_postid
message_json['type'] = 'Update'
print('DEBUG: sending edited public post ' +
str(message_json))
if fields['schedulePost']: if fields['schedulePost']:
return 1 return 1
if pin_to_profile: if pin_to_profile:
@ -19613,6 +19675,17 @@ class PubServer(BaseHTTPRequestHandler):
languages_understood, languages_understood,
self.server.translate) self.server.translate)
if message_json: if message_json:
if edited_postid:
message_json['id'] = \
edited_postid + '/activity'
message_json['object']['id'] = \
edited_postid
message_json['object']['url'] = \
edited_postid
message_json['type'] = 'Update'
print('DEBUG: sending edited unlisted post ' +
str(message_json))
if fields['schedulePost']: if fields['schedulePost']:
return 1 return 1
if self._post_to_outbox(message_json, if self._post_to_outbox(message_json,
@ -19674,6 +19747,17 @@ class PubServer(BaseHTTPRequestHandler):
languages_understood, languages_understood,
self.server.translate) self.server.translate)
if message_json: if message_json:
if edited_postid:
message_json['id'] = \
edited_postid + '/activity'
message_json['object']['id'] = \
edited_postid
message_json['object']['url'] = \
edited_postid
message_json['type'] = 'Update'
print('DEBUG: sending edited followers post ' +
str(message_json))
if fields['schedulePost']: if fields['schedulePost']:
return 1 return 1
if self._post_to_outbox(message_json, if self._post_to_outbox(message_json,
@ -19747,6 +19831,17 @@ class PubServer(BaseHTTPRequestHandler):
reply_is_chat, reply_is_chat,
self.server.translate) self.server.translate)
if message_json: if message_json:
if edited_postid:
message_json['id'] = \
edited_postid + '/activity'
message_json['object']['id'] = \
edited_postid
message_json['object']['url'] = \
edited_postid
message_json['type'] = 'Update'
print('DEBUG: sending edited dm post ' +
str(message_json))
if fields['schedulePost']: if fields['schedulePost']:
return 1 return 1
print('Sending new DM to ' + print('Sending new DM to ' +

View File

@ -2353,6 +2353,23 @@ def is_public_post(post_json_object: {}) -> bool:
return False return False
def is_followers_post(post_json_object: {}) -> bool:
"""Returns true if the given post is to followers
"""
if not post_json_object.get('type'):
return False
if post_json_object['type'] != 'Create':
return False
if not has_object_dict(post_json_object):
return False
if not post_json_object['object'].get('to'):
return False
for recipient in post_json_object['object']['to']:
if recipient.endswith('/followers'):
return True
return False
def is_unlisted_post(post_json_object: {}) -> bool: def is_unlisted_post(post_json_object: {}) -> bool:
"""Returns true if the given post is unlisted """Returns true if the given post is unlisted
""" """

View File

@ -8,6 +8,11 @@ __status__ = "Production"
__module_group__ = "Web Interface" __module_group__ = "Web Interface"
import os 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 get_new_post_endpoints
from utils import is_public_post_from_url from utils import is_public_post_from_url
from utils import get_nickname_from_actor from utils import get_nickname_from_actor
@ -31,6 +36,7 @@ from webapp_utils import edit_currency_field
from webapp_post import individual_post_as_html from webapp_post import individual_post_as_html
from maps import get_map_preferences_url from maps import get_map_preferences_url
from maps import get_map_preferences_coords from maps import get_map_preferences_coords
from maps import get_location_from_tags
def _html_following_data_list(base_dir: str, nickname: str, def _html_following_data_list(base_dir: str, nickname: str,
@ -197,7 +203,34 @@ def _html_new_post_drop_down(scope_icon: str, scope_description: str,
return drop_down_content return drop_down_content
def html_new_post(media_instance: bool, translate: {}, 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 html_new_post(edit_post_params: {},
media_instance: bool, translate: {},
base_dir: str, http_prefix: str, base_dir: str, http_prefix: str,
path: str, in_reply_to: str, path: str, in_reply_to: str,
mentions: [], mentions: [],
@ -221,6 +254,7 @@ def html_new_post(media_instance: bool, translate: {},
peertube_instances: [], peertube_instances: [],
allow_local_network_access: bool, allow_local_network_access: bool,
system_language: str, system_language: str,
languages_understood: [],
max_like_count: int, signing_priv_key_pem: str, max_like_count: int, signing_priv_key_pem: str,
cw_lists: {}, lists_enabled: str, cw_lists: {}, lists_enabled: str,
box_name: str, box_name: str,
@ -229,6 +263,48 @@ def html_new_post(media_instance: bool, translate: {},
min_images_for_accounts: []) -> str: min_images_for_accounts: []) -> str:
"""New post screen """New post screen
""" """
# get the json if this is an edited post
edited_post_json = None
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 ''
if edited_post_json['object'].get('conversation'):
conversation_id = edited_post_json['object']['conversation']
# default subject line or content warning
default_subject = ''
if share_description:
default_subject = share_description
default_location = ''
default_start_time = ''
default_end_time = ''
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_tags(edited_post_json['object']['tag'])
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 = '' reply_str = ''
is_new_reminder = False is_new_reminder = False
@ -244,15 +320,25 @@ def html_new_post(media_instance: bool, translate: {},
# select a date and time for this post # select a date and time for this post
date_and_time_str += '<label class="labels">' + \ date_and_time_str += '<label class="labels">' + \
translate['Date'] + ': </label>\n' translate['Date'] + ': </label>\n'
date_and_time_str += '<input type="date" name="eventDate">\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] + '"'
if default_end_time:
end_time_default = ' value="' + default_end_time.split('T')[1] + '"'
date_and_time_str += \
'<input type="date" name="eventDate"' + date_default + '>\n'
date_and_time_str += '<label class="labelsright">' + \ date_and_time_str += '<label class="labelsright">' + \
translate['Start Time'] + ': ' translate['Start Time'] + ': '
date_and_time_str += \ date_and_time_str += \
'<input type="time" name="eventTime"></label>\n<br>\n' '<input type="time" name="eventTime"' + \
time_default + '></label>\n<br>\n'
date_and_time_str += '<label class="labelsright">' + \ date_and_time_str += '<label class="labelsright">' + \
translate['End Time'] + ': ' translate['End Time'] + ': '
date_and_time_str += \ date_and_time_str += \
'<input type="time" name="eventEndTime"></label>\n</p>\n' '<input type="time" name="eventEndTime"' + \
end_time_default + '></label>\n</p>\n'
show_public_on_dropdown = True show_public_on_dropdown = True
message_box_height = 400 message_box_height = 400
@ -521,7 +607,8 @@ def html_new_post(media_instance: bool, translate: {},
extra_fields += '</div>\n' extra_fields += '</div>\n'
extra_fields += '<div class="container">\n' extra_fields += '<div class="container">\n'
city_or_loc_str = translate['City or location of the shared item'] city_or_loc_str = translate['City or location of the shared item']
extra_fields += edit_text_field(city_or_loc_str + ':', 'location', '', extra_fields += edit_text_field(city_or_loc_str + ':', 'location',
default_location,
'https://www.openstreetmap.org/#map=') 'https://www.openstreetmap.org/#map=')
extra_fields += '</div>\n' extra_fields += '</div>\n'
extra_fields += '<div class="container">\n' extra_fields += '<div class="container">\n'
@ -587,7 +674,8 @@ def html_new_post(media_instance: bool, translate: {},
extra_fields += '</div>\n' extra_fields += '</div>\n'
extra_fields += '<div class="container">\n' extra_fields += '<div class="container">\n'
city_or_loc_str = translate['City or location of the wanted item'] city_or_loc_str = translate['City or location of the wanted item']
extra_fields += edit_text_field(city_or_loc_str + ':', 'location', '', extra_fields += edit_text_field(city_or_loc_str + ':', 'location',
default_location,
'https://www.openstreetmap.org/#map=') 'https://www.openstreetmap.org/#map=')
extra_fields += '</div>\n' extra_fields += '</div>\n'
extra_fields += '<div class="container">\n' extra_fields += '<div class="container">\n'
@ -745,7 +833,8 @@ def html_new_post(media_instance: bool, translate: {},
'rel="nofollow noopener noreferrer" target="_blank">🗺️ ' + \ 'rel="nofollow noopener noreferrer" target="_blank">🗺️ ' + \
translate['Location'] + '</a>' translate['Location'] + '</a>'
date_and_location += '<br><p>\n' + \ date_and_location += '<br><p>\n' + \
edit_text_field(location_label_with_link, 'location', '', edit_text_field(location_label_with_link, 'location',
default_location,
'https://www.openstreetmap.org/#map=') + '</p>\n' 'https://www.openstreetmap.org/#map=') + '</p>\n'
date_and_location += end_edit_section() date_and_location += end_edit_section()
@ -844,10 +933,17 @@ def html_new_post(media_instance: bool, translate: {},
# reporting a post to moderator # reporting a post to moderator
mentions_str = 'Re: ' + report_url + '\n\n' + mentions_str mentions_str = 'Re: ' + report_url + '\n\n' + mentions_str
new_post_form += \ if edited_post_json:
'<form enctype="multipart/form-data" method="POST" ' + \ new_post_form += \
'accept-charset="UTF-8" action="' + \ '<form enctype="multipart/form-data" method="POST" ' + \
path + '?' + endpoint + '?page=' + str(page_number) + '">\n' 'accept-charset="UTF-8" action="' + \
path + '?' + endpoint + '?page=' + str(page_number) + \
'?editid=' + edit_post_params['post_url'] + '">\n'
else:
new_post_form += \
'<form enctype="multipart/form-data" method="POST" ' + \
'accept-charset="UTF-8" action="' + \
path + '?' + endpoint + '?page=' + str(page_number) + '">\n'
if reply_is_chat: if reply_is_chat:
new_post_form += \ new_post_form += \
' <input type="hidden" name="replychatmsg" value="yes">\n' ' <input type="hidden" name="replychatmsg" value="yes">\n'
@ -908,9 +1004,6 @@ def html_new_post(media_instance: bool, translate: {},
if media_instance and not reply_str: if media_instance and not reply_str:
new_post_form += new_post_image_section new_post_form += new_post_image_section
if not share_description:
share_description = ''
# for reminders show the date and time at the top # for reminders show the date and time at the top
if is_new_reminder: if is_new_reminder:
new_post_form += '<div class="containerNoOverflow">\n' new_post_form += '<div class="containerNoOverflow">\n'
@ -918,7 +1011,7 @@ def html_new_post(media_instance: bool, translate: {},
new_post_form += '</div>\n' new_post_form += '</div>\n'
new_post_form += \ new_post_form += \
edit_text_field(placeholder_subject, 'subject', share_description) edit_text_field(placeholder_subject, 'subject', default_subject)
new_post_form += '' new_post_form += ''
selected_str = ' selected' selected_str = ' selected'
@ -952,11 +1045,20 @@ def html_new_post(media_instance: bool, translate: {},
elif endpoint == 'newblog': elif endpoint == 'newblog':
message_box_height = 800 message_box_height = 800
# get the default message text
default_message = ''
if edited_post_json:
content_str = \
get_content_from_post(edited_post_json, system_language,
languages_understood, "content")
if content_str:
default_message = remove_html(content_str)
new_post_form += \ new_post_form += \
' <textarea id="message" name="message" style="height:' + \ ' <textarea id="message" name="message" style="height:' + \
str(message_box_height) + 'px"' + selected_str + \ str(message_box_height) + 'px"' + selected_str + \
' spellcheck="true" autocomplete="on">' + \ ' spellcheck="true" autocomplete="on">' + \
'</textarea>\n' default_message + '</textarea>\n'
new_post_form += \ new_post_form += \
extra_fields + citations_str + replies_section + date_and_location extra_fields + citations_str + replies_section + date_and_location
if not media_instance or reply_str: if not media_instance or reply_str:

View File

@ -56,6 +56,7 @@ from utils import is_blog_post
from utils import get_display_name from utils import get_display_name
from utils import display_name_is_emoji from utils import display_name_is_emoji
from utils import is_public_post from utils import is_public_post
from utils import is_followers_post
from utils import update_recent_posts_cache from utils import update_recent_posts_cache
from utils import remove_id_ending from utils import remove_id_ending
from utils import get_nickname_from_actor from utils import get_nickname_from_actor
@ -574,6 +575,71 @@ def _get_edit_icon_html(base_dir: str, nickname: str, domain_full: str,
'<img loading="lazy" decoding="async" title="' + \ '<img loading="lazy" decoding="async" title="' + \
edit_event_str + '" alt="' + edit_event_str + \ edit_event_str + '" alt="' + edit_event_str + \
' |" src="/icons/edit.png"/></a>\n' ' |" src="/icons/edit.png"/></a>\n'
elif is_public_post(post_json_object):
# Edit a public post
edit_post_str = 'Edit post'
if translate.get(edit_post_str):
edit_post_str = translate[edit_post_str]
edit_str += \
' ' + \
'<a class="imageAnchor" href="/users/' + \
nickname + \
'/editpost?scope=public;postid=' + \
post_id.split('/statuses/')[1] + \
';actor=' + actor_nickname + \
'" title="' + edit_post_str + '" tabindex="10">' + \
'<img loading="lazy" decoding="async" title="' + \
edit_post_str + '" alt="' + edit_post_str + \
' |" src="/icons/edit.png"/></a>\n'
elif is_dm(post_json_object):
# Edit a DM
edit_post_str = 'Edit post'
if translate.get(edit_post_str):
edit_post_str = translate[edit_post_str]
edit_str += \
' ' + \
'<a class="imageAnchor" href="/users/' + \
nickname + \
'/editpost?scope=dm;postid=' + \
post_id.split('/statuses/')[1] + \
';actor=' + actor_nickname + \
'" title="' + edit_post_str + '" tabindex="10">' + \
'<img loading="lazy" decoding="async" title="' + \
edit_post_str + '" alt="' + edit_post_str + \
' |" src="/icons/edit.png"/></a>\n'
elif is_unlisted_post(post_json_object):
# Edit an unlisted post
edit_post_str = 'Edit post'
if translate.get(edit_post_str):
edit_post_str = translate[edit_post_str]
edit_str += \
' ' + \
'<a class="imageAnchor" href="/users/' + \
nickname + \
'/editpost?scope=unlisted;postid=' + \
post_id.split('/statuses/')[1] + \
';actor=' + actor_nickname + \
'" title="' + edit_post_str + '" tabindex="10">' + \
'<img loading="lazy" decoding="async" title="' + \
edit_post_str + '" alt="' + edit_post_str + \
' |" src="/icons/edit.png"/></a>\n'
elif is_followers_post(post_json_object):
# Edit a followers only post
edit_post_str = 'Edit post'
if translate.get(edit_post_str):
edit_post_str = translate[edit_post_str]
edit_str += \
' ' + \
'<a class="imageAnchor" href="/users/' + \
nickname + \
'/editpost?scope=followers;postid=' + \
post_id.split('/statuses/')[1] + \
';actor=' + actor_nickname + \
'" title="' + edit_post_str + '" tabindex="10">' + \
'<img loading="lazy" decoding="async" title="' + \
edit_post_str + '" alt="' + edit_post_str + \
' |" src="/icons/edit.png"/></a>\n'
return edit_str return edit_str