Creating posts

master
Bob Mottram 2019-06-29 11:08:59 +01:00
parent e3eb2e3af9
commit b508abaf9d
4 changed files with 112 additions and 13 deletions

View File

@ -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

View File

@ -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))

View File

@ -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)

View File

@ -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'}