From 6b3e9396d747a2f5acb2354b1d41f8f420356863 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Mon, 13 Jul 2020 14:36:45 +0100
Subject: [PATCH 1/7] Check if post was already liked
---
inbox.py | 46 +++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 41 insertions(+), 5 deletions(-)
diff --git a/inbox.py b/inbox.py
index 864def14e..be5af0ce0 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
From 333357400761037f9dba5aa8636524f1e43afaae Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Mon, 13 Jul 2020 20:42:30 +0100
Subject: [PATCH 2/7] Link to who liked a post
---
daemon.py | 19 +++++++++++++++++--
inbox.py | 2 +-
translations/ar.json | 3 ++-
translations/ca.json | 3 ++-
translations/cy.json | 3 ++-
translations/de.json | 3 ++-
translations/en.json | 3 ++-
translations/es.json | 3 ++-
translations/fr.json | 3 ++-
translations/ga.json | 3 ++-
translations/hi.json | 3 ++-
translations/it.json | 3 ++-
translations/ja.json | 3 ++-
translations/oc.json | 3 ++-
translations/pt.json | 3 ++-
translations/ru.json | 3 ++-
translations/zh.json | 3 ++-
webinterface.py | 15 +++++++++++++--
18 files changed, 61 insertions(+), 20 deletions(-)
diff --git a/daemon.py b/daemon.py
index 6795a1504..6b9892f95 100644
--- a/daemon.py
+++ b/daemon.py
@@ -3444,6 +3444,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 +3511,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 +3905,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 +3971,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/inbox.py b/inbox.py
index be5af0ce0..171206ce5 100644
--- a/inbox.py
+++ b/inbox.py
@@ -1775,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..2453e50cd 100644
--- a/webinterface.py
+++ b/webinterface.py
@@ -4983,11 +4983,22 @@ 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)
+ postStr += \
+ '' + translate['Liked by'] + \
+ ' @' + \
+ likedByNickname + '@' + likedByDomain + '
\n'
+ postStr += \
individualPostAsHtml(recentPostsCache, maxRecentPosts,
iconsDir, translate, None,
baseDir, session, wfRequest, personCache,
From 295f2accf827729f6d3fad51ae17741ce798e5e3 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 14 Jul 2020 10:09:33 +0100
Subject: [PATCH 3/7] Button to follow liker
---
follow.py | 2 +-
webinterface.py | 24 +++++++++++++++++++++++-
2 files changed, 24 insertions(+), 2 deletions(-)
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/webinterface.py b/webinterface.py
index 2453e50cd..8099bc338 100644
--- a/webinterface.py
+++ b/webinterface.py
@@ -4994,10 +4994,32 @@ def htmlIndividualPost(recentPostsCache: {}, maxRecentPosts: int,
if likedByPort:
if likedByPort != 80 and likedByPort != 443:
likedByDomain += ':' + str(likedByPort)
+ likedByHandle = likedByNickname + '@' + likedByDomain
postStr += \
'' + translate['Liked by'] + \
' @' + \
- likedByNickname + '@' + likedByDomain + '
\n'
+ 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,
From fac5b6ecb3eed5c044cec52af1515f788f329bd4 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 14 Jul 2020 14:52:47 +0100
Subject: [PATCH 4/7] Notes on notifications
---
epicyon-notification | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
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
# =======
From c28041140f8294badf767ec381844bed12cd0708 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 14 Jul 2020 15:36:18 +0100
Subject: [PATCH 5/7] Arror style tweaks
---
img/icons/starlight/pagedown.png | Bin 3544 -> 3140 bytes
img/icons/starlight/pageup.png | Bin 3565 -> 3103 bytes
img/icons/starlight/prev.png | Bin 3548 -> 3178 bytes
3 files changed, 0 insertions(+), 0 deletions(-)
diff --git a/img/icons/starlight/pagedown.png b/img/icons/starlight/pagedown.png
index 28bbd007415d15c717ff8f6fe0d4936d4a7d25ee..a71972c14e5019105aba2211d5c3b42f72715a91 100644
GIT binary patch
delta 3059
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
B(?tLP
delta 3466
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
diff --git a/img/icons/starlight/pageup.png b/img/icons/starlight/pageup.png
index 40bee46d6fd8c2667ddc994889333bcbbdab0540..ef0e4c0de9d95fb28d7bba4365e33350af15f8c1 100644
GIT binary patch
delta 3046
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
delta 3528
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
delta 3470
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
From 0dd0ffc3d8fc6d6a6de414f1214e548be5e5b7e4 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 14 Jul 2020 18:41:57 +0100
Subject: [PATCH 6/7] handle followers/following pages
---
daemon.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/daemon.py b/daemon.py
index 6b9892f95..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'):
From eceb815cab4c6db050694f3557ec7cbf4f045301 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Tue, 14 Jul 2020 18:50:32 +0100
Subject: [PATCH 7/7] Use userspath
---
webinterface.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/webinterface.py b/webinterface.py
index 8099bc338..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 += \