forked from indymedia/epicyon
Creating posts
parent
e3eb2e3af9
commit
b508abaf9d
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
Some experiments with ActivityPub in Python.
|
Some experiments with ActivityPub in Python.
|
||||||
|
|
||||||
|
Based on the specification: https://www.w3.org/TR/activitypub
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
|
|
|
@ -11,6 +11,7 @@ from person import setPreferredUsername
|
||||||
from person import setBio
|
from person import setBio
|
||||||
from webfinger import webfingerHandle
|
from webfinger import webfingerHandle
|
||||||
from posts import getUserPosts
|
from posts import getUserPosts
|
||||||
|
from posts import createPublicPost
|
||||||
from session import createSession
|
from session import createSession
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
|
@ -32,10 +33,12 @@ session = createSession(useTor)
|
||||||
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(username,domain,https,True)
|
privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(username,domain,https,True)
|
||||||
setPreferredUsername(username,domain,'badger')
|
setPreferredUsername(username,domain,'badger')
|
||||||
setBio(username,domain,'Some personal info')
|
setBio(username,domain,'Some personal info')
|
||||||
runDaemon(domain,port,federationList,useTor)
|
createPublicPost(username, domain, https, "G'day world!", False, True)
|
||||||
|
|
||||||
|
#runDaemon(domain,port,federationList,useTor)
|
||||||
|
|
||||||
#testHttpsig()
|
#testHttpsig()
|
||||||
#sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
#pprint(person)
|
#pprint(person)
|
||||||
#print('\n')
|
#print('\n')
|
||||||
|
@ -53,4 +56,4 @@ maxMentions=10
|
||||||
maxEmoji=10
|
maxEmoji=10
|
||||||
maxAttachments=5
|
maxAttachments=5
|
||||||
userPosts = getUserPosts(session,wfRequest,2,maxMentions,maxEmoji,maxAttachments,federationList)
|
userPosts = getUserPosts(session,wfRequest,2,maxMentions,maxEmoji,maxAttachments,federationList)
|
||||||
print(str(userPosts))
|
#print(str(userPosts))
|
||||||
|
|
44
inbox.py
44
inbox.py
|
@ -8,6 +8,7 @@ __status__ = "Production"
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import datetime
|
||||||
|
|
||||||
def inboxPermittedMessage(messageJson,federationList) -> bool:
|
def inboxPermittedMessage(messageJson,federationList) -> bool:
|
||||||
""" check that we are receiving from a permitted domain
|
""" check that we are receiving from a permitted domain
|
||||||
|
@ -40,3 +41,46 @@ def inboxPermittedMessage(messageJson,federationList) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def receivePublicMessage(message) -> bool:
|
||||||
|
print("TODO")
|
||||||
|
|
||||||
|
def validPublishedDate(published):
|
||||||
|
currTime=datetime.datetime.utcnow()
|
||||||
|
pubDate=datetime.datetime.strptime(published,"%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
daysSincePublished = (currTime - pubTime).days
|
||||||
|
if daysSincePublished>30:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def receiveMessage(message):
|
||||||
|
if not message.get('type'):
|
||||||
|
return
|
||||||
|
if message['type']!='Create':
|
||||||
|
return
|
||||||
|
if not message.get('published'):
|
||||||
|
return
|
||||||
|
# is the message too old?
|
||||||
|
if not validPublishedDate(message['published']):
|
||||||
|
return
|
||||||
|
if not message.get('to'):
|
||||||
|
return
|
||||||
|
if not message.get('id'):
|
||||||
|
return
|
||||||
|
for recipient in message['to']:
|
||||||
|
if recipient.endswith('/activitystreams#Public'):
|
||||||
|
receivePublicMessage(message)
|
||||||
|
continue
|
||||||
|
|
||||||
|
username=''
|
||||||
|
domain=''
|
||||||
|
messageId=message['id'].replace('/','_')
|
||||||
|
handle=username.lower()+'@'+domain.lower()
|
||||||
|
baseDir=os.getcwd()
|
||||||
|
if not os.path.isdir(baseDir+'/accounts/'+handle):
|
||||||
|
os.mkdir(baseDir+'/accounts/'+handle)
|
||||||
|
if not os.path.isdir(baseDir+'/accounts/'+handle+'/inbox'):
|
||||||
|
os.mkdir(baseDir+'/accounts/'+handle+'/inbox')
|
||||||
|
filename=baseDir+'/accounts/'+handle+'/inbox/'+messageId+'.json'
|
||||||
|
with open(filename, 'w') as fp:
|
||||||
|
commentjson.dump(personJson, fp, indent=4, sort_keys=False)
|
||||||
|
|
70
posts.py
70
posts.py
|
@ -8,7 +8,11 @@ __status__ = "Production"
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
import json
|
import json
|
||||||
|
import commentjson
|
||||||
import html
|
import html
|
||||||
|
import datetime
|
||||||
|
import os
|
||||||
|
from pprint import pprint
|
||||||
from random import randint
|
from random import randint
|
||||||
from session import getJson
|
from session import getJson
|
||||||
try:
|
try:
|
||||||
|
@ -37,17 +41,18 @@ def getUserUrl(wfRequest) -> str:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def parseUserFeed(session,feedUrl,asHeader) -> None:
|
def parseUserFeed(session,feedUrl,asHeader) -> None:
|
||||||
feed = getJson(session,feedUrl,asHeader,None)
|
feedJson = getJson(session,feedUrl,asHeader,None)
|
||||||
|
pprint(feedJson)
|
||||||
|
|
||||||
if 'orderedItems' in feed:
|
if 'orderedItems' in feedJson:
|
||||||
for item in feed['orderedItems']:
|
for item in feed['orderedItems']:
|
||||||
yield item
|
yield item
|
||||||
|
|
||||||
nextUrl = None
|
nextUrl = None
|
||||||
if 'first' in feed:
|
if 'first' in feedJson:
|
||||||
nextUrl = feed['first']
|
nextUrl = feed['first']
|
||||||
elif 'next' in feed:
|
elif 'next' in feedJson:
|
||||||
nextUrl = feed['next']
|
nextUrl = feedJson['next']
|
||||||
|
|
||||||
if nextUrl:
|
if nextUrl:
|
||||||
for item in parseUserFeed(session,nextUrl,asHeader):
|
for item in parseUserFeed(session,nextUrl,asHeader):
|
||||||
|
@ -149,28 +154,45 @@ def getUserPosts(session,wfRequest,maxPosts,maxMentions,maxEmoji,maxAttachments,
|
||||||
break
|
break
|
||||||
return userPosts
|
return userPosts
|
||||||
|
|
||||||
def createPublicPost(username: str, domain: str, https: bool, content: str, followersOnly: bool) -> {}:
|
def createOutboxDir(username: str,domain: str) -> (str,str):
|
||||||
|
"""Create an outbox for a person and returns the feed filename and directory
|
||||||
|
"""
|
||||||
|
handle=username.lower()+'@'+domain.lower()
|
||||||
|
baseDir=os.getcwd()
|
||||||
|
if not os.path.isdir(baseDir+'/accounts/'+handle):
|
||||||
|
os.mkdir(baseDir+'/accounts/'+handle)
|
||||||
|
outboxDir=baseDir+'/accounts/'+handle+'/outbox'
|
||||||
|
if not os.path.isdir(outboxDir):
|
||||||
|
os.mkdir(outboxDir)
|
||||||
|
outboxJsonFilename=baseDir+'/accounts/'+handle+'/outbox.json'
|
||||||
|
return outboxJsonFilename,outboxDir
|
||||||
|
|
||||||
|
def createPublicPost(username: str, domain: str, https: bool, content: str, followersOnly: bool, saveToFile: bool) -> {}:
|
||||||
|
"""Creates a post
|
||||||
|
"""
|
||||||
prefix='https'
|
prefix='https'
|
||||||
if not https:
|
if not https:
|
||||||
prefix='http'
|
prefix='http'
|
||||||
statusNumber=str(randint(100000000000000000,999999999999999999))
|
|
||||||
currTime=datetime.datetime.utcnow()
|
currTime=datetime.datetime.utcnow()
|
||||||
|
daysSinceEpoch=(currTime - datetime.datetime(1970,1,1)).days
|
||||||
|
statusNumber=str((daysSinceEpoch*24*60*60) + (currTime.hour*60*60) + (currTime.minute*60) + currTime.second)
|
||||||
published=currTime.strftime("%Y-%m-%dT%H:%M:%SZ")
|
published=currTime.strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||||
conversationDate=currTime.strftime("%Y-%m-%d")
|
conversationDate=currTime.strftime("%Y-%m-%d")
|
||||||
conversationId=str(randint(100000000,999999999))
|
conversationId=statusNumber
|
||||||
postTo='https://www.w3.org/ns/activitystreams#Public'
|
postTo='https://www.w3.org/ns/activitystreams#Public'
|
||||||
postCC=prefix+'://'+domain+'/users/'+username+'/followers'
|
postCC=prefix+'://'+domain+'/users/'+username+'/followers'
|
||||||
if followersOnly:
|
if followersOnly:
|
||||||
postTo=postCC
|
postTo=postCC
|
||||||
postCC=''
|
postCC=''
|
||||||
|
newPostId=prefix+'://'+domain+'/users/'+username+'/statuses/'+statusNumber
|
||||||
newPost = {
|
newPost = {
|
||||||
'id': prefix+'://'+domain+'/users/'+username+'/statuses/'+statusNumber+'/activity',
|
'id': newPostId+'/activity',
|
||||||
'type': 'Create',
|
'type': 'Create',
|
||||||
'actor': prefix+'://'+domain+'/users/'+username,
|
'actor': prefix+'://'+domain+'/users/'+username,
|
||||||
'published': published,
|
'published': published,
|
||||||
'to': ['https://www.w3.org/ns/activitystreams#Public'],
|
'to': ['https://www.w3.org/ns/activitystreams#Public'],
|
||||||
'cc': [prefix+'://'+domain+'/users/'+username+'/followers'],
|
'cc': [prefix+'://'+domain+'/users/'+username+'/followers'],
|
||||||
'object': {'id': prefix+'://'+domain+'/users/'+username+'/statuses/'+statusNumber,
|
'object': {'id': newPostId,
|
||||||
'type': 'Note',
|
'type': 'Note',
|
||||||
'summary': None,
|
'summary': None,
|
||||||
'inReplyTo': None,
|
'inReplyTo': None,
|
||||||
|
@ -200,4 +222,32 @@ def createPublicPost(username: str, domain: str, https: bool, content: str, foll
|
||||||
#}
|
#}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if saveToFile:
|
||||||
|
outboxJsonFilename,outboxDir = createOutboxDir(username,domain)
|
||||||
|
filename=outboxDir+'/'+newPostId.replace('/','#')+'.json'
|
||||||
|
with open(filename, 'w') as fp:
|
||||||
|
commentjson.dump(newPost, fp, indent=4, sort_keys=False)
|
||||||
return newPost
|
return newPost
|
||||||
|
|
||||||
|
def createOutbox(username: str,domain: str,https: bool,noOfItems: int):
|
||||||
|
prefix='https'
|
||||||
|
if not https:
|
||||||
|
prefix='http'
|
||||||
|
outboxJsonFilename,outboxDir = createOutboxDir(username,domain)
|
||||||
|
outboxItems=0
|
||||||
|
outboxHeader = {'@context': 'https://www.w3.org/ns/activitystreams',
|
||||||
|
'first': prefix+'://'+domain+'/users/'+username+'/outbox?page=true',
|
||||||
|
'id': prefix+'://'+domain+'/users/'+username+'/outbox',
|
||||||
|
'last': prefix+'://'+domain+'/users/'+username+'/outbox?min_id=0&page=true',
|
||||||
|
'totalItems': str(outboxItems),
|
||||||
|
'type': 'OrderedCollection'}
|
||||||
|
maxMessageId=100000000000000000
|
||||||
|
minMessageId=100000000000000000
|
||||||
|
outboxItems = {'@context': 'https://www.w3.org/ns/activitystreams',
|
||||||
|
'id': prefix+'://'+domain+'/users/'+username+'/outbox?page=true',
|
||||||
|
'next': prefix+'://'+domain+'/users/'+username+'/outbox?max_id='+str(maxMessageId)+'&page=true',
|
||||||
|
'orderedItems': [
|
||||||
|
],
|
||||||
|
'partOf': prefix+'://'+domain+'/users/'+username+'/outbox',
|
||||||
|
'prev': prefix+'://'+domain+'/users/'+username+'/outbox?min_id='+str(minMessageId)+'&page=true',
|
||||||
|
'type': 'OrderedCollectionPage'}
|
||||||
|
|
Loading…
Reference in New Issue