Add hashtag conversion to html

master
Bob Mottram 2019-08-09 12:12:08 +01:00
parent 9976e016b1
commit 52162d1b9b
4 changed files with 71 additions and 9 deletions

View File

@ -9,6 +9,37 @@ __status__ = "Production"
import os import os
import commentjson import commentjson
def validHashTag(hashtag: str) -> bool:
"""Returns true if the give hashtag contains valid characters
"""
validChars = set('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
if set(hashtag).issubset(validChars):
return True
return False
def addHashTags(wordStr: str,httpPrefix: str,domain: str,replaceHashTags: {},postHashtags: {}) -> bool:
"""Detects hashtags and adds them to the replacements dict
Also updates the hashtags list to be added to the post
"""
if not wordStr.startswith('#'):
return False
if len(wordStr)<2:
return False
if replaceHashTags.get(wordStr):
return True
hashtag=wordStr[1:]
if not validHashTag(hashtag):
return False
hashtagUrl=httpPrefix+"://"+domain+"/tags/"+hashtag
postHashtags[hashtag]= {
'href': hashtagUrl,
'name': '#'+hashtag,
'type': 'Hashtag'
}
replaceHashTags[wordStr]= \
"<a href=\""+hashtagUrl+"\" class=\"mention hashtag\" rel=\"tag\">#<span>"+hashtag+"</span></a>"
return True
def addMention(wordStr: str,httpPrefix: str,following: str,replaceMentions: {},recipients: []) -> bool: def addMention(wordStr: str,httpPrefix: str,following: str,replaceMentions: {},recipients: []) -> bool:
"""Detects mentions and adds them to the replacements dict and recipients list """Detects mentions and adds them to the replacements dict and recipients list
""" """
@ -44,7 +75,7 @@ def addMention(wordStr: str,httpPrefix: str,following: str,replaceMentions: {},r
def addHtmlTags(baseDir: str,httpPrefix: str, \ def addHtmlTags(baseDir: str,httpPrefix: str, \
nickname: str,domain: str,content: str, \ nickname: str,domain: str,content: str, \
recipients: []) -> str: recipients: [],hashtags: {}) -> str:
""" Replaces plaintext mentions such as @nick@domain into html """ Replaces plaintext mentions such as @nick@domain into html
by matching against known following accounts by matching against known following accounts
""" """
@ -53,6 +84,7 @@ def addHtmlTags(baseDir: str,httpPrefix: str, \
wordsOnly=content.replace(',',' ').replace(';',' ').replace('.',' ').replace(':',' ') wordsOnly=content.replace(',',' ').replace(';',' ').replace('.',' ').replace(':',' ')
words=wordsOnly.split(' ') words=wordsOnly.split(' ')
replaceMentions={} replaceMentions={}
replaceHashTags={}
if ':' in domain: if ':' in domain:
domain=domain.split(':')[0] domain=domain.split(':')[0]
followingFilename=baseDir+'/accounts/'+nickname+'@'+domain+'/following.txt' followingFilename=baseDir+'/accounts/'+nickname+'@'+domain+'/following.txt'
@ -70,10 +102,14 @@ def addHtmlTags(baseDir: str,httpPrefix: str, \
for wordStr in words: for wordStr in words:
if addMention(wordStr,httpPrefix,following,replaceMentions,recipients): if addMention(wordStr,httpPrefix,following,replaceMentions,recipients):
continue continue
addHashTags(wordStr,httpPrefix,domain,replaceHashTags,hashtags)
# replace words with their html versions # replace words with their html versions
for wordStr,replaceStr in replaceMentions.items(): for wordStr,replaceStr in replaceMentions.items():
content=content.replace(wordStr,replaceStr) content=content.replace(wordStr,replaceStr)
for wordStr,replaceStr in replaceHashTags.items():
content=content.replace(wordStr,replaceStr)
content=content.replace('\n','</p><p>') content=content.replace('\n','</p><p>')
return '<p>'+content+'</p>' return '<p>'+content+'</p>'

View File

@ -1838,7 +1838,7 @@ class PubServer(BaseHTTPRequestHandler):
addHtmlTags(self.server.baseDir, \ addHtmlTags(self.server.baseDir, \
self.server.httpPrefix, \ self.server.httpPrefix, \
nickname, \ nickname, \
self.server.domain,fields['bio'],[]) self.server.domain,fields['bio'],[],{})
actorChanged=True actorChanged=True
approveFollowers=False approveFollowers=False
if fields.get('approveFollowers'): if fields.get('approveFollowers'):

View File

@ -371,6 +371,22 @@ def savePostToBox(baseDir: str,httpPrefix: str,postId: str, \
commentjson.dump(postJsonObject, fp, indent=4, sort_keys=False) commentjson.dump(postJsonObject, fp, indent=4, sort_keys=False)
return filename return filename
def updateHashtagsIndex(baseDir: str,tag: {},newPostId: str) -> None:
"""Writes the post url for hashtags to a file
This allows posts for a hashtag to be quickly looked up
"""
# create hashtags directory
tagsDir=baseDir+'/tags'
if not os.path.isdir(tagsDir):
os.mkdir(tagsDir)
tagName=tag['name']
tagsFilename=tagsDir+'/'+tagName[1:]+'.txt'
tagFile=open(tagsFilename, "a+")
if not tagFile:
return
tagFile.write(newPostId+'\n')
tagFile.close()
def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
toUrl: str, ccUrl: str, httpPrefix: str, content: str, \ toUrl: str, ccUrl: str, httpPrefix: str, content: str, \
followersOnly: bool, saveToFile: bool, clientToServer: bool, followersOnly: bool, saveToFile: bool, clientToServer: bool,
@ -379,11 +395,15 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
"""Creates a message """Creates a message
""" """
mentionedRecipients=[] mentionedRecipients=[]
tags=[]
hashtagsDict={}
if not clientToServer: if not clientToServer:
# convert content to html # convert content to html
content=addHtmlTags(baseDir,httpPrefix, \ content= \
nickname,domain,content, \ addHtmlTags(baseDir,httpPrefix, \
mentionedRecipients) nickname,domain,content, \
mentionedRecipients, \
hashtagsDict)
if port!=80 and port!=443: if port!=80 and port!=443:
if ':' not in domain: if ':' not in domain:
@ -407,7 +427,13 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
# who to send to # who to send to
toRecipients=[toUrl] + mentionedRecipients toRecipients=[toUrl] + mentionedRecipients
# create a list of hashtags
if hashtagsDict:
for tagName,tag in hashtagsDict.items():
tags.append(tag)
updateHashtagsIndex(baseDir,tag,newPostId)
if not clientToServer: if not clientToServer:
actorUrl=httpPrefix+'://'+domain+'/users/'+nickname actorUrl=httpPrefix+'://'+domain+'/users/'+nickname
@ -449,7 +475,7 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
'en': content 'en': content
}, },
'attachment': [], 'attachment': [],
'tag': [], 'tag': tags,
'replies': { 'replies': {
'id': 'https://'+domain+'/users/'+nickname+'/statuses/'+statusNumber+'/replies', 'id': 'https://'+domain+'/users/'+nickname+'/statuses/'+statusNumber+'/replies',
'type': 'Collection', 'type': 'Collection',
@ -486,7 +512,7 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \
'en': content 'en': content
}, },
'attachment': [], 'attachment': [],
'tag': [], 'tag': tags,
'replies': { 'replies': {
'id': 'https://'+domain+'/users/'+nickname+'/statuses/'+statusNumber+'/replies', 'id': 'https://'+domain+'/users/'+nickname+'/statuses/'+statusNumber+'/replies',
'type': 'Collection', 'type': 'Collection',

View File

@ -353,7 +353,7 @@ def testPostMessageBetweenServers():
sendResult = \ sendResult = \
sendPost(sessionAlice,aliceDir,'alice', aliceDomain, alicePort, \ sendPost(sessionAlice,aliceDir,'alice', aliceDomain, alicePort, \
'bob', bobDomain, bobPort, ccUrl, httpPrefix, \ 'bob', bobDomain, bobPort, ccUrl, httpPrefix, \
'Why is a mouse when it spins?', followersOnly, \ 'Why is a mouse when it spins? #sillyquestion', followersOnly, \
saveToFile, clientToServer,attachedImageFilename, \ saveToFile, clientToServer,attachedImageFilename, \
attachedImageDescription,useBlurhash, federationList, \ attachedImageDescription,useBlurhash, federationList, \
aliceSendThreads, alicePostLog, aliceCachedWebfingers, \ aliceSendThreads, alicePostLog, aliceCachedWebfingers, \