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

main
Bob Mottram 2020-07-14 20:29:04 +01:00
commit 2c4fbbcef6
23 changed files with 135 additions and 29 deletions

View File

@ -1744,7 +1744,9 @@ class PubServer(BaseHTTPRequestHandler):
divertToLoginScreen = False divertToLoginScreen = False
else: else:
if self.path.endswith('/following') or \ if self.path.endswith('/following') or \
'/following?page=' in self.path or \
self.path.endswith('/followers') or \ self.path.endswith('/followers') or \
'/followers?page=' in self.path or \
self.path.endswith('/skills') or \ self.path.endswith('/skills') or \
self.path.endswith('/roles') or \ self.path.endswith('/roles') or \
self.path.endswith('/shares'): self.path.endswith('/shares'):
@ -3444,6 +3446,13 @@ class PubServer(BaseHTTPRequestHandler):
# get an individual post from the path /@nickname/statusnumber # get an individual post from the path /@nickname/statusnumber
if '/@' in self.path: if '/@' in self.path:
likedBy = None
if '?likedBy=' in self.path:
likedBy = self.path.split('?likedBy=')[1].strip()
if '?' in likedBy:
likedBy = likedBy.split('?')[0]
self.path = self.path.split('?likedBy=')[0]
namedStatus = self.path.split('/@')[1] namedStatus = self.path.split('/@')[1]
if '/' not in namedStatus: if '/' not in namedStatus:
# show actor # show actor
@ -3504,7 +3513,8 @@ class PubServer(BaseHTTPRequestHandler):
authorized, authorized,
postJsonObject, postJsonObject,
httpPrefix, httpPrefix,
projectVersion) projectVersion,
likedBy)
msg = msg.encode('utf-8') msg = msg.encode('utf-8')
self._set_headers('text/html', len(msg), self._set_headers('text/html', len(msg),
cookie, callingDomain) cookie, callingDomain)
@ -3897,6 +3907,12 @@ class PubServer(BaseHTTPRequestHandler):
# get an individual post from the path # get an individual post from the path
# /users/nickname/statuses/number # /users/nickname/statuses/number
if '/statuses/' in self.path and '/users/' in self.path: if '/statuses/' in self.path and '/users/' in self.path:
likedBy = None
if '?likedBy=' in self.path:
likedBy = self.path.split('?likedBy=')[1].strip()
if '?' in likedBy:
likedBy = likedBy.split('?')[0]
self.path = self.path.split('?likedBy=')[0]
namedStatus = self.path.split('/users/')[1] namedStatus = self.path.split('/users/')[1]
if '/' in namedStatus: if '/' in namedStatus:
postSections = namedStatus.split('/') postSections = namedStatus.split('/')
@ -3957,7 +3973,8 @@ class PubServer(BaseHTTPRequestHandler):
authorized, authorized,
postJsonObject, postJsonObject,
httpPrefix, httpPrefix,
projectVersion) projectVersion,
likedBy)
msg = msg.encode('utf-8') msg = msg.encode('utf-8')
self._set_headers('text/html', self._set_headers('text/html',
len(msg), len(msg),

View File

@ -1,7 +1,12 @@
#!/bin/bash #!/bin/bash
# #
# This can be called from a crontab entry to send notifications # This can be called from a crontab entry to send notifications
# when Epicyon events occur # when Epicyon events occur. You will need to have
# sendxmpp+prosody or Synapse (matrix) installed.
#
# Something like:
#
# */1 * * * * root /usr/local/bin/epicyon-notification --epicyon yes
# #
# License # License
# ======= # =======

View File

@ -84,7 +84,7 @@ def removeFromFollowRejects(baseDir: str,
def isFollowingActor(baseDir: str, def isFollowingActor(baseDir: str,
nickname: str, domain: str, actor: str) -> bool: nickname: str, domain: str, actor: str) -> bool:
"""Is the given actor a follower of the given nickname? """Is the given nickname following the given actor?
""" """
if ':' in domain: if ':' in domain:
domain = domain.split(':')[0] domain = domain.split(':')[0]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -1032,11 +1032,16 @@ def receiveLike(recentPostsCache: {},
if debug: if debug:
print('DEBUG: liked post found in inbox') print('DEBUG: liked post found in inbox')
updateLikesCollection(recentPostsCache, baseDir, postFilename, if not alreadyLiked(baseDir,
messageJson['object'], handle.split('@')[0],
messageJson['actor'], domain, debug) handle.split('@')[1],
likeNotify(baseDir, domain, onionDomain, handle, messageJson['object'],
messageJson['actor'], messageJson['object']) messageJson['actor']):
updateLikesCollection(recentPostsCache, baseDir, postFilename,
messageJson['object'],
messageJson['actor'], domain, debug)
likeNotify(baseDir, domain, onionDomain, handle,
messageJson['actor'], messageJson['object'])
return True return True
@ -1706,6 +1711,37 @@ def dmNotify(baseDir: str, handle: str, url: str) -> None:
fp.write(url) fp.write(url)
def alreadyLiked(baseDir: str, nickname: str, domain: str,
postUrl: str, likerActor: str) -> bool:
"""Is the given post already liked by the given handle?
"""
postFilename = \
locatePost(baseDir, nickname, domain, postUrl)
if not postFilename:
return False
postJsonObject = loadJson(postFilename, 1)
if not postJsonObject:
return False
if not postJsonObject.get('object'):
return False
if not isinstance(postJsonObject['object'], dict):
return False
if not postJsonObject['object'].get('likes'):
return False
if not postJsonObject['object']['likes'].get('items'):
return False
for like in postJsonObject['object']['likes']['items']:
if not like.get('type'):
continue
if not like.get('actor'):
continue
if like['type'] != 'Like':
continue
if like['actor'] == likerActor:
return True
return False
def likeNotify(baseDir: str, domain: str, onionDomain: str, def likeNotify(baseDir: str, domain: str, onionDomain: str,
handle: str, actor: str, url: str) -> None: handle: str, actor: str, url: str) -> None:
"""Creates a notification that a like has arrived """Creates a notification that a like has arrived
@ -1739,7 +1775,7 @@ def likeNotify(baseDir: str, domain: str, onionDomain: str,
str(likerNickname) + '@' + str(likerDomain)) str(likerNickname) + '@' + str(likerDomain))
likerHandle = actor likerHandle = actor
if likerHandle != handle: if likerHandle != handle:
likeStr = likerHandle + ' ' + url likeStr = likerHandle + ' ' + url + '?likedBy=' + actor
prevLikeFile = accountDir + '/.prevLike' prevLikeFile = accountDir + '/.prevLike'
# was there a previous like notification? # was there a previous like notification?
if os.path.isfile(prevLikeFile): if os.path.isfile(prevLikeFile):

View File

@ -251,5 +251,6 @@
"Unavailable": "غير متوفره", "Unavailable": "غير متوفره",
"The server is busy. Please try again later": "الخادم مشغول. الرجاء معاودة المحاولة في وقت لاحق", "The server is busy. Please try again later": "الخادم مشغول. الرجاء معاودة المحاولة في وقت لاحق",
"Receive calendar events from this account": "تلقي أحداث التقويم من هذا الحساب", "Receive calendar events from this account": "تلقي أحداث التقويم من هذا الحساب",
"Grayscale": "درجات الرمادي" "Grayscale": "درجات الرمادي",
"Liked by": "نال إعجاب"
} }

View File

@ -251,5 +251,6 @@
"Unavailable": "No disponible", "Unavailable": "No disponible",
"The server is busy. Please try again later": "El servidor està ocupat. Siusplau, intenta-ho més tard", "The server is busy. Please try again later": "El servidor està ocupat. Siusplau, intenta-ho més tard",
"Receive calendar events from this account": "Rep esdeveniments del calendari des daquest compte", "Receive calendar events from this account": "Rep esdeveniments del calendari des daquest compte",
"Grayscale": "Escala de grisos" "Grayscale": "Escala de grisos",
"Liked by": "M'agrada"
} }

