| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  | __filename__ = "schedule.py" | 
					
						
							|  |  |  | __author__ = "Bob Mottram" | 
					
						
							|  |  |  | __license__ = "AGPL3+" | 
					
						
							| 
									
										
										
										
											2021-01-26 10:07:42 +00:00
										 |  |  | __version__ = "1.2.0" | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  | __maintainer__ = "Bob Mottram" | 
					
						
							|  |  |  | __email__ = "bob@freedombone.net" | 
					
						
							|  |  |  | __status__ = "Production" | 
					
						
							| 
									
										
										
										
											2021-06-15 15:08:12 +00:00
										 |  |  | __module_group__ = "Calendar" | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | import os | 
					
						
							| 
									
										
										
										
											2020-01-12 20:16:33 +00:00
										 |  |  | import time | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  | import datetime | 
					
						
							| 
									
										
										
										
											2021-06-22 15:45:59 +00:00
										 |  |  | from utils import hasObjectDict | 
					
						
							| 
									
										
										
										
											2020-01-13 11:36:42 +00:00
										 |  |  | from utils import getStatusNumber | 
					
						
							| 
									
										
										
										
											2020-01-12 21:47:36 +00:00
										 |  |  | from utils import loadJson | 
					
						
							| 
									
										
										
										
											2020-01-13 10:45:02 +00:00
										 |  |  | from outbox import postMessageToOutbox | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  | def _updatePostSchedule(baseDir: str, handle: str, httpd, | 
					
						
							|  |  |  |                         maxScheduledPosts: int) -> None: | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  |     """Checks if posts are due to be delivered and if so moves them to the outbox
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |     scheduleIndexFilename = baseDir + '/accounts/' + handle + '/schedule.index' | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  |     if not os.path.isfile(scheduleIndexFilename): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # get the current time as an int | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |     currTime = datetime.datetime.utcnow() | 
					
						
							|  |  |  |     daysSinceEpoch = (currTime - datetime.datetime(1970, 1, 1)).days | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |     scheduleDir = baseDir + '/accounts/' + handle + '/scheduled/' | 
					
						
							|  |  |  |     indexLines = [] | 
					
						
							|  |  |  |     deleteSchedulePost = False | 
					
						
							|  |  |  |     nickname = handle.split('@')[0] | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  |     with open(scheduleIndexFilename, 'r') as fp: | 
					
						
							|  |  |  |         for line in fp: | 
					
						
							|  |  |  |             if ' ' not in line: | 
					
						
							|  |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |             dateStr = line.split(' ')[0] | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  |             if 'T' not in dateStr: | 
					
						
							|  |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2020-05-22 11:32:38 +00:00
										 |  |  |             postId = line.split(' ', 1)[1].replace('\n', '').replace('\r', '') | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |             postFilename = scheduleDir + postId + '.json' | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  |             if deleteSchedulePost: | 
					
						
							|  |  |  |                 # delete extraneous scheduled posts | 
					
						
							|  |  |  |                 if os.path.isfile(postFilename): | 
					
						
							|  |  |  |                     os.remove(postFilename) | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             # create the new index file | 
					
						
							|  |  |  |             indexLines.append(line) | 
					
						
							|  |  |  |             # convert string date to int | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |             postTime = \ | 
					
						
							|  |  |  |                 datetime.datetime.strptime(dateStr, "%Y-%m-%dT%H:%M:%S%z") | 
					
						
							|  |  |  |             postTime = postTime.replace(tzinfo=None) | 
					
						
							|  |  |  |             postDaysSinceEpoch = \ | 
					
						
							|  |  |  |                 (postTime - datetime.datetime(1970, 1, 1)).days | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  |             if daysSinceEpoch < postDaysSinceEpoch: | 
					
						
							|  |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2020-01-13 11:16:35 +00:00
										 |  |  |             if daysSinceEpoch == postDaysSinceEpoch: | 
					
						
							|  |  |  |                 if currTime.time().hour < postTime.time().hour: | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 if currTime.time().minute < postTime.time().minute: | 
					
						
							|  |  |  |                     continue | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  |             if not os.path.isfile(postFilename): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |                 print('WARN: schedule missing postFilename=' + postFilename) | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  |                 indexLines.remove(line) | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             # load post | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |             postJsonObject = loadJson(postFilename) | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  |             if not postJsonObject: | 
					
						
							| 
									
										
										
										
											2020-01-13 11:13:30 +00:00
										 |  |  |                 print('WARN: schedule json not loaded') | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  |                 indexLines.remove(line) | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-13 11:36:42 +00:00
										 |  |  |             # set the published time | 
					
						
							|  |  |  |             # If this is not recent then http checks on the receiving side | 
					
						
							|  |  |  |             # will reject it | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |             statusNumber, published = getStatusNumber() | 
					
						
							| 
									
										
										
										
											2020-01-13 11:36:42 +00:00
										 |  |  |             if postJsonObject.get('published'): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |                 postJsonObject['published'] = published | 
					
						
							| 
									
										
										
										
											2021-06-22 15:45:59 +00:00
										 |  |  |             if hasObjectDict(postJsonObject): | 
					
						
							|  |  |  |                 if postJsonObject['object'].get('published'): | 
					
						
							|  |  |  |                     postJsonObject['published'] = published | 
					
						
							| 
									
										
										
										
											2020-01-13 11:36:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |             print('Sending scheduled post ' + postId) | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-13 12:27:27 +00:00
										 |  |  |             if nickname: | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |                 httpd.postToNickname = nickname | 
					
						
							| 
									
										
										
										
											2021-03-06 21:32:27 +00:00
										 |  |  |             if not postMessageToOutbox(httpd.session, | 
					
						
							|  |  |  |                                        httpd.translate, | 
					
						
							|  |  |  |                                        postJsonObject, nickname, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |                                        httpd, baseDir, | 
					
						
							|  |  |  |                                        httpd.httpPrefix, | 
					
						
							|  |  |  |                                        httpd.domain, | 
					
						
							|  |  |  |                                        httpd.domainFull, | 
					
						
							|  |  |  |                                        httpd.onionDomain, | 
					
						
							| 
									
										
										
										
											2020-06-03 20:21:44 +00:00
										 |  |  |                                        httpd.i2pDomain, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |                                        httpd.port, | 
					
						
							|  |  |  |                                        httpd.recentPostsCache, | 
					
						
							|  |  |  |                                        httpd.followersThreads, | 
					
						
							|  |  |  |                                        httpd.federationList, | 
					
						
							|  |  |  |                                        httpd.sendThreads, | 
					
						
							|  |  |  |                                        httpd.postLog, | 
					
						
							|  |  |  |                                        httpd.cachedWebfingers, | 
					
						
							|  |  |  |                                        httpd.personCache, | 
					
						
							|  |  |  |                                        httpd.allowDeletion, | 
					
						
							| 
									
										
										
										
											2020-06-09 11:03:59 +00:00
										 |  |  |                                        httpd.proxyType, | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |                                        httpd.projectVersion, | 
					
						
							| 
									
										
										
										
											2020-08-02 09:51:20 +00:00
										 |  |  |                                        httpd.debug, | 
					
						
							| 
									
										
										
										
											2020-12-22 21:24:46 +00:00
										 |  |  |                                        httpd.YTReplacementDomain, | 
					
						
							|  |  |  |                                        httpd.showPublishedDateOnly, | 
					
						
							| 
									
										
										
										
											2021-05-09 19:11:05 +00:00
										 |  |  |                                        httpd.allowLocalNetworkAccess, | 
					
						
							|  |  |  |                                        httpd.city): | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  |                 indexLines.remove(line) | 
					
						
							| 
									
										
										
										
											2020-01-13 11:36:42 +00:00
										 |  |  |                 os.remove(postFilename) | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  |                 continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # move to the outbox | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |             outboxPostFilename = \ | 
					
						
							|  |  |  |                 postFilename.replace('/scheduled/', '/outbox/') | 
					
						
							|  |  |  |             os.rename(postFilename, outboxPostFilename) | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |             print('Scheduled post sent ' + postId) | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             indexLines.remove(line) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |             if len(indexLines) > maxScheduledPosts: | 
					
						
							|  |  |  |                 deleteSchedulePost = True | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # write the new schedule index file | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |     scheduleIndexFile = \ | 
					
						
							|  |  |  |         baseDir + '/accounts/' + handle + '/schedule.index' | 
					
						
							| 
									
										
										
										
											2021-06-22 12:27:10 +00:00
										 |  |  |     with open(scheduleIndexFile, 'w+') as scheduleFile: | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  |         for line in indexLines: | 
					
						
							|  |  |  |             scheduleFile.write(line) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def runPostSchedule(baseDir: str, httpd, maxScheduledPosts: int): | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  |     """Dispatches scheduled posts
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     while True: | 
					
						
							|  |  |  |         time.sleep(60) | 
					
						
							|  |  |  |         # for each account | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |         for subdir, dirs, files in os.walk(baseDir + '/accounts'): | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  |             for account in dirs: | 
					
						
							|  |  |  |                 if '@' not in account: | 
					
						
							|  |  |  |                     continue | 
					
						
							| 
									
										
										
										
											2021-01-09 21:47:52 +00:00
										 |  |  |                 if account.startswith('inbox@'): | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 if account.startswith('news@'): | 
					
						
							|  |  |  |                     continue | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  |                 # scheduled posts index for this account | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |                 scheduleIndexFilename = \ | 
					
						
							|  |  |  |                     baseDir + '/accounts/' + account + '/schedule.index' | 
					
						
							| 
									
										
										
										
											2020-01-12 21:15:42 +00:00
										 |  |  |                 if not os.path.isfile(scheduleIndexFilename): | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  |                     continue | 
					
						
							| 
									
										
										
										
											2020-12-22 18:06:23 +00:00
										 |  |  |                 _updatePostSchedule(baseDir, account, httpd, maxScheduledPosts) | 
					
						
							| 
									
										
										
										
											2021-06-05 12:57:24 +00:00
										 |  |  |             break | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def runPostScheduleWatchdog(projectVersion: str, httpd) -> None: | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  |     """This tries to keep the scheduled post thread running even if it dies
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     print('Starting scheduled post watchdog') | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |     postScheduleOriginal = \ | 
					
						
							| 
									
										
										
										
											2020-01-12 20:13:44 +00:00
										 |  |  |         httpd.thrPostSchedule.clone(runPostSchedule) | 
					
						
							|  |  |  |     httpd.thrPostSchedule.start() | 
					
						
							|  |  |  |     while True: | 
					
						
							| 
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 |  |  |         time.sleep(20) | 
					
						
							| 
									
										
										
										
											2021-06-05 12:43:57 +00:00
										 |  |  |         if httpd.thrPostSchedule.is_alive(): | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         httpd.thrPostSchedule.kill() | 
					
						
							|  |  |  |         httpd.thrPostSchedule = \ | 
					
						
							|  |  |  |             postScheduleOriginal.clone(runPostSchedule) | 
					
						
							|  |  |  |         httpd.thrPostSchedule.start() | 
					
						
							|  |  |  |         print('Restarting scheduled posts...') | 
					
						
							| 
									
										
										
										
											2020-01-14 10:23:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def removeScheduledPosts(baseDir: str, nickname: str, domain: str) -> None: | 
					
						
							| 
									
										
										
										
											2020-01-14 10:23:17 +00:00
										 |  |  |     """Removes any scheduled posts
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     # remove the index | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |     scheduleIndexFilename = \ | 
					
						
							|  |  |  |         baseDir + '/accounts/' + nickname + '@' + domain + '/schedule.index' | 
					
						
							| 
									
										
										
										
											2020-01-14 10:23:17 +00:00
										 |  |  |     if os.path.isfile(scheduleIndexFilename): | 
					
						
							|  |  |  |         os.remove(scheduleIndexFilename) | 
					
						
							|  |  |  |     # remove the scheduled posts | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |     scheduledDir = baseDir + '/accounts/' + \ | 
					
						
							|  |  |  |         nickname + '@' + domain + '/scheduled' | 
					
						
							| 
									
										
										
										
											2020-01-14 10:23:17 +00:00
										 |  |  |     if not os.path.isdir(scheduledDir): | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     for scheduledPostFilename in os.listdir(scheduledDir): | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |         filePath = os.path.join(scheduledDir, scheduledPostFilename) | 
					
						
							| 
									
										
										
										
											2020-01-14 10:23:17 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             if os.path.isfile(filePath): | 
					
						
							|  |  |  |                 os.remove(filePath) | 
					
						
							| 
									
										
										
										
											2020-04-04 10:52:30 +00:00
										 |  |  |         except BaseException: | 
					
						
							| 
									
										
										
										
											2020-01-14 10:23:17 +00:00
										 |  |  |             pass |