forked from indymedia/epicyon
Begin on a web interface
parent
0350b9e33b
commit
2b02a1a442
19
README.md
19
README.md
|
@ -14,29 +14,30 @@ This project is currently *pre alpha* and not recommended for any real world use
|
|||
|
||||
## Goals
|
||||
|
||||
* A minimal ActivityPub server, comparable to an email MTA.
|
||||
* A minimal ActivityPub server, comparable to an email MTA
|
||||
* AGPLv3+
|
||||
* Server-to-server and client-to-server protocols supported.
|
||||
* Server-to-server and client-to-server protocols supported
|
||||
* Implemented in a common language (Python 3)
|
||||
* Keyword filtering.
|
||||
* Being able to build crowdsouced organizations with roles and skills
|
||||
* Sharings collection, similar to the gnusocial sharings plugin
|
||||
* Quotas for received posts per day, per domain and per account
|
||||
* Hellthread detection and removal
|
||||
* Support content warnings, reporting and blocking.
|
||||
* http signatures and basic auth.
|
||||
* Compatible with http (onion addresses), https and dat.
|
||||
* Support content warnings, reporting and blocking
|
||||
* http signatures and basic auth
|
||||
* Compatible with http (onion addresses), https and dat
|
||||
* Minimal dependencies.
|
||||
* Capabilities based security
|
||||
* Support image blurhashes
|
||||
* Data minimization principle. Configurable post expiry time.
|
||||
* Data minimization principle. Configurable post expiry time
|
||||
* Likes and repeats only visible to authorized viewers
|
||||
* ReplyGuy mitigation - maxmimum replies per post or posts per day
|
||||
* Ability to delete or hide specific conversation threads
|
||||
* Commandline interface. If there's a GUI it should be a separate project.
|
||||
* Designed for intermittent connectivity. Assume network disruptions.
|
||||
* Commandline interface
|
||||
* Simple web interface
|
||||
* Designed for intermittent connectivity. Assume network disruptions
|
||||
* Limited visibility of follows/followers
|
||||
* Suitable for single board computers.
|
||||
* Suitable for single board computers
|
||||
|
||||
## Install
|
||||
|
||||
|
|
81
daemon.py
81
daemon.py
|
@ -44,6 +44,13 @@ from config import setConfigParam
|
|||
from roles import outboxDelegate
|
||||
from skills import outboxSkills
|
||||
from availability import outboxAvailability
|
||||
from webinterface import htmlIndividualPost
|
||||
from webinterface import htmlProfile
|
||||
from webinterface import htmlFollowing
|
||||
from webinterface import htmlFollowers
|
||||
from webinterface import htmlInbox
|
||||
from webinterface import htmlOutbox
|
||||
from webinterface import htmlPostReplies
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
@ -329,7 +336,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.lastGET=currTimeGET
|
||||
self.server.GETbusy=True
|
||||
|
||||
#print('Content-type: '+self.headers['Accept'])
|
||||
#print('Accept: '+self.headers['Accept'])
|
||||
|
||||
if not self._permittedDir(self.path):
|
||||
if self.server.debug:
|
||||
|
@ -416,8 +423,12 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
if not self._isAuthorized():
|
||||
if postJsonObject.get('likes'):
|
||||
postJsonObject['likes']={}
|
||||
self._set_headers('application/json')
|
||||
self.wfile.write(json.dumps(postJsonObject).encode('utf-8'))
|
||||
if 'text/html' in self.headers['Accept']:
|
||||
self._set_headers('text/html')
|
||||
self.wfile.write(htmlIndividualPost(postJsonObject).encode('utf-8'))
|
||||
else:
|
||||
self._set_headers('application/json')
|
||||
self.wfile.write(json.dumps(postJsonObject).encode('utf-8'))
|
||||
self.server.GETbusy=False
|
||||
return
|
||||
else:
|
||||
|
@ -453,8 +464,12 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
'last': self.server.httpPrefix+'://'+domainFull+'/users/'+nickname+'/statuses/'+statusNumber+'/replies?page=true',
|
||||
'totalItems': 0,
|
||||
'type': 'OrderedCollection'}
|
||||
self._set_headers('application/json')
|
||||
self.wfile.write(json.dumps(repliesJson).encode('utf-8'))
|
||||
if 'text/html' in self.headers['Accept']:
|
||||
self._set_headers('text/html')
|
||||
self.wfile.write(htmlPostReplies(repliesJson).encode('utf-8'))
|
||||
else:
|
||||
self._set_headers('application/json')
|
||||
self.wfile.write(json.dumps(repliesJson).encode('utf-8'))
|
||||
self.server.GETbusy=False
|
||||
return
|
||||
else:
|
||||
|
@ -521,8 +536,12 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
'https://www.w3.org/ns/activitystreams#Public' in postJsonObject['object']['to']:
|
||||
repliesJson['orderedItems'].append(postJsonObject)
|
||||
# send the replies json
|
||||
self._set_headers('application/json')
|
||||
self.wfile.write(json.dumps(repliesJson).encode('utf-8'))
|
||||
if 'text/html' in self.headers['Accept']:
|
||||
self._set_headers('text/html')
|
||||
self.wfile.write(htmlPostReplies(repliesJson).encode('utf-8'))
|
||||
else:
|
||||
self._set_headers('application/json')
|
||||
self.wfile.write(json.dumps(repliesJson).encode('utf-8'))
|
||||
self.server.GETbusy=False
|
||||
return
|
||||
|
||||
|
@ -550,8 +569,12 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
if not self._isAuthorized():
|
||||
if postJsonObject.get('likes'):
|
||||
postJsonObject['likes']={}
|
||||
self._set_headers('application/json')
|
||||
self.wfile.write(json.dumps(postJsonObject).encode('utf-8'))
|
||||
if 'text/html' in self.headers['Accept']:
|
||||
self._set_headers('text/html')
|
||||
self.wfile.write(htmlIndividualPost(postJsonObject).encode('utf-8'))
|
||||
else:
|
||||
self._set_headers('application/json')
|
||||
self.wfile.write(json.dumps(postJsonObject).encode('utf-8'))
|
||||
self.server.GETbusy=False
|
||||
return
|
||||
else:
|
||||
|
@ -570,8 +593,12 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
maxPostsInFeed, 'inbox', \
|
||||
True,self.server.ocapAlways)
|
||||
if inboxFeed:
|
||||
self._set_headers('application/json')
|
||||
self.wfile.write(json.dumps(inboxFeed).encode('utf-8'))
|
||||
if 'text/html' in self.headers['Accept']:
|
||||
self._set_headers('text/html')
|
||||
self.wfile.write(htmlInbox(inboxFeed).encode('utf-8'))
|
||||
else:
|
||||
self._set_headers('application/json')
|
||||
self.wfile.write(json.dumps(inboxFeed).encode('utf-8'))
|
||||
self.server.GETbusy=False
|
||||
return
|
||||
else:
|
||||
|
@ -593,8 +620,12 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self._isAuthorized(), \
|
||||
self.server.ocapAlways)
|
||||
if outboxFeed:
|
||||
self._set_headers('application/json')
|
||||
self.wfile.write(json.dumps(outboxFeed).encode('utf-8'))
|
||||
if 'text/html' in self.headers['Accept']:
|
||||
self._set_headers('text/html')
|
||||
self.wfile.write(htmlOutbox(outboxFeed).encode('utf-8'))
|
||||
else:
|
||||
self._set_headers('application/json')
|
||||
self.wfile.write(json.dumps(outboxFeed).encode('utf-8'))
|
||||
self.server.GETbusy=False
|
||||
return
|
||||
authorized=self._isAuthorized()
|
||||
|
@ -603,8 +634,12 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.httpPrefix,
|
||||
authorized,followsPerPage)
|
||||
if following:
|
||||
self._set_headers('application/json')
|
||||
self.wfile.write(json.dumps(following).encode('utf-8'))
|
||||
if 'text/html' in self.headers['Accept']:
|
||||
self._set_headers('text/html')
|
||||
self.wfile.write(htmlFollowing(following).encode('utf-8'))
|
||||
else:
|
||||
self._set_headers('application/json')
|
||||
self.wfile.write(json.dumps(following).encode('utf-8'))
|
||||
self.server.GETbusy=False
|
||||
return
|
||||
followers=getFollowingFeed(self.server.baseDir,self.server.domain, \
|
||||
|
@ -612,16 +647,24 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.httpPrefix, \
|
||||
authorized,followsPerPage,'followers')
|
||||
if followers:
|
||||
self._set_headers('application/json')
|
||||
self.wfile.write(json.dumps(followers).encode('utf-8'))
|
||||
if 'text/html' in self.headers['Accept']:
|
||||
self._set_headers('text/html')
|
||||
self.wfile.write(htmlFollowers(followers).encode('utf-8'))
|
||||
else:
|
||||
self._set_headers('application/json')
|
||||
self.wfile.write(json.dumps(followers).encode('utf-8'))
|
||||
self.server.GETbusy=False
|
||||
return
|
||||
# look up a person
|
||||
getPerson = personLookup(self.server.domain,self.path, \
|
||||
self.server.baseDir)
|
||||
if getPerson:
|
||||
self._set_headers('application/json')
|
||||
self.wfile.write(json.dumps(getPerson).encode('utf-8'))
|
||||
if 'text/html' in self.headers['Accept']:
|
||||
self._set_headers('text/html')
|
||||
self.wfile.write(htmlProfile(getPerson).encode('utf-8'))
|
||||
else:
|
||||
self._set_headers('application/json')
|
||||
self.wfile.write(json.dumps(getPerson).encode('utf-8'))
|
||||
self.server.GETbusy=False
|
||||
return
|
||||
# check that a json file was requested
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
__filename__ = "webinterface.py"
|
||||
__author__ = "Bob Mottram"
|
||||
__license__ = "AGPL3+"
|
||||
__version__ = "0.0.1"
|
||||
__maintainer__ = "Bob Mottram"
|
||||
__email__ = "bob@freedombone.net"
|
||||
__status__ = "Production"
|
||||
|
||||
import json
|
||||
|
||||
def htmlHeader(lang='en') -> str:
|
||||
htmlStr= \
|
||||
'<!DOCTYPE html>\n' \
|
||||
'<html lang="'+lang+'">\n' \
|
||||
' <meta charset="utf-8">\n' \
|
||||
' <style>\n' \
|
||||
' @import url("epicyon.css");\n' \
|
||||
' </style>\n' \
|
||||
' <body>\n'
|
||||
return htmlStr
|
||||
|
||||
def htmlFooter() -> str:
|
||||
htmlStr= \
|
||||
' </body>\n' \
|
||||
'</html>\n'
|
||||
return htmlStr
|
||||
|
||||
def htmlProfile(profileJson: {}) -> str:
|
||||
"""Show the profile page as html
|
||||
"""
|
||||
return htmlHeader()+"<h1>Profile page</h1>"+htmlFooter()
|
||||
|
||||
def htmlFollowing(followingJson: {}) -> str:
|
||||
"""Show the following collection as html
|
||||
"""
|
||||
return htmlHeader()+"<h1>Following collection</h1>"+htmlFooter()
|
||||
|
||||
def htmlFollowers(followersJson: {}) -> str:
|
||||
"""Show the followers collection as html
|
||||
"""
|
||||
return htmlHeader()+"<h1>Followers collection</h1>"+htmlFooter()
|
||||
|
||||
def htmlInbox(inboxJson: {}) -> str:
|
||||
"""Show the inbox as html
|
||||
"""
|
||||
return htmlHeader()+"<h1>Inbox</h1>"+htmlFooter()
|
||||
|
||||
def htmlOutbox(outboxJson: {}) -> str:
|
||||
"""Show the Outbox as html
|
||||
"""
|
||||
return htmlHeader()+"<h1>Outbox</h1>"+htmlFooter()
|
||||
|
||||
def htmlIndividualPost(postJsonObject: {}) -> str:
|
||||
"""Show an individual post as html
|
||||
"""
|
||||
return htmlHeader()+"<h1>Post</h1>"+htmlFooter()
|
||||
|
||||
def htmlPostReplies(postJsonObject: {}) -> str:
|
||||
"""Show the replies to an individual post as html
|
||||
"""
|
||||
return htmlHeader()+"<h1>Replies</h1>"+htmlFooter()
|
Loading…
Reference in New Issue