View File

@ -251,5 +251,6 @@
"Unavailable": "Ddim ar gael", "Unavailable": "Ddim ar gael",
"The server is busy. Please try again later": "Mae'r gweinydd yn brysur. Rho gynnig Arni eto'n hwyrach", "The server is busy. Please try again later": "Mae'r gweinydd yn brysur. Rho gynnig Arni eto'n hwyrach",
"Receive calendar events from this account": "Derbyn digwyddiadau calendr o'r cyfrif hwn", "Receive calendar events from this account": "Derbyn digwyddiadau calendr o'r cyfrif hwn",
"Grayscale": "Graddlwyd" "Grayscale": "Graddlwyd",
"Liked by": "Hoffi"
} }

View File

@ -251,5 +251,6 @@
"Unavailable": "Nicht verfügbar", "Unavailable": "Nicht verfügbar",
"The server is busy. Please try again later": "Der Server ist beschäftigt. Bitte versuchen Sie es später noch einmal", "The server is busy. Please try again later": "Der Server ist beschäftigt. Bitte versuchen Sie es später noch einmal",
"Receive calendar events from this account": "Erhalten Sie Kalenderereignisse von diesem Konto", "Receive calendar events from this account": "Erhalten Sie Kalenderereignisse von diesem Konto",
"Grayscale": "Graustufen" "Grayscale": "Graustufen",
"Liked by": "Gefallen von"
} }

