diff --git a/daemon.py b/daemon.py index 6795a1504..16ec828dd 100644 --- a/daemon.py +++ b/daemon.py @@ -1744,7 +1744,9 @@ class PubServer(BaseHTTPRequestHandler): divertToLoginScreen = False else: if self.path.endswith('/following') or \ + '/following?page=' in self.path or \ self.path.endswith('/followers') or \ + '/followers?page=' in self.path or \ self.path.endswith('/skills') or \ self.path.endswith('/roles') or \ self.path.endswith('/shares'): @@ -3444,6 +3446,13 @@ class PubServer(BaseHTTPRequestHandler): # get an individual post from the path /@nickname/statusnumber 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] if '/' not in namedStatus: # show actor @@ -3504,7 +3513,8 @@ class PubServer(BaseHTTPRequestHandler): authorized, postJsonObject, httpPrefix, - projectVersion) + projectVersion, + likedBy) msg = msg.encode('utf-8') self._set_headers('text/html', len(msg), cookie, callingDomain) @@ -3897,6 +3907,12 @@ class PubServer(BaseHTTPRequestHandler): # get an individual post from the path # /users/nickname/statuses/number 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] if '/' in namedStatus: postSections = namedStatus.split('/') @@ -3957,7 +3973,8 @@ class PubServer(BaseHTTPRequestHandler): authorized, postJsonObject, httpPrefix, - projectVersion) + projectVersion, + likedBy) msg = msg.encode('utf-8') self._set_headers('text/html', len(msg), diff --git a/epicyon-notification b/epicyon-notification index 1d3d5a8ec..358d5f11b 100755 --- a/epicyon-notification +++ b/epicyon-notification @@ -1,7 +1,12 @@ #!/bin/bash # # 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 # ======= diff --git a/follow.py b/follow.py index b39636547..a66cadf10 100644 --- a/follow.py +++ b/follow.py @@ -84,7 +84,7 @@ def removeFromFollowRejects(baseDir: str, def isFollowingActor(baseDir: str, 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: domain = domain.split(':')[0] diff --git a/img/icons/starlight/pagedown.png b/img/icons/starlight/pagedown.png index 28bbd0074..a71972c14 100644 Binary files a/img/icons/starlight/pagedown.png and b/img/icons/starlight/pagedown.png differ diff --git a/img/icons/starlight/pageup.png b/img/icons/starlight/pageup.png index 40bee46d6..ef0e4c0de 100644 Binary files a/img/icons/starlight/pageup.png and b/img/icons/starlight/pageup.png differ diff --git a/img/icons/starlight/prev.png b/img/icons/starlight/prev.png index e954ae0c6..cf2eb3e6f 100644 Binary files a/img/icons/starlight/prev.png and b/img/icons/starlight/prev.png differ diff --git a/inbox.py b/inbox.py index 864def14e..171206ce5 100644 --- a/inbox.py +++ b/inbox.py @@ -1032,11 +1032,16 @@ def receiveLike(recentPostsCache: {}, if debug: print('DEBUG: liked post found in inbox') - updateLikesCollection(recentPostsCache, baseDir, postFilename, - messageJson['object'], - messageJson['actor'], domain, debug) - likeNotify(baseDir, domain, onionDomain, handle, - messageJson['actor'], messageJson['object']) + if not alreadyLiked(baseDir, + handle.split('@')[0], + handle.split('@')[1], + 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 @@ -1706,6 +1711,37 @@ def dmNotify(baseDir: str, handle: str, url: str) -> None: 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, handle: str, actor: str, url: str) -> None: """Creates a notification that a like has arrived @@ -1739,7 +1775,7 @@ def likeNotify(baseDir: str, domain: str, onionDomain: str, str(likerNickname) + '@' + str(likerDomain)) likerHandle = actor if likerHandle != handle: - likeStr = likerHandle + ' ' + url + likeStr = likerHandle + ' ' + url + '?likedBy=' + actor prevLikeFile = accountDir + '/.prevLike' # was there a previous like notification? if os.path.isfile(prevLikeFile): diff --git a/translations/ar.json b/translations/ar.json index cf3cad0fb..4bd93a6ce 100644 --- a/translations/ar.json +++ b/translations/ar.json @@ -251,5 +251,6 @@ "Unavailable": "غير متوفره", "The server is busy. Please try again later": "الخادم مشغول. الرجاء معاودة المحاولة في وقت لاحق", "Receive calendar events from this account": "تلقي أحداث التقويم من هذا الحساب", - "Grayscale": "درجات الرمادي" + "Grayscale": "درجات الرمادي", + "Liked by": "نال إعجاب" } diff --git a/translations/ca.json b/translations/ca.json index cfb4be41c..ccaebffa1 100644 --- a/translations/ca.json +++ b/translations/ca.json @@ -251,5 +251,6 @@ "Unavailable": "No disponible", "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 d’aquest compte", - "Grayscale": "Escala de grisos" + "Grayscale": "Escala de grisos", + "Liked by": "M'agrada" } diff --git a/translations/cy.json b/translations/cy.json index 508955a57..4544c2de4 100644 --- a/translations/cy.json +++ b/translations/cy.json @@ -251,5 +251,6 @@ "Unavailable": "Ddim ar gael", "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", - "Grayscale": "Graddlwyd" + "Grayscale": "Graddlwyd", + "Liked by": "Hoffi" } diff --git a/translations/de.json b/translations/de.json index 63919ff73..25e70a00e 100644 --- a/translations/de.json +++ b/translations/de.json @@ -251,5 +251,6 @@ "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", "Receive calendar events from this account": "Erhalten Sie Kalenderereignisse von diesem Konto", - "Grayscale": "Graustufen" + "Grayscale": "Graustufen", + "Liked by": "Gefallen von" } diff --git a/translations/en.json b/translations/en.json index 3f8e37521..44a323614 100644 --- a/translations/en.json +++ b/translations/en.json @@ -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" + "Grayscale": "Grayscale", + "Liked by": "Liked by" } diff --git a/translations/es.json b/translations/es.json index a49c3e296..cedb08a47 100644 --- a/translations/es.json +++ b/translations/es.json @@ -251,5 +251,6 @@ "Unavailable": "Indisponible", "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", - "Grayscale": "Escala de grises" + "Grayscale": "Escala de grises", + "Liked by": "Apreciado por" } diff --git a/translations/fr.json b/translations/fr.json index 3b59c6ce2..35413a30d 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -251,5 +251,6 @@ "Unavailable": "Indisponible", "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", - "Grayscale": "Niveaux de gris" + "Grayscale": "Niveaux de gris", + "Liked by": "Aimé par" } diff --git a/translations/ga.json b/translations/ga.json index f905ea89e..89c3d8df4 100644 --- a/translations/ga.json +++ b/translations/ga.json @@ -251,5 +251,6 @@ "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í", "Receive calendar events from this account": "Faigh imeachtaí féilire ón gcuntas seo", - "Grayscale": "Liathscála" + "Grayscale": "Liathscála", + "Liked by": "Thaitin" } diff --git a/translations/hi.json b/translations/hi.json index 253a727a0..7222f66c6 100644 --- a/translations/hi.json +++ b/translations/hi.json @@ -251,5 +251,6 @@ "Unavailable": "अनुपलब्ध", "The server is busy. Please try again later": "सर्वर व्यस्त है। बाद में पुन: प्रयास करें", "Receive calendar events from this account": "इस खाते से कैलेंडर ईवेंट प्राप्त करें", - "Grayscale": "ग्रेस्केल" + "Grayscale": "ग्रेस्केल", + "Liked by": "द्वारा पसंद किया गया" } diff --git a/translations/it.json b/translations/it.json index a5d0ace2f..fa88fb7d4 100644 --- a/translations/it.json +++ b/translations/it.json @@ -251,5 +251,6 @@ "Unavailable": "non disponibile", "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", - "Grayscale": "Scala di grigi" + "Grayscale": "Scala di grigi", + "Liked by": "Mi è piaciuto" } diff --git a/translations/ja.json b/translations/ja.json index 33574f2c2..7952606c5 100644 --- a/translations/ja.json +++ b/translations/ja.json @@ -251,5 +251,6 @@ "Unavailable": "利用できません", "The server is busy. Please try again later": "サーバーはビジーです。 後でもう一度やり直してください", "Receive calendar events from this account": "このアカウントからカレンダーイベントを受信します", - "Grayscale": "グレースケール" + "Grayscale": "グレースケール", + "Liked by": "好き" } diff --git a/translations/oc.json b/translations/oc.json index e1f09dfd5..006a4f40a 100644 --- a/translations/oc.json +++ b/translations/oc.json @@ -247,5 +247,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" + "Grayscale": "Grayscale", + "Liked by": "Liked by" } diff --git a/translations/pt.json b/translations/pt.json index fa1299000..930e15d55 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -251,5 +251,6 @@ "Unavailable": "Indisponível", "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", - "Grayscale": "Escala de cinza" + "Grayscale": "Escala de cinza", + "Liked by": "Curtida por" } diff --git a/translations/ru.json b/translations/ru.json index c15f68cd4..bf69ce736 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -251,5 +251,6 @@ "Unavailable": "Недоступен", "The server is busy. Please try again later": "Сервер занят. Пожалуйста, попробуйте позже", "Receive calendar events from this account": "Получать события календаря от этого аккаунта", - "Grayscale": "Оттенки серого" + "Grayscale": "Оттенки серого", + "Liked by": "Понравилось" } diff --git a/translations/zh.json b/translations/zh.json index a1886a2c8..8b8c89c38 100644 --- a/translations/zh.json +++ b/translations/zh.json @@ -250,5 +250,6 @@ "Unavailable": "不可用", "The server is busy. Please try again later": "服务器忙。 请稍后再试", "Receive calendar events from this account": "从该帐户接收日历事件", - "Grayscale": "灰阶" + "Grayscale": "灰阶", + "Liked by": "喜欢的人" } diff --git a/webinterface.py b/webinterface.py index ecc49606b..ad7db9acb 100644 --- a/webinterface.py +++ b/webinterface.py @@ -2821,7 +2821,7 @@ def htmlProfile(defaultTimeline: str, domain, port, session, wfRequest, personCache, extraJson, projectVersion, ["unfollow"], selected, - actor, pageNumber, maxItemsPerPage) + usersPath, pageNumber, maxItemsPerPage) if selected == 'followers': profileStr += \ htmlProfileFollowing(translate, baseDir, httpPrefix, @@ -2829,7 +2829,7 @@ def htmlProfile(defaultTimeline: str, domain, port, session, wfRequest, personCache, extraJson, projectVersion, ["block"], - selected, actor, pageNumber, + selected, usersPath, pageNumber, maxItemsPerPage) if selected == 'roles': profileStr += \ @@ -4983,11 +4983,44 @@ def htmlIndividualPost(recentPostsCache: {}, maxRecentPosts: int, baseDir: str, session, wfRequest: {}, personCache: {}, nickname: str, domain: str, port: int, authorized: bool, postJsonObject: {}, httpPrefix: str, - projectVersion: str) -> str: + projectVersion: str, likedBy: str) -> str: """Show an individual post as html """ 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 += \ + '
' + translate['Liked by'] + \ + ' @' + \ + likedByHandle + '' + + domainFull = domain + if port: + if port != 80 and port != 443: + domainFull = domain + ':' + str(port) + actor = '/users/' + nickname + followStr = '
' + postStr += followStr + '\n' + + postStr += \ individualPostAsHtml(recentPostsCache, maxRecentPosts, iconsDir, translate, None, baseDir, session, wfRequest, personCache,