forked from indymedia/epicyon
Move shared inbox account into daemon
parent
cb79ddb760
commit
c301f45b33
|
@ -18,6 +18,7 @@ from webfinger import webfingerLookup
|
||||||
from webfinger import webfingerHandle
|
from webfinger import webfingerHandle
|
||||||
from person import personLookup
|
from person import personLookup
|
||||||
from person import personBoxJson
|
from person import personBoxJson
|
||||||
|
from person import createSharedInbox
|
||||||
from posts import outboxMessageCreateWrap
|
from posts import outboxMessageCreateWrap
|
||||||
from posts import savePostToBox
|
from posts import savePostToBox
|
||||||
from inbox import inboxPermittedMessage
|
from inbox import inboxPermittedMessage
|
||||||
|
@ -540,6 +541,10 @@ def runDaemon(baseDir: str,domain: str,port=80,httpPrefix='https', \
|
||||||
httpd.acceptedCaps.append('inbox:noannounce')
|
httpd.acceptedCaps.append('inbox:noannounce')
|
||||||
if cw:
|
if cw:
|
||||||
httpd.acceptedCaps.append('inbox:cw')
|
httpd.acceptedCaps.append('inbox:cw')
|
||||||
|
|
||||||
|
print('Creating shared inbox: inbox@'+domain)
|
||||||
|
createSharedInbox(baseDir,'inbox',domain,port,httpPrefix)
|
||||||
|
|
||||||
print('Running ActivityPub daemon on ' + domain + ' port ' + str(port))
|
print('Running ActivityPub daemon on ' + domain + ' port ' + str(port))
|
||||||
httpd.thrInboxQueue= \
|
httpd.thrInboxQueue= \
|
||||||
threadWithTrace(target=runInboxQueue, \
|
threadWithTrace(target=runInboxQueue, \
|
||||||
|
|
10
epicyon.py
10
epicyon.py
|
@ -400,13 +400,9 @@ if not os.path.isdir(baseDir+'/accounts/'+nickname+'@'+domain):
|
||||||
setConfigParam(baseDir,'adminPassword',adminPassword)
|
setConfigParam(baseDir,'adminPassword',adminPassword)
|
||||||
createPerson(baseDir,nickname,domain,port,httpPrefix,True,adminPassword)
|
createPerson(baseDir,nickname,domain,port,httpPrefix,True,adminPassword)
|
||||||
|
|
||||||
if not os.path.isdir(baseDir+'/accounts/inbox@'+domain):
|
#if not os.path.isdir(baseDir+'/accounts/capabilities@'+domain):
|
||||||
print('Creating shared inbox: inbox@'+domain)
|
# print('Creating capabilities account which can sign requests')
|
||||||
createSharedInbox(baseDir,'inbox',domain,port,httpPrefix)
|
# createCapabilitiesInbox(baseDir,'capabilities',domain,port,httpPrefix)
|
||||||
|
|
||||||
if not os.path.isdir(baseDir+'/accounts/capabilities@'+domain):
|
|
||||||
print('Creating capabilities account which can sign requests')
|
|
||||||
createCapabilitiesInbox(baseDir,'capabilities',domain,port,httpPrefix)
|
|
||||||
|
|
||||||
if args.testdata:
|
if args.testdata:
|
||||||
nickname='testuser567'
|
nickname='testuser567'
|
||||||
|
|
38
follow.py
38
follow.py
|
@ -27,6 +27,8 @@ def getFollowersOfPerson(baseDir: str, \
|
||||||
Used by the shared inbox to know who to send incoming mail to
|
Used by the shared inbox to know who to send incoming mail to
|
||||||
"""
|
"""
|
||||||
followers=[]
|
followers=[]
|
||||||
|
if ':' in domain:
|
||||||
|
domain=domain.split(':')[0]
|
||||||
handle=nickname.lower()+'@'+domain.lower()
|
handle=nickname.lower()+'@'+domain.lower()
|
||||||
if not os.path.isdir(baseDir+'/accounts/'+handle):
|
if not os.path.isdir(baseDir+'/accounts/'+handle):
|
||||||
return followers
|
return followers
|
||||||
|
@ -345,38 +347,64 @@ def sendFollowRequest(session,baseDir: str, \
|
||||||
|
|
||||||
return newFollowJson
|
return newFollowJson
|
||||||
|
|
||||||
def getFollowersOfActor(baseDir :str,actor :str,recipientsDict: {}) -> {}:
|
def getFollowersOfActor(baseDir :str,actor :str,debug: bool) -> {}:
|
||||||
"""In a shared inbox if we receive a post we know who it's from
|
"""In a shared inbox if we receive a post we know who it's from
|
||||||
and if it's addressed to followers then we need to get a list of those.
|
and if it's addressed to followers then we need to get a list of those.
|
||||||
This returns a list of account handles which follow the given actor
|
This returns a list of account handles which follow the given actor
|
||||||
and also the corresponding capability id if it exists
|
and also the corresponding capability id if it exists
|
||||||
"""
|
"""
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: getting followers of '+actor)
|
||||||
|
recipientsDict={}
|
||||||
if ':' not in actor:
|
if ':' not in actor:
|
||||||
return recipientsDict
|
return recipientsDict
|
||||||
httpPrefix=actor.split(':')[0]
|
httpPrefix=actor.split(':')[0]
|
||||||
nickname=getNicknameFromActor(actor)
|
nickname=getNicknameFromActor(actor)
|
||||||
if not nickname:
|
if not nickname:
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: no nickname found in '+actor)
|
||||||
return recipientsDict
|
return recipientsDict
|
||||||
domain,port=getDomainFromActor(actor)
|
domain,port=getDomainFromActor(actor)
|
||||||
if not domain:
|
if not domain:
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: no domain found in '+actor)
|
||||||
return recipientsDict
|
return recipientsDict
|
||||||
actorHandle=nickname+'@'+domain
|
actorHandle=nickname+'@'+domain
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: searching for handle '+actorHandle)
|
||||||
# for each of the accounts
|
# for each of the accounts
|
||||||
for subdir, dirs, files in os.walk(baseDir+'/accounts'):
|
for subdir, dirs, files in os.walk(baseDir+'/accounts'):
|
||||||
for account in dirs:
|
for account in dirs:
|
||||||
if '@' in account and not account.startswith('inbox@'):
|
if '@' in account and not account.startswith('inbox@'):
|
||||||
followingFilename = os.path.join(subdir, account)+'/following.txt'
|
followingFilename = os.path.join(subdir, account)+'/following.txt'
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: examining follows of '+account)
|
||||||
|
print(followingFilename)
|
||||||
if os.path.isfile(followingFilename):
|
if os.path.isfile(followingFilename):
|
||||||
# does this account follow the given actor?
|
# does this account follow the given actor?
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: checking if '+actorHandle+' in '+followingFilename)
|
||||||
if actorHandle in open(followingFilename).read():
|
if actorHandle in open(followingFilename).read():
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: '+account+' follows '+actorHandle)
|
||||||
ocapFilename=baseDir+'/accounts/'+account+'/ocap/accept/'+httpPrefix+':##'+domain+':'+str(port)+'#users#'+nickname+'.json'
|
ocapFilename=baseDir+'/accounts/'+account+'/ocap/accept/'+httpPrefix+':##'+domain+':'+str(port)+'#users#'+nickname+'.json'
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: checking capabilities of'+account)
|
||||||
if os.path.isfile(ocapFilename):
|
if os.path.isfile(ocapFilename):
|
||||||
with open(ocapFilename, 'r') as fp:
|
with open(ocapFilename, 'r') as fp:
|
||||||
ocapJson=commentjson.load(fp)
|
ocapJson=commentjson.load(fp)
|
||||||
if ocapJson.get('id'):
|
if ocapJson.get('id'):
|
||||||
recipientsDict[account]=ocapJson['id']
|
if debug:
|
||||||
else:
|
print('DEBUG: capabilities id found for '+account)
|
||||||
recipientsDict[account]=None
|
|
||||||
|
recipientsDict[account]=ocapJson['id']
|
||||||
|
else:
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: capabilities has no id attribute')
|
||||||
|
recipientsDict[account]=None
|
||||||
else:
|
else:
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: No capabilities file found for '+account+' granted by '+actorHandle)
|
||||||
|
print(ocapFilename)
|
||||||
recipientsDict[account]=None
|
recipientsDict[account]=None
|
||||||
return recipientsDict
|
return recipientsDict
|
||||||
|
|
80
inbox.py
80
inbox.py
|
@ -19,6 +19,7 @@ from utils import getStatusNumber
|
||||||
from utils import getDomainFromActor
|
from utils import getDomainFromActor
|
||||||
from utils import getNicknameFromActor
|
from utils import getNicknameFromActor
|
||||||
from utils import domainPermitted
|
from utils import domainPermitted
|
||||||
|
from utils import locatePost
|
||||||
from httpsig import verifyPostHeaders
|
from httpsig import verifyPostHeaders
|
||||||
from session import createSession
|
from session import createSession
|
||||||
from session import getJson
|
from session import getJson
|
||||||
|
@ -87,7 +88,7 @@ def inboxPermittedMessage(domain: str,messageJson: {},federationList: []) -> boo
|
||||||
if not urlPermitted(actor,federationList,"inbox:write"):
|
if not urlPermitted(actor,federationList,"inbox:write"):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if messageJson['type']!='Follow':
|
if messageJson['type']!='Follow' and messageJson['type']!='Like':
|
||||||
if messageJson.get('object'):
|
if messageJson.get('object'):
|
||||||
if messageJson['object'].get('inReplyTo'):
|
if messageJson['object'].get('inReplyTo'):
|
||||||
inReplyTo=messageJson['object']['inReplyTo']
|
inReplyTo=messageJson['object']['inReplyTo']
|
||||||
|
@ -210,7 +211,7 @@ def inboxCheckCapabilities(baseDir :str,nickname :str,domain :str, \
|
||||||
def inboxPostRecipientsAdd(baseDir :str,httpPrefix :str,toList :[], \
|
def inboxPostRecipientsAdd(baseDir :str,httpPrefix :str,toList :[], \
|
||||||
recipientsDict :{}, \
|
recipientsDict :{}, \
|
||||||
domainMatch: str,domain :str, \
|
domainMatch: str,domain :str, \
|
||||||
actor :str) -> bool:
|
actor :str,debug: bool) -> bool:
|
||||||
"""Given a list of post recipients (toList) from 'to' or 'cc' parameters
|
"""Given a list of post recipients (toList) from 'to' or 'cc' parameters
|
||||||
populate a recipientsDict with the handle and capabilities id for each
|
populate a recipientsDict with the handle and capabilities id for each
|
||||||
"""
|
"""
|
||||||
|
@ -235,12 +236,23 @@ def inboxPostRecipientsAdd(baseDir :str,httpPrefix :str,toList :[], \
|
||||||
else:
|
else:
|
||||||
recipientsDict[handle]=None
|
recipientsDict[handle]=None
|
||||||
else:
|
else:
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: '+ocapFilename+' not found')
|
||||||
recipientsDict[handle]=None
|
recipientsDict[handle]=None
|
||||||
|
else:
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: '+baseDir+'/accounts/'+handle+' does not exist')
|
||||||
|
else:
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: '+recipient+' is not local to '+domainMatch)
|
||||||
|
print(str(toList))
|
||||||
if recipient.endswith('followers'):
|
if recipient.endswith('followers'):
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: followers detected as post recipients')
|
||||||
followerRecipients=True
|
followerRecipients=True
|
||||||
return followerRecipients,recipientsDict
|
return followerRecipients,recipientsDict
|
||||||
|
|
||||||
def inboxPostRecipients(baseDir :str,postJsonObject :{},httpPrefix :str,domain : str,port :int) -> ([],[]):
|
def inboxPostRecipients(baseDir :str,postJsonObject :{},httpPrefix :str,domain : str,port :int, debug :bool) -> ([],[]):
|
||||||
"""Returns dictionaries containing the recipients of the given post
|
"""Returns dictionaries containing the recipients of the given post
|
||||||
The shared dictionary contains followers
|
The shared dictionary contains followers
|
||||||
"""
|
"""
|
||||||
|
@ -248,6 +260,9 @@ def inboxPostRecipients(baseDir :str,postJsonObject :{},httpPrefix :str,domain :
|
||||||
recipientsDictFollowers={}
|
recipientsDictFollowers={}
|
||||||
|
|
||||||
if not postJsonObject.get('actor'):
|
if not postJsonObject.get('actor'):
|
||||||
|
if debug:
|
||||||
|
pprint(postJsonObject)
|
||||||
|
print('WARNING: inbox post has no actor')
|
||||||
return recipientsDict,recipientsDictFollowers
|
return recipientsDict,recipientsDictFollowers
|
||||||
|
|
||||||
if ':' in domain:
|
if ':' in domain:
|
||||||
|
@ -264,29 +279,48 @@ def inboxPostRecipients(baseDir :str,postJsonObject :{},httpPrefix :str,domain :
|
||||||
if postJsonObject.get('object'):
|
if postJsonObject.get('object'):
|
||||||
if isinstance(postJsonObject['object'], dict):
|
if isinstance(postJsonObject['object'], dict):
|
||||||
if postJsonObject['object'].get('to'):
|
if postJsonObject['object'].get('to'):
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: resolving "to"')
|
||||||
includesFollowers,recipientsDict= \
|
includesFollowers,recipientsDict= \
|
||||||
inboxPostRecipientsAdd(baseDir,httpPrefix, \
|
inboxPostRecipientsAdd(baseDir,httpPrefix, \
|
||||||
postJsonObject['object']['to'], \
|
postJsonObject['object']['to'], \
|
||||||
recipientsDict, \
|
recipientsDict, \
|
||||||
domainMatch,domainBase,actor)
|
domainMatch,domainBase, \
|
||||||
|
actor,debug)
|
||||||
if includesFollowers:
|
if includesFollowers:
|
||||||
followerRecipients=True
|
followerRecipients=True
|
||||||
|
else:
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: inbox post has no "to"')
|
||||||
|
|
||||||
if postJsonObject['object'].get('cc'):
|
if postJsonObject['object'].get('cc'):
|
||||||
includesFollowers,recipientsDict= \
|
includesFollowers,recipientsDict= \
|
||||||
inboxPostRecipientsAdd(baseDir,httpPrefix, \
|
inboxPostRecipientsAdd(baseDir,httpPrefix, \
|
||||||
postJsonObject['object']['cc'], \
|
postJsonObject['object']['cc'], \
|
||||||
recipientsDict, \
|
recipientsDict, \
|
||||||
domainMatch,domainBase,actor)
|
domainMatch,domainBase, \
|
||||||
|
actor,debug)
|
||||||
if includesFollowers:
|
if includesFollowers:
|
||||||
followerRecipients=True
|
followerRecipients=True
|
||||||
|
else:
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: inbox post has no cc')
|
||||||
|
else:
|
||||||
|
if debug:
|
||||||
|
if isinstance(postJsonObject['object'], str):
|
||||||
|
if '/statuses/' in postJsonObject['object']:
|
||||||
|
print('DEBUG: inbox item is a link to a post')
|
||||||
|
else:
|
||||||
|
if '/users/' in postJsonObject['object']:
|
||||||
|
print('DEBUG: inbox item is a link to an actor')
|
||||||
|
|
||||||
if postJsonObject.get('to'):
|
if postJsonObject.get('to'):
|
||||||
includesFollowers,recipientsDict= \
|
includesFollowers,recipientsDict= \
|
||||||
inboxPostRecipientsAdd(baseDir,httpPrefix, \
|
inboxPostRecipientsAdd(baseDir,httpPrefix, \
|
||||||
postJsonObject['to'], \
|
postJsonObject['to'], \
|
||||||
recipientsDict, \
|
recipientsDict, \
|
||||||
domainMatch,domainBase,actor)
|
domainMatch,domainBase, \
|
||||||
|
actor,debug)
|
||||||
if includesFollowers:
|
if includesFollowers:
|
||||||
followerRecipients=True
|
followerRecipients=True
|
||||||
|
|
||||||
|
@ -295,16 +329,19 @@ def inboxPostRecipients(baseDir :str,postJsonObject :{},httpPrefix :str,domain :
|
||||||
inboxPostRecipientsAdd(baseDir,httpPrefix, \
|
inboxPostRecipientsAdd(baseDir,httpPrefix, \
|
||||||
postJsonObject['cc'], \
|
postJsonObject['cc'], \
|
||||||
recipientsDict, \
|
recipientsDict, \
|
||||||
domainMatch,domainBase,actor)
|
domainMatch,domainBase, \
|
||||||
|
actor,debug)
|
||||||
if includesFollowers:
|
if includesFollowers:
|
||||||
followerRecipients=True
|
followerRecipients=True
|
||||||
|
|
||||||
if not followerRecipients:
|
if not followerRecipients:
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: no followers were resolved')
|
||||||
return recipientsDict,recipientsDictFollowers
|
return recipientsDict,recipientsDictFollowers
|
||||||
|
|
||||||
# now resolve the followers
|
# now resolve the followers
|
||||||
recipientsDictFollowers= \
|
recipientsDictFollowers= \
|
||||||
getFollowersOfActor(baseDir,actor,recipientsDict)
|
getFollowersOfActor(baseDir,actor,debug)
|
||||||
|
|
||||||
return recipientsDict,recipientsDictFollowers
|
return recipientsDict,recipientsDictFollowers
|
||||||
|
|
||||||
|
@ -388,18 +425,7 @@ def receiveLike(session,handle: str,baseDir: str, \
|
||||||
if not os.path.isdir(baseDir+'/accounts/'+handle):
|
if not os.path.isdir(baseDir+'/accounts/'+handle):
|
||||||
print('DEBUG: unknown recipient of like - '+handle)
|
print('DEBUG: unknown recipient of like - '+handle)
|
||||||
# if this post in the outbox of the person?
|
# if this post in the outbox of the person?
|
||||||
boxName='outbox'
|
postFilename=locatePost(baseDir,handle.split('@')[0],handle.split('@')[1],messageJson['object'])
|
||||||
postFilename=baseDir+'/accounts/'+handle+'/'+boxName+'/'+messageJson['object'].replace('/','#')+'.json'
|
|
||||||
if not os.path.isfile(postFilename):
|
|
||||||
# if this post in the inbox of the person?
|
|
||||||
boxName='inbox'
|
|
||||||
postFilename=baseDir+'/accounts/'+handle+'/'+boxName+'/'+messageJson['object'].replace('/','#')+'.json'
|
|
||||||
if not os.path.isfile(postFilename):
|
|
||||||
# if this post in the shared inbox?
|
|
||||||
handle='inbox@'+domain
|
|
||||||
postFilename=baseDir+'/accounts/'+handle+'/'+boxName+'/'+messageJson['object'].replace('/','#')+'.json'
|
|
||||||
if not os.path.isfile(postFilename):
|
|
||||||
postFilename=None
|
|
||||||
if not postFilename:
|
if not postFilename:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: post not found in inbox or outbox')
|
print('DEBUG: post not found in inbox or outbox')
|
||||||
|
@ -569,7 +595,15 @@ def runInboxQueue(baseDir: str,httpPrefix: str,sendThreads: [],postLog: [],cache
|
||||||
|
|
||||||
# get recipients list
|
# get recipients list
|
||||||
recipientsDict,recipientsDictFollowers= \
|
recipientsDict,recipientsDictFollowers= \
|
||||||
inboxPostRecipients(baseDir,queueJson['post'],httpPrefix,domain,port)
|
inboxPostRecipients(baseDir,queueJson['post'],httpPrefix,domain,port,debug)
|
||||||
|
if len(recipientsDict.items())==0 and \
|
||||||
|
len(recipientsDictFollowers.items())==0:
|
||||||
|
if debug:
|
||||||
|
pprint(queueJson['post'])
|
||||||
|
print('DEBUG: no recipients were resolved for post arriving in inbox')
|
||||||
|
os.remove(queueFilename)
|
||||||
|
queue.pop(0)
|
||||||
|
continue
|
||||||
|
|
||||||
# if there are only a small number of followers then process them as if they
|
# if there are only a small number of followers then process them as if they
|
||||||
# were specifically addresses to particular accounts
|
# were specifically addresses to particular accounts
|
||||||
|
@ -579,7 +613,7 @@ def runInboxQueue(baseDir: str,httpPrefix: str,sendThreads: [],postLog: [],cache
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: moving '+str(noOfFollowItems)+' inbox posts addressed to followers')
|
print('DEBUG: moving '+str(noOfFollowItems)+' inbox posts addressed to followers')
|
||||||
for handle,postItem in recipientsDictFollowers.items():
|
for handle,postItem in recipientsDictFollowers.items():
|
||||||
recipientsDict['handle']=postItem
|
recipientsDict[handle]=postItem
|
||||||
recipientsDictFollowers={}
|
recipientsDictFollowers={}
|
||||||
recipientsList=[recipientsDict,recipientsDictFollowers]
|
recipientsList=[recipientsDict,recipientsDictFollowers]
|
||||||
|
|
||||||
|
@ -587,7 +621,7 @@ def runInboxQueue(baseDir: str,httpPrefix: str,sendThreads: [],postLog: [],cache
|
||||||
print('*************************************')
|
print('*************************************')
|
||||||
print('Resolved recipients list:')
|
print('Resolved recipients list:')
|
||||||
pprint(recipientsDict)
|
pprint(recipientsDict)
|
||||||
print('Resolved sollowers list:')
|
print('Resolved followers list:')
|
||||||
pprint(recipientsDictFollowers)
|
pprint(recipientsDictFollowers)
|
||||||
print('*************************************')
|
print('*************************************')
|
||||||
|
|
||||||
|
|
174
like.py
174
like.py
|
@ -8,80 +8,28 @@ __status__ = "Production"
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import commentjson
|
import commentjson
|
||||||
|
from pprint import pprint
|
||||||
from utils import urlPermitted
|
from utils import urlPermitted
|
||||||
from utils import getNicknameFromActor
|
from utils import getNicknameFromActor
|
||||||
from utils import getDomainFromActor
|
from utils import getDomainFromActor
|
||||||
|
from utils import locatePost
|
||||||
|
from posts import sendSignedJson
|
||||||
|
|
||||||
def like(session,baseDir: str,federationList: [],nickname: str,domain: str,port: int, \
|
def updateLikesCollection(postFilename: str,objectUrl: str, actor: str,debug: bool) -> None:
|
||||||
ccUrl: str,httpPrefix: str,objectUrl: str,clientToServer: bool, \
|
|
||||||
sendThreads: [],postLog: [],personCache: {},cachedWebfingers: {}) -> {}:
|
|
||||||
"""Creates a like
|
|
||||||
ccUrl might be a specific person whose post was liked
|
|
||||||
objectUrl is typically the url of the message, corresponding to url or atomUri in createPostBase
|
|
||||||
"""
|
|
||||||
if not urlPermitted(objectUrl,federationList,"inbox:write"):
|
|
||||||
return None
|
|
||||||
|
|
||||||
if port!=80 and port!=443:
|
|
||||||
domain=domain+':'+str(port)
|
|
||||||
|
|
||||||
newLikeJson = {
|
|
||||||
'type': 'Like',
|
|
||||||
'actor': httpPrefix+'://'+domain+'/users/'+nickname,
|
|
||||||
'object': objectUrl,
|
|
||||||
'to': [httpPrefix+'://'+domain+'/users/'+nickname+'/followers'],
|
|
||||||
'cc': []
|
|
||||||
}
|
|
||||||
if ccUrl:
|
|
||||||
if len(ccUrl)>0:
|
|
||||||
newLikeJson['cc']=ccUrl
|
|
||||||
|
|
||||||
# Extract the domain and nickname from a statuses link
|
|
||||||
likedPostNickname=None
|
|
||||||
likedPostDomain=None
|
|
||||||
likedPostPort=None
|
|
||||||
if '/users/' in objectUrl:
|
|
||||||
likedPostNickname=getNicknameFromActor(objectUrl)
|
|
||||||
likedPostDomain,likedPostPort=getDomainFromActor(objectUrl)
|
|
||||||
|
|
||||||
if likedPostNickname:
|
|
||||||
sendSignedJson(newlikeJson,session,baseDir, \
|
|
||||||
nickname,domain,port, \
|
|
||||||
likedPostNickname,likedPostDomain,likedPostPort, \
|
|
||||||
'https://www.w3.org/ns/activitystreams#Public', \
|
|
||||||
httpPrefix,True,clientToServer,federationList, \
|
|
||||||
sendThreads,postLog,cachedWebfingers,personCache,debug)
|
|
||||||
|
|
||||||
return newLikeJson
|
|
||||||
|
|
||||||
def likePost(session,baseDir: str,federationList: [], \
|
|
||||||
nickname: str, domain: str, port: int, httpPrefix: str, \
|
|
||||||
likeNickname: str, likeDomain: str, likePort: int, \
|
|
||||||
likeHttps: bool, likeStatusNumber: int, \
|
|
||||||
clientToServer: bool,sendThreads: [],postLog: [], \
|
|
||||||
personCache: {},cachedWebfingers: {}) -> {}:
|
|
||||||
"""Likes a given status post
|
|
||||||
"""
|
|
||||||
likeDomain=likeDomain
|
|
||||||
if likePort!=80 and likePort!=443:
|
|
||||||
likeDomain=likeDomain+':'+str(likePort)
|
|
||||||
|
|
||||||
objectUrl = \
|
|
||||||
httpPrefix + '://'+likeDomain+'/users/'+likeNickname+ \
|
|
||||||
'/statuses/'+str(likeStatusNumber)
|
|
||||||
|
|
||||||
return like(session,baseDir,federationList,nickname,domain,port, \
|
|
||||||
ccUrl,httpPrefix,objectUrl,clientToServer, \
|
|
||||||
sendThreads,postLog,personCache,cachedWebfingers)
|
|
||||||
|
|
||||||
def updateLikesCollection(postFilename: str,objectUrl: str, actor: str) -> None:
|
|
||||||
"""Updates the likes collection within a post
|
"""Updates the likes collection within a post
|
||||||
"""
|
"""
|
||||||
with open(postFilename, 'r') as fp:
|
with open(postFilename, 'r') as fp:
|
||||||
postJson=commentjson.load(fp)
|
postJson=commentjson.load(fp)
|
||||||
|
if not postJson.get('object'):
|
||||||
|
if debug:
|
||||||
|
pprint(postJson)
|
||||||
|
print('DEBUG: post '+objectUrl+' has no object')
|
||||||
|
return
|
||||||
if not objectUrl.endswith('/likes'):
|
if not objectUrl.endswith('/likes'):
|
||||||
objectUrl=objectUrl+'/likes'
|
objectUrl=objectUrl+'/likes'
|
||||||
if not postJson.get('likes'):
|
if not postJson['object'].get('likes'):
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: Adding initial likes to '+objectUrl)
|
||||||
likesJson = {
|
likesJson = {
|
||||||
'id': objectUrl,
|
'id': objectUrl,
|
||||||
'type': 'Collection',
|
'type': 'Collection',
|
||||||
|
@ -92,17 +40,103 @@ def updateLikesCollection(postFilename: str,objectUrl: str, actor: str) -> None:
|
||||||
|
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
postJson['likes']=likesJson
|
postJson['object']['likes']=likesJson
|
||||||
else:
|
else:
|
||||||
if postJson['likes'].get('items'):
|
if postJson['object']['likes'].get('items'):
|
||||||
for likeItem in postJson['likes']['items']:
|
for likeItem in postJson['likes']['items']:
|
||||||
if likeItem['actor']==actor:
|
if likeItem.get('actor'):
|
||||||
return
|
if likeItem['actor']==actor:
|
||||||
|
return
|
||||||
newLike={
|
newLike={
|
||||||
'type': 'Like',
|
'type': 'Like',
|
||||||
'actor': actor
|
'actor': actor
|
||||||
}
|
}
|
||||||
postJson['likes']['items'].append(newLike)
|
postJson['object']['likes']['items'].append(newLike)
|
||||||
postJson['likes']['totalItems']=len(postJson['likes']['items'])
|
postJson['object']['likes']['totalItems']=len(postJson['likes']['items'])
|
||||||
|
else:
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: likes section of post has no items list')
|
||||||
|
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: saving post with likes added')
|
||||||
with open(postFilename, 'w') as fp:
|
with open(postFilename, 'w') as fp:
|
||||||
commentjson.dump(postJson, fp, indent=4, sort_keys=True)
|
commentjson.dump(postJson, fp, indent=4, sort_keys=True)
|
||||||
|
|
||||||
|
def like(session,baseDir: str,federationList: [],nickname: str,domain: str,port: int, \
|
||||||
|
ccList: [],httpPrefix: str,objectUrl: str,clientToServer: bool, \
|
||||||
|
sendThreads: [],postLog: [],personCache: {},cachedWebfingers: {}, \
|
||||||
|
debug: bool) -> {}:
|
||||||
|
"""Creates a like
|
||||||
|
ccUrl might be a specific person whose post was liked
|
||||||
|
objectUrl is typically the url of the message, corresponding to url or atomUri in createPostBase
|
||||||
|
"""
|
||||||
|
if not urlPermitted(objectUrl,federationList,"inbox:write"):
|
||||||
|
return None
|
||||||
|
|
||||||
|
fullDomain=domain
|
||||||
|
if port!=80 and port!=443:
|
||||||
|
if ':' not in domain:
|
||||||
|
fullDomain=domain+':'+str(port)
|
||||||
|
|
||||||
|
newLikeJson = {
|
||||||
|
'type': 'Like',
|
||||||
|
'actor': httpPrefix+'://'+fullDomain+'/users/'+nickname,
|
||||||
|
'object': objectUrl,
|
||||||
|
'to': [httpPrefix+'://'+fullDomain+'/users/'+nickname+'/followers'],
|
||||||
|
'cc': []
|
||||||
|
}
|
||||||
|
if ccList:
|
||||||
|
if len(ccList)>0:
|
||||||
|
newLikeJson['cc']=ccList
|
||||||
|
|
||||||
|
# Extract the domain and nickname from a statuses link
|
||||||
|
likedPostNickname=None
|
||||||
|
likedPostDomain=None
|
||||||
|
likedPostPort=None
|
||||||
|
if '/users/' in objectUrl:
|
||||||
|
likedPostNickname=getNicknameFromActor(objectUrl)
|
||||||
|
likedPostDomain,likedPostPort=getDomainFromActor(objectUrl)
|
||||||
|
|
||||||
|
if likedPostNickname:
|
||||||
|
postFilename=locatePost(baseDir,nickname,domain,objectUrl)
|
||||||
|
if not postFilename:
|
||||||
|
return None
|
||||||
|
|
||||||
|
updateLikesCollection(postFilename,objectUrl,newLikeJson['actor'],debug)
|
||||||
|
|
||||||
|
sendSignedJson(newLikeJson,session,baseDir, \
|
||||||
|
nickname,domain,port, \
|
||||||
|
likedPostNickname,likedPostDomain,likedPostPort, \
|
||||||
|
'https://www.w3.org/ns/activitystreams#Public', \
|
||||||
|
httpPrefix,True,clientToServer,federationList, \
|
||||||
|
sendThreads,postLog,cachedWebfingers,personCache,debug)
|
||||||
|
|
||||||
|
return newLikeJson
|
||||||
|
|
||||||
|
def likePost(session,baseDir: str,federationList: [], \
|
||||||
|
nickname: str,domain: str,port: int,httpPrefix: str, \
|
||||||
|
likeNickname: str,likeDomain: str,likePort: int, \
|
||||||
|
ccList: [], \
|
||||||
|
likeStatusNumber: int,clientToServer: bool, \
|
||||||
|
sendThreads: [],postLog: [], \
|
||||||
|
personCache: {},cachedWebfingers: {}, \
|
||||||
|
debug: bool) -> {}:
|
||||||
|
"""Likes a given status post
|
||||||
|
"""
|
||||||
|
likeDomain=likeDomain
|
||||||
|
if likePort!=80 and likePort!=443:
|
||||||
|
likeDomain=likeDomain+':'+str(likePort)
|
||||||
|
|
||||||
|
objectUrl = \
|
||||||
|
httpPrefix + '://'+likeDomain+'/users/'+likeNickname+ \
|
||||||
|
'/statuses/'+str(likeStatusNumber)
|
||||||
|
|
||||||
|
if likePort!=80 and likePort!=443:
|
||||||
|
ccUrl=httpPrefix+'://'+likeDomain+':'+str(likePort)+'/users/'+likeNickname
|
||||||
|
else:
|
||||||
|
ccUrl=httpPrefix+'://'+likeDomain+'/users/'+likeNickname
|
||||||
|
|
||||||
|
return like(session,baseDir,federationList,nickname,domain,port, \
|
||||||
|
ccList,httpPrefix,objectUrl,clientToServer, \
|
||||||
|
sendThreads,postLog,personCache,cachedWebfingers,debug)
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,14 @@ def createPersonBase(baseDir: str,nickname: str,domain: str,port: int, \
|
||||||
os.mkdir(baseDir+peopleSubdir)
|
os.mkdir(baseDir+peopleSubdir)
|
||||||
if not os.path.isdir(baseDir+peopleSubdir+'/'+handle):
|
if not os.path.isdir(baseDir+peopleSubdir+'/'+handle):
|
||||||
os.mkdir(baseDir+peopleSubdir+'/'+handle)
|
os.mkdir(baseDir+peopleSubdir+'/'+handle)
|
||||||
|
if not os.path.isdir(baseDir+peopleSubdir+'/'+handle+'/inbox'):
|
||||||
|
os.mkdir(baseDir+peopleSubdir+'/'+handle+'/inbox')
|
||||||
|
if not os.path.isdir(baseDir+peopleSubdir+'/'+handle+'/outbox'):
|
||||||
|
os.mkdir(baseDir+peopleSubdir+'/'+handle+'/outbox')
|
||||||
|
if not os.path.isdir(baseDir+peopleSubdir+'/'+handle+'/ocap'):
|
||||||
|
os.mkdir(baseDir+peopleSubdir+'/'+handle+'/ocap')
|
||||||
|
if not os.path.isdir(baseDir+peopleSubdir+'/'+handle+'/queue'):
|
||||||
|
os.mkdir(baseDir+peopleSubdir+'/'+handle+'/queue')
|
||||||
filename=baseDir+peopleSubdir+'/'+handle+'.json'
|
filename=baseDir+peopleSubdir+'/'+handle+'.json'
|
||||||
with open(filename, 'w') as fp:
|
with open(filename, 'w') as fp:
|
||||||
commentjson.dump(newPerson, fp, indent=4, sort_keys=False)
|
commentjson.dump(newPerson, fp, indent=4, sort_keys=False)
|
||||||
|
|
69
tests.py
69
tests.py
|
@ -36,13 +36,13 @@ from follow import unfollowPerson
|
||||||
from follow import unfollowerOfPerson
|
from follow import unfollowerOfPerson
|
||||||
from follow import getFollowersOfPerson
|
from follow import getFollowersOfPerson
|
||||||
from follow import sendFollowRequest
|
from follow import sendFollowRequest
|
||||||
from follow import getFollowersOfActor
|
|
||||||
from person import createPerson
|
from person import createPerson
|
||||||
from person import setPreferredNickname
|
from person import setPreferredNickname
|
||||||
from person import setBio
|
from person import setBio
|
||||||
from auth import createBasicAuthHeader
|
from auth import createBasicAuthHeader
|
||||||
from auth import authorizeBasic
|
from auth import authorizeBasic
|
||||||
from auth import storeBasicCredentials
|
from auth import storeBasicCredentials
|
||||||
|
from like import likePost
|
||||||
|
|
||||||
testServerAliceRunning = False
|
testServerAliceRunning = False
|
||||||
testServerBobRunning = False
|
testServerBobRunning = False
|
||||||
|
@ -210,7 +210,6 @@ def testPostMessageBetweenServers():
|
||||||
|
|
||||||
httpPrefix='http'
|
httpPrefix='http'
|
||||||
useTor=False
|
useTor=False
|
||||||
federationList=['127.0.0.50','127.0.0.100']
|
|
||||||
|
|
||||||
baseDir=os.getcwd()
|
baseDir=os.getcwd()
|
||||||
if os.path.isdir(baseDir+'/.tests'):
|
if os.path.isdir(baseDir+'/.tests'):
|
||||||
|
@ -223,12 +222,13 @@ def testPostMessageBetweenServers():
|
||||||
aliceDir=baseDir+'/.tests/alice'
|
aliceDir=baseDir+'/.tests/alice'
|
||||||
aliceDomain='127.0.0.50'
|
aliceDomain='127.0.0.50'
|
||||||
alicePort=61935
|
alicePort=61935
|
||||||
thrAlice = threadWithTrace(target=createServerAlice,args=(aliceDir,aliceDomain,alicePort,federationList,True,True,ocapAlways),daemon=True)
|
|
||||||
|
|
||||||
bobDir=baseDir+'/.tests/bob'
|
bobDir=baseDir+'/.tests/bob'
|
||||||
bobDomain='127.0.0.100'
|
bobDomain='127.0.0.100'
|
||||||
bobPort=61936
|
bobPort=61936
|
||||||
thrBob = threadWithTrace(target=createServerBob,args=(bobDir,bobDomain,bobPort,federationList,True,True,ocapAlways),daemon=True)
|
federationList=[bobDomain,aliceDomain]
|
||||||
|
|
||||||
|
thrAlice = threadWithTrace(target=createServerAlice,args=(aliceDir,aliceDomain,alicePort,federationList,False,False,ocapAlways),daemon=True)
|
||||||
|
thrBob = threadWithTrace(target=createServerBob,args=(bobDir,bobDomain,bobPort,federationList,False,False,ocapAlways),daemon=True)
|
||||||
|
|
||||||
thrAlice.start()
|
thrAlice.start()
|
||||||
thrBob.start()
|
thrBob.start()
|
||||||
|
@ -241,6 +241,7 @@ def testPostMessageBetweenServers():
|
||||||
|
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
|
print('\n\n*******************************************************')
|
||||||
print('Alice sends to Bob')
|
print('Alice sends to Bob')
|
||||||
os.chdir(aliceDir)
|
os.chdir(aliceDir)
|
||||||
sessionAlice = createSession(aliceDomain,alicePort,useTor)
|
sessionAlice = createSession(aliceDomain,alicePort,useTor)
|
||||||
|
@ -255,6 +256,11 @@ def testPostMessageBetweenServers():
|
||||||
ccUrl=None
|
ccUrl=None
|
||||||
alicePersonCache={}
|
alicePersonCache={}
|
||||||
aliceCachedWebfingers={}
|
aliceCachedWebfingers={}
|
||||||
|
|
||||||
|
# nothing in Alice's outbox
|
||||||
|
outboxPath=aliceDir+'/accounts/alice@'+aliceDomain+'/outbox'
|
||||||
|
assert len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==0
|
||||||
|
|
||||||
sendResult = sendPost(sessionAlice,aliceDir,'alice', aliceDomain, alicePort, 'bob', bobDomain, bobPort, ccUrl, httpPrefix, 'Why is a mouse when it spins?', followersOnly, saveToFile, clientToServer, federationList, aliceSendThreads, alicePostLog, aliceCachedWebfingers,alicePersonCache,inReplyTo, inReplyToAtomUri, subject)
|
sendResult = sendPost(sessionAlice,aliceDir,'alice', aliceDomain, alicePort, 'bob', bobDomain, bobPort, ccUrl, httpPrefix, 'Why is a mouse when it spins?', followersOnly, saveToFile, clientToServer, federationList, aliceSendThreads, alicePostLog, aliceCachedWebfingers,alicePersonCache,inReplyTo, inReplyToAtomUri, subject)
|
||||||
print('sendResult: '+str(sendResult))
|
print('sendResult: '+str(sendResult))
|
||||||
|
|
||||||
|
@ -263,9 +269,53 @@ def testPostMessageBetweenServers():
|
||||||
for i in range(30):
|
for i in range(30):
|
||||||
if os.path.isdir(inboxPath):
|
if os.path.isdir(inboxPath):
|
||||||
if len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])>0:
|
if len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])>0:
|
||||||
break
|
if len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==1:
|
||||||
|
break
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
|
# inbox item created
|
||||||
|
assert len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==1
|
||||||
|
# queue item removed
|
||||||
|
assert len([name for name in os.listdir(queuePath) if os.path.isfile(os.path.join(queuePath, name))])==0
|
||||||
|
|
||||||
|
#print('\n\n*******************************************************')
|
||||||
|
#print("Bob likes Alice's post")
|
||||||
|
|
||||||
|
#followerOfPerson(bobDir,'bob',bobDomain,'alice',aliceDomain+':'+str(alicePort),federationList,True)
|
||||||
|
#followPerson(aliceDir,'alice',aliceDomain,'bob',bobDomain+':'+str(bobPort),federationList,True)
|
||||||
|
#followList=getFollowersOfPerson(bobDir,'bob',bobDomain,'followers.txt')
|
||||||
|
#assert len(followList)==1
|
||||||
|
|
||||||
|
#sessionBob = createSession(bobDomain,bobPort,useTor)
|
||||||
|
#bobSendThreads = []
|
||||||
|
#bobPostLog = []
|
||||||
|
#bobPersonCache={}
|
||||||
|
#bobCachedWebfingers={}
|
||||||
|
#statusNumber=None
|
||||||
|
#outboxPostFilename=None
|
||||||
|
#outboxPath=aliceDir+'/accounts/alice@'+aliceDomain+'/outbox'
|
||||||
|
#for name in os.listdir(outboxPath):
|
||||||
|
# if '#statuses#' in name:
|
||||||
|
# statusNumber=int(name.split('#statuses#')[1].replace('.json',''))
|
||||||
|
# outboxPostFilename=outboxPath+'/'+name
|
||||||
|
#assert statusNumber
|
||||||
|
#assert outboxPostFilename
|
||||||
|
#assert likePost(sessionBob,bobDir,federationList, \
|
||||||
|
# 'bob',bobDomain,bobPort,httpPrefix, \
|
||||||
|
# 'alice',aliceDomain,alicePort,[], \
|
||||||
|
# statusNumber,False,bobSendThreads,bobPostLog, \
|
||||||
|
# bobPersonCache,bobCachedWebfingers,True)
|
||||||
|
|
||||||
|
#for i in range(20):
|
||||||
|
# if 'likes' in open(outboxPostFilename).read():
|
||||||
|
# break
|
||||||
|
# time.sleep(1)
|
||||||
|
|
||||||
|
#with open(outboxPostFilename, 'r') as fp:
|
||||||
|
# alicePostJson=commentjson.load(fp)
|
||||||
|
# pprint(alicePostJson)
|
||||||
|
#assert 'likes' in open(outboxPostFilename).read()
|
||||||
|
|
||||||
# stop the servers
|
# stop the servers
|
||||||
thrAlice.kill()
|
thrAlice.kill()
|
||||||
thrAlice.join()
|
thrAlice.join()
|
||||||
|
@ -275,11 +325,6 @@ def testPostMessageBetweenServers():
|
||||||
thrBob.join()
|
thrBob.join()
|
||||||
assert thrBob.isAlive()==False
|
assert thrBob.isAlive()==False
|
||||||
|
|
||||||
# inbox item created
|
|
||||||
assert len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==1
|
|
||||||
# queue item removed
|
|
||||||
assert len([name for name in os.listdir(queuePath) if os.path.isfile(os.path.join(queuePath, name))])==0
|
|
||||||
|
|
||||||
os.chdir(baseDir)
|
os.chdir(baseDir)
|
||||||
shutil.rmtree(aliceDir)
|
shutil.rmtree(aliceDir)
|
||||||
shutil.rmtree(bobDir)
|
shutil.rmtree(bobDir)
|
||||||
|
@ -439,7 +484,7 @@ def testFollowBetweenServers():
|
||||||
|
|
||||||
assert aliceMessageArrived==True
|
assert aliceMessageArrived==True
|
||||||
print('Message from Alice to Bob succeeded, since it was granted capabilities')
|
print('Message from Alice to Bob succeeded, since it was granted capabilities')
|
||||||
|
|
||||||
print('\n\n*********************************************************')
|
print('\n\n*********************************************************')
|
||||||
print("\nBob changes Alice's capabilities so that she can't reply on his posts")
|
print("\nBob changes Alice's capabilities so that she can't reply on his posts")
|
||||||
bobCapsFilename=bobDir+'/accounts/bob@'+bobDomain+'/ocap/accept/'+httpPrefix+':##'+aliceDomain+':'+str(alicePort)+'#users#alice.json'
|
bobCapsFilename=bobDir+'/accounts/bob@'+bobDomain+'/ocap/accept/'+httpPrefix+':##'+aliceDomain+':'+str(alicePort)+'#users#alice.json'
|
||||||
|
|
27
utils.py
27
utils.py
|
@ -44,6 +44,8 @@ def createInboxQueueDir(nickname: str,domain: str,baseDir: str) -> str:
|
||||||
def domainPermitted(domain: str, federationList: []):
|
def domainPermitted(domain: str, federationList: []):
|
||||||
if len(federationList)==0:
|
if len(federationList)==0:
|
||||||
return True
|
return True
|
||||||
|
if ':' in domain:
|
||||||
|
domain=domain.split(':')[0]
|
||||||
if domain in federationList:
|
if domain in federationList:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
@ -91,6 +93,8 @@ def followPerson(baseDir: str,nickname: str, domain: str, \
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: follow of domain '+followDomain+' not permitted')
|
print('DEBUG: follow of domain '+followDomain+' not permitted')
|
||||||
return False
|
return False
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: follow of domain '+followDomain)
|
||||||
handle=nickname.lower()+'@'+domain.lower()
|
handle=nickname.lower()+'@'+domain.lower()
|
||||||
handleToFollow=followNickname.lower()+'@'+followDomain.lower()
|
handleToFollow=followNickname.lower()+'@'+followDomain.lower()
|
||||||
if not os.path.isdir(baseDir+'/accounts'):
|
if not os.path.isdir(baseDir+'/accounts'):
|
||||||
|
@ -100,10 +104,33 @@ def followPerson(baseDir: str,nickname: str, domain: str, \
|
||||||
filename=baseDir+'/accounts/'+handle+'/'+followFile
|
filename=baseDir+'/accounts/'+handle+'/'+followFile
|
||||||
if os.path.isfile(filename):
|
if os.path.isfile(filename):
|
||||||
if handleToFollow in open(filename).read():
|
if handleToFollow in open(filename).read():
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: follow already exists')
|
||||||
return True
|
return True
|
||||||
with open(filename, "a") as followfile:
|
with open(filename, "a") as followfile:
|
||||||
followfile.write(handleToFollow+'\n')
|
followfile.write(handleToFollow+'\n')
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: follow added')
|
||||||
return True
|
return True
|
||||||
|
if debug:
|
||||||
|
print('DEBUG: creating new following file')
|
||||||
with open(filename, "w") as followfile:
|
with open(filename, "w") as followfile:
|
||||||
followfile.write(handleToFollow+'\n')
|
followfile.write(handleToFollow+'\n')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def locatePost(baseDir: str,nickname: str,domain: str,postUrl: str):
|
||||||
|
"""Returns the filename for the given status post url
|
||||||
|
"""
|
||||||
|
boxName='outbox'
|
||||||
|
postFilename=baseDir+'/accounts/'+nickname+'@'+domain+'/'+boxName+'/'+postUrl.replace('/','#')+'.json'
|
||||||
|
if not os.path.isfile(postFilename):
|
||||||
|
# if this post in the inbox of the person?
|
||||||
|
boxName='inbox'
|
||||||
|
postFilename=baseDir+'/accounts/'+nickname+'@'+domain+'/'+boxName+'/'+postUrl.replace('/','#')+'.json'
|
||||||
|
if not os.path.isfile(postFilename):
|
||||||
|
# if this post in the shared inbox?
|
||||||
|
handle='inbox@'+domain
|
||||||
|
postFilename=baseDir+'/accounts/'+nickname+'@'+domain+'/'+boxName+'/'+postUrl.replace('/','#')+'.json'
|
||||||
|
if not os.path.isfile(postFilename):
|
||||||
|
postFilename=None
|
||||||
|
return postFilename
|
||||||
|
|
Loading…
Reference in New Issue