View File

@ -251,5 +251,6 @@
"Unavailable": "Unavailable", "Unavailable": "Unavailable",
"The server is busy. Please try again later": "The server is busy. Please try again later", "The server is busy. Please try again later": "The server is busy. Please try again later",
"Receive calendar events from this account": "Receive calendar events from this account", "Receive calendar events from this account": "Receive calendar events from this account",
"Grayscale": "Grayscale" "Grayscale": "Grayscale",
"Liked by": "Liked by"
} }

View File

@ -251,5 +251,6 @@
"Unavailable": "Indisponible", "Unavailable": "Indisponible",
"The server is busy. Please try again later": "El servidor esta ocupado. Por favor, inténtelo de nuevo más tarde", "The server is busy. Please try again later": "El servidor esta ocupado. Por favor, inténtelo de nuevo más tarde",
"Receive calendar events from this account": "Recibe eventos de calendario de esta cuenta", "Receive calendar events from this account": "Recibe eventos de calendario de esta cuenta",
"Grayscale": "Escala de grises" "Grayscale": "Escala de grises",
"Liked by": "Apreciado por"
} }

View File

@ -251,5 +251,6 @@
"Unavailable": "Indisponible", "Unavailable": "Indisponible",
"The server is busy. Please try again later": "Le serveur est occupé. Veuillez réessayer plus tard", "The server is busy. Please try again later": "Le serveur est occupé. Veuillez réessayer plus tard",
"Receive calendar events from this account": "Recevoir des événements d'agenda de ce compte", "Receive calendar events from this account": "Recevoir des événements d'agenda de ce compte",
"Grayscale": "Niveaux de gris" "Grayscale": "Niveaux de gris",
"Liked by": "Aimé par"
} }

View File

@ -251,5 +251,6 @@
"Unavailable": "Níl sé ar fáil", "Unavailable": "Níl sé ar fáil",
"The server is busy. Please try again later": "Tá an freastalaí gnóthach. Bain triail eile as níos déanaí", "The server is busy. Please try again later": "Tá an freastalaí gnóthach. Bain triail eile as níos déanaí",
"Receive calendar events from this account": "Faigh imeachtaí féilire ón gcuntas seo", "Receive calendar events from this account": "Faigh imeachtaí féilire ón gcuntas seo",
"Grayscale": "Liathscála" "Grayscale": "Liathscála",
"Liked by": "Thaitin"
} }

