| 
									
										
										
										
											2021-08-12 10:26:24 +00:00
										 |  |  | __filename__ = "conversation.py" | 
					
						
							|  |  |  | __author__ = "Bob Mottram" | 
					
						
							|  |  |  | __license__ = "AGPL3+" | 
					
						
							| 
									
										
										
										
											2022-02-03 13:58:20 +00:00
										 |  |  | __version__ = "1.3.0" | 
					
						
							| 
									
										
										
										
											2021-08-12 10:26:24 +00:00
										 |  |  | __maintainer__ = "Bob Mottram" | 
					
						
							| 
									
										
										
										
											2021-09-10 16:14:50 +00:00
										 |  |  | __email__ = "bob@libreserver.org" | 
					
						
							| 
									
										
										
										
											2021-08-12 10:26:24 +00:00
										 |  |  | __status__ = "Production" | 
					
						
							|  |  |  | __module_group__ = "Timeline" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import os | 
					
						
							| 
									
										
										
										
											2021-12-26 10:57:03 +00:00
										 |  |  | from utils import has_object_dict | 
					
						
							| 
									
										
										
										
											2021-12-26 12:02:29 +00:00
										 |  |  | from utils import acct_dir | 
					
						
							| 
									
										
										
										
											2021-12-27 11:20:57 +00:00
										 |  |  | from utils import remove_id_ending | 
					
						
							| 
									
										
										
										
											2022-06-10 11:43:33 +00:00
										 |  |  | from utils import text_in_file | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:13 +00:00
										 |  |  | from utils import locate_post | 
					
						
							|  |  |  | from utils import load_json | 
					
						
							| 
									
										
										
										
											2023-01-07 11:45:19 +00:00
										 |  |  | from utils import harmless_markup | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:13 +00:00
										 |  |  | from keys import get_instance_actor_key | 
					
						
							|  |  |  | from session import get_json | 
					
						
							| 
									
										
										
										
											2021-08-12 10:26:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def _get_conversation_filename(base_dir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                                post_json_object: {}) -> str: | 
					
						
							| 
									
										
										
										
											2021-10-14 15:12:35 +00:00
										 |  |  |     """Returns the conversation filename
 | 
					
						
							| 
									
										
										
										
											2021-08-12 10:26:24 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2021-12-26 10:57:03 +00:00
										 |  |  |     if not has_object_dict(post_json_object): | 
					
						
							| 
									
										
										
										
											2021-10-14 15:12:35 +00:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2023-01-09 11:38:05 +00:00
										 |  |  |     if not post_json_object['object'].get('conversation') and \ | 
					
						
							|  |  |  |        not post_json_object['object'].get('context'): | 
					
						
							| 
									
										
										
										
											2021-10-14 15:12:35 +00:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2021-12-25 22:09:19 +00:00
										 |  |  |     if not post_json_object['object'].get('id'): | 
					
						
							| 
									
										
										
										
											2021-10-14 15:12:35 +00:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2021-12-30 20:32:19 +00:00
										 |  |  |     conversation_dir = acct_dir(base_dir, nickname, domain) + '/conversation' | 
					
						
							|  |  |  |     if not os.path.isdir(conversation_dir): | 
					
						
							|  |  |  |         os.mkdir(conversation_dir) | 
					
						
							| 
									
										
										
										
											2023-01-09 11:38:05 +00:00
										 |  |  |     if post_json_object['object'].get('conversation'): | 
					
						
							|  |  |  |         conversation_id = post_json_object['object']['conversation'] | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         conversation_id = post_json_object['object']['context'] | 
					
						
							| 
									
										
										
										
											2021-12-30 20:32:19 +00:00
										 |  |  |     conversation_id = conversation_id.replace('/', '#') | 
					
						
							|  |  |  |     return conversation_dir + '/' + conversation_id | 
					
						
							| 
									
										
										
										
											2021-10-14 15:12:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def update_conversation(base_dir: str, nickname: str, domain: str, | 
					
						
							|  |  |  |                         post_json_object: {}) -> bool: | 
					
						
							| 
									
										
										
										
											2022-12-23 18:27:27 +00:00
										 |  |  |     """Adds a post to a conversation index in the /conversation subdirectory
 | 
					
						
							| 
									
										
										
										
											2021-10-14 15:12:35 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2021-12-30 20:32:19 +00:00
										 |  |  |     conversation_filename = \ | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |         _get_conversation_filename(base_dir, nickname, domain, | 
					
						
							|  |  |  |                                    post_json_object) | 
					
						
							| 
									
										
										
										
											2021-12-30 20:32:19 +00:00
										 |  |  |     if not conversation_filename: | 
					
						
							| 
									
										
										
										
											2021-10-14 15:12:35 +00:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2021-12-27 11:20:57 +00:00
										 |  |  |     post_id = remove_id_ending(post_json_object['object']['id']) | 
					
						
							| 
									
										
										
										
											2021-12-30 20:32:19 +00:00
										 |  |  |     if not os.path.isfile(conversation_filename): | 
					
						
							| 
									
										
										
										
											2021-08-12 10:26:24 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2022-06-09 14:46:30 +00:00
										 |  |  |             with open(conversation_filename, 'w+', | 
					
						
							|  |  |  |                       encoding='utf-8') as conv_file: | 
					
						
							| 
									
										
										
										
											2021-12-30 20:32:19 +00:00
										 |  |  |                 conv_file.write(post_id + '\n') | 
					
						
							| 
									
										
										
										
											2021-08-12 10:26:24 +00:00
										 |  |  |                 return True | 
					
						
							| 
									
										
										
										
											2021-11-25 18:42:38 +00:00
										 |  |  |         except OSError: | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |             print('EX: update_conversation ' + | 
					
						
							| 
									
										
										
										
											2021-12-30 20:32:19 +00:00
										 |  |  |                   'unable to write to ' + conversation_filename) | 
					
						
							| 
									
										
										
										
											2022-06-10 11:43:33 +00:00
										 |  |  |     elif not text_in_file(post_id + '\n', conversation_filename): | 
					
						
							| 
									
										
										
										
											2021-08-12 10:26:24 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2022-06-09 14:46:30 +00:00
										 |  |  |             with open(conversation_filename, 'a+', | 
					
						
							|  |  |  |                       encoding='utf-8') as conv_file: | 
					
						
							| 
									
										
										
										
											2021-12-30 20:32:19 +00:00
										 |  |  |                 conv_file.write(post_id + '\n') | 
					
						
							| 
									
										
										
										
											2021-08-12 10:26:24 +00:00
										 |  |  |                 return True | 
					
						
							| 
									
										
										
										
											2021-11-25 18:42:38 +00:00
										 |  |  |         except OSError: | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |             print('EX: update_conversation 2 ' + | 
					
						
							| 
									
										
										
										
											2021-12-30 20:32:19 +00:00
										 |  |  |                   'unable to write to ' + conversation_filename) | 
					
						
							| 
									
										
										
										
											2021-08-12 10:26:24 +00:00
										 |  |  |     return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def mute_conversation(base_dir: str, nickname: str, domain: str, | 
					
						
							| 
									
										
										
										
											2021-12-30 20:32:19 +00:00
										 |  |  |                       conversation_id: str) -> None: | 
					
						
							| 
									
										
										
										
											2021-08-12 10:26:24 +00:00
										 |  |  |     """Mutes the given conversation
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2021-12-30 20:32:19 +00:00
										 |  |  |     conversation_dir = acct_dir(base_dir, nickname, domain) + '/conversation' | 
					
						
							|  |  |  |     conversation_filename = \ | 
					
						
							|  |  |  |         conversation_dir + '/' + conversation_id.replace('/', '#') | 
					
						
							|  |  |  |     if not os.path.isfile(conversation_filename): | 
					
						
							| 
									
										
										
										
											2021-08-12 10:26:24 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2021-12-30 20:32:19 +00:00
										 |  |  |     if os.path.isfile(conversation_filename + '.muted'): | 
					
						
							| 
									
										
										
										
											2021-08-12 10:26:24 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2021-11-25 18:42:38 +00:00
										 |  |  |     try: | 
					
						
							| 
									
										
										
										
											2022-06-09 14:46:30 +00:00
										 |  |  |         with open(conversation_filename + '.muted', 'w+', | 
					
						
							|  |  |  |                   encoding='utf-8') as conv_file: | 
					
						
							| 
									
										
										
										
											2021-12-30 20:32:19 +00:00
										 |  |  |             conv_file.write('\n') | 
					
						
							| 
									
										
										
										
											2021-11-25 18:42:38 +00:00
										 |  |  |     except OSError: | 
					
						
							| 
									
										
										
										
											2021-12-30 20:32:19 +00:00
										 |  |  |         print('EX: unable to write mute ' + conversation_filename) | 
					
						
							| 
									
										
										
										
											2021-08-12 10:26:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  | def unmute_conversation(base_dir: str, nickname: str, domain: str, | 
					
						
							| 
									
										
										
										
											2021-12-30 20:32:19 +00:00
										 |  |  |                         conversation_id: str) -> None: | 
					
						
							| 
									
										
										
										
											2021-08-12 10:26:24 +00:00
										 |  |  |     """Unmutes the given conversation
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2021-12-30 20:32:19 +00:00
										 |  |  |     conversation_dir = acct_dir(base_dir, nickname, domain) + '/conversation' | 
					
						
							|  |  |  |     conversation_filename = \ | 
					
						
							|  |  |  |         conversation_dir + '/' + conversation_id.replace('/', '#') | 
					
						
							|  |  |  |     if not os.path.isfile(conversation_filename): | 
					
						
							| 
									
										
										
										
											2021-08-12 10:26:24 +00:00
										 |  |  |         return | 
					
						
							| 
									
										
										
										
											2021-12-30 20:32:19 +00:00
										 |  |  |     if not os.path.isfile(conversation_filename + '.muted'): | 
					
						
							| 
									
										
										
										
											2021-08-12 10:26:24 +00:00
										 |  |  |         return | 
					
						
							|  |  |  |     try: | 
					
						
							| 
									
										
										
										
											2021-12-30 20:32:19 +00:00
										 |  |  |         os.remove(conversation_filename + '.muted') | 
					
						
							| 
									
										
										
										
											2021-11-25 18:42:38 +00:00
										 |  |  |     except OSError: | 
					
						
							| 
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 |  |  |         print('EX: unmute_conversation unable to delete ' + | 
					
						
							| 
									
										
										
										
											2021-12-30 20:32:19 +00:00
										 |  |  |               conversation_filename + '.muted') | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def download_conversation_posts(session, http_prefix: str, base_dir: str, | 
					
						
							|  |  |  |                                 nickname: str, domain: str, | 
					
						
							|  |  |  |                                 post_id: str, debug: bool) -> []: | 
					
						
							|  |  |  |     """Downloads all posts for a conversation and returns a list of the
 | 
					
						
							|  |  |  |     json objects | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if '://' not in post_id: | 
					
						
							|  |  |  |         return [] | 
					
						
							|  |  |  |     profile_str = 'https://www.w3.org/ns/activitystreams' | 
					
						
							|  |  |  |     as_header = { | 
					
						
							|  |  |  |         'Accept': 'application/ld+json; profile="' + profile_str + '"' | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:58 +00:00
										 |  |  |     conversation_view = [] | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:13 +00:00
										 |  |  |     signing_priv_key_pem = get_instance_actor_key(base_dir, domain) | 
					
						
							|  |  |  |     post_id = remove_id_ending(post_id) | 
					
						
							|  |  |  |     post_filename = \ | 
					
						
							|  |  |  |         locate_post(base_dir, nickname, domain, post_id) | 
					
						
							|  |  |  |     if post_filename: | 
					
						
							| 
									
										
										
										
											2023-01-07 18:13:15 +00:00
										 |  |  |         post_json_object = load_json(post_filename) | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:13 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2023-01-07 18:13:15 +00:00
										 |  |  |         post_json_object = \ | 
					
						
							|  |  |  |             get_json(signing_priv_key_pem, session, post_id, | 
					
						
							|  |  |  |                      as_header, None, debug, __version__, | 
					
						
							|  |  |  |                      http_prefix, domain) | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:13 +00:00
										 |  |  |     if debug: | 
					
						
							| 
									
										
										
										
											2023-01-07 18:13:15 +00:00
										 |  |  |         if not post_json_object: | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:13 +00:00
										 |  |  |             print(post_id + ' returned no json') | 
					
						
							| 
									
										
										
										
											2023-01-07 18:13:15 +00:00
										 |  |  |     while post_json_object: | 
					
						
							|  |  |  |         if not isinstance(post_json_object, dict): | 
					
						
							| 
									
										
										
										
											2022-12-28 10:28:15 +00:00
										 |  |  |             break | 
					
						
							| 
									
										
										
										
											2023-01-07 18:13:15 +00:00
										 |  |  |         if not has_object_dict(post_json_object): | 
					
						
							|  |  |  |             if not post_json_object.get('attributedTo'): | 
					
						
							|  |  |  |                 print(str(post_json_object)) | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:13 +00:00
										 |  |  |                 if debug: | 
					
						
							|  |  |  |                     print(post_id + ' has no attributedTo') | 
					
						
							|  |  |  |                 break | 
					
						
							| 
									
										
										
										
											2023-01-07 18:13:15 +00:00
										 |  |  |             if not isinstance(post_json_object['attributedTo'], str): | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:13 +00:00
										 |  |  |                 break | 
					
						
							| 
									
										
										
										
											2023-01-07 18:13:15 +00:00
										 |  |  |             if not post_json_object.get('published'): | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:13 +00:00
										 |  |  |                 if debug: | 
					
						
							|  |  |  |                     print(post_id + ' has no published date') | 
					
						
							|  |  |  |                 break | 
					
						
							| 
									
										
										
										
											2023-01-07 18:13:15 +00:00
										 |  |  |             if not post_json_object.get('to'): | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:13 +00:00
										 |  |  |                 if debug: | 
					
						
							|  |  |  |                     print(post_id + ' has no "to" list') | 
					
						
							|  |  |  |                 break | 
					
						
							| 
									
										
										
										
											2023-01-07 18:13:15 +00:00
										 |  |  |             if not isinstance(post_json_object['to'], list): | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:13 +00:00
										 |  |  |                 break | 
					
						
							| 
									
										
										
										
											2023-01-07 18:13:15 +00:00
										 |  |  |             if 'cc' not in post_json_object: | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:13 +00:00
										 |  |  |                 if debug: | 
					
						
							|  |  |  |                     print(post_id + ' has no "cc" list') | 
					
						
							|  |  |  |                 break | 
					
						
							| 
									
										
										
										
											2023-01-07 18:13:15 +00:00
										 |  |  |             if not isinstance(post_json_object['cc'], list): | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:13 +00:00
										 |  |  |                 break | 
					
						
							|  |  |  |             wrapped_post = { | 
					
						
							|  |  |  |                 "@context": "https://www.w3.org/ns/activitystreams", | 
					
						
							|  |  |  |                 'id': post_id + '/activity', | 
					
						
							|  |  |  |                 'type': 'Create', | 
					
						
							| 
									
										
										
										
											2023-01-07 18:13:15 +00:00
										 |  |  |                 'actor': post_json_object['attributedTo'], | 
					
						
							|  |  |  |                 'published': post_json_object['published'], | 
					
						
							|  |  |  |                 'to': post_json_object['to'], | 
					
						
							|  |  |  |                 'cc': post_json_object['cc'], | 
					
						
							|  |  |  |                 'object': post_json_object | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:13 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-01-07 18:13:15 +00:00
										 |  |  |             post_json_object = wrapped_post | 
					
						
							|  |  |  |         if not post_json_object['object'].get('published'): | 
					
						
							| 
									
										
										
										
											2022-12-30 17:32:49 +00:00
										 |  |  |             break | 
					
						
							| 
									
										
										
										
											2023-01-07 11:07:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-07 11:45:19 +00:00
										 |  |  |         # render harmless any dangerous markup | 
					
						
							| 
									
										
										
										
											2023-01-07 18:13:15 +00:00
										 |  |  |         harmless_markup(post_json_object) | 
					
						
							| 
									
										
										
										
											2023-01-07 11:07:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-07 18:13:15 +00:00
										 |  |  |         conversation_view = [post_json_object] + conversation_view | 
					
						
							|  |  |  |         if not post_json_object['object'].get('inReplyTo'): | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:13 +00:00
										 |  |  |             if debug: | 
					
						
							|  |  |  |                 print(post_id + ' is not a reply') | 
					
						
							|  |  |  |             break | 
					
						
							| 
									
										
										
										
											2023-01-07 18:13:15 +00:00
										 |  |  |         post_id = post_json_object['object']['inReplyTo'] | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:13 +00:00
										 |  |  |         post_id = remove_id_ending(post_id) | 
					
						
							|  |  |  |         post_filename = \ | 
					
						
							|  |  |  |             locate_post(base_dir, nickname, domain, post_id) | 
					
						
							|  |  |  |         if post_filename: | 
					
						
							| 
									
										
										
										
											2023-01-07 18:13:15 +00:00
										 |  |  |             post_json_object = load_json(post_filename) | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:13 +00:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2023-01-07 18:13:15 +00:00
										 |  |  |             post_json_object = \ | 
					
						
							|  |  |  |                 get_json(signing_priv_key_pem, session, post_id, | 
					
						
							|  |  |  |                          as_header, None, debug, __version__, | 
					
						
							|  |  |  |                          http_prefix, domain) | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:13 +00:00
										 |  |  |         if debug: | 
					
						
							| 
									
										
										
										
											2023-01-07 18:13:15 +00:00
										 |  |  |             if not post_json_object: | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:13 +00:00
										 |  |  |                 print(post_id + ' returned no json') | 
					
						
							| 
									
										
										
										
											2022-12-28 10:18:58 +00:00
										 |  |  |     return conversation_view |