Merge branch 'main' of gitlab.com:bashrc2/epicyon

merge-requests/30/head
Bob Mottram 2022-03-01 19:03:33 +00:00
commit 5a0d104abc
24 changed files with 305 additions and 36 deletions

View File

@ -377,6 +377,7 @@ from fitnessFunctions import fitness_thread
from fitnessFunctions import sorted_watch_points from fitnessFunctions import sorted_watch_points
from fitnessFunctions import html_watch_points_graph from fitnessFunctions import html_watch_points_graph
from siteactive import referer_is_active from siteactive import referer_is_active
from webapp_likers import html_likers_of_post
import os import os
@ -10421,6 +10422,66 @@ class PubServer(BaseHTTPRequestHandler):
self.server.debug) self.server.debug)
return result return result
def _show_likers_of_post(self, authorized: bool,
calling_domain: str, path: str,
base_dir: str, http_prefix: str,
domain: str, domain_full: str, port: int,
onion_domain: str, i2p_domain: str,
getreq_start_time,
proxy_type: str, cookie: str,
debug: str) -> bool:
"""Show the likers of a post
"""
if not authorized:
return False
if '?likers=' not in path:
return False
if '/users/' not in path:
return False
nickname = path.split('/users/')[1]
if '?' in nickname:
nickname = nickname.split('?')[0]
post_url = path.split('?likers=')[1]
if '?' in post_url:
post_url = post_url.split('?')[0]
post_url = post_url.replace('--', '/')
msg = \
html_likers_of_post(base_dir, nickname, domain, port,
post_url, self.server.translate,
http_prefix,
self.server.theme_name,
self.server.access_keys,
self.server.recent_posts_cache,
self.server.max_recent_posts,
self.server.session,
self.server.cached_webfingers,
self.server.person_cache,
self.server.project_version,
self.server.yt_replace_domain,
self.server.twitter_replacement_domain,
self.server.show_published_date_only,
self.server.peertube_instances,
self.server.allow_local_network_access,
self.server.system_language,
self.server.max_like_count,
self.server.signing_priv_key_pem,
self.server.cw_lists,
self.server.lists_enabled,
'inbox', self.server.default_timeline)
if not msg:
self._404()
return True
msg = msg.encode('utf-8')
msglen = len(msg)
self._set_headers('text/html', msglen,
cookie, calling_domain, False)
self._write(msg)
fitness_performance(getreq_start_time, self.server.fitness,
'_GET', '_show_likers_of_post',
self.server.debug)
return True
def _show_post_from_file(self, post_filename: str, liked_by: str, def _show_post_from_file(self, post_filename: str, liked_by: str,
react_by: str, react_emoji: str, react_by: str, react_emoji: str,
authorized: bool, authorized: bool,
@ -16487,6 +16548,22 @@ class PubServer(BaseHTTPRequestHandler):
self.server.getreq_busy = False self.server.getreq_busy = False
return return
# show the likers of a post
if self._show_likers_of_post(authorized,
calling_domain, self.path,
self.server.base_dir,
self.server.http_prefix,
self.server.domain,
self.server.domain_full,
self.server.port,
self.server.onion_domain,
self.server.i2p_domain,
getreq_start_time,
self.server.proxy_type,
cookie, self.server.debug):
self.server.getreq_busy = False
return
fitness_performance(getreq_start_time, self.server.fitness, fitness_performance(getreq_start_time, self.server.fitness,
'_GET', 'individual post done', '_GET', 'individual post done',
self.server.debug) self.server.debug)

View File

@ -24,7 +24,7 @@ Moderators rely upon your reports. Don't assume that something of concern has al
Content found to be non-compliant with this policy will be removed and any accounts on this instance producing, repeating or linking to such content will be deleted typically without prior notification. Content found to be non-compliant with this policy will be removed and any accounts on this instance producing, repeating or linking to such content will be deleted typically without prior notification.
### Federation Policy ### Federation Policy
In a proactive effort to avoid the classic fate of *"embrace, extend, extinguish"* this system will block any instance launched, acquired or funded by Alphabet/Google, Facebook, Twitter, Microsoft, Apple, Amazon, Elsevier or other monopolistic Silicon Valley companies. In a proactive effort to avoid the classic fate of *"embrace, extend, extinguish"* this system will block any instance launched, acquired or funded by Alphabet/Google, Facebook/Meta, Twitter, Microsoft, Apple, Amazon, Elsevier or other monopolistic Silicon Valley companies.
This system will not federate with instances whose moderation policy is incompatible with the content policy described above. If an instance lacks a moderation policy, or refuses to enforce one, it will be assumed to be incompatible. This system will not federate with instances whose moderation policy is incompatible with the content policy described above. If an instance lacks a moderation policy, or refuses to enforce one, it will be assumed to be incompatible.

View File

@ -1,6 +1,12 @@
@charset "UTF-8"; @charset "UTF-8";
:root { :root {
--likes-names-margin: 2%;
--likes-names-size1: 30px;
--likes-names-size2: 40px;
--liker-names-margin: 2%;
--liker-names-vertical-spacing1: 50px;
--liker-names-vertical-spacing2: 100px;
--pwa-theme-color: apple-mobile-web-app-status-bar-style; --pwa-theme-color: apple-mobile-web-app-status-bar-style;
--pwa-theme-background-color: black-translucent; --pwa-theme-background-color: black-translucent;
--avatar-rounding: 10%; --avatar-rounding: 10%;
@ -54,8 +60,14 @@
--font-size4: 18px; --font-size4: 18px;
--font-size5: 16px; --font-size5: 16px;
--font-size-likes: 14px; --font-size-likes: 14px;
--font-size-likes-mobile: 32px; --font-size-likes-mobile: 64px;
--font-size-likes-tiny: 16px; --font-size-likes-tiny: 16px;
--likes-margin-left-tiny: 10px;
--likes-margin-right-tiny: 10px;
--likes-margin-top-tiny: -10px;
--likes-margin-left-mobile: 20px;
--likes-margin-right-mobile: 0px;
--likes-margin-top-mobile: 0px;
--font-size-pgp-key: 16px; --font-size-pgp-key: 16px;
--font-size-pgp-key2: 18px; --font-size-pgp-key2: 18px;
--font-size-tox: 16px; --font-size-tox: 16px;
@ -166,8 +178,6 @@
--containericons-vertical-align-mobile: 1%; --containericons-vertical-align-mobile: 1%;
--containericons-vertical-align-tiny: 0.5%; --containericons-vertical-align-tiny: 0.5%;
--likes-count-offset: 5px; --likes-count-offset: 5px;
--likes-count-offset-mobile: 10px;
--likes-count-offset-tiny: 5px;
--publish-button-vertical-offset: 10px; --publish-button-vertical-offset: 10px;
--publish-button-bottom-offset: 10px; --publish-button-bottom-offset: 10px;
--banner-height: 20vh; --banner-height: 20vh;
@ -1078,6 +1088,12 @@ div.container {
font-size: var(--font-size); font-size: var(--font-size);
color: var(--title-color); color: var(--title-color);
} }
.likerNames {
font-size: var(--liker-names-size1);
font-family: Arial, Helvetica, sans-serif;
margin: var(--liker-names-margin);
line-height: var(--liker-names-vertical-spacing1);
}
.profileHeader img.vcard { .profileHeader img.vcard {
width: var(--vcard-icon-size); width: var(--vcard-icon-size);
float: right; float: right;
@ -1845,6 +1861,12 @@ div.container {
blockquote { blockquote {
font-size: var(--quote-font-size-mobile); font-size: var(--quote-font-size-mobile);
} }
.likerNames {
font-size: var(--liker-names-size2);
font-family: Arial, Helvetica, sans-serif;
margin: var(--liker-names-margin);
line-height: var(--liker-names-vertical-spacing2);
}
.profileHeader img.vcard { .profileHeader img.vcard {
width: var(--vcard-icon-size-mobile); width: var(--vcard-icon-size-mobile);
float: right; float: right;
@ -2026,9 +2048,9 @@ div.container {
.likesCount { .likesCount {
font-size: var(--font-size-likes-mobile); font-size: var(--font-size-likes-mobile);
font-family: 'NimbusSanL'; font-family: 'NimbusSanL';
float: right; margin-left: var(--likes-margin-left-mobile);
padding: 32px 0; margin-right: var(--likes-margin-right-mobile);
transform: translateX(var(--likes-count-offset-mobile)); margin-top: var(--likes-margin-top-mobile);
font-weight: bold; font-weight: bold;
} }
.container p.administeredby { .container p.administeredby {
@ -2584,6 +2606,12 @@ div.container {
blockquote { blockquote {
font-size: var(--quote-font-size-tiny); font-size: var(--quote-font-size-tiny);
} }
.likerNames {
font-size: var(--font-size2);
font-family: 'NimbusSanL';
margin: var(--liker-names-margin);
line-height: var(--liker-names-vertical-spacing2);
}
.profileHeader img.vcard { .profileHeader img.vcard {
width: var(--vcard-icon-size-tiny); width: var(--vcard-icon-size-tiny);
float: right; float: right;
@ -2765,9 +2793,9 @@ div.container {
.likesCount { .likesCount {
font-size: var(--font-size-likes-tiny); font-size: var(--font-size-likes-tiny);
font-family: 'NimbusSanL'; font-family: 'NimbusSanL';
float: right; margin-left: var(--likes-margin-left-tiny);
padding: 32px 0; margin-right: var(--likes-margin-right-tiny);
transform: translateX(var(--likes-count-offset-tiny)); margin-top: var(--likes-margin-top-tiny);
font-weight: bold; font-weight: bold;
} }
.container p.administeredby { .container p.administeredby {

View File

@ -36,7 +36,7 @@ from posts import get_person_box
def no_of_likes(post_json_object: {}) -> int: def no_of_likes(post_json_object: {}) -> int:
"""Returns the number of likes ona given post """Returns the number of likes on a given post
""" """
obj = post_json_object obj = post_json_object
if has_object_dict(post_json_object): if has_object_dict(post_json_object):

View File

@ -1,4 +1,8 @@
{ {
"font-size-likes-mobile": "64px",
"likes-margin-left-mobile": "20px",
"likes-margin-right-mobile": "0px",
"likes-margin-top-mobile": "0px",
"pwa-theme-color": "apple-mobile-web-app-status-bar-style", "pwa-theme-color": "apple-mobile-web-app-status-bar-style",
"pwa-theme-background-color": "black-translucent", "pwa-theme-background-color": "black-translucent",
"dropdown-fg-color": "#d5c7b7", "dropdown-fg-color": "#d5c7b7",

View File

@ -511,5 +511,6 @@
"Lots of things": "أشياء كثيرة", "Lots of things": "أشياء كثيرة",
"Created": "مخلوق", "Created": "مخلوق",
"It is done": "تم", "It is done": "تم",
"Time Zone": "وحدة زمنية" "Time Zone": "وحدة زمنية",
"Show who liked this post": "أظهر من أحب هذا المنشور"
} }

View File

@ -511,5 +511,6 @@
"Lots of things": "Moltes coses", "Lots of things": "Moltes coses",
"Created": "Creat", "Created": "Creat",
"It is done": "Esta fet", "It is done": "Esta fet",
"Time Zone": "Fus horari" "Time Zone": "Fus horari",
"Show who liked this post": "Mostra a qui li agrada aquesta publicació"
} }

View File

@ -511,5 +511,6 @@
"Lots of things": "Llawer o pethau", "Lots of things": "Llawer o pethau",
"Created": "Wedi creu", "Created": "Wedi creu",
"It is done": "Mae'n cael ei wneud", "It is done": "Mae'n cael ei wneud",
"Time Zone": "Parth Amser" "Time Zone": "Parth Amser",
"Show who liked this post": "Dangoswch pwy oedd yn hoffi'r post hwn"
} }

View File

@ -511,5 +511,6 @@
"Lots of things": "Viele Dinge", "Lots of things": "Viele Dinge",
"Created": "Erstellt", "Created": "Erstellt",
"It is done": "Es ist vollbracht", "It is done": "Es ist vollbracht",
"Time Zone": "Zeitzone" "Time Zone": "Zeitzone",
"Show who liked this post": "Zeigen, wem dieser Beitrag gefallen hat"
} }

View File

@ -511,5 +511,6 @@
"Lots of things": "Lots of things", "Lots of things": "Lots of things",
"Created": "Created", "Created": "Created",
"It is done": "It is done", "It is done": "It is done",
"Time Zone": "Time Zone" "Time Zone": "Time Zone",
"Show who liked this post": "Show who liked this post"
} }

View File

@ -511,5 +511,6 @@
"Lots of things": "Muchas cosas", "Lots of things": "Muchas cosas",
"Created": "Creada", "Created": "Creada",
"It is done": "Se hace", "It is done": "Se hace",
"Time Zone": "Zona horaria" "Time Zone": "Zona horaria",
"Show who liked this post": "Mostrar a quién le gustó esta publicación"
} }

View File

@ -511,5 +511,6 @@
"Lots of things": "Beaucoup de choses", "Lots of things": "Beaucoup de choses",
"Created": "Créé", "Created": "Créé",
"It is done": "C'est fait", "It is done": "C'est fait",
"Time Zone": "Fuseau horaire" "Time Zone": "Fuseau horaire",
"Show who liked this post": "Montrer qui a aimé ce post"
} }

View File

@ -511,5 +511,6 @@
"Lots of things": "A lán rudaí", "Lots of things": "A lán rudaí",
"Created": "Cruthaithe", "Created": "Cruthaithe",
"It is done": "Déantar é", "It is done": "Déantar é",
"Time Zone": "Crios Ama" "Time Zone": "Crios Ama",
"Show who liked this post": "Taispeáin cé a thaitin an postáil seo"
} }

View File

@ -511,5 +511,6 @@
"Lots of things": "बहुत सी बातें", "Lots of things": "बहुत सी बातें",
"Created": "बनाया था", "Created": "बनाया था",
"It is done": "हो गया है", "It is done": "हो गया है",
"Time Zone": "समय क्षेत्र" "Time Zone": "समय क्षेत्र",
"Show who liked this post": "दिखाएँ कि इस पोस्ट को किसने पसंद किया"
} }

View File

@ -511,5 +511,6 @@
"Lots of things": "Un sacco di cose", "Lots of things": "Un sacco di cose",
"Created": "Creata", "Created": "Creata",
"It is done": "È fatta", "It is done": "È fatta",
"Time Zone": "Fuso orario" "Time Zone": "Fuso orario",
"Show who liked this post": "Mostra a chi è piaciuto questo post"
} }

