mirror of https://gitlab.com/bashrc2/epicyon
Merge branch 'main' of ssh://code.freedombone.net:2222/bashrc/epicyon
commit
3825949bab
|
|
@ -1,22 +1,24 @@
|
|||
# Roadman
|
||||
# Roadmap
|
||||
|
||||
## 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
|
||||
* Templates for different group organizations
|
||||
|
||||
## Events
|
||||
## Questions
|
||||
|
||||
* Events timeline
|
||||
* Events appear on calendar
|
||||
* Check compatibility with Mobilizon
|
||||
* Still not implemented ideally
|
||||
* Instance-only questions
|
||||
* Active polls screen?
|
||||
* Questions more integrated into overall organization
|
||||
|
||||
## Code
|
||||
|
||||
* Modularize daemon
|
||||
* Move modules out of the daemon
|
||||
* Make comment notes linking daemon functions to webinterface
|
||||
* More unit test coverage
|
||||
* Break up large functions into smaller ones
|
||||
* Architecture diagrams
|
||||
* Code documentation?
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
18
daemon.py
18
daemon.py
|
|
@ -44,6 +44,8 @@ from briar import getBriarAddress
|
|||
from briar import setBriarAddress
|
||||
from jami import getJamiAddress
|
||||
from jami import setJamiAddress
|
||||
from cwtch import getCwtchAddress
|
||||
from cwtch import setCwtchAddress
|
||||
from matrix import getMatrixAddress
|
||||
from matrix import setMatrixAddress
|
||||
from donate import getDonationUrl
|
||||
|
|
@ -4517,6 +4519,18 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
setJamiAddress(actorJson, '')
|
||||
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
|
||||
currentPGPpubKey = getPGPpubKey(actorJson)
|
||||
if fields.get('pgp'):
|
||||
|
|
@ -5811,6 +5825,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
toxAddress = None
|
||||
briarAddress = None
|
||||
jamiAddress = None
|
||||
cwtchAddress = None
|
||||
ssbAddress = None
|
||||
emailAddress = None
|
||||
lockedAccount = False
|
||||
|
|
@ -5832,6 +5847,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
toxAddress = getToxAddress(actorJson)
|
||||
briarAddress = getBriarAddress(actorJson)
|
||||
jamiAddress = getJamiAddress(actorJson)
|
||||
cwtchAddress = getCwtchAddress(actorJson)
|
||||
emailAddress = getEmailAddress(actorJson)
|
||||
PGPpubKey = getPGPpubKey(actorJson)
|
||||
PGPfingerprint = getPGPfingerprint(actorJson)
|
||||
|
|
@ -5866,7 +5882,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
xmppAddress, matrixAddress,
|
||||
ssbAddress, blogAddress,
|
||||
toxAddress, briarAddress,
|
||||
jamiAddress,
|
||||
jamiAddress, cwtchAddress,
|
||||
PGPpubKey, PGPfingerprint,
|
||||
emailAddress,
|
||||
self.server.dormantMonths,
|
||||
|
|
|
|||
42
posts.py
42
posts.py
|
|
@ -852,6 +852,30 @@ def _addAutoCW(baseDir: str, nickname: str, domain: str,
|
|||
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,
|
||||
toUrl: str, ccUrl: str, httpPrefix: str, content: str,
|
||||
followersOnly: bool, saveToFile: bool,
|
||||
|
|
@ -952,21 +976,9 @@ def _createPostBase(baseDir: str, nickname: str, domain: str, port: int,
|
|||
_updateHashtagsIndex(baseDir, tag, newPostId)
|
||||
# print('Content tags: ' + str(tags))
|
||||
|
||||
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']
|
||||
sensitive, summary = \
|
||||
_createPostCWFromReply(baseDir, nickname, domain,
|
||||
inReplyTo, sensitive, summary)
|
||||
|
||||
# get the ending date and time
|
||||
endDateStr = None
|
||||
|
|
|
|||
39
shares.py
39
shares.py
|
|
@ -72,6 +72,27 @@ def removeShare(baseDir: str, nickname: str, domain: str,
|
|||
'" 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,
|
||||
httpPrefix: str, nickname: str, domain: str, port: int,
|
||||
displayName: str, summary: str, imageFilename: str,
|
||||
|
|
@ -86,24 +107,8 @@ def addShare(baseDir: str,
|
|||
sharesJson = loadJson(sharesFilename)
|
||||
|
||||
duration = duration.lower()
|
||||
durationSec = 0
|
||||
published = int(time.time())
|
||||
if ' ' in duration:
|
||||
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)
|
||||
durationSec = _addShareDurationSec(duration, published)
|
||||
|
||||
itemID = getValidSharedItemID(displayName)
|
||||
|
||||
|
|
|
|||
43
tests.py
43
tests.py
|
|
@ -2981,6 +2981,7 @@ def _testFunctions():
|
|||
functionProperties = {}
|
||||
modules = {}
|
||||
modGroups = {}
|
||||
methodLOC = []
|
||||
|
||||
for subdir, dirs, files in os.walk('.'):
|
||||
for sourceFile in files:
|
||||
|
|
@ -2997,6 +2998,9 @@ def _testFunctions():
|
|||
with open(sourceFile, "r") as f:
|
||||
lines = f.readlines()
|
||||
modules[modName]['lines'] = lines
|
||||
lineCount = 0
|
||||
prevLine = 'start'
|
||||
methodName = ''
|
||||
for line in lines:
|
||||
if '__module_group__' in line:
|
||||
if '=' in line:
|
||||
|
|
@ -3010,7 +3014,28 @@ def _testFunctions():
|
|||
if modName not in modGroups[groupName]:
|
||||
modGroups[groupName].append(modName)
|
||||
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
|
||||
prevLine = line
|
||||
lineCount = 1
|
||||
methodName = line.split('def ', 1)[1].split('(')[0]
|
||||
methodArgs = \
|
||||
sourceStr.split('def ' + methodName + '(')[1]
|
||||
|
|
@ -3027,8 +3052,26 @@ def _testFunctions():
|
|||
"module": modName,
|
||||
"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
|
||||
|
||||
print('LOC counts:')
|
||||
methodLOC.sort()
|
||||
for locStr in methodLOC:
|
||||
print(locStr.split(';')[0] + ' ' + locStr.split(';')[1])
|
||||
|
||||
excludeFuncArgs = [
|
||||
'pyjsonld'
|
||||
]
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ def htmlPersonOptions(defaultTimeline: str,
|
|||
toxAddress: str,
|
||||
briarAddress: str,
|
||||
jamiAddress: str,
|
||||
cwtchAddress: str,
|
||||
PGPpubKey: str,
|
||||
PGPfingerprint: str,
|
||||
emailAddress: str,
|
||||
|
|
@ -214,6 +215,9 @@ def htmlPersonOptions(defaultTimeline: str,
|
|||
if jamiAddress:
|
||||
optionsStr += \
|
||||
'<p class="imText">Jami: ' + removeHtml(jamiAddress) + '</p>\n'
|
||||
if cwtchAddress:
|
||||
optionsStr += \
|
||||
'<p class="imText">Cwtch: ' + removeHtml(cwtchAddress) + '</p>\n'
|
||||
if PGPfingerprint:
|
||||
optionsStr += '<p class="pgp">PGP: ' + \
|
||||
removeHtml(PGPfingerprint).replace('\n', '<br>') + '</p>\n'
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ from pgp import getPGPpubKey
|
|||
from tox import getToxAddress
|
||||
from briar import getBriarAddress
|
||||
from jami import getJamiAddress
|
||||
from cwtch import getCwtchAddress
|
||||
from filters import isFiltered
|
||||
from follow import isFollowerOfPerson
|
||||
from webapp_frontscreen import htmlFrontScreen
|
||||
|
|
@ -517,9 +518,10 @@ def htmlProfile(rssIconAtTop: bool,
|
|||
toxAddress = getToxAddress(profileJson)
|
||||
briarAddress = getBriarAddress(profileJson)
|
||||
jamiAddress = getJamiAddress(profileJson)
|
||||
cwtchAddress = getCwtchAddress(profileJson)
|
||||
if donateUrl or xmppAddress or matrixAddress or \
|
||||
ssbAddress or toxAddress or briarAddress or \
|
||||
jamiAddress or PGPpubKey or \
|
||||
jamiAddress or cwtchAddress or PGPpubKey or \
|
||||
PGPfingerprint or emailAddress:
|
||||
donateSection = '<div class="container">\n'
|
||||
donateSection += ' <center>\n'
|
||||
|
|
@ -560,6 +562,10 @@ def htmlProfile(rssIconAtTop: bool,
|
|||
donateSection += \
|
||||
'<p>Jami: <label class="toxaddr">' + \
|
||||
jamiAddress + '</label></p>\n'
|
||||
if cwtchAddress:
|
||||
donateSection += \
|
||||
'<p>Cwtch: <label class="toxaddr">' + \
|
||||
cwtchAddress + '</label></p>\n'
|
||||
if PGPfingerprint:
|
||||
donateSection += \
|
||||
'<p class="pgp">PGP: ' + \
|
||||
|
|
@ -1063,6 +1069,7 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
|
|||
toxAddress = getToxAddress(actorJson)
|
||||
briarAddress = getBriarAddress(actorJson)
|
||||
jamiAddress = getJamiAddress(actorJson)
|
||||
cwtchAddress = getCwtchAddress(actorJson)
|
||||
emailAddress = getEmailAddress(actorJson)
|
||||
PGPpubKey = getPGPpubKey(actorJson)
|
||||
PGPfingerprint = getPGPfingerprint(actorJson)
|
||||
|
|
@ -1698,6 +1705,11 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
|
|||
' <input type="text" name="jamiAddress" value="' + \
|
||||
jamiAddress + '">\n'
|
||||
|
||||
editProfileForm += '<label class="labels">Cwtch</label><br>\n'
|
||||
editProfileForm += \
|
||||
' <input type="text" name="cwtchAddress" value="' + \
|
||||
cwtchAddress + '">\n'
|
||||
|
||||
editProfileForm += \
|
||||
'<label class="labels">' + \
|
||||
translate['PGP Fingerprint'] + '</label><br>\n'
|
||||
|
|
|
|||
Loading…
Reference in New Issue