Merge branch 'main' of ssh://code.freedombone.net:2222/bashrc/epicyon

main
Bob Mottram 2021-06-27 12:57:09 +01:00
commit 3825949bab
8 changed files with 232 additions and 46 deletions

View File

@ -1,22 +1,24 @@
# Roadman # Roadmap
## UX ## UX
* Change animation on buttons (themeable?) * Minimize button shows different icons or highlighting
* Layout of buttons on person options screen
## Teams ## Groups
* Test groups * Unit test for group creation
* Groups can be defined as having particular roles/skills * Groups can be defined as having particular roles/skills
* Templates for different group organizations
## Events ## Questions
* Events timeline * Still not implemented ideally
* Events appear on calendar * Instance-only questions
* Check compatibility with Mobilizon * Active polls screen?
* Questions more integrated into overall organization
## Code ## Code
* Modularize daemon * More unit test coverage
* Move modules out of the daemon * Break up large functions into smaller ones
* Make comment notes linking daemon functions to webinterface * Architecture diagrams
* Code documentation?

92
cwtch.py 100644
View File

@ -0,0 +1,92 @@
__filename__ = "cwtch.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
__version__ = "1.2.0"
__maintainer__ = "Bob Mottram"
__email__ = "bob@freedombone.net"
__status__ = "Production"
__module_group__ = "Profile Metadata"
import re
def getCwtchAddress(actorJson: {}) -> str:
"""Returns cwtch address for the given actor
"""
if not actorJson.get('attachment'):
return ''
for propertyValue in actorJson['attachment']:
if not propertyValue.get('name'):
continue
if not propertyValue['name'].lower().startswith('cwtch'):
continue
if not propertyValue.get('type'):
continue
if not propertyValue.get('value'):
continue
if propertyValue['type'] != 'PropertyValue':
continue
propertyValue['value'] = propertyValue['value'].strip()
if len(propertyValue['value']) < 2:
continue
if '"' in propertyValue['value']:
continue
if ' ' in propertyValue['value']:
continue
if ',' in propertyValue['value']:
continue
if '.' in propertyValue['value']:
continue
return propertyValue['value']
return ''
def setCwtchAddress(actorJson: {}, cwtchAddress: str) -> None:
"""Sets an cwtch address for the given actor
"""
notCwtchAddress = False
if len(cwtchAddress) < 56:
notCwtchAddress = True
if cwtchAddress != cwtchAddress.lower():
notCwtchAddress = True
if not re.match("^[a-z0-9]*$", cwtchAddress):
notCwtchAddress = True
if not actorJson.get('attachment'):
actorJson['attachment'] = []
# remove any existing value
propertyFound = None
for propertyValue in actorJson['attachment']:
if not propertyValue.get('name'):
continue
if not propertyValue.get('type'):
continue
if not propertyValue['name'].lower().startswith('cwtch'):
continue
propertyFound = propertyValue
break
if propertyFound:
actorJson['attachment'].remove(propertyFound)
if notCwtchAddress:
return
for propertyValue in actorJson['attachment']:
if not propertyValue.get('name'):
continue
if not propertyValue.get('type'):
continue
if not propertyValue['name'].lower().startswith('cwtch'):
continue
if propertyValue['type'] != 'PropertyValue':
continue
propertyValue['value'] = cwtchAddress
return
newCwtchAddress = {
"name": "Cwtch",
"type": "PropertyValue",
"value": cwtchAddress
}
actorJson['attachment'].append(newCwtchAddress)

View File