View File

@ -511,5 +511,6 @@
"Lots of things": "多くの物", "Lots of things": "多くの物",
"Created": "作成した", "Created": "作成した",
"It is done": "されております", "It is done": "されております",
"Time Zone": "タイムゾーン" "Time Zone": "タイムゾーン",
"Show who liked this post": "この投稿を高く評価した人を表示する"
} }

View File

@ -511,5 +511,6 @@
"Lots of things": "Gelek tişt", "Lots of things": "Gelek tişt",
"Created": "Afirandin", "Created": "Afirandin",
"It is done": "Tê kirin", "It is done": "Tê kirin",
"Time Zone": "Qada demê" "Time Zone": "Qada demê",
"Show who liked this post": "Nîşan bide kê ev post eciband"
} }

View File

@ -507,5 +507,6 @@
"Lots of things": "Lots of things", "Lots of things": "Lots of things",
"Created": "Created", "Created": "Created",
"It is done": "It is done", "It is done": "It is done",
"Time Zone": "Time Zone" "Time Zone": "Time Zone",
"Show who liked this post": "Show who liked this post"
} }

View File

@ -511,5 +511,6 @@
"Lots of things": "Muitas coisas", "Lots of things": "Muitas coisas",
"Created": "Criada", "Created": "Criada",
"It is done": "Está feito", "It is done": "Está feito",
"Time Zone": "Fuso horário" "Time Zone": "Fuso horário",
"Show who liked this post": "Mostrar quem gostou deste post"
} }