View File

@ -251,5 +251,6 @@
"Unavailable": "अनुपलब्ध", "Unavailable": "अनुपलब्ध",
"The server is busy. Please try again later": "सर्वर व्यस्त है। बाद में पुन: प्रयास करें", "The server is busy. Please try again later": "सर्वर व्यस्त है। बाद में पुन: प्रयास करें",
"Receive calendar events from this account": "इस खाते से कैलेंडर ईवेंट प्राप्त करें", "Receive calendar events from this account": "इस खाते से कैलेंडर ईवेंट प्राप्त करें",
"Grayscale": "ग्रेस्केल" "Grayscale": "ग्रेस्केल",
"Liked by": "द्वारा पसंद किया गया"
} }

View File

@ -251,5 +251,6 @@
"Unavailable": "non disponibile", "Unavailable": "non disponibile",
"The server is busy. Please try again later": "Il server è occupato. Per favore riprova più tardi", "The server is busy. Please try again later": "Il server è occupato. Per favore riprova più tardi",
"Receive calendar events from this account": "Ricevi eventi di calendario da questo account", "Receive calendar events from this account": "Ricevi eventi di calendario da questo account",
"Grayscale": "Scala di grigi" "Grayscale": "Scala di grigi",
"Liked by": "Mi è piaciuto"
} }

View File

@ -251,5 +251,6 @@
"Unavailable": "利用できません", "Unavailable": "利用できません",
"The server is busy. Please try again later": "サーバーはビジーです。 後でもう一度やり直してください", "The server is busy. Please try again later": "サーバーはビジーです。 後でもう一度やり直してください",
"Receive calendar events from this account": "このアカウントからカレンダーイベントを受信します", "Receive calendar events from this account": "このアカウントからカレンダーイベントを受信します",
"Grayscale": "グレースケール" "Grayscale": "グレースケール",
"Liked by": "好き"
} }

View File

@ -247,5 +247,6 @@
"Unavailable": "Unavailable", "Unavailable": "Unavailable",
"The server is busy. Please try again later": "The server is busy. Please try again later", "The server is busy. Please try again later": "The server is busy. Please try again later",
"Receive calendar events from this account": "Receive calendar events from this account", "Receive calendar events from this account": "Receive calendar events from this account",
"Grayscale": "Grayscale" "Grayscale": "Grayscale",
"Liked by": "Liked by"
} }

View File

@ -251,5 +251,6 @@
"Unavailable": "Indisponível", "Unavailable": "Indisponível",
"The server is busy. Please try again later": "O servidor está ocupado. Por favor, tente novamente mais tarde", "The server is busy. Please try again later": "O servidor está ocupado. Por favor, tente novamente mais tarde",
"Receive calendar events from this account": "Receba eventos da agenda desta conta", "Receive calendar events from this account": "Receba eventos da agenda desta conta",
"Grayscale": "Escala de cinza" "Grayscale": "Escala de cinza",
"Liked by": "Curtida por"
} }

View File

@ -251,5 +251,6 @@
"Unavailable": "Недоступен", "Unavailable": "Недоступен",
"The server is busy. Please try again later": "Сервер занят. Пожалуйста, попробуйте позже", "The server is busy. Please try again later": "Сервер занят. Пожалуйста, попробуйте позже",
"Receive calendar events from this account": "Получать события календаря от этого аккаунта", "Receive calendar events from this account": "Получать события календаря от этого аккаунта",
"Grayscale": "Оттенки серого" "Grayscale": "Оттенки серого",
"Liked by": "Понравилось"
} }

View File

