Blogs timeline

main
Bob Mottram 2020-02-24 14:39:25 +00:00
parent 9b48742ae3
commit 0bd778d553
8 changed files with 205 additions and 14 deletions

102
daemon.py
View File

@ -115,6 +115,7 @@ from webinterface import htmlRemoveSharedItem
from webinterface import htmlInboxDMs from webinterface import htmlInboxDMs
from webinterface import htmlInboxReplies from webinterface import htmlInboxReplies
from webinterface import htmlInboxMedia from webinterface import htmlInboxMedia
from webinterface import htmlInboxBlogs
from webinterface import htmlUnblockConfirm from webinterface import htmlUnblockConfirm
from webinterface import htmlPersonOptions from webinterface import htmlPersonOptions
from webinterface import htmlIndividualPost from webinterface import htmlIndividualPost
@ -186,6 +187,9 @@ maxPostsInFeed=12
# reduced posts for media feed because it can take a while # reduced posts for media feed because it can take a while
maxPostsInMediaFeed=6 maxPostsInMediaFeed=6
# Blogs can be longer, so don't show many per page
maxPostsInBlogsFeed=4
# number of follows/followers per page # number of follows/followers per page
followsPerPage=12 followsPerPage=12
@ -2894,6 +2898,84 @@ class PubServer(BaseHTTPRequestHandler):
self.server.GETbusy=False self.server.GETbusy=False
return return
# get the blogs for a given person
if self.path.endswith('/tlblogs') or '/tlblogs?page=' in self.path:
if '/users/' in self.path:
if authorized:
inboxBlogsFeed= \
personBoxJson(self.server.recentPostsCache, \
self.server.session, \
self.server.baseDir, \
self.server.domain, \
self.server.port, \
self.path, \
self.server.httpPrefix, \
maxPostsInBlogsFeed, 'tlblogs', \
True,self.server.ocapAlways)
if not inboxBlogsFeed:
inboxBlogsFeed=[]
if self._requestHTTP():
nickname=self.path.replace('/users/','').replace('/tlblogs','')
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
inboxBlogsFeed= \
personBoxJson(self.server.recentPostsCache, \
self.server.session, \
self.server.baseDir, \
self.server.domain, \
self.server.port, \
self.path+'?page=1', \
self.server.httpPrefix, \
maxPostsInBlogsFeed, 'tlblogs', \
True,self.server.ocapAlways)
msg=htmlInboxBlogs(self.server.defaultTimeline, \
self.server.recentPostsCache, \
self.server.maxRecentPosts, \
self.server.translate, \
pageNumber,maxPostsInBlogsFeed, \
self.server.session, \
self.server.baseDir, \
self.server.cachedWebfingers, \
self.server.personCache, \
nickname, \
self.server.domain, \
self.server.port, \
inboxBlogsFeed, \
self.server.allowDeletion, \
self.server.httpPrefix, \
self.server.projectVersion).encode('utf-8')
self._set_headers('text/html',len(msg),cookie)
self._write(msg)
else:
# don't need authenticated fetch here because there is
# already the authorization check
msg=json.dumps(inboxBlogsFeed,ensure_ascii=False).encode('utf-8')
self._set_headers('application/json',len(msg),None)
self._write(msg)
self.server.GETbusy=False
return
else:
if self.server.debug:
nickname=self.path.replace('/users/','').replace('/tlblogs','')
print('DEBUG: '+nickname+ \
' was not authorized to access '+self.path)
if self.path!='/tlblogs':
# not the blogs inbox
if self.server.debug:
print('DEBUG: GET access to blogs is unauthorized')
self.send_response(405)
self.end_headers()
self.server.GETbusy=False
return
self._benchmarkGETtimings(GETstartTime,GETtimings,46) self._benchmarkGETtimings(GETstartTime,GETtimings,46)
# get the shared items timeline for a given person # get the shared items timeline for a given person
@ -4343,6 +4425,20 @@ class PubServer(BaseHTTPRequestHandler):
self.server.defaultTimeline='inbox' self.server.defaultTimeline='inbox'
setConfigParam(self.server.baseDir,"mediaInstance", \ setConfigParam(self.server.baseDir,"mediaInstance", \
self.server.mediaInstance) self.server.mediaInstance)
if fields.get('blogsInstance'):
self.server.blogsInstance=False
self.server.defaultTimeline='inbox'
if fields['blogsInstance']=='on':
self.server.blogsInstance=True
self.server.defaultTimeline='tlblogs'
setConfigParam(self.server.baseDir,"blogsInstance", \
self.server.blogsInstance)
else:
if self.server.blogsInstance:
self.server.blogsInstance=False
self.server.defaultTimeline='inbox'
setConfigParam(self.server.baseDir,"blogsInstance", \
self.server.blogsInstance)
# only receive DMs from accounts you follow # only receive DMs from accounts you follow
followDMsFilename= \ followDMsFilename= \
self.server.baseDir+'/accounts/'+ \ self.server.baseDir+'/accounts/'+ \
@ -5574,7 +5670,8 @@ def loadTokens(baseDir: str,tokensDict: {},tokensLookup: {}) -> None:
tokensDict[nickname]=token tokensDict[nickname]=token
tokensLookup[token]=nickname tokensLookup[token]=nickname
def runDaemon(mediaInstance: bool,maxRecentPosts: int, \ def runDaemon(blogsInstance: bool,mediaInstance: bool, \
maxRecentPosts: int, \
enableSharedInbox: bool,registration: bool, \ enableSharedInbox: bool,registration: bool, \
language: str,projectVersion: str, \ language: str,projectVersion: str, \
instanceId: str,clientToServer: bool, \ instanceId: str,clientToServer: bool, \
@ -5615,9 +5712,12 @@ def runDaemon(mediaInstance: bool,maxRecentPosts: int, \
httpd.useBlurHash=useBlurHash httpd.useBlurHash=useBlurHash
httpd.mediaInstance=mediaInstance httpd.mediaInstance=mediaInstance
httpd.blogsInstance=blogsInstance
httpd.defaultTimeline='inbox' httpd.defaultTimeline='inbox'
if mediaInstance: if mediaInstance:
httpd.defaultTimeline='tlmedia' httpd.defaultTimeline='tlmedia'
if blogsInstance:
httpd.defaultTimeline='tlblogs'
# load translations dictionary # load translations dictionary
httpd.translate={} httpd.translate={}

View File

@ -151,6 +151,9 @@ parser.add_argument('-f','--federate', nargs='+',dest='federationList', \
parser.add_argument("--mediainstance", type=str2bool, nargs='?', \ parser.add_argument("--mediainstance", type=str2bool, nargs='?', \
const=True, default=False, \ const=True, default=False, \
help="Media Instance - favor media over text") help="Media Instance - favor media over text")
parser.add_argument("--blogsinstance", type=str2bool, nargs='?', \
const=True, default=False, \
help="Blogs Instance - favor blogs over microblogging")
parser.add_argument("--debug", type=str2bool, nargs='?', \ parser.add_argument("--debug", type=str2bool, nargs='?', \
const=True, default=False, \ const=True, default=False, \
help="Show debug messages") help="Show debug messages")
@ -387,6 +390,11 @@ if not args.mediainstance:
if mediaInstance!=None: if mediaInstance!=None:
args.mediainstance=mediaInstance args.mediainstance=mediaInstance
if not args.blogsinstance:
blogsInstance=getConfigParam(baseDir,'blogsInstance')
if blogsInstance!=None:
args.blogsinstance=blogsInstance
# set the instance title in config.json # set the instance title in config.json
title=getConfigParam(baseDir,'instanceTitle') title=getConfigParam(baseDir,'instanceTitle')
if not title: if not title:
@ -1504,7 +1512,8 @@ if not registration:
if setTheme(baseDir,themeName): if setTheme(baseDir,themeName):
print('Theme set to '+themeName) print('Theme set to '+themeName)
runDaemon(args.mediainstance,args.maxRecentPosts, \ runDaemon(args.blogsinstance,args.mediainstance, \
args.maxRecentPosts, \
not args.nosharedinbox, \ not args.nosharedinbox, \
registration,args.language,__version__, \ registration,args.language,__version__, \
instanceId,args.client,baseDir, \ instanceId,args.client,baseDir, \

View File

@ -62,6 +62,23 @@ from webinterface import getIconsDir
from question import questionUpdateVotes from question import questionUpdateVotes
from media import replaceYouTube from media import replaceYouTube
def isBlogPost(postJsonObject: {}) -> bool:
"""Is the given post a blog post?
"""
if postJsonObject['type']!='Create':
return False
if not postJsonObject.get('object'):
return False
if not isinstance(postJsonObject['object'], dict):
return False
if not postJsonObject['object'].get('type'):
return False
if not postJsonObject['object'].get('content'):
return False
if postJsonObject['object']['type']!='Article':
return False
return True
def storeHashTags(baseDir: str,nickname: str,postJsonObject: {}) -> None: def storeHashTags(baseDir: str,nickname: str,postJsonObject: {}) -> None:
"""Extracts hashtags from an incoming post and updates the """Extracts hashtags from an incoming post and updates the
relevant tags files. relevant tags files.
@ -1924,6 +1941,9 @@ def inboxAfterCapabilities(recentPostsCache: {},maxRecentPosts: int, \
if isImageMedia(session,baseDir,httpPrefix,nickname,domain,postJsonObject): if isImageMedia(session,baseDir,httpPrefix,nickname,domain,postJsonObject):
# media index will be updated # media index will be updated
updateIndexList.append('tlmedia') updateIndexList.append('tlmedia')
if isBlogPost(postJsonObject):
# blogs index will be updated
updateIndexList.append('tlblogs')
# get the avatar for a reply/announce # get the avatar for a reply/announce
obtainAvatarForReplyPost(session,baseDir,httpPrefix,domain,personCache,postJsonObject,debug) obtainAvatarForReplyPost(session,baseDir,httpPrefix,domain,personCache,postJsonObject,debug)

View File

@ -21,6 +21,7 @@ from webfinger import storeWebfingerEndpoint
from posts import createDMTimeline from posts import createDMTimeline
from posts import createRepliesTimeline from posts import createRepliesTimeline
from posts import createMediaTimeline from posts import createMediaTimeline
from posts import createBlogsTimeline
from posts import createBookmarksTimeline from posts import createBookmarksTimeline
from posts import createInbox from posts import createInbox
from posts import createOutbox from posts import createOutbox
@ -470,6 +471,7 @@ def personBoxJson(recentPostsCache: {}, \
""" """
if boxname!='inbox' and boxname!='dm' and \ if boxname!='inbox' and boxname!='dm' and \
boxname!='tlreplies' and boxname!='tlmedia' and \ boxname!='tlreplies' and boxname!='tlmedia' and \
boxname!='tlblogs' and \
boxname!='outbox' and boxname!='moderation' and \ boxname!='outbox' and boxname!='moderation' and \
boxname!='tlbookmarks': boxname!='tlbookmarks':
return None return None
@ -521,6 +523,9 @@ def personBoxJson(recentPostsCache: {}, \
elif boxname=='tlmedia': elif boxname=='tlmedia':
return createMediaTimeline(session,baseDir,nickname,domain,port,httpPrefix, \ return createMediaTimeline(session,baseDir,nickname,domain,port,httpPrefix, \
noOfItems,headerOnly,ocapAlways,pageNumber) noOfItems,headerOnly,ocapAlways,pageNumber)
elif boxname=='tlblogs':
return createBlogsTimeline(session,baseDir,nickname,domain,port,httpPrefix, \
noOfItems,headerOnly,ocapAlways,pageNumber)
elif boxname=='outbox': elif boxname=='outbox':
return createOutbox(session,baseDir,nickname,domain,port,httpPrefix, \ return createOutbox(session,baseDir,nickname,domain,port,httpPrefix, \
noOfItems,headerOnly,authorized,pageNumber) noOfItems,headerOnly,authorized,pageNumber)

View File

@ -1956,6 +1956,13 @@ def createInbox(recentPostsCache: {}, \
session,baseDir,'inbox',nickname,domain,port,httpPrefix, \ session,baseDir,'inbox',nickname,domain,port,httpPrefix, \
itemsPerPage,headerOnly,True,ocapAlways,pageNumber) itemsPerPage,headerOnly,True,ocapAlways,pageNumber)
def createBlogsTimeline(recentPostsCache: {}, \
session,baseDir: str,nickname: str,domain: str,port: int,httpPrefix: str, \
itemsPerPage: int,headerOnly: bool,ocapAlways: bool,pageNumber=None) -> {}:
return createBoxIndexed(recentPostsCache, \
session,baseDir,'tlblogs',nickname,domain,port,httpPrefix, \
itemsPerPage,headerOnly,True,ocapAlways,pageNumber)
def createBookmarksTimeline(session,baseDir: str,nickname: str,domain: str,port: int,httpPrefix: str, \ def createBookmarksTimeline(session,baseDir: str,nickname: str,domain: str,port: int,httpPrefix: str, \
itemsPerPage: int,headerOnly: bool,ocapAlways: bool,pageNumber=None) -> {}: itemsPerPage: int,headerOnly: bool,ocapAlways: bool,pageNumber=None) -> {}:
return createBoxIndexed({},session,baseDir,'tlbookmarks',nickname,domain,port,httpPrefix, \ return createBoxIndexed({},session,baseDir,'tlbookmarks',nickname,domain,port,httpPrefix, \
@ -2240,6 +2247,11 @@ def addPostStringToTimeline(postStr: str,boxname: str, \
elif boxname=='tlreplies': elif boxname=='tlreplies':
if boxActor not in postStr: if boxActor not in postStr:
return False return False
elif boxname=='tlblogs':
if '"Create"' not in postStr:
return False
if '"Article"' not in postStr:
return False
elif boxname=='tlmedia': elif boxname=='tlmedia':
if '"Create"' in postStr: if '"Create"' in postStr:
if 'mediaType' not in postStr or 'image/' not in postStr: if 'mediaType' not in postStr or 'image/' not in postStr:
@ -2270,11 +2282,13 @@ def createBoxIndexed(recentPostsCache: {}, \
if boxname!='inbox' and boxname!='dm' and \ if boxname!='inbox' and boxname!='dm' and \
boxname!='tlreplies' and boxname!='tlmedia' and \ boxname!='tlreplies' and boxname!='tlmedia' and \
boxname!='tlblogs' and \
boxname!='outbox' and boxname!='tlbookmarks': boxname!='outbox' and boxname!='tlbookmarks':
return None return None
if boxname!='dm' and boxname!='tlreplies' and \ if boxname!='dm' and boxname!='tlreplies' and \
boxname!='tlmedia' and boxname!='tlbookmarks': boxname!='tlmedia' and boxname!='tlblogs' and \
boxname!='tlbookmarks':
boxDir = createPersonDir(nickname,domain,baseDir,boxname) boxDir = createPersonDir(nickname,domain,baseDir,boxname)
else: else:
# extract DMs or replies or media from the inbox # extract DMs or replies or media from the inbox
@ -2284,7 +2298,7 @@ def createBoxIndexed(recentPostsCache: {}, \
sharedBoxDir=None sharedBoxDir=None
if boxname=='inbox' or boxname=='tlreplies' or \ if boxname=='inbox' or boxname=='tlreplies' or \
boxname=='tlmedia': boxname=='tlmedia' or boxname=='tlblogs':
sharedBoxDir = createPersonDir('inbox',domain,baseDir,boxname) sharedBoxDir = createPersonDir('inbox',domain,baseDir,boxname)
# bookmarks timeline is like the inbox but has its own separate index # bookmarks timeline is like the inbox but has its own separate index
@ -2297,6 +2311,8 @@ def createBoxIndexed(recentPostsCache: {}, \
indexBoxName='tlreplies' indexBoxName='tlreplies'
elif boxname=='tlmedia': elif boxname=='tlmedia':
indexBoxName='tlmedia' indexBoxName='tlmedia'
elif boxname=='tlblogs':
indexBoxName='tlblogs'
if port: if port:
if port!=80 and port!=443: if port!=80 and port!=443:

View File

@ -236,7 +236,7 @@ def createServerAlice(path: str,domain: str,port: int,bobAddress: str,federation
maxMentions=10 maxMentions=10
maxEmoji=10 maxEmoji=10
print('Server running: Alice') print('Server running: Alice')
runDaemon(False,5,True,True,'en',__version__, \ runDaemon(False,False,5,True,True,'en',__version__, \
"instanceId",False,path,domain,port,port, \ "instanceId",False,path,domain,port,port, \
httpPrefix,federationList,maxMentions,maxEmoji,False, \ httpPrefix,federationList,maxMentions,maxEmoji,False, \
noreply,nolike,nopics,noannounce,cw,ocapAlways, \ noreply,nolike,nopics,noannounce,cw,ocapAlways, \
@ -292,7 +292,7 @@ def createServerBob(path: str,domain: str,port: int,aliceAddress: str,federation
maxMentions=10 maxMentions=10
maxEmoji=10 maxEmoji=10
print('Server running: Bob') print('Server running: Bob')
runDaemon(False,5,True,True,'en',__version__, \ runDaemon(False,False,5,True,True,'en',__version__, \
"instanceId",False,path,domain,port,port, \ "instanceId",False,path,domain,port,port, \
httpPrefix,federationList,maxMentions,maxEmoji,False, \ httpPrefix,federationList,maxMentions,maxEmoji,False, \
noreply,nolike,nopics,noannounce,cw,ocapAlways, \ noreply,nolike,nopics,noannounce,cw,ocapAlways, \
@ -328,7 +328,7 @@ def createServerEve(path: str,domain: str,port: int,federationList: [], \
maxMentions=10 maxMentions=10
maxEmoji=10 maxEmoji=10
print('Server running: Eve') print('Server running: Eve')
runDaemon(False,5,True,True,'en',__version__, \ runDaemon(False,False,5,True,True,'en',__version__, \
"instanceId",False,path,domain,port,port, \ "instanceId",False,path,domain,port,port, \
httpPrefix,federationList,maxMentions,maxEmoji,False, \ httpPrefix,federationList,maxMentions,maxEmoji,False, \
noreply,nolike,nopics,noannounce,cw,ocapAlways, \ noreply,nolike,nopics,noannounce,cw,ocapAlways, \

View File

@ -429,7 +429,7 @@ def validNickname(domain: str,nickname: str) -> bool:
return False return False
if nickname==domain: if nickname==domain:
return False return False
reservedNames=['inbox','dm','outbox','following','public','followers','profile','channel','capabilities','calendar','tlreplies','tlmedia','moderation','activity','undo','reply','replies','question','like','likes','users','statuses','updates','repeat','announce','shares'] reservedNames=['inbox','dm','outbox','following','public','followers','profile','channel','capabilities','calendar','tlreplies','tlmedia','tlblogs','moderation','activity','undo','reply','replies','question','like','likes','users','statuses','updates','repeat','announce','shares']
if nickname in reservedNames: if nickname in reservedNames:
return False return False
return True return True

View File

@ -3395,6 +3395,7 @@ def htmlTimeline(defaultTimeline: str, \
moderator=isModerator(baseDir,nickname) moderator=isModerator(baseDir,nickname)
inboxButton='button' inboxButton='button'
blogsButton='button'
dmButton='button' dmButton='button'
if newDM: if newDM:
dmButton='buttonhighlighted' dmButton='buttonhighlighted'
@ -3412,6 +3413,8 @@ def htmlTimeline(defaultTimeline: str, \
moderationButton='buttonhighlighted' moderationButton='buttonhighlighted'
if boxName=='inbox': if boxName=='inbox':
inboxButton='buttonselected' inboxButton='buttonselected'
elif boxName=='tlblogs':
blogsButton='buttonselected'
elif boxName=='dm': elif boxName=='dm':
dmButton='buttonselected' dmButton='buttonselected'
if newDM: if newDM:
@ -3511,16 +3514,24 @@ def htmlTimeline(defaultTimeline: str, \
tlStr+='<div class="timeline-banner">' tlStr+='<div class="timeline-banner">'
tlStr+='</div></a>' tlStr+='</div></a>'
tlStr+='<div class="container">\n' tlStr+='<div class="container">\n'
if defaultTimeline!='tlmedia':
tlStr+= \ # first button
' <a href="'+actor+'/inbox"><button class="'+ \ if defaultTimeline=='tlmedia':
inboxButton+'"><span>'+ \
translate['Inbox']+'</span></button></a>'
else:
tlStr+= \ tlStr+= \
' <a href="'+actor+'/tlmedia"><button class="'+ \ ' <a href="'+actor+'/tlmedia"><button class="'+ \
mediaButton+'"><span>'+translate['Media']+ \ mediaButton+'"><span>'+translate['Media']+ \
'</span></button></a>' '</span></button></a>'
elif defaultTimeline=='tlblogs':
tlStr+= \
' <a href="'+actor+'/tlblogs"><button class="'+ \
blogsButton+'"><span>'+translate['Blogs']+ \
'</span></button></a>'
else:
tlStr+= \
' <a href="'+actor+'/inbox"><button class="'+ \
inboxButton+'"><span>'+ \
translate['Inbox']+'</span></button></a>'
tlStr+= \ tlStr+= \
' <a href="'+actor+'/dm"><button class="'+dmButton+ \ ' <a href="'+actor+'/dm"><button class="'+dmButton+ \
'"><span>'+translate['DM']+'</span></button></a>' '"><span>'+translate['DM']+'</span></button></a>'
@ -3528,6 +3539,8 @@ def htmlTimeline(defaultTimeline: str, \
' <a href="'+actor+'/tlreplies"><button class="'+ \ ' <a href="'+actor+'/tlreplies"><button class="'+ \
repliesButton+'"><span>'+translate['Replies']+ \ repliesButton+'"><span>'+translate['Replies']+ \
'</span></button></a>' '</span></button></a>'
# typically the media button
if defaultTimeline!='tlmedia': if defaultTimeline!='tlmedia':
tlStr+= \ tlStr+= \
' <a href="'+actor+'/tlmedia"><button class="'+ \ ' <a href="'+actor+'/tlmedia"><button class="'+ \
@ -3538,6 +3551,19 @@ def htmlTimeline(defaultTimeline: str, \
' <a href="'+actor+'/inbox"><button class="'+ \ ' <a href="'+actor+'/inbox"><button class="'+ \
inboxButton+'"><span>'+translate['Inbox']+ \ inboxButton+'"><span>'+translate['Inbox']+ \
'</span></button></a>' '</span></button></a>'
# typically the blogs button
if defaultTimeline!='tlblogs':
tlStr+= \
' <a href="'+actor+'/tlblogs"><button class="'+ \
blogsButton+'"><span>'+translate['Blogs']+ \
'</span></button></a>'
else:
tlStr+= \
' <a href="'+actor+'/inbox"><button class="'+ \
inboxButton+'"><span>'+translate['Inbox']+ \
'</span></button></a>'
tlStr+= \ tlStr+= \
' <a href="'+actor+'/outbox"><button class="'+ \ ' <a href="'+actor+'/outbox"><button class="'+ \
sentButton+'"><span>'+translate['Outbox']+ \ sentButton+'"><span>'+translate['Outbox']+ \
@ -3792,6 +3818,21 @@ def htmlInboxMedia(defaultTimeline: str, \
nickname,domain,port,inboxJson,'tlmedia',allowDeletion, \ nickname,domain,port,inboxJson,'tlmedia',allowDeletion, \
httpPrefix,projectVersion,False) httpPrefix,projectVersion,False)
def htmlInboxBlogs(defaultTimeline: str, \
recentPostsCache: {},maxRecentPosts: int, \
translate: {},pageNumber: int,itemsPerPage: int, \
session,baseDir: str,wfRequest: {},personCache: {}, \
nickname: str,domain: str,port: int,inboxJson: {}, \
allowDeletion: bool, \
httpPrefix: str,projectVersion: str) -> str:
"""Show the blogs timeline as html
"""
return htmlTimeline(defaultTimeline,recentPostsCache,maxRecentPosts, \
translate,pageNumber, \
itemsPerPage,session,baseDir,wfRequest,personCache, \
nickname,domain,port,inboxJson,'tlblogs',allowDeletion, \
httpPrefix,projectVersion,False)
def htmlModeration(defaultTimeline: str, \ def htmlModeration(defaultTimeline: str, \
recentPostsCache: {},maxRecentPosts: int, \ recentPostsCache: {},maxRecentPosts: int, \
translate: {},pageNumber: int,itemsPerPage: int, \ translate: {},pageNumber: int,itemsPerPage: int, \