View File

@ -511,5 +511,6 @@
"Lots of things": "Много всего", "Lots of things": "Много всего",
"Created": "Созданный", "Created": "Созданный",
"It is done": "Сделано", "It is done": "Сделано",
"Time Zone": "Часовой пояс" "Time Zone": "Часовой пояс",
"Show who liked this post": "Показать, кому понравился этот пост"
} }

View File

@ -511,5 +511,6 @@
"Lots of things": "Mambo mengi", "Lots of things": "Mambo mengi",
"Created": "Imeundwa", "Created": "Imeundwa",
"It is done": "Imefanyika", "It is done": "Imefanyika",
"Time Zone": "Eneo la Saa" "Time Zone": "Eneo la Saa",
"Show who liked this post": "Onyesha ni nani aliyependa chapisho hili"
} }

View File

@ -511,5 +511,6 @@
"Lots of things": "很多事情", "Lots of things": "很多事情",
"Created": "已创建", "Created": "已创建",
"It is done": "完成了", "It is done": "完成了",
"Time Zone": "时区" "Time Zone": "时区",
"Show who liked this post": "显示谁喜欢这篇文章"
} }

136
webapp_likers.py 100644
View File

@ -0,0 +1,136 @@
__filename__ = "webapp_likers.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
__version__ = "1.3.0"
__maintainer__ = "Bob Mottram"
__email__ = "bob@libreserver.org"
__status__ = "Production"
__module_group__ = "ActivityPub"
import os
from utils import locate_post
from utils import get_config_param
from utils import get_account_timezone
from utils import get_display_name
from utils import get_nickname_from_actor
from utils import has_object_dict
from utils import load_json
from webapp_utils import html_header_with_external_style
from webapp_utils import html_footer
from webapp_utils import get_banner_file
from webapp_post import individual_post_as_html
def html_likers_of_post(base_dir: str, nickname: str,
domain: str, port: int,
post_url: str, translate: {},
http_prefix: str,
theme: str, access_keys: {},
recent_posts_cache: {}, max_recent_posts: int,
session, cached_webfingers: {},
person_cache: {},
project_version: str,
yt_replace_domain: str,
twitter_replacement_domain: str,
show_published_date_only: bool,
peertube_instances: [],
allow_local_network_access: bool,
system_language: str,
max_like_count: int, signing_priv_key_pem: str,
cw_lists: {}, lists_enabled: str,
boxName: str, default_timeline: str) -> str:
"""Returns html for a screen showing who liked a post
"""
css_filename = base_dir + '/epicyon-profile.css'
if os.path.isfile(base_dir + '/epicyon.css'):
css_filename = base_dir + '/epicyon.css'
instance_title = get_config_param(base_dir, 'instanceTitle')
html_str = \
html_header_with_external_style(css_filename, instance_title, None)
# get the post which was liked
filename = locate_post(base_dir, nickname, domain, post_url)
if not filename:
return None
post_json_object = load_json(filename)
if not post_json_object:
return None
if not post_json_object.get('actor') or not post_json_object.get('object'):
return None
# show the top banner
banner_file, _ = \
get_banner_file(base_dir, nickname, domain, theme)
html_str += \
'<header>\n' + \
'<a href="/users/' + nickname + '/' + default_timeline + \
'" title="' + \
translate['Switch to timeline view'] + '" alt="' + \
translate['Switch to timeline view'] + '" ' + \
'accesskey="' + access_keys['menuTimeline'] + '">\n'
html_str += '<img loading="lazy" class="timeline-banner" src="' + \
'/users/' + nickname + '/' + banner_file + '" alt="" /></a>\n' + \
'</header>\n'
# show the post which was liked
timezone = get_account_timezone(base_dir, nickname, domain)
html_str += \
individual_post_as_html(signing_priv_key_pem,
True, recent_posts_cache,
max_recent_posts,
translate, None,
base_dir, session,
cached_webfingers,
person_cache,
nickname, domain, port,
post_json_object,
None, True, False,
http_prefix,
project_version,
boxName,
yt_replace_domain,
twitter_replacement_domain,
show_published_date_only,
peertube_instances,
allow_local_network_access,
theme, system_language,
max_like_count,
False, False, False,
False, False, False,
cw_lists, lists_enabled,
timezone)
# show likers beneath the post
obj = post_json_object
if has_object_dict(post_json_object):
obj = post_json_object['object']
if not obj.get('likes'):
return None
if not isinstance(obj['likes'], dict):
return None
if not obj['likes'].get('items'):
return None
html_str += '<center><h2>' + translate['Liked by'] + '</h2></center>\n'
likers_list = ''
for like_item in obj['likes']['items']:
if not like_item.get('actor'):
continue
liker_actor = like_item['actor']
liker_display_name = \
get_display_name(base_dir, liker_actor, person_cache)
if liker_display_name:
liker_name = liker_display_name
else:
liker_name = get_nickname_from_actor(liker_actor)
if likers_list:
likers_list += ' '
likers_list += \
'<label class="likerNames">' + \
'<a href="' + liker_actor + '">' + liker_name + '</a>' + \
'</label>'
html_str += '<center>\n' + likers_list + '\n</center>\n'
return html_str + html_footer()

