Moderate button

master
Bob Mottram 2019-08-12 14:22:17 +01:00
parent 6f882ada1a
commit cc81de178f
6 changed files with 212 additions and 8 deletions

View File

@ -67,6 +67,7 @@ from webinterface import htmlIndividualPost
from webinterface import htmlProfile
from webinterface import htmlInbox
from webinterface import htmlOutbox
from webinterface import htmlModeration
from webinterface import htmlPostReplies
from webinterface import htmlLogin
from webinterface import htmlGetLoginCredentials
@ -1185,8 +1186,9 @@ class PubServer(BaseHTTPRequestHandler):
self._404()
self.server.GETbusy=False
return
# get the inbox for a given person
if self.path.endswith('/inbox'):
if self.path.endswith('/inbox') or '/inbox?page=' in self.path:
if '/users/' in self.path:
if authorized:
inboxFeed=personBoxJson(self.server.baseDir, \
@ -1243,7 +1245,7 @@ class PubServer(BaseHTTPRequestHandler):
print('DEBUG: GET access to inbox is unauthorized')
self.send_response(405)
self.end_headers()
self.server.POSTbusy=False
self.server.GETbusy=False
return
# get outbox feed for a person
@ -1290,6 +1292,67 @@ class PubServer(BaseHTTPRequestHandler):
self.server.GETbusy=False
return
# get the moderation feed for a moderator
if self.path.endswith('/moderation') or '/moderation?page=' in self.path:
if '/users/' in self.path:
if authorized:
moderationFeed= \
personBoxJson(self.server.baseDir, \
self.server.domain, \
self.server.port, \
self.path, \
self.server.httpPrefix, \
maxPostsInFeed, 'moderation', \
True,self.server.ocapAlways)
if moderationFeed:
if 'text/html' in self.headers['Accept']:
nickname=self.path.replace('/users/','').replace('/moderation','')
pageNumber=1
if '?page=' in nickname:
pageNumber=nickname.split('?page=')[1]
nickname=nickname.split('?page=')[0]
if pageNumber.isdigit():
pageNumber=int(pageNumber)
else:
pageNumber=1
if 'page=' not in self.path:
# if no page was specified then show the first
moderationFeed= \
personBoxJson(self.server.baseDir, \
self.server.domain, \
self.server.port, \
self.path+'?page=1', \
self.server.httpPrefix, \
maxPostsInFeed, 'moderation', \
True,self.server.ocapAlways)
self._set_headers('text/html',cookie)
self.wfile.write(htmlModeration(pageNumber,maxPostsInFeed, \
self.server.session, \
self.server.baseDir, \
self.server.cachedWebfingers, \
self.server.personCache, \
nickname, \
self.server.domain, \
self.server.port, \
moderationFeed, \
True).encode('utf-8'))
else:
self._set_headers('application/json',None)
self.wfile.write(json.dumps(moderationFeed).encode('utf-8'))
self.server.GETbusy=False
return
else:
if self.server.debug:
nickname=self.path.replace('/users/','').replace('/moderation','')
print('DEBUG: '+nickname+ \
' was not authorized to access '+self.path)
if self.server.debug:
print('DEBUG: GET access to moderation feed is unauthorized')
self.send_response(405)
self.end_headers()
self.server.GETbusy=False
return
shares=getSharesFeedForPerson(self.server.baseDir, \
self.server.domain, \
self.server.port,self.path, \

View File

@ -151,7 +151,7 @@ a:link {
text-align: center;
font-size: 18px;
padding: 10px;
width: 20%;
width: 15%;
max-width: 200px;
min-width: 100px;
transition: all 0.5s;

View File

@ -19,6 +19,7 @@ from webfinger import createWebfingerEndpoint
from webfinger import storeWebfingerEndpoint
from posts import createInbox
from posts import createOutbox
from posts import createModeration
from auth import storeBasicCredentials
from roles import setRole
from media import removeMetaData
@ -340,9 +341,9 @@ def personLookup(domain: str,path: str,baseDir: str) -> {}:
def personBoxJson(baseDir: str,domain: str,port: int,path: str, \
httpPrefix: str,noOfItems: int,boxname: str, \
authorized: bool,ocapAlways: bool) -> []:
"""Obtain the inbox/outbox feed for the given person
"""Obtain the inbox/outbox/moderation feed for the given person
"""
if boxname!='inbox' and boxname!='outbox':
if boxname!='inbox' and boxname!='outbox' and boxname!='moderation':
return None
if not '/'+boxname in path:
@ -379,8 +380,13 @@ def personBoxJson(baseDir: str,domain: str,port: int,path: str, \
if boxname=='inbox':
return createInbox(baseDir,nickname,domain,port,httpPrefix, \
noOfItems,headerOnly,ocapAlways,pageNumber)
return createOutbox(baseDir,nickname,domain,port,httpPrefix, \
noOfItems,headerOnly,authorized,pageNumber)
elif boxname=='outbox':
return createOutbox(baseDir,nickname,domain,port,httpPrefix, \
noOfItems,headerOnly,authorized,pageNumber)
elif boxname=='moderation':
return createModeration(baseDir,nickname,domain,port,httpPrefix, \
noOfItems,headerOnly,authorized,pageNumber)
return None
def personInboxJson(baseDir: str,domain: str,port: int,path: str, \
httpPrefix: str,noOfItems: int,ocapAlways: bool) -> []:

View File

@ -47,6 +47,27 @@ try:
except ImportError:
from bs4 import BeautifulSoup
def isModerator(baseDir: str,nickname: str) -> bool:
"""Returns true if the given nickname is a moderator
"""
moderatorsFile=baseDir+'/accounts/moderators.txt'
if not os.path.isfile(moderatorsFile):
if getConfigParam(baseDir,'admin')==nickname:
return True
return False
with open(moderatorsFile, "r") as f:
lines = f.readlines()
if len(lines)==0:
if getConfigParam(baseDir,'admin')==nickname:
return True
for moderator in lines:
moderator=moderator.strip('\n')
if moderator==nickname:
return True
return False
def noOfFollowersOnDomain(baseDir: str,handle: str, \
domain: str, followFile='followers.txt') -> int:
"""Returns the number of followers of the given handle from the given domain
@ -551,10 +572,17 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
# if this is a moderation report then add a status
if isModerationReport:
# add status
if newPost.get('object'):
newPost['object']['moderationStatus']='pending'
else:
newPost['moderationStatus']='pending'
# save to index file
moderationIndexFile=baseDir+'/accounts/moderation.txt'
modFile=open(moderationIndexFile, "a+")
if modFile:
modFile.write(newPostId+'\n')
modFile.close()
if saveToFile:
savePostToBox(baseDir,httpPrefix,newPostId, \
@ -1298,11 +1326,69 @@ def createInbox(baseDir: str,nickname: str,domain: str,port: int,httpPrefix: str
itemsPerPage: int,headerOnly: bool,ocapAlways: bool,pageNumber=None) -> {}:
return createBoxBase(baseDir,'inbox',nickname,domain,port,httpPrefix, \
itemsPerPage,headerOnly,True,ocapAlways,pageNumber)
def createOutbox(baseDir: str,nickname: str,domain: str,port: int,httpPrefix: str, \
itemsPerPage: int,headerOnly: bool,authorized: bool,pageNumber=None) -> {}:
return createBoxBase(baseDir,'outbox',nickname,domain,port,httpPrefix, \
itemsPerPage,headerOnly,authorized,False,pageNumber)
def createModeration(baseDir: str,nickname: str,domain: str,port: int,httpPrefix: str, \
itemsPerPage: int,headerOnly: bool,ocapAlways: bool,pageNumber=None) -> {}:
boxDir = createPersonDir(nickname,domain,baseDir,'inbox')
boxname='moderation'
if port!=80 and port!=443:
domain = domain+':'+str(port)
if not pageNumber:
pageNumber=1
pageStr='?page='+str(pageNumber)
boxHeader = {'@context': 'https://www.w3.org/ns/activitystreams',
'first': httpPrefix+'://'+domain+'/users/'+nickname+'/'+boxname+'?page=true',
'id': httpPrefix+'://'+domain+'/users/'+nickname+'/'+boxname,
'last': httpPrefix+'://'+domain+'/users/'+nickname+'/'+boxname+'?page=true',
'totalItems': 0,
'type': 'OrderedCollection'}
boxItems = {'@context': 'https://www.w3.org/ns/activitystreams',
'id': httpPrefix+'://'+domain+'/users/'+nickname+'/'+boxname+pageStr,
'orderedItems': [
],
'partOf': httpPrefix+'://'+domain+'/users/'+nickname+'/'+boxname,
'type': 'OrderedCollectionPage'}
if isModerator(baseDir,nickname):
moderationIndexFile=baseDir+'/accounts/moderation.txt'
if os.path.isfile(moderationIndexFile):
with open(moderationIndexFile, "r") as f:
lines = f.readlines()
boxHeader['totalItems']=len(lines)
if headerOnly:
return boxHeader
pageLines=[]
if len(lines)>0:
endLineNumber=len(lines)-1-int(itemsPerPage*pageNumber)
if endLineNumber<0:
endLineNumber=0
startLineNumber=len(lines)-1-int(itemsPerPage*(pageNumber-1))
if startLineNumber<0:
startLineNumber=0
lineNumber=startLineNumber
while lineNumber>=endLineNumber:
pageLines.append(lines[lineNumber].strip('\n'))
lineNumber-=1
for postUrl in pageLines:
postFilename=boxDir+'/'+postUrl.replace('/','#')+'.json'
if os.path.isfile(postFilename):
with open(postFilename, 'r') as fp:
postJsonObject=commentjson.load(fp)
boxItems['orderedItems'].append(postJsonObject)
if headerOnly:
return boxHeader
return boxItems
def getStatusNumberFromPostFilename(filename) -> int:
"""Gets the status number from a post filename
eg. https:##testdomain.com:8085#users#testuser567#statuses#1562958506952068.json

View File

@ -175,6 +175,23 @@ def deletePost(baseDir: str,httpPrefix: str,nickname: str,domain: str,postFilena
# remove any attachment
removeAttachment(baseDir,httpPrefix,domain,postJsonObject)
# remove from moderation index file
if postJsonObject.get('moderationStatus'):
moderationIndexFile=baseDir+'/accounts/moderation.txt'
if os.path.isfile(moderationIndexFile):
if postJsonObject.get('object'):
if isinstance(postJsonObject['object'], dict):
if postJsonObject['object'].get('id'):
# get the id of the post
postId=postJsonObject['object']['id'].replace('/activity','')
if postId in open(moderationIndexFile).read():
with open(moderationIndexFile, "r") as f:
lines = f.readlines()
with open(moderationIndexFile, "w+") as f:
for line in lines:
if line.strip("\n") != postId:
f.write(line)
# remove any hashtags index entries
removeHashtagIndex=False

View File

@ -25,6 +25,7 @@ from posts import getPersonBox
from posts import getUserUrl
from posts import parseUserFeed
from posts import populateRepliesJson
from posts import isModerator
from session import getJson
from auth import createPassword
from like import likedByPerson
@ -34,6 +35,17 @@ from content import getMentionsFromHtml
from config import getConfigParam
from skills import getSkills
def noOfModerationPosts(baseDir: str) -> int:
"""Returns the number of posts addressed to moderators
"""
moderationIndexFile=baseDir+'/accounts/moderation.txt'
if not os.path.isfile(moderationIndexFile):
return 0
with open(moderationIndexFile, "r") as f:
lines = f.readlines()
return len(lines)
return 0
def htmlHashtagSearch(baseDir: str,hashtag: str,pageNumber: int,postsPerPage: int,
session,wfRequest: {},personCache: {}) -> str:
"""Show a page containing search results for a hashtag
@ -961,12 +973,17 @@ def htmlTimeline(pageNumber: int,itemsPerPage: int,session,baseDir: str, \
cssFile.read().replace('banner.png', \
'/users/'+nickname+'/banner.png')
moderator=isModerator(baseDir,nickname)
inboxButton='button'
sentButton='button'
moderationButton='button'
if boxName=='inbox':
inboxButton='buttonselected'
elif boxName=='outbox':
sentButton='buttonselected'
elif boxName=='moderation':
moderationButton='buttonselected'
actor='/users/'+nickname
showIndividualPostIcons=True
@ -983,6 +1000,11 @@ def htmlTimeline(pageNumber: int,itemsPerPage: int,session,baseDir: str, \
followApprovals='<a href="'+actor+'/followers"><img class="right" alt="Approve follow requests" title="Approve follow requests" src="/icons/person.png"/></a>'
break
moderationButtonStr=''
if moderator:
if noOfModerationPosts(baseDir)>0:
moderationButtonStr='<a href="'+actor+'/moderation"><button class="'+moderationButton+'"><span>Moderate </span></button></a>'
tlStr=htmlHeader(profileStyle)
tlStr+= \
'<a href="/users/'+nickname+'" title="Switch to profile view" alt="Switch to profile view">' \
@ -990,7 +1012,8 @@ def htmlTimeline(pageNumber: int,itemsPerPage: int,session,baseDir: str, \
'</div></a>' \
'<div class="container">\n'+ \
' <a href="'+actor+'/inbox"><button class="'+inboxButton+'"><span>Inbox </span></button></a>' \
' <a href="'+actor+'/outbox"><button class="'+sentButton+'"><span>Sent </span></button></a>' \
' <a href="'+actor+'/outbox"><button class="'+sentButton+'"><span>Sent </span></button></a>'+ \
moderationButtonStr+ \
' <a href="'+actor+'/newpost"><img src="/icons/newpost.png" title="Create a new post" alt="Create a new post" class="right"/></a>'+ \
' <a href="'+actor+'/search"><img src="/icons/search.png" title="Search and follow" alt="Search and follow" class="right"/></a>'+ \
followApprovals+ \
@ -1019,6 +1042,15 @@ def htmlInbox(pageNumber: int,itemsPerPage: int, \
return htmlTimeline(pageNumber,itemsPerPage,session,baseDir,wfRequest,personCache, \
nickname,domain,port,inboxJson,'inbox',allowDeletion)
def htmlModeration(pageNumber: int,itemsPerPage: int, \
session,baseDir: str,wfRequest: {},personCache: {}, \
nickname: str,domain: str,port: int,inboxJson: {}, \
allowDeletion: bool) -> str:
"""Show the moderation feed as html
"""
return htmlTimeline(pageNumber,itemsPerPage,session,baseDir,wfRequest,personCache, \
nickname,domain,port,inboxJson,'moderation',allowDeletion)
def htmlOutbox(pageNumber: int,itemsPerPage: int, \
session,baseDir: str,wfRequest: {},personCache: {}, \
nickname: str,domain: str,port: int,outboxJson: {}, \