diff --git a/content.py b/content.py index aaa1545a3..5bebdb0de 100644 --- a/content.py +++ b/content.py @@ -48,7 +48,7 @@ INVALID_CONTENT_STRINGS = ( 'graph', 'showshare', 'category', 'showwanted', 'rmshare', 'rmwanted', 'repeatprivate', 'unrepeatprivate', 'replyto', - 'replyfollowers', 'replydm', 'editblogpost', + 'replyfollowers', 'replydm', 'replychat', 'editblogpost', 'handle', 'blockdomain' ) diff --git a/daemon.py b/daemon.py index c3a19c9ea..7b8a40715 100644 --- a/daemon.py +++ b/daemon.py @@ -2838,6 +2838,7 @@ class PubServer(BaseHTTPRequestHandler): custom_submit_text = get_config_param(base_dir, 'customSubmitText') conversation_id = None + reply_is_chat = False msg = html_new_post(self.server.css_cache, False, self.server.translate, base_dir, @@ -2872,7 +2873,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - self.server.default_timeline).encode('utf-8') + self.server.default_timeline, + reply_is_chat).encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, cookie, calling_domain, False) @@ -2973,6 +2975,7 @@ class PubServer(BaseHTTPRequestHandler): custom_submit_text = get_config_param(base_dir, 'customSubmitText') conversation_id = None + reply_is_chat = False msg = html_new_post(self.server.css_cache, False, self.server.translate, base_dir, @@ -3006,7 +3009,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - self.server.default_timeline).encode('utf-8') + self.server.default_timeline, + reply_is_chat).encode('utf-8') msglen = len(msg) self._set_headers('text/html', msglen, cookie, calling_domain, False) @@ -13188,6 +13192,7 @@ class PubServer(BaseHTTPRequestHandler): media_instance: bool, translate: {}, base_dir: str, http_prefix: str, in_reply_to_url: str, reply_to_list: [], + reply_is_chat: bool, share_description: str, reply_page_number: int, reply_category: str, domain: str, domain_full: str, @@ -13214,7 +13219,7 @@ class PubServer(BaseHTTPRequestHandler): str(reply_interval_hours) + ' hours') self._403() return True - elif self.server.debug: + if self.server.debug: print('Reply is within time interval: ' + str(reply_interval_hours) + ' hours') @@ -13267,7 +13272,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.signing_priv_key_pem, self.server.cw_lists, self.server.lists_enabled, - self.server.default_timeline).encode('utf-8') + self.server.default_timeline, + reply_is_chat).encode('utf-8') if not msg: print('Error replying to ' + in_reply_to_url) self._404() @@ -15932,8 +15938,13 @@ class PubServer(BaseHTTPRequestHandler): # replying as a direct message, # for moderation posts or the dm timeline - if '?replydm=' in self.path: - in_reply_to_url = self.path.split('?replydm=')[1] + reply_is_chat = False + if '?replydm=' in self.path or '?replychat=' in self.path: + reply_type = 'replydm' + if '?replychat=' in self.path: + reply_type = 'replychat' + reply_is_chat = True + in_reply_to_url = self.path.split('?' + reply_type + '=')[1] in_reply_to_url = urllib.parse.unquote_plus(in_reply_to_url) if '?' in in_reply_to_url: # multiple parameters @@ -15970,9 +15981,10 @@ class PubServer(BaseHTTPRequestHandler): share_description = \ share_description.replace('_', ' ') - self.path = self.path.split('?replydm=')[0] + '/newdm' + self.path = \ + self.path.split('?' + reply_type + '=')[0] + '/newdm' if self.server.debug: - print('DEBUG: replydm path ' + self.path) + print('DEBUG: ' + reply_type + ' path ' + self.path) # Edit a blog post if authorized and \ @@ -16067,6 +16079,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.base_dir, self.server.http_prefix, in_reply_to_url, reply_to_list, + reply_is_chat, share_description, reply_page_number, reply_category, self.server.domain, @@ -16915,6 +16928,7 @@ class PubServer(BaseHTTPRequestHandler): city = get_spoofed_city(self.server.city, self.server.base_dir, nickname, self.server.domain) + conversation_id = None if fields.get('conversationId'): conversation_id = fields['conversationId'] @@ -17301,6 +17315,10 @@ class PubServer(BaseHTTPRequestHandler): self.server.domain_full, self.server.person_cache) + reply_is_chat = False + if fields.get('replychatmsg'): + reply_is_chat = fields['replychatmsg'] + message_json = \ create_direct_message_post(self.server.base_dir, nickname, @@ -17329,7 +17347,8 @@ class PubServer(BaseHTTPRequestHandler): conversation_id, self.server.low_bandwidth, content_license_url, - languages_understood) + languages_understood, + reply_is_chat) if message_json: if fields['schedulePost']: return 1 @@ -17392,7 +17411,8 @@ class PubServer(BaseHTTPRequestHandler): conversation_id, self.server.low_bandwidth, self.server.content_license_url, - languages_understood) + languages_understood, + False) if message_json: if fields['schedulePost']: return 1 diff --git a/inbox.py b/inbox.py index e8afe0df4..b4a97e296 100644 --- a/inbox.py +++ b/inbox.py @@ -2826,7 +2826,8 @@ def _bounce_dm(senderPostId: str, session, http_prefix: str, last_bounce_message: [], system_language: str, signing_priv_key_pem: str, content_license_url: str, - languages_understood: []) -> bool: + languages_understood: [], + bounce_is_chat: bool) -> bool: """Sends a bounce message back to the sending handle if a DM has been rejected """ @@ -2888,7 +2889,7 @@ def _bounce_dm(senderPostId: str, session, http_prefix: str, system_language, conversation_id, low_bandwidth, content_license_url, - languages_understood) + languages_understood, bounce_is_chat) if not post_json_object: print('WARN: unable to create bounce message to ' + sending_handle) return False @@ -2984,6 +2985,10 @@ def _is_valid_dm(base_dir: str, nickname: str, domain: str, port: int, if not obj.get('inReplyTo'): bounced_id = \ remove_id_ending(post_json_object['id']) + bounce_chat = False + if obj.get('type'): + if obj['type'] == 'ChatMessage': + bounce_chat = True _bounce_dm(bounced_id, session, http_prefix, base_dir, @@ -2998,7 +3003,8 @@ def _is_valid_dm(base_dir: str, nickname: str, domain: str, port: int, system_language, signing_priv_key_pem, content_license_url, - languages_understood) + languages_understood, + bounce_chat) return False # dm index will be updated diff --git a/outbox.py b/outbox.py index db6e6a690..371d7ae20 100644 --- a/outbox.py +++ b/outbox.py @@ -408,7 +408,7 @@ def post_message_to_outbox(session, translate: {}, # The following activity types get added to the index files indexed_activities = ( 'Create', 'Question', 'Note', 'EncryptedMessage', 'Article', - 'Patch', 'Announce' + 'Patch', 'Announce', 'ChatMessage' ) if message_json['type'] in indexed_activities: indexes = [outbox_name, "inbox"] diff --git a/posts.py b/posts.py index 96b827a2c..7137e4ede 100644 --- a/posts.py +++ b/posts.py @@ -484,9 +484,9 @@ def _is_public_feed_post(item: {}, person_posts: {}, debug: bool) -> bool: this_item = item['object'] # check that this is a public post # #Public should appear in the "to" list - itemIsNote = False + item_is_note = False if item['type'] == 'Note' or item['type'] == 'Page': - itemIsNote = True + item_is_note = True if isinstance(this_item, dict): if this_item.get('to'): @@ -497,7 +497,7 @@ def _is_public_feed_post(item: {}, person_posts: {}, debug: bool) -> bool: break if not is_public: return False - elif isinstance(this_item, str) or itemIsNote: + elif isinstance(this_item, str) or item_is_note: if item.get('to'): is_public = False for recipient in item['to']: @@ -2113,7 +2113,8 @@ def create_direct_message_post(base_dir: str, location: str, system_language: str, conversation_id: str, low_bandwidth: bool, content_license_url: str, - languages_understood: []) -> {}: + languages_understood: [], + dm_is_chat: bool) -> {}: """Direct Message post """ content = resolve_petnames(base_dir, nickname, domain, content) @@ -2144,6 +2145,8 @@ def create_direct_message_post(base_dir: str, message_json['object']['to'] = message_json['to'] message_json['cc'] = [] message_json['object']['cc'] = [] + if dm_is_chat: + message_json['object']['type'] = 'ChatMessage' if schedule_post: post_id = remove_id_ending(message_json['object']['id']) save_post_to_box(base_dir, http_prefix, post_id, @@ -3561,6 +3564,7 @@ def is_image_media(session, base_dir: str, http_prefix: str, if post_json_object['object']['type'] != 'Note' and \ post_json_object['object']['type'] != 'Page' and \ post_json_object['object']['type'] != 'Event' and \ + post_json_object['object']['type'] != 'ChatMessage' and \ post_json_object['object']['type'] != 'Article': return False if not post_json_object['object'].get('attachment'): @@ -3583,6 +3587,7 @@ def _add_post_string_to_timeline(post_str: str, boxname: str, # must be a recognized ActivityPub type if ('"Note"' in post_str or '"EncryptedMessage"' in post_str or + '"ChatMessage"' in post_str or '"Event"' in post_str or '"Article"' in post_str or '"Patch"' in post_str or diff --git a/utils.py b/utils.py index 5def9ec8f..b03a719df 100644 --- a/utils.py +++ b/utils.py @@ -2654,6 +2654,19 @@ def reject_post_id(base_dir: str, nickname: str, domain: str, reject_file.write('\n') +def is_chat_message(post_json_object: {}) -> bool: + """Returns true if the given post is a chat message + Note that is_dm should be checked before calling this + """ + if post_json_object['type'] != 'Create': + return False + if not has_object_dict(post_json_object): + return False + if post_json_object['object']['type'] != 'ChatMessage': + return False + return True + + def is_dm(post_json_object: {}) -> bool: """Returns true if the given post is a DM """ @@ -2661,12 +2674,13 @@ def is_dm(post_json_object: {}) -> bool: return False if not has_object_dict(post_json_object): return False - if post_json_object['object']['type'] != 'Note' and \ - post_json_object['object']['type'] != 'Page' and \ - post_json_object['object']['type'] != 'Patch' and \ - post_json_object['object']['type'] != 'EncryptedMessage' and \ - post_json_object['object']['type'] != 'Article': - return False + if post_json_object['object']['type'] != 'ChatMessage': + if post_json_object['object']['type'] != 'Note' and \ + post_json_object['object']['type'] != 'Page' and \ + post_json_object['object']['type'] != 'Patch' and \ + post_json_object['object']['type'] != 'EncryptedMessage' and \ + post_json_object['object']['type'] != 'Article': + return False if post_json_object['object'].get('moderationStatus'): return False fields = ('to', 'cc') @@ -2693,6 +2707,7 @@ def is_reply(post_json_object: {}, actor: str) -> bool: if post_json_object['object']['type'] != 'Note' and \ post_json_object['object']['type'] != 'Page' and \ post_json_object['object']['type'] != 'EncryptedMessage' and \ + post_json_object['object']['type'] != 'ChatMessage' and \ post_json_object['object']['type'] != 'Article': return False if post_json_object['object'].get('inReplyTo'): diff --git a/webapp_create_post.py b/webapp_create_post.py index b96ff2cda..dd39ad58e 100644 --- a/webapp_create_post.py +++ b/webapp_create_post.py @@ -210,7 +210,8 @@ def html_new_post(css_cache: {}, media_instance: bool, translate: {}, system_language: str, max_like_count: int, signing_priv_key_pem: str, cw_lists: {}, lists_enabled: str, - boxName: str) -> str: + boxName: str, + reply_is_chat: bool) -> str: """New post screen """ reply_str = '' @@ -691,7 +692,10 @@ def html_new_post(css_cache: {}, media_instance: bool, translate: {}, dropdown_new_blog_suffix += '?replyto=' + inReplyTo dropdown_unlisted_suffix += '?replyto=' + inReplyTo dropdown_followers_suffix += '?replyfollowers=' + inReplyTo - dropdown_dm_suffix += '?replydm=' + inReplyTo + if reply_is_chat: + dropdown_dm_suffix += '?replychat=' + inReplyTo + else: + dropdown_dm_suffix += '?replydm=' + inReplyTo for mentioned_actor in mentions: dropdown_new_post_suffix += '?mention=' + mentioned_actor dropdown_new_blog_suffix += '?mention=' + mentioned_actor @@ -732,6 +736,9 @@ def html_new_post(css_cache: {}, media_instance: bool, translate: {}, '