@ -44,6 +44,8 @@ from briar import getBriarAddress
from briar import setBriarAddress from briar import setBriarAddress
from jami import getJamiAddress from jami import getJamiAddress
from jami import setJamiAddress from jami import setJamiAddress
from cwtch import getCwtchAddress
from cwtch import setCwtchAddress
from matrix import getMatrixAddress from matrix import getMatrixAddress
from matrix import setMatrixAddress from matrix import setMatrixAddress
from donate import getDonationUrl from donate import getDonationUrl
@ -4517,6 +4519,18 @@ class PubServer(BaseHTTPRequestHandler):
setJamiAddress(actorJson, '') setJamiAddress(actorJson, '')
actorChanged = True actorChanged = True
# change cwtch address
currentCwtchAddress = getCwtchAddress(actorJson)
if fields.get('cwtchAddress'):
if fields['cwtchAddress'] != currentCwtchAddress:
setCwtchAddress(actorJson,
fields['cwtchAddress'])
actorChanged = True
else:
if currentCwtchAddress:
setCwtchAddress(actorJson, '')
actorChanged = True
# change PGP public key # change PGP public key
currentPGPpubKey = getPGPpubKey(actorJson) currentPGPpubKey = getPGPpubKey(actorJson)
if fields.get('pgp'): if fields.get('pgp'):
@ -5811,6 +5825,7 @@ class PubServer(BaseHTTPRequestHandler):
toxAddress = None toxAddress = None
briarAddress = None briarAddress = None
jamiAddress = None jamiAddress = None
cwtchAddress = None
ssbAddress = None ssbAddress = None
emailAddress = None emailAddress = None
lockedAccount = False lockedAccount = False
@ -5832,6 +5847,7 @@ class PubServer(BaseHTTPRequestHandler):
toxAddress = getToxAddress(actorJson) toxAddress = getToxAddress(actorJson)
briarAddress = getBriarAddress(actorJson) briarAddress = getBriarAddress(actorJson)
jamiAddress = getJamiAddress(actorJson) jamiAddress = getJamiAddress(actorJson)
cwtchAddress = getCwtchAddress(actorJson)
emailAddress = getEmailAddress(actorJson) emailAddress = getEmailAddress(actorJson)
PGPpubKey = getPGPpubKey(actorJson) PGPpubKey = getPGPpubKey(actorJson)
PGPfingerprint = getPGPfingerprint(actorJson) PGPfingerprint = getPGPfingerprint(actorJson)
@ -5866,7 +5882,7 @@ class PubServer(BaseHTTPRequestHandler):
xmppAddress, matrixAddress, xmppAddress, matrixAddress,
ssbAddress, blogAddress, ssbAddress, blogAddress,
toxAddress, briarAddress, toxAddress, briarAddress,
jamiAddress, jamiAddress, cwtchAddress,
PGPpubKey, PGPfingerprint, PGPpubKey, PGPfingerprint,
emailAddress, emailAddress,
self.server.dormantMonths, self.server.dormantMonths,

View File

