diff --git a/daemon.py b/daemon.py index 424ad0fe..377c70fc 100644 --- a/daemon.py +++ b/daemon.py @@ -1100,55 +1100,70 @@ class PubServer(BaseHTTPRequestHandler): inReplyToUrl=None replyWithDM=False replyToList=[] - if htmlGET and '?replyto=' in self.path: - inReplyToUrl=self.path.split('?replyto=')[1] - if '?' in inReplyToUrl: - mentionsList=inReplyToUrl.split('?') - for m in mentionsList: - if m.startswith('mention='): - replyToList.append(m.replace('mention=','')) - inReplyToUrl=mentionsList[0] - self.path=self.path.split('?replyto=')[0]+'/newpost' - if self.server.debug: - print('DEBUG: replyto path '+self.path) - - # replying as a direct message, for moderation posts shareDescription=None - if htmlGET and '?replydm=' in self.path: - inReplyToUrl=self.path.split('?replydm=')[1] - if '?' in inReplyToUrl: - mentionsList=inReplyToUrl.split('?') - for m in mentionsList: - if m.startswith('mention='): - replyToList.append(m.replace('mention=','')) - inReplyToUrl=mentionsList[0] - if inReplyToUrl.startswith('sharedesc:'): - shareDescription=inReplyToUrl.replace('sharedesc:','').replace('%20',' ').replace('%40','@').replace('%3A',':').replace('%23','#') - self.path=self.path.split('?replydm=')[0]+'/newdm' - if self.server.debug: - print('DEBUG: replydm path '+self.path) + if htmlGET: + # public reply + if '?replyto=' in self.path: + inReplyToUrl=self.path.split('?replyto=')[1] + if '?' in inReplyToUrl: + mentionsList=inReplyToUrl.split('?') + for m in mentionsList: + if m.startswith('mention='): + replyToList.append(m.replace('mention=','')) + inReplyToUrl=mentionsList[0] + self.path=self.path.split('?replyto=')[0]+'/newpost' + if self.server.debug: + print('DEBUG: replyto path '+self.path) - # edit profile in web interface - if htmlGET and '/users/' in self.path and self.path.endswith('/editprofile'): - msg=htmlEditProfile(self.server.baseDir,self.path,self.server.domain,self.server.port).encode() - self._set_headers('text/html',len(msg),cookie) - self.wfile.write(msg) - self.server.GETbusy=False - return + # reply to followers + if '?replyfollowers=' in self.path: + inReplyToUrl=self.path.split('?replyfollowers=')[1] + if '?' in inReplyToUrl: + mentionsList=inReplyToUrl.split('?') + for m in mentionsList: + if m.startswith('mention='): + replyToList.append(m.replace('mention=','')) + inReplyToUrl=mentionsList[0] + self.path=self.path.split('?replyfollowers=')[0]+'/newfollowers' + if self.server.debug: + print('DEBUG: replyfollowers path '+self.path) - # Various types of new post in the web interface - if htmlGET and '/users/' in self.path and \ - (self.path.endswith('/newpost') or \ - self.path.endswith('/newunlisted') or \ - self.path.endswith('/newfollowers') or \ - self.path.endswith('/newdm') or \ - self.path.endswith('/newreport') or \ - self.path.endswith('/newshare')): - msg=htmlNewPost(self.server.baseDir,self.path,inReplyToUrl,replyToList,shareDescription).encode() - self._set_headers('text/html',len(msg),cookie) - self.wfile.write(msg) - self.server.GETbusy=False - return + # replying as a direct message, for moderation posts or the dm timeline + if '?replydm=' in self.path: + inReplyToUrl=self.path.split('?replydm=')[1] + if '?' in inReplyToUrl: + mentionsList=inReplyToUrl.split('?') + for m in mentionsList: + if m.startswith('mention='): + replyToList.append(m.replace('mention=','')) + inReplyToUrl=mentionsList[0] + if inReplyToUrl.startswith('sharedesc:'): + shareDescription=inReplyToUrl.replace('sharedesc:','').replace('%20',' ').replace('%40','@').replace('%3A',':').replace('%23','#') + self.path=self.path.split('?replydm=')[0]+'/newdm' + if self.server.debug: + print('DEBUG: replydm path '+self.path) + + # edit profile in web interface + if '/users/' in self.path and self.path.endswith('/editprofile'): + msg=htmlEditProfile(self.server.baseDir,self.path,self.server.domain,self.server.port).encode() + self._set_headers('text/html',len(msg),cookie) + self.wfile.write(msg) + self.server.GETbusy=False + return + + # Various types of new post in the web interface + if '/users/' in self.path and \ + (self.path.endswith('/newpost') or \ + self.path.endswith('/newunlisted') or \ + self.path.endswith('/newfollowers') or \ + self.path.endswith('/newdm') or \ + self.path.endswith('/newreport') or \ + self.path.endswith('/newshare')): + msg=htmlNewPost(self.server.baseDir,self.path,inReplyToUrl,replyToList,shareDescription).encode() + self._set_headers('text/html',len(msg),cookie) + self.wfile.write(msg) + self.server.GETbusy=False + return # get an individual post from the path /@nickname/statusnumber if '/@' in self.path: diff --git a/webinterface.py b/webinterface.py index a03f79ae..f08c8b8a 100644 --- a/webinterface.py +++ b/webinterface.py @@ -276,7 +276,7 @@ def htmlHashtagSearch(baseDir: str,hashtag: str,pageNumber: int,postsPerPage: in nickname,domain,port,postJsonObject, \ None,True,False, \ httpPrefix,projectVersion, \ - False,False) + False,False,False) index-=1 if endIndex>0: @@ -874,7 +874,7 @@ def htmlProfilePosts(baseDir: str,httpPrefix: str, \ individualPostAsHtml(baseDir,session,wfRequest,personCache, \ nickname,domain,port,item,None,True,False, \ httpPrefix,projectVersion, \ - False,False) + False,False,False) return profileStr def htmlProfileFollowing(baseDir: str,httpPrefix: str, \ @@ -1303,7 +1303,19 @@ def addEmbeddedElements(content: str) -> str: content=addEmbeddedVideoFromSites(content) content=addEmbeddedAudio(content) return addEmbeddedVideo(content) - + +def followerApprovalActive(baseDir: str,nickname: str,domain: str) -> bool: + """Returns true if the given account requires follower approval + """ + manuallyApprovesFollowers=False + actorFilename=baseDir+'/accounts/'+nickname+'@'+domain+'.json' + if os.path.isfile(actorFilename): + with open(actorFilename, 'r') as fp: + actorJson=commentjson.load(fp) + if actorJson.get('manuallyApprovesFollowers'): + manuallyApprovesFollowers=actorJson['manuallyApprovesFollowers'] + return manuallyApprovesFollowers + def individualPostAsHtml(baseDir: str, \ session,wfRequest: {},personCache: {}, \ nickname: str,domain: str,port: int, \ @@ -1311,8 +1323,9 @@ def individualPostAsHtml(baseDir: str, \ avatarUrl: str, showAvatarDropdown: bool, allowDeletion: bool, \ httpPrefix: str, projectVersion: str, \ - showRepeats=True, - showIcons=False) -> str: + showRepeats=True, \ + showIcons=False, \ + manuallyApprovesFollowers=False) -> str: """ Shows a single post as html """ # If this is the inbox timeline then don't show the repeat icon on any DMs @@ -1593,10 +1606,13 @@ def individualPostAsHtml(baseDir: str, \ replyToLink+='?mention='+actorUrl if len(replyToLink)>500: break - + footerStr='
' if not isModerationPost and showRepeatIcon: - footerStr+='' + if not manuallyApprovesFollowers: + footerStr+='' + else: + footerStr+='' else: footerStr+='' footerStr+='' @@ -1638,7 +1654,8 @@ def htmlTimeline(pageNumber: int,itemsPerPage: int,session,baseDir: str, \ wfRequest: {},personCache: {}, \ nickname: str,domain: str,port: int,timelineJson: {}, \ boxName: str,allowDeletion: bool, \ - httpPrefix: str,projectVersion: str) -> str: + httpPrefix: str,projectVersion: str, \ + manuallyApproveFollowers: bool) -> str: """Show the timeline as html """ with open(baseDir+'/epicyon-profile.css', 'r') as cssFile: @@ -1734,9 +1751,10 @@ def htmlTimeline(pageNumber: int,itemsPerPage: int,session,baseDir: str, \ tlStr+=individualPostAsHtml(baseDir,session,wfRequest,personCache, \ nickname,domain,port,item,avatarUrl,True, \ allowDeletion, \ - httpPrefix,projectVersion, - boxName!='dm', - showIndividualPostIcons) + httpPrefix,projectVersion, \ + boxName!='dm', \ + showIndividualPostIcons, \ + manuallyApproveFollowers) # page down arrow if itemCtr>=itemsPerPage: @@ -1751,9 +1769,12 @@ def htmlInbox(pageNumber: int,itemsPerPage: int, \ httpPrefix: str,projectVersion: str) -> str: """Show the inbox as html """ + manuallyApproveFollowers= \ + followerApprovalActive(baseDir,nickname,domain) + return htmlTimeline(pageNumber,itemsPerPage,session,baseDir,wfRequest,personCache, \ nickname,domain,port,inboxJson,'inbox',allowDeletion, \ - httpPrefix,projectVersion) + httpPrefix,projectVersion,manuallyApproveFollowers) def htmlInboxDMs(pageNumber: int,itemsPerPage: int, \ session,baseDir: str,wfRequest: {},personCache: {}, \ @@ -1764,7 +1785,7 @@ def htmlInboxDMs(pageNumber: int,itemsPerPage: int, \ """ return htmlTimeline(pageNumber,itemsPerPage,session,baseDir,wfRequest,personCache, \ nickname,domain,port,inboxJson,'dm',allowDeletion, \ - httpPrefix,projectVersion) + httpPrefix,projectVersion,False) def htmlModeration(pageNumber: int,itemsPerPage: int, \ session,baseDir: str,wfRequest: {},personCache: {}, \ @@ -1775,7 +1796,7 @@ def htmlModeration(pageNumber: int,itemsPerPage: int, \ """ return htmlTimeline(pageNumber,itemsPerPage,session,baseDir,wfRequest,personCache, \ nickname,domain,port,inboxJson,'moderation',allowDeletion, \ - httpPrefix,projectVersion) + httpPrefix,projectVersion,True) def htmlOutbox(pageNumber: int,itemsPerPage: int, \ session,baseDir: str,wfRequest: {},personCache: {}, \ @@ -1784,9 +1805,11 @@ def htmlOutbox(pageNumber: int,itemsPerPage: int, \ httpPrefix: str,projectVersion: str) -> str: """Show the Outbox as html """ + manuallyApproveFollowers= \ + followerApprovalActive(baseDir,nickname,domain) return htmlTimeline(pageNumber,itemsPerPage,session,baseDir,wfRequest,personCache, \ nickname,domain,port,outboxJson,'outbox',allowDeletion, \ - httpPrefix,projectVersion) + httpPrefix,projectVersion,manuallyApproveFollowers) def htmlIndividualPost(baseDir: str,session,wfRequest: {},personCache: {}, \ nickname: str,domain: str,port: int,authorized: bool, \ @@ -1797,7 +1820,7 @@ def htmlIndividualPost(baseDir: str,session,wfRequest: {},personCache: {}, \ postStr+= \ individualPostAsHtml(baseDir,session,wfRequest,personCache, \ nickname,domain,port,postJsonObject,None,True,False, \ - httpPrefix,projectVersion,False,False) + httpPrefix,projectVersion,False,False,False) messageId=postJsonObject['id'].replace('/activity','') # show the previous posts @@ -1812,7 +1835,7 @@ def htmlIndividualPost(baseDir: str,session,wfRequest: {},personCache: {}, \ nickname,domain,port,postJsonObject, \ None,True,False, \ httpPrefix,projectVersion, \ - False,False)+postStr + False,False,False)+postStr # show the following posts postFilename=locatePost(baseDir,nickname,domain,messageId) @@ -1828,7 +1851,7 @@ def htmlIndividualPost(baseDir: str,session,wfRequest: {},personCache: {}, \ postStr+= \ individualPostAsHtml(baseDir,session,wfRequest,personCache, \ nickname,domain,port,item,None,True,False, \ - httpPrefix,projectVersion,False,False) + httpPrefix,projectVersion,False,False,False) return htmlHeader()+postStr+htmlFooter() def htmlPostReplies(baseDir: str,session,wfRequest: {},personCache: {}, \ @@ -1841,7 +1864,7 @@ def htmlPostReplies(baseDir: str,session,wfRequest: {},personCache: {}, \ for item in repliesJson['orderedItems']: repliesStr+=individualPostAsHtml(baseDir,session,wfRequest,personCache, \ nickname,domain,port,item,None,True,False, \ - httpPrefix,projectVersion,False,False) + httpPrefix,projectVersion,False,False,False) return htmlHeader()+repliesStr+htmlFooter() @@ -1921,7 +1944,7 @@ def htmlDeletePost(session,baseDir: str,messageId: str, \ deletePostStr+= \ individualPostAsHtml(baseDir,session,wfRequest,personCache, \ nickname,domain,port,postJsonObject,None,True,False, \ - httpPrefix,projectVersion,False,False) + httpPrefix,projectVersion,False,False,False) deletePostStr+='
' deletePostStr+='

Delete this post?

' deletePostStr+= \ @@ -2299,7 +2322,7 @@ def htmlProfileAfterSearch(baseDir: str,path: str,httpPrefix: str, \ nickname,domain,port, \ item,avatarUrl,False,False, \ httpPrefix,projectVersion, \ - False,False) + False,False,False) i+=1 if i>=20: break