@ -250,5 +250,6 @@
"Unavailable": "不可用", "Unavailable": "不可用",
"The server is busy. Please try again later": "服务器忙。 请稍后再试", "The server is busy. Please try again later": "服务器忙。 请稍后再试",
"Receive calendar events from this account": "从该帐户接收日历事件", "Receive calendar events from this account": "从该帐户接收日历事件",
"Grayscale": "灰阶" "Grayscale": "灰阶",
"Liked by": "喜欢的人"
} }

View File

@ -2821,7 +2821,7 @@ def htmlProfile(defaultTimeline: str,
domain, port, session, domain, port, session,
wfRequest, personCache, extraJson, wfRequest, personCache, extraJson,
projectVersion, ["unfollow"], selected, projectVersion, ["unfollow"], selected,
actor, pageNumber, maxItemsPerPage) usersPath, pageNumber, maxItemsPerPage)
if selected == 'followers': if selected == 'followers':
profileStr += \ profileStr += \
htmlProfileFollowing(translate, baseDir, httpPrefix, htmlProfileFollowing(translate, baseDir, httpPrefix,
@ -2829,7 +2829,7 @@ def htmlProfile(defaultTimeline: str,
domain, port, session, domain, port, session,
wfRequest, personCache, extraJson, wfRequest, personCache, extraJson,
projectVersion, ["block"], projectVersion, ["block"],
selected, actor, pageNumber, selected, usersPath, pageNumber,
maxItemsPerPage) maxItemsPerPage)
if selected == 'roles': if selected == 'roles':
profileStr += \ profileStr += \
@ -4983,11 +4983,44 @@ def htmlIndividualPost(recentPostsCache: {}, maxRecentPosts: int,
baseDir: str, session, wfRequest: {}, personCache: {}, baseDir: str, session, wfRequest: {}, personCache: {},
nickname: str, domain: str, port: int, authorized: bool, nickname: str, domain: str, port: int, authorized: bool,
postJsonObject: {}, httpPrefix: str, postJsonObject: {}, httpPrefix: str,
projectVersion: str) -> str: projectVersion: str, likedBy: str) -> str:
"""Show an individual post as html """Show an individual post as html
""" """
iconsDir = getIconsDir(baseDir) iconsDir = getIconsDir(baseDir)
postStr = \ postStr = ''
if likedBy:
likedByNickname = getNicknameFromActor(likedBy)
likedByDomain, likedByPort = getDomainFromActor(likedBy)
if likedByPort:
if likedByPort != 80 and likedByPort != 443:
likedByDomain += ':' + str(likedByPort)
likedByHandle = likedByNickname + '@' + likedByDomain
postStr += \
'<p>' + translate['Liked by'] + \
' <a href="' + likedBy + '">@' + \
likedByHandle + '</a>'
domainFull = domain
if port:
if port != 80 and port != 443:
domainFull = domain + ':' + str(port)
actor = '/users/' + nickname
followStr = ' <form method="POST" ' + \
'accept-charset="UTF-8" action="' + actor + '/searchhandle">'
followStr += \
' <input type="hidden" name="actor" value="' + actor + '">'
followStr += \
' <input type="hidden" name="searchtext" value="' + \
likedByHandle + '">'
if not isFollowingActor(baseDir, nickname, domainFull, likedBy):
followStr += ' <button type="submit" class="button" ' + \
'name="submitSearch">' + translate['Follow'] + '</button>'
followStr += ' <button type="submit" class="button" ' + \
'name="submitBack">' + translate['Go Back'] + '</button>'
followStr += ' </form>'
postStr += followStr + '</p>\n'
postStr += \
individualPostAsHtml(recentPostsCache, maxRecentPosts, individualPostAsHtml(recentPostsCache, maxRecentPosts,
iconsDir, translate, None, iconsDir, translate, None,
baseDir, session, wfRequest, personCache, baseDir, session, wfRequest, personCache,