| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  | __filename__ = "daemon_post_newswire.py" | 
					
						
							|  |  |  | __author__ = "Bob Mottram" | 
					
						
							|  |  |  | __license__ = "AGPL3+" | 
					
						
							| 
									
										
										
										
											2024-12-22 23:37:30 +00:00
										 |  |  | __version__ = "1.6.0" | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  | __maintainer__ = "Bob Mottram" | 
					
						
							|  |  |  | __email__ = "bob@libreserver.org" | 
					
						
							|  |  |  | __status__ = "Production" | 
					
						
							| 
									
										
										
										
											2024-12-25 14:31:14 +00:00
										 |  |  | __module_group__ = "Daemon POST" | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | import errno | 
					
						
							|  |  |  | from socket import error as SocketError | 
					
						
							| 
									
										
										
										
											2024-09-13 13:58:14 +00:00
										 |  |  | from flags import is_editor | 
					
						
							| 
									
										
										
										
											2025-05-27 13:16:19 +00:00
										 |  |  | from cache import clear_from_post_caches | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  | from utils import data_dir | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  | from utils import remove_id_ending | 
					
						
							|  |  |  | from utils import save_json | 
					
						
							|  |  |  | from utils import first_paragraph_from_string | 
					
						
							|  |  |  | from utils import load_json | 
					
						
							|  |  |  | from utils import locate_post | 
					
						
							|  |  |  | from utils import acct_dir | 
					
						
							|  |  |  | from utils import get_instance_url | 
					
						
							|  |  |  | from utils import get_nickname_from_actor | 
					
						
							| 
									
										
										
										
											2025-05-28 11:38:45 +00:00
										 |  |  | from timeFunctions import date_from_string_format | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  | from httpheaders import redirect_headers | 
					
						
							|  |  |  | from posts import is_moderator | 
					
						
							|  |  |  | from content import extract_text_fields_in_post | 
					
						
							|  |  |  | from content import load_dogwhistles | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def newswire_update(self, calling_domain: str, cookie: str, | 
					
						
							|  |  |  |                     path: str, base_dir: str, | 
					
						
							|  |  |  |                     domain: str, debug: bool, | 
					
						
							| 
									
										
										
										
											2024-04-14 12:02:51 +00:00
										 |  |  |                     default_timeline: str, | 
					
						
							|  |  |  |                     http_prefix: str, domain_full: str, | 
					
						
							|  |  |  |                     onion_domain: str, i2p_domain: str, | 
					
						
							|  |  |  |                     max_post_length: int) -> None: | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |     """Updates the right newswire column of the timeline
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     users_path = path.replace('/newswiredata', '') | 
					
						
							|  |  |  |     users_path = users_path.replace('/editnewswire', '') | 
					
						
							|  |  |  |     actor_str = \ | 
					
						
							|  |  |  |         get_instance_url(calling_domain, | 
					
						
							| 
									
										
										
										
											2024-04-14 12:02:51 +00:00
										 |  |  |                          http_prefix, domain_full, | 
					
						
							|  |  |  |                          onion_domain, i2p_domain) + \ | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |         users_path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     boundary = None | 
					
						
							|  |  |  |     if ' boundary=' in self.headers['Content-type']: | 
					
						
							|  |  |  |         boundary = self.headers['Content-type'].split('boundary=')[1] | 
					
						
							|  |  |  |         if ';' in boundary: | 
					
						
							|  |  |  |             boundary = boundary.split(';')[0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # get the nickname | 
					
						
							|  |  |  |     nickname = get_nickname_from_actor(actor_str) | 
					
						
							|  |  |  |     moderator = None | 
					
						
							|  |  |  |     if nickname: | 
					
						
							|  |  |  |         moderator = is_moderator(base_dir, nickname) | 
					
						
							|  |  |  |     if not nickname or not moderator: | 
					
						
							|  |  |  |         if not nickname: | 
					
						
							|  |  |  |             print('WARN: nickname not found in ' + actor_str) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             print('WARN: nickname is not a moderator' + actor_str) | 
					
						
							| 
									
										
										
										
											2024-04-16 13:47:21 +00:00
										 |  |  |         redirect_headers(self, actor_str, cookie, calling_domain, 303) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |         self.server.postreq_busy = False | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if self.headers.get('Content-length'): | 
					
						
							|  |  |  |         length = int(self.headers['Content-length']) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # check that the POST isn't too large | 
					
						
							| 
									
										
										
										
											2024-04-14 12:02:51 +00:00
										 |  |  |         if length > max_post_length: | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |             print('Maximum newswire data length exceeded ' + str(length)) | 
					
						
							| 
									
										
										
										
											2024-04-16 13:47:21 +00:00
										 |  |  |             redirect_headers(self, actor_str, cookie, calling_domain, 303) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |             self.server.postreq_busy = False | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         # read the bytes of the http form POST | 
					
						
							|  |  |  |         post_bytes = self.rfile.read(length) | 
					
						
							|  |  |  |     except SocketError as ex: | 
					
						
							|  |  |  |         if ex.errno == errno.ECONNRESET: | 
					
						
							|  |  |  |             print('EX: connection was reset while ' + | 
					
						
							|  |  |  |                   'reading bytes from http form POST') | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             print('EX: error while reading bytes ' + | 
					
						
							|  |  |  |                   'from http form POST') | 
					
						
							|  |  |  |         self.send_response(400) | 
					
						
							|  |  |  |         self.end_headers() | 
					
						
							|  |  |  |         self.server.postreq_busy = False | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     except ValueError as ex: | 
					
						
							|  |  |  |         print('EX: failed to read bytes for POST, ' + str(ex)) | 
					
						
							|  |  |  |         self.send_response(400) | 
					
						
							|  |  |  |         self.end_headers() | 
					
						
							|  |  |  |         self.server.postreq_busy = False | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |     newswire_filename = data_dir(base_dir) + '/newswire.txt' | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if not boundary: | 
					
						
							|  |  |  |         if b'--LYNX' in post_bytes: | 
					
						
							|  |  |  |             boundary = '--LYNX' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if boundary: | 
					
						
							|  |  |  |         # extract all of the text fields into a dict | 
					
						
							|  |  |  |         fields = \ | 
					
						
							|  |  |  |             extract_text_fields_in_post(post_bytes, boundary, debug, None) | 
					
						
							|  |  |  |         if fields.get('editedNewswire'): | 
					
						
							|  |  |  |             newswire_str = fields['editedNewswire'] | 
					
						
							|  |  |  |             # append a new newswire entry | 
					
						
							|  |  |  |             if fields.get('newNewswireFeed'): | 
					
						
							|  |  |  |                 if newswire_str: | 
					
						
							|  |  |  |                     if not newswire_str.endswith('\n'): | 
					
						
							|  |  |  |                         newswire_str += '\n' | 
					
						
							|  |  |  |                 newswire_str += fields['newNewswireFeed'] + '\n' | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 with open(newswire_filename, 'w+', | 
					
						
							| 
									
										
										
										
											2024-07-16 11:21:28 +00:00
										 |  |  |                           encoding='utf-8') as fp_news: | 
					
						
							|  |  |  |                     fp_news.write(newswire_str) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |             except OSError: | 
					
						
							|  |  |  |                 print('EX: unable to write ' + newswire_filename) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             if fields.get('newNewswireFeed'): | 
					
						
							|  |  |  |                 # the text area is empty but there is a new feed added | 
					
						
							|  |  |  |                 newswire_str = fields['newNewswireFeed'] + '\n' | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     with open(newswire_filename, 'w+', | 
					
						
							| 
									
										
										
										
											2024-07-16 11:21:28 +00:00
										 |  |  |                               encoding='utf-8') as fp_news: | 
					
						
							|  |  |  |                         fp_news.write(newswire_str) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |                 except OSError: | 
					
						
							|  |  |  |                     print('EX: unable to write ' + newswire_filename) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 # text area has been cleared and there is no new feed | 
					
						
							|  |  |  |                 if os.path.isfile(newswire_filename): | 
					
						
							|  |  |  |                     try: | 
					
						
							|  |  |  |                         os.remove(newswire_filename) | 
					
						
							|  |  |  |                     except OSError: | 
					
						
							|  |  |  |                         print('EX: _newswire_update unable to delete ' + | 
					
						
							|  |  |  |                               newswire_filename) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # save filtered words list for the newswire | 
					
						
							|  |  |  |         filter_newswire_filename = \ | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |             data_dir(base_dir) + '/' + 'news@' + domain + '/filters.txt' | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |         if fields.get('filteredWordsNewswire'): | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 with open(filter_newswire_filename, 'w+', | 
					
						
							| 
									
										
										
										
											2024-07-16 11:21:28 +00:00
										 |  |  |                           encoding='utf-8') as fp_filter: | 
					
						
							|  |  |  |                     fp_filter.write(fields['filteredWordsNewswire']) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |             except OSError: | 
					
						
							| 
									
										
										
										
											2024-07-02 22:16:13 +00:00
										 |  |  |                 print('EX: newswire_update unable to write ' + | 
					
						
							|  |  |  |                       filter_newswire_filename) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |         else: | 
					
						
							|  |  |  |             if os.path.isfile(filter_newswire_filename): | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     os.remove(filter_newswire_filename) | 
					
						
							|  |  |  |                 except OSError: | 
					
						
							|  |  |  |                     print('EX: _newswire_update unable to delete ' + | 
					
						
							|  |  |  |                           filter_newswire_filename) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # save dogwhistle words list | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |         dogwhistles_filename = data_dir(base_dir) + '/dogwhistles.txt' | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |         if fields.get('dogwhistleWords'): | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 with open(dogwhistles_filename, 'w+', | 
					
						
							|  |  |  |                           encoding='utf-8') as fp_dogwhistles: | 
					
						
							|  |  |  |                     fp_dogwhistles.write(fields['dogwhistleWords']) | 
					
						
							|  |  |  |             except OSError: | 
					
						
							| 
									
										
										
										
											2024-07-02 22:16:13 +00:00
										 |  |  |                 print('EX: newswire_update unable to write 2 ' + | 
					
						
							|  |  |  |                       dogwhistles_filename) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |             self.server.dogwhistles = \ | 
					
						
							|  |  |  |                 load_dogwhistles(dogwhistles_filename) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             # save an empty file | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 with open(dogwhistles_filename, 'w+', | 
					
						
							|  |  |  |                           encoding='utf-8') as fp_dogwhistles: | 
					
						
							|  |  |  |                     fp_dogwhistles.write('') | 
					
						
							|  |  |  |             except OSError: | 
					
						
							| 
									
										
										
										
											2024-07-02 22:16:13 +00:00
										 |  |  |                 print('EX: newswire_update unable unable to write 3 ' + | 
					
						
							|  |  |  |                       dogwhistles_filename) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |             self.server.dogwhistles = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # save news tagging rules | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |         hashtag_rules_filename = data_dir(base_dir) + '/hashtagrules.txt' | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |         if fields.get('hashtagRulesList'): | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 with open(hashtag_rules_filename, 'w+', | 
					
						
							| 
									
										
										
										
											2024-07-16 11:21:28 +00:00
										 |  |  |                           encoding='utf-8') as fp_rules: | 
					
						
							|  |  |  |                     fp_rules.write(fields['hashtagRulesList']) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |             except OSError: | 
					
						
							| 
									
										
										
										
											2024-07-02 22:16:13 +00:00
										 |  |  |                 print('EX: newswire_update unable to write 4 ' + | 
					
						
							|  |  |  |                       hashtag_rules_filename) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |         else: | 
					
						
							|  |  |  |             if os.path.isfile(hashtag_rules_filename): | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     os.remove(hashtag_rules_filename) | 
					
						
							|  |  |  |                 except OSError: | 
					
						
							|  |  |  |                     print('EX: _newswire_update unable to delete ' + | 
					
						
							|  |  |  |                           hashtag_rules_filename) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |         newswire_tusted_filename = data_dir(base_dir) + '/newswiretrusted.txt' | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |         if fields.get('trustedNewswire'): | 
					
						
							|  |  |  |             newswire_trusted = fields['trustedNewswire'] | 
					
						
							|  |  |  |             if not newswire_trusted.endswith('\n'): | 
					
						
							|  |  |  |                 newswire_trusted += '\n' | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 with open(newswire_tusted_filename, 'w+', | 
					
						
							| 
									
										
										
										
											2024-07-16 11:21:28 +00:00
										 |  |  |                           encoding='utf-8') as fp_trust: | 
					
						
							|  |  |  |                     fp_trust.write(newswire_trusted) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |             except OSError: | 
					
						
							| 
									
										
										
										
											2024-07-02 22:16:13 +00:00
										 |  |  |                 print('EX: newswire_update unable to write 5 ' + | 
					
						
							|  |  |  |                       newswire_tusted_filename) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |         else: | 
					
						
							|  |  |  |             if os.path.isfile(newswire_tusted_filename): | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     os.remove(newswire_tusted_filename) | 
					
						
							|  |  |  |                 except OSError: | 
					
						
							|  |  |  |                     print('EX: _newswire_update unable to delete ' + | 
					
						
							|  |  |  |                           newswire_tusted_filename) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # redirect back to the default timeline | 
					
						
							|  |  |  |     redirect_headers(self, actor_str + '/' + default_timeline, | 
					
						
							| 
									
										
										
										
											2024-04-16 13:47:21 +00:00
										 |  |  |                      cookie, calling_domain, 303) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |     self.server.postreq_busy = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def citations_update(self, calling_domain: str, cookie: str, | 
					
						
							|  |  |  |                      path: str, base_dir: str, | 
					
						
							|  |  |  |                      domain: str, debug: bool, | 
					
						
							| 
									
										
										
										
											2024-04-14 12:02:51 +00:00
										 |  |  |                      newswire: {}, | 
					
						
							|  |  |  |                      http_prefix: str, domain_full: str, | 
					
						
							|  |  |  |                      onion_domain: str, i2p_domain: str, | 
					
						
							|  |  |  |                      max_post_length: int) -> None: | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |     """Updates the citations for a blog post after hitting
 | 
					
						
							|  |  |  |     update button on the citations screen | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     users_path = path.replace('/citationsdata', '') | 
					
						
							|  |  |  |     actor_str = \ | 
					
						
							|  |  |  |         get_instance_url(calling_domain, | 
					
						
							| 
									
										
										
										
											2024-04-14 12:02:51 +00:00
										 |  |  |                          http_prefix, domain_full, | 
					
						
							|  |  |  |                          onion_domain, i2p_domain) + \ | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |         users_path | 
					
						
							|  |  |  |     nickname = get_nickname_from_actor(actor_str) | 
					
						
							|  |  |  |     if not nickname: | 
					
						
							|  |  |  |         self.server.postreq_busy = False | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     citations_filename = \ | 
					
						
							|  |  |  |         acct_dir(base_dir, nickname, domain) + '/.citations.txt' | 
					
						
							|  |  |  |     # remove any existing citations file | 
					
						
							|  |  |  |     if os.path.isfile(citations_filename): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             os.remove(citations_filename) | 
					
						
							|  |  |  |         except OSError: | 
					
						
							|  |  |  |             print('EX: _citations_update unable to delete ' + | 
					
						
							|  |  |  |                   citations_filename) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if newswire and \ | 
					
						
							|  |  |  |        ' boundary=' in self.headers['Content-type']: | 
					
						
							|  |  |  |         boundary = self.headers['Content-type'].split('boundary=')[1] | 
					
						
							|  |  |  |         if ';' in boundary: | 
					
						
							|  |  |  |             boundary = boundary.split(';')[0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         length = int(self.headers['Content-length']) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # check that the POST isn't too large | 
					
						
							| 
									
										
										
										
											2024-04-14 12:02:51 +00:00
										 |  |  |         if length > max_post_length: | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |             print('Maximum citations data length exceeded ' + str(length)) | 
					
						
							| 
									
										
										
										
											2024-04-16 13:47:21 +00:00
										 |  |  |             redirect_headers(self, actor_str, cookie, calling_domain, 303) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |             self.server.postreq_busy = False | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             # read the bytes of the http form POST | 
					
						
							|  |  |  |             post_bytes = self.rfile.read(length) | 
					
						
							|  |  |  |         except SocketError as ex: | 
					
						
							|  |  |  |             if ex.errno == errno.ECONNRESET: | 
					
						
							|  |  |  |                 print('EX: connection was reset while ' + | 
					
						
							|  |  |  |                       'reading bytes from http form ' + | 
					
						
							|  |  |  |                       'citation screen POST') | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 print('EX: error while reading bytes ' + | 
					
						
							|  |  |  |                       'from http form citations screen POST') | 
					
						
							|  |  |  |             self.send_response(400) | 
					
						
							|  |  |  |             self.end_headers() | 
					
						
							|  |  |  |             self.server.postreq_busy = False | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         except ValueError as ex: | 
					
						
							|  |  |  |             print('EX: failed to read bytes for ' + | 
					
						
							|  |  |  |                   'citations screen POST, ' + str(ex)) | 
					
						
							|  |  |  |             self.send_response(400) | 
					
						
							|  |  |  |             self.end_headers() | 
					
						
							|  |  |  |             self.server.postreq_busy = False | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # extract all of the text fields into a dict | 
					
						
							|  |  |  |         fields = \ | 
					
						
							|  |  |  |             extract_text_fields_in_post(post_bytes, boundary, debug, None) | 
					
						
							|  |  |  |         print('citationstest: ' + str(fields)) | 
					
						
							| 
									
										
										
										
											2024-12-23 17:45:20 +00:00
										 |  |  |         citations: list[str] = [] | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |         for ctr in range(0, 128): | 
					
						
							|  |  |  |             field_name = 'newswire' + str(ctr) | 
					
						
							|  |  |  |             if not fields.get(field_name): | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             citations.append(fields[field_name]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if citations: | 
					
						
							|  |  |  |             citations_str = '' | 
					
						
							|  |  |  |             for citation_date in citations: | 
					
						
							|  |  |  |                 citations_str += citation_date + '\n' | 
					
						
							|  |  |  |             # save citations dates, so that they can be added when | 
					
						
							|  |  |  |             # reloading the newblog screen | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 with open(citations_filename, 'w+', | 
					
						
							| 
									
										
										
										
											2024-07-16 11:21:28 +00:00
										 |  |  |                           encoding='utf-8') as fp_cit: | 
					
						
							|  |  |  |                     fp_cit.write(citations_str) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |             except OSError: | 
					
						
							| 
									
										
										
										
											2024-07-02 22:16:13 +00:00
										 |  |  |                 print('EX: citations_update unable to write ' + | 
					
						
							|  |  |  |                       citations_filename) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # redirect back to the default timeline | 
					
						
							|  |  |  |     redirect_headers(self, actor_str + '/newblog', | 
					
						
							| 
									
										
										
										
											2024-04-16 13:47:21 +00:00
										 |  |  |                      cookie, calling_domain, 303) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |     self.server.postreq_busy = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def news_post_edit(self, calling_domain: str, cookie: str, | 
					
						
							|  |  |  |                    path: str, base_dir: str, | 
					
						
							| 
									
										
										
										
											2024-04-14 12:02:51 +00:00
										 |  |  |                    domain: str, debug: bool, | 
					
						
							|  |  |  |                    http_prefix: str, domain_full: str, | 
					
						
							|  |  |  |                    onion_domain: str, i2p_domain: str, | 
					
						
							|  |  |  |                    news_instance: bool, | 
					
						
							|  |  |  |                    max_post_length: int, | 
					
						
							|  |  |  |                    system_language: str, | 
					
						
							|  |  |  |                    recent_posts_cache: {}, | 
					
						
							|  |  |  |                    newswire: {}) -> None: | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |     """edits a news post after receiving POST
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     users_path = path.replace('/newseditdata', '') | 
					
						
							|  |  |  |     users_path = users_path.replace('/editnewspost', '') | 
					
						
							|  |  |  |     actor_str = \ | 
					
						
							|  |  |  |         get_instance_url(calling_domain, | 
					
						
							| 
									
										
										
										
											2024-04-14 12:02:51 +00:00
										 |  |  |                          http_prefix, domain_full, | 
					
						
							|  |  |  |                          onion_domain, i2p_domain) + \ | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |         users_path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     boundary = None | 
					
						
							|  |  |  |     if ' boundary=' in self.headers['Content-type']: | 
					
						
							|  |  |  |         boundary = self.headers['Content-type'].split('boundary=')[1] | 
					
						
							|  |  |  |         if ';' in boundary: | 
					
						
							|  |  |  |             boundary = boundary.split(';')[0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # get the nickname | 
					
						
							|  |  |  |     nickname = get_nickname_from_actor(actor_str) | 
					
						
							|  |  |  |     editor_role = None | 
					
						
							|  |  |  |     if nickname: | 
					
						
							|  |  |  |         editor_role = is_editor(base_dir, nickname) | 
					
						
							|  |  |  |     if not nickname or not editor_role: | 
					
						
							|  |  |  |         if not nickname: | 
					
						
							|  |  |  |             print('WARN: nickname not found in ' + actor_str) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             print('WARN: nickname is not an editor' + actor_str) | 
					
						
							| 
									
										
										
										
											2024-04-14 12:02:51 +00:00
										 |  |  |         if news_instance: | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |             redirect_headers(self, actor_str + '/tlfeatures', | 
					
						
							| 
									
										
										
										
											2024-04-16 13:47:21 +00:00
										 |  |  |                              cookie, calling_domain, 303) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |         else: | 
					
						
							|  |  |  |             redirect_headers(self, actor_str + '/tlnews', | 
					
						
							| 
									
										
										
										
											2024-04-16 13:47:21 +00:00
										 |  |  |                              cookie, calling_domain, 303) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |         self.server.postreq_busy = False | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if self.headers.get('Content-length'): | 
					
						
							|  |  |  |         length = int(self.headers['Content-length']) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # check that the POST isn't too large | 
					
						
							| 
									
										
										
										
											2024-04-14 12:02:51 +00:00
										 |  |  |         if length > max_post_length: | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |             print('Maximum news data length exceeded ' + str(length)) | 
					
						
							| 
									
										
										
										
											2024-04-14 12:02:51 +00:00
										 |  |  |             if news_instance: | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |                 redirect_headers(self, actor_str + '/tlfeatures', | 
					
						
							| 
									
										
										
										
											2024-04-16 13:47:21 +00:00
										 |  |  |                                  cookie, calling_domain, 303) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |             else: | 
					
						
							|  |  |  |                 redirect_headers(self, actor_str + '/tlnews', | 
					
						
							| 
									
										
										
										
											2024-04-16 13:47:21 +00:00
										 |  |  |                                  cookie, calling_domain, 303) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |             self.server.postreq_busy = False | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         # read the bytes of the http form POST | 
					
						
							|  |  |  |         post_bytes = self.rfile.read(length) | 
					
						
							|  |  |  |     except SocketError as ex: | 
					
						
							|  |  |  |         if ex.errno == errno.ECONNRESET: | 
					
						
							|  |  |  |             print('EX: connection was reset while ' + | 
					
						
							|  |  |  |                   'reading bytes from http form POST') | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             print('EX: error while reading bytes ' + | 
					
						
							|  |  |  |                   'from http form POST') | 
					
						
							|  |  |  |         self.send_response(400) | 
					
						
							|  |  |  |         self.end_headers() | 
					
						
							|  |  |  |         self.server.postreq_busy = False | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     except ValueError as ex: | 
					
						
							|  |  |  |         print('EX: failed to read bytes for POST, ' + str(ex)) | 
					
						
							|  |  |  |         self.send_response(400) | 
					
						
							|  |  |  |         self.end_headers() | 
					
						
							|  |  |  |         self.server.postreq_busy = False | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not boundary: | 
					
						
							|  |  |  |         if b'--LYNX' in post_bytes: | 
					
						
							|  |  |  |             boundary = '--LYNX' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if boundary: | 
					
						
							|  |  |  |         # extract all of the text fields into a dict | 
					
						
							|  |  |  |         fields = \ | 
					
						
							|  |  |  |             extract_text_fields_in_post(post_bytes, boundary, debug, None) | 
					
						
							|  |  |  |         news_post_url = None | 
					
						
							|  |  |  |         news_post_title = None | 
					
						
							|  |  |  |         news_post_content = None | 
					
						
							|  |  |  |         if fields.get('newsPostUrl'): | 
					
						
							|  |  |  |             news_post_url = fields['newsPostUrl'] | 
					
						
							|  |  |  |         if fields.get('newsPostTitle'): | 
					
						
							|  |  |  |             news_post_title = fields['newsPostTitle'] | 
					
						
							|  |  |  |         if fields.get('editedNewsPost'): | 
					
						
							|  |  |  |             news_post_content = fields['editedNewsPost'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if news_post_url and news_post_content and news_post_title: | 
					
						
							|  |  |  |             # load the post | 
					
						
							|  |  |  |             post_filename = \ | 
					
						
							|  |  |  |                 locate_post(base_dir, nickname, domain, | 
					
						
							|  |  |  |                             news_post_url) | 
					
						
							|  |  |  |             if post_filename: | 
					
						
							|  |  |  |                 post_json_object = load_json(post_filename) | 
					
						
							| 
									
										
										
										
											2024-04-14 12:02:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |                 # update the content and title | 
					
						
							|  |  |  |                 post_json_object['object']['summary'] = \ | 
					
						
							|  |  |  |                     news_post_title | 
					
						
							|  |  |  |                 post_json_object['object']['content'] = \ | 
					
						
							|  |  |  |                     news_post_content | 
					
						
							|  |  |  |                 content_map = post_json_object['object']['contentMap'] | 
					
						
							| 
									
										
										
										
											2024-04-14 12:02:51 +00:00
										 |  |  |                 content_map[system_language] = \ | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |                     news_post_content | 
					
						
							| 
									
										
										
										
											2024-04-14 12:02:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |                 # update newswire | 
					
						
							|  |  |  |                 pub_date = post_json_object['object']['published'] | 
					
						
							|  |  |  |                 published_date = \ | 
					
						
							|  |  |  |                     date_from_string_format(pub_date, | 
					
						
							|  |  |  |                                             ["%Y-%m-%dT%H:%M:%S%z"]) | 
					
						
							| 
									
										
										
										
											2024-04-14 12:02:51 +00:00
										 |  |  |                 if newswire.get(str(published_date)): | 
					
						
							|  |  |  |                     newswire[published_date][0] = news_post_title | 
					
						
							|  |  |  |                     newswire[published_date][4] = \ | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |                         first_paragraph_from_string(news_post_content) | 
					
						
							|  |  |  |                     # save newswire | 
					
						
							|  |  |  |                     newswire_state_filename = \ | 
					
						
							| 
									
										
										
										
											2024-05-12 12:35:26 +00:00
										 |  |  |                         data_dir(base_dir) + '/.newswirestate.json' | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |                     try: | 
					
						
							| 
									
										
										
										
											2024-04-14 12:02:51 +00:00
										 |  |  |                         save_json(newswire, newswire_state_filename) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |                     except BaseException as ex: | 
					
						
							|  |  |  |                         print('EX: saving newswire state, ' + str(ex)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 # remove any previous cached news posts | 
					
						
							|  |  |  |                 news_id = \ | 
					
						
							|  |  |  |                     remove_id_ending(post_json_object['object']['id']) | 
					
						
							|  |  |  |                 news_id = news_id.replace('/', '#') | 
					
						
							| 
									
										
										
										
											2024-04-14 12:02:51 +00:00
										 |  |  |                 clear_from_post_caches(base_dir, recent_posts_cache, | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |                                        news_id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 # save the news post | 
					
						
							|  |  |  |                 save_json(post_json_object, post_filename) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # redirect back to the default timeline | 
					
						
							| 
									
										
										
										
											2024-04-14 12:02:51 +00:00
										 |  |  |     if news_instance: | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |         redirect_headers(self, actor_str + '/tlfeatures', | 
					
						
							| 
									
										
										
										
											2024-04-16 13:47:21 +00:00
										 |  |  |                          cookie, calling_domain, 303) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |     else: | 
					
						
							|  |  |  |         redirect_headers(self, actor_str + '/tlnews', | 
					
						
							| 
									
										
										
										
											2024-04-16 13:47:21 +00:00
										 |  |  |                          cookie, calling_domain, 303) | 
					
						
							| 
									
										
										
										
											2024-03-03 22:21:28 +00:00
										 |  |  |     self.server.postreq_busy = False |