View File

@ -651,22 +651,29 @@ def _get_like_icon_html(nickname: str, domain_full: str,
_log_post_timing(enable_timing_log, post_start_time, '12.2') _log_post_timing(enable_timing_log, post_start_time, '12.2')
like_str = ''
if like_count_str:
# show the number of likes next to icon
like_str += '<label class="likesCount">'
like_str += like_count_str.replace('(', '').replace(')', '').strip()
like_str += '</label>\n'
like_post_id = remove_hash_from_post_id(post_json_object['id']) like_post_id = remove_hash_from_post_id(post_json_object['id'])
like_post_id = remove_id_ending(like_post_id) like_post_id = remove_id_ending(like_post_id)
like_str = ''
if like_count_str:
likers_post_id = like_post_id.replace('/', '--')
likers_screen_link = \
'/users/' + nickname + '?likers=' + likers_post_id
# show the number of likes next to icon
like_str += '<label class="likesCount">'
like_str += '<a href="' + likers_screen_link + '" ' + \
'title="' + translate['Show who liked this post'] + '">'
like_str += like_count_str.replace('(', '').replace(')', '').strip()
like_str += '</a></label>\n'
like_str += \ like_str += \
' <a class="imageAnchor" href="/users/' + nickname + '?' + \ ' <a class="imageAnchor" href="/users/' + nickname + '?' + \
like_link + '=' + like_post_id + \ like_link + '=' + like_post_id + \
page_number_param + \ page_number_param + \
'?actor=' + post_json_object['actor'] + \ '?actor=' + post_json_object['actor'] + \
'?bm=' + timeline_post_bookmark + \ '?bm=' + timeline_post_bookmark + \
'?tl=' + box_name + '" title="' + \ '?tl=' + box_name + '" title="' + like_title + like_count_str + '">\n'
like_title + like_count_str + '">\n'
like_str += \ like_str += \
' ' + \ ' ' + \
'<img loading="lazy" title="' + like_title + like_count_str + \ '<img loading="lazy" title="' + like_title + like_count_str + \