@ -852,6 +852,30 @@ def _addAutoCW(baseDir: str, nickname: str, domain: str,
return newSubject return newSubject
def _createPostCWFromReply(baseDir: str, nickname: str, domain: str,
inReplyTo: str,
sensitive: bool, summary: str) -> (bool, str):
"""If this is a reply and the original post has a CW
then use the same CW
"""
if inReplyTo and not sensitive:
# locate the post which this is a reply to and check if
# it has a content warning. If it does then reproduce
# the same warning
replyPostFilename = \
locatePost(baseDir, nickname, domain, inReplyTo)
if replyPostFilename:
replyToJson = loadJson(replyPostFilename)
if replyToJson:
if replyToJson.get('object'):
if replyToJson['object'].get('sensitive'):
if replyToJson['object']['sensitive']:
sensitive = True
if replyToJson['object'].get('summary'):
summary = replyToJson['object']['summary']
return sensitive, summary
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, followersOnly: bool, saveToFile: bool,
@ -952,21 +976,9 @@ def _createPostBase(baseDir: str, nickname: str, domain: str, port: int,
_updateHashtagsIndex(baseDir, tag, newPostId) _updateHashtagsIndex(baseDir, tag, newPostId)
# print('Content tags: ' + str(tags)) # print('Content tags: ' + str(tags))
if inReplyTo and not sensitive: sensitive, summary = \
# locate the post which this is a reply to and check if _createPostCWFromReply(baseDir, nickname, domain,
# it has a content warning. If it does then reproduce inReplyTo, sensitive, summary)
# the same warning
replyPostFilename = \
locatePost(baseDir, nickname, domain, inReplyTo)
if replyPostFilename:
replyToJson = loadJson(replyPostFilename)
if replyToJson:
if replyToJson.get('object'):
if replyToJson['object'].get('sensitive'):
if replyToJson['object']['sensitive']:
sensitive = True
if replyToJson['object'].get('summary'):
summary = replyToJson['object']['summary']
# get the ending date and time # get the ending date and time
endDateStr = None endDateStr = None

View File

@ -72,6 +72,27 @@ def removeShare(baseDir: str, nickname: str, domain: str,
'" does not exist in ' + sharesFilename) '" does not exist in ' + sharesFilename)
def _addShareDurationSec(duration: str, published: str) -> int:
"""Returns the duration for the shared item in seconds
"""
if ' ' not in duration:
return 0
durationList = duration.split(' ')
if not durationList[0].isdigit():
return 0
if 'hour' in durationList[1]:
return published + (int(durationList[0]) * 60 * 60)
if 'day' in durationList[1]:
return published + (int(durationList[0]) * 60 * 60 * 24)
if 'week' in durationList[1]:
return published + (int(durationList[0]) * 60 * 60 * 24 * 7)
if 'month' in durationList[1]:
return published + (int(durationList[0]) * 60 * 60 * 24 * 30)
if 'year' in durationList[1]:
return published + (int(durationList[0]) * 60 * 60 * 24 * 365)
return 0
def addShare(baseDir: str, def addShare(baseDir: str,
httpPrefix: str, nickname: str, domain: str, port: int, httpPrefix: str, nickname: str, domain: str, port: int,
displayName: str, summary: str, imageFilename: str, displayName: str, summary: str, imageFilename: str,
@ -86,24 +107,8 @@ def addShare(baseDir: str,
sharesJson = loadJson(sharesFilename) sharesJson = loadJson(sharesFilename)
duration = duration.lower() duration = duration.lower()
durationSec = 0
published = int(time.time()) published = int(time.time())
if ' ' in duration: durationSec = _addShareDurationSec(duration, published)
durationList = duration.split(' ')
if durationList[0].isdigit():
if 'hour' in durationList[1]:
durationSec = published + (int(durationList[0]) * 60 * 60)
if 'day' in durationList[1]:
durationSec = published + (int(durationList[0]) * 60 * 60 * 24)
if 'week' in durationList[1]:
durationSec = \
published + (int(durationList[0]) * 60 * 60 * 24 * 7)
if 'month' in durationList[1]:
durationSec = \
published + (int(durationList[0]) * 60 * 60 * 24 * 30)
if 'year' in durationList[1]:
durationSec = \
published + (int(durationList[0]) * 60 * 60 * 24 * 365)
itemID = getValidSharedItemID(displayName) itemID = getValidSharedItemID(displayName)

View File

@ -2981,6 +2981,7 @@ def _testFunctions():
functionProperties = {} functionProperties = {}
modules = {} modules = {}
modGroups = {} modGroups = {}
methodLOC = []
for subdir, dirs, files in os.walk('.'): for subdir, dirs, files in os.walk('.'):
for sourceFile in files: for sourceFile in files:
@ -2997,6 +2998,9 @@ def _testFunctions():
with open(sourceFile, "r") as f: with open(sourceFile, "r") as f:
lines = f.readlines() lines = f.readlines()
modules[modName]['lines'] = lines modules[modName]['lines'] = lines
lineCount = 0
prevLine = 'start'
methodName = ''
for line in lines: for line in lines:
if '__module_group__' in line: if '__module_group__' in line:
if '=' in line: if '=' in line:
@ -3010,7 +3014,28 @@ def _testFunctions():
if modName not in modGroups[groupName]: if modName not in modGroups[groupName]:
modGroups[groupName].append(modName) modGroups[groupName].append(modName)
if not line.strip().startswith('def '): if not line.strip().startswith('def '):
if lineCount > 0:
lineCount += 1
# add LOC count for this function
if len(prevLine.strip()) == 0 and \
len(line.strip()) == 0 and \
lineCount > 2:
lineCount -= 2
if lineCount > 80:
locStr = str(lineCount) + ';' + methodName
if lineCount < 1000:
locStr = '0' + locStr
if lineCount < 100:
locStr = '0' + locStr
if lineCount < 10:
locStr = '0' + locStr
if locStr not in methodLOC:
methodLOC.append(locStr)
lineCount = 0
prevLine = line
continue continue
prevLine = line
lineCount = 1
methodName = line.split('def ', 1)[1].split('(')[0] methodName = line.split('def ', 1)[1].split('(')[0]
methodArgs = \ methodArgs = \
sourceStr.split('def ' + methodName + '(')[1] sourceStr.split('def ' + methodName + '(')[1]
@ -3027,8 +3052,26 @@ def _testFunctions():
"module": modName, "module": modName,
"calledInModule": [] "calledInModule": []
} }
# LOC count for the last function
if lineCount > 2:
lineCount -= 2
if lineCount > 80:
locStr = str(lineCount) + ';' + methodName
if lineCount < 1000:
locStr = '0' + locStr
if lineCount < 100:
locStr = '0' + locStr
if lineCount < 10:
locStr = '0' + locStr
if locStr not in methodLOC:
methodLOC.append(locStr)
break break
print('LOC counts:')
methodLOC.sort()
for locStr in methodLOC:
print(locStr.split(';')[0] + ' ' + locStr.split(';')[1])
excludeFuncArgs = [ excludeFuncArgs = [
'pyjsonld' 'pyjsonld'
] ]

View File

@ -45,6 +45,7 @@ def htmlPersonOptions(defaultTimeline: str,
toxAddress: str, toxAddress: str,
briarAddress: str, briarAddress: str,
jamiAddress: str, jamiAddress: str,
cwtchAddress: str,
PGPpubKey: str, PGPpubKey: str,
PGPfingerprint: str, PGPfingerprint: str,
emailAddress: str, emailAddress: str,
@ -214,6 +215,9 @@ def htmlPersonOptions(defaultTimeline: str,
if jamiAddress: if jamiAddress:
optionsStr += \ optionsStr += \
'<p class="imText">Jami: ' + removeHtml(jamiAddress) + '</p>\n' '<p class="imText">Jami: ' + removeHtml(jamiAddress) + '</p>\n'
if cwtchAddress:
optionsStr += \
'<p class="imText">Cwtch: ' + removeHtml(cwtchAddress) + '</p>\n'
if PGPfingerprint: if PGPfingerprint:
optionsStr += '<p class="pgp">PGP: ' + \ optionsStr += '<p class="pgp">PGP: ' + \
removeHtml(PGPfingerprint).replace('\n', '<br>') + '</p>\n' removeHtml(PGPfingerprint).replace('\n', '<br>') + '</p>\n'

View File

@ -40,6 +40,7 @@ from pgp import getPGPpubKey
from tox import getToxAddress from tox import getToxAddress
from briar import getBriarAddress from briar import getBriarAddress
from jami import getJamiAddress from jami import getJamiAddress
from cwtch import getCwtchAddress
from filters import isFiltered from filters import isFiltered
from follow import isFollowerOfPerson from follow import isFollowerOfPerson
from webapp_frontscreen import htmlFrontScreen from webapp_frontscreen import htmlFrontScreen
@ -517,9 +518,10 @@ def htmlProfile(rssIconAtTop: bool,
toxAddress = getToxAddress(profileJson) toxAddress = getToxAddress(profileJson)
briarAddress = getBriarAddress(profileJson) briarAddress = getBriarAddress(profileJson)
jamiAddress = getJamiAddress(profileJson) jamiAddress = getJamiAddress(profileJson)
cwtchAddress = getCwtchAddress(profileJson)
if donateUrl or xmppAddress or matrixAddress or \ if donateUrl or xmppAddress or matrixAddress or \
ssbAddress or toxAddress or briarAddress or \ ssbAddress or toxAddress or briarAddress or \
jamiAddress or PGPpubKey or \ jamiAddress or cwtchAddress or PGPpubKey or \
PGPfingerprint or emailAddress: PGPfingerprint or emailAddress:
donateSection = '<div class="container">\n' donateSection = '<div class="container">\n'
donateSection += ' <center>\n' donateSection += ' <center>\n'
@ -560,6 +562,10 @@ def htmlProfile(rssIconAtTop: bool,
donateSection += \ donateSection += \
'<p>Jami: <label class="toxaddr">' + \ '<p>Jami: <label class="toxaddr">' + \
jamiAddress + '</label></p>\n' jamiAddress + '</label></p>\n'
if cwtchAddress:
donateSection += \
'<p>Cwtch: <label class="toxaddr">' + \
cwtchAddress + '</label></p>\n'
if PGPfingerprint: if PGPfingerprint:
donateSection += \ donateSection += \
'<p class="pgp">PGP: ' + \ '<p class="pgp">PGP: ' + \
@ -1063,6 +1069,7 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
toxAddress = getToxAddress(actorJson) toxAddress = getToxAddress(actorJson)
briarAddress = getBriarAddress(actorJson) briarAddress = getBriarAddress(actorJson)
jamiAddress = getJamiAddress(actorJson) jamiAddress = getJamiAddress(actorJson)
cwtchAddress = getCwtchAddress(actorJson)
emailAddress = getEmailAddress(actorJson) emailAddress = getEmailAddress(actorJson)
PGPpubKey = getPGPpubKey(actorJson) PGPpubKey = getPGPpubKey(actorJson)
PGPfingerprint = getPGPfingerprint(actorJson) PGPfingerprint = getPGPfingerprint(actorJson)
@ -1698,6 +1705,11 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
' <input type="text" name="jamiAddress" value="' + \ ' <input type="text" name="jamiAddress" value="' + \
jamiAddress + '">\n' jamiAddress + '">\n'
editProfileForm += '<label class="labels">Cwtch</label><br>\n'
editProfileForm += \
' <input type="text" name="cwtchAddress" value="' + \
cwtchAddress + '">\n'
editProfileForm += \ editProfileForm += \
'<label class="labels">' + \ '<label class="labels">' + \
translate['PGP Fingerprint'] + '</label><br>\n' translate['PGP Fingerprint'] + '</label><br>\n'