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

main
Bob Mottram 2021-03-09 12:03:02 +00:00
commit a9375537db
21 changed files with 207 additions and 57 deletions

View File

@ -120,6 +120,7 @@ from blocking import getDomainBlocklist
from roles import setRole from roles import setRole
from roles import clearModeratorStatus from roles import clearModeratorStatus
from roles import clearEditorStatus from roles import clearEditorStatus
from roles import clearCounselorStatus
from blog import htmlBlogPageRSS2 from blog import htmlBlogPageRSS2
from blog import htmlBlogPageRSS3 from blog import htmlBlogPageRSS3
from blog import htmlBlogView from blog import htmlBlogView
@ -4728,6 +4729,63 @@ class PubServer(BaseHTTPRequestHandler):
'instance', 'instance',
'editor') 'editor')
# change site counselors list
if fields.get('counselors'):
if path.startswith('/users/' +
adminNickname + '/'):
counselorsFile = \
baseDir + \
'/accounts/counselors.txt'
clearCounselorStatus(baseDir)
if ',' in fields['counselors']:
# if the list was given as comma separated
edFile = open(counselorsFile, "w+")
eds = fields['counselors'].split(',')
for edNick in eds:
edNick = edNick.strip()
edDir = baseDir + \
'/accounts/' + edNick + \
'@' + domain
if os.path.isdir(edDir):
edFile.write(edNick + '\n')
edFile.close()
eds = fields['counselors'].split(',')
for edNick in eds:
edNick = edNick.strip()
edDir = baseDir + \
'/accounts/' + edNick + \
'@' + domain
if os.path.isdir(edDir):
setRole(baseDir,
edNick, domain,
'instance', 'counselor')
else:
# nicknames on separate lines
edFile = open(counselorsFile, "w+")
eds = fields['counselors'].split('\n')
for edNick in eds:
edNick = edNick.strip()
edDir = \
baseDir + \
'/accounts/' + edNick + \
'@' + domain
if os.path.isdir(edDir):
edFile.write(edNick + '\n')
edFile.close()
eds = fields['counselors'].split('\n')
for edNick in eds:
edNick = edNick.strip()
edDir = \
baseDir + \
'/accounts/' + \
edNick + '@' + \
domain
if os.path.isdir(edDir):
setRole(baseDir,
edNick, domain,
'instance',
'counselor')
# remove scheduled posts # remove scheduled posts
if fields.get('removeScheduledPosts'): if fields.get('removeScheduledPosts'):
if fields['removeScheduledPosts'] == 'on': if fields['removeScheduledPosts'] == 'on':

View File

@ -51,6 +51,14 @@ def clearEditorStatus(baseDir: str) -> None:
_clearRoleStatus(baseDir, 'editor') _clearRoleStatus(baseDir, 'editor')
def clearCounselorStatus(baseDir: str) -> None:
"""Removes counselor status from all accounts
This could be slow if there are many users, but only happens
rarely when counselors are appointed or removed
"""
_clearRoleStatus(baseDir, 'editor')
def clearModeratorStatus(baseDir: str) -> None: def clearModeratorStatus(baseDir: str) -> None:
"""Removes moderator status from all accounts """Removes moderator status from all accounts
This could be slow if there are many users, but only happens This could be slow if there are many users, but only happens
@ -119,7 +127,8 @@ def setRole(baseDir: str, nickname: str, domain: str,
roleFiles = { roleFiles = {
"moderator": "moderators.txt", "moderator": "moderators.txt",
"editor": "editors.txt" "editor": "editors.txt",
"counselor": "counselors.txt"
} }
actorJson = loadJson(actorFilename) actorJson = loadJson(actorFilename)

View File

@ -6,7 +6,7 @@
# #
# Something like: # Something like:
# #
# */1 * * * * root /usr/local/bin/epicyon-notification --epicyon yes # */1 * * * * root /usr/local/bin/epicyon-notification
# #
# License # License
# ======= # =======
@ -29,6 +29,8 @@
PROJECT_NAME=epicyon PROJECT_NAME=epicyon
epicyonInstallDir=/opt/${PROJECT_NAME} epicyonInstallDir=/opt/${PROJECT_NAME}
MY_EMAIL_ADDRESS="username@domain"
local_domain=$HOSTNAME local_domain=$HOSTNAME
if [ -f /var/lib/tor/hidden_service_epicyon/hostname ]; then if [ -f /var/lib/tor/hidden_service_epicyon/hostname ]; then
local_domain=$(cat /var/lib/tor/hidden_service_epicyon/hostname) local_domain=$(cat /var/lib/tor/hidden_service_epicyon/hostname)
@ -111,25 +113,41 @@ function sendNotification {
SUBJECT="$2" SUBJECT="$2"
MESSAGE="$3" MESSAGE="$3"
hasSent=
if [ -d /etc/prosody ]; then if [ -d /etc/prosody ]; then
if [ -f /usr/bin/sendxmpp ]; then if [ -f /usr/bin/sendxmpp ]; then
# generate a random password for a temporary user account
notification_user_password=$(openssl rand -base64 32 | tr -dc A-Za-z0-9 | head -c 30 ; echo -n '') notification_user_password=$(openssl rand -base64 32 | tr -dc A-Za-z0-9 | head -c 30 ; echo -n '')
# register a temporary xmpp user account to send the message
if prosodyctl register "notification" "$local_domain" "$notification_user_password"; then if prosodyctl register "notification" "$local_domain" "$notification_user_password"; then
if [[ "$SUBJECT" == *' Tor '* ]]; then if [[ "$SUBJECT" == *' Tor '* ]]; then
MESSAGE="$SUBJECT" MESSAGE="$SUBJECT"
fi fi
if [ -f /usr/bin/sendxmpp ]; then if [ -f /usr/bin/sendxmpp ]; then
# kill any existing message which hasn't sent
kill_sendxmpp_process kill_sendxmpp_process
# send the xmpp notification using the temporary account
echo "${MESSAGE}" | /usr/bin/sendxmpp -u notification -p "${notification_user_password}" -j localhost -o ${local_domain} --message-type=headline -n -t -s ${PROJECT_NAME} ${USERNAME}@${local_domain} echo "${MESSAGE}" | /usr/bin/sendxmpp -u notification -p "${notification_user_password}" -j localhost -o ${local_domain} --message-type=headline -n -t -s ${PROJECT_NAME} ${USERNAME}@${local_domain}
hasSent=1
fi fi
fi fi
# remove the temporary xmpp account
prosodyctl deluser "notification@$local_domain" prosodyctl deluser "notification@$local_domain"
fi fi
fi fi
if [ -d /etc/matrix ]; then if [ -d /etc/matrix ]; then
matrix_server_message "${USERNAME}" "${USERNAME}" "$MESSAGE" matrix_server_message "${USERNAME}" "${USERNAME}" "$MESSAGE"
hasSent=1
fi
if [ ! "$hasSent" ]; then
if [[ "$MY_EMAIL_ADDRESS" != "username@domain" ]]; then
# send to a fixed email address for a single user instance
echo "$MESSAGE" | /usr/bin/mail -s "$SUBJECT" "$MY_EMAIL_ADDRESS"
fi
fi fi
} }
@ -156,7 +174,7 @@ function notifications {
epicyonCalendarfile="$epicyonDir/.newCalendar" epicyonCalendarfile="$epicyonDir/.newCalendar"
if [ -f "$epicyonCalendarfile" ]; then if [ -f "$epicyonCalendarfile" ]; then
if ! grep -q "##sent##" "$epicyonCalendarfile"; then if ! grep -q "##sent##" "$epicyonCalendarfile"; then
epicyonCalendarmessage=$(notification_translate_text 'New calendar event') epicyonCalendarmessage=$(notification_translate_text 'Calendar')
epicyonCalendarfileContent=$(echo "$epicyonCalendarmessage")" "$(cat "$epicyonCalendarfile") epicyonCalendarfileContent=$(echo "$epicyonCalendarmessage")" "$(cat "$epicyonCalendarfile")
if [[ "$epicyonCalendarfileContent" == '/calendar'* ]]; then if [[ "$epicyonCalendarfileContent" == '/calendar'* ]]; then
epicyonCalendarmessage="Epicyon: ${EPICYON_DOMAIN_NAME}/users/${USERNAME}${epicyonCalendarfileContent}" epicyonCalendarmessage="Epicyon: ${EPICYON_DOMAIN_NAME}/users/${USERNAME}${epicyonCalendarfileContent}"
@ -171,7 +189,7 @@ function notifications {
epicyonDMfile="$epicyonDir/.newDM" epicyonDMfile="$epicyonDir/.newDM"
if [ -f "$epicyonDMfile" ]; then if [ -f "$epicyonDMfile" ]; then
if ! grep -q "##sent##" "$epicyonDMfile"; then if ! grep -q "##sent##" "$epicyonDMfile"; then
epicyonDMmessage=$(notification_translate_text 'New direct message') epicyonDMmessage=$(notification_translate_text 'DM')
epicyonDMfileContent=$(echo "$epicyonDMmessage")" "$(cat "$epicyonDMfile") epicyonDMfileContent=$(echo "$epicyonDMmessage")" "$(cat "$epicyonDMfile")
if [[ "$epicyonDMfileContent" == *':'* ]]; then if [[ "$epicyonDMfileContent" == *':'* ]]; then
epicyonDMmessage="Epicyon: $epicyonDMfileContent" epicyonDMmessage="Epicyon: $epicyonDMfileContent"
@ -186,7 +204,7 @@ function notifications {
epicyonLikeFile="$epicyonDir/.newLike" epicyonLikeFile="$epicyonDir/.newLike"
if [ -f "$epicyonLikeFile" ]; then if [ -f "$epicyonLikeFile" ]; then
if ! grep -q "##sent##" "$epicyonLikeFile"; then if ! grep -q "##sent##" "$epicyonLikeFile"; then
epicyonLikeMessage=$(notification_translate_text 'liked your post') epicyonLikeMessage=$(notification_translate_text 'Liked by')
epicyonLikeFileContent=$(cat "$epicyonLikeFile" | awk -F ' ' '{print $1}')" "$(echo "$epicyonLikeMessage")" "$(cat "$epicyonLikeFile" | awk -F ' ' '{print $2}') epicyonLikeFileContent=$(cat "$epicyonLikeFile" | awk -F ' ' '{print $1}')" "$(echo "$epicyonLikeMessage")" "$(cat "$epicyonLikeFile" | awk -F ' ' '{print $2}')
if [[ "$epicyonLikeFileContent" == *':'* ]]; then if [[ "$epicyonLikeFileContent" == *':'* ]]; then
epicyonLikeMessage="Epicyon: $epicyonLikeFileContent" epicyonLikeMessage="Epicyon: $epicyonLikeFileContent"
@ -201,7 +219,7 @@ function notifications {
epicyonReplyFile="$epicyonDir/.newReply" epicyonReplyFile="$epicyonDir/.newReply"
if [ -f "$epicyonReplyFile" ]; then if [ -f "$epicyonReplyFile" ]; then
if ! grep -q "##sent##" "$epicyonReplyFile"; then if ! grep -q "##sent##" "$epicyonReplyFile"; then
epicyonReplyMessage=$(notification_translate_text 'New reply') epicyonReplyMessage=$(notification_translate_text 'Replies')
epicyonReplyFileContent=$(echo "$epicyonReplyMessage")" "$(cat "$epicyonReplyFile") epicyonReplyFileContent=$(echo "$epicyonReplyMessage")" "$(cat "$epicyonReplyFile")
if [[ "$epicyonReplyFileContent" == *':'* ]]; then if [[ "$epicyonReplyFileContent" == *':'* ]]; then
epicyonReplyMessage="Epicyon: $epicyonReplyFileContent" epicyonReplyMessage="Epicyon: $epicyonReplyFileContent"
@ -235,7 +253,7 @@ function notifications {
epicyonShareFile="$epicyonDir/.newShare" epicyonShareFile="$epicyonDir/.newShare"
if [ -f "$epicyonShareFile" ]; then if [ -f "$epicyonShareFile" ]; then
if ! grep -q "##sent##" "$epicyonShareFile"; then if ! grep -q "##sent##" "$epicyonShareFile"; then
epicyonShareMessage=$(notification_translate_text 'New shared item') epicyonShareMessage=$(notification_translate_text 'Shares')
epicyonShareFileContent=$(echo "$epicyonShareMessage")" "$(cat "$epicyonShareFile") epicyonShareFileContent=$(echo "$epicyonShareMessage")" "$(cat "$epicyonShareFile")
if [[ "$epicyonShareFileContent" == *':'* ]]; then if [[ "$epicyonShareFileContent" == *':'* ]]; then
epicyonShareMessage="Epicyon: $epicyonShareFileContent" epicyonShareMessage="Epicyon: $epicyonShareFileContent"
@ -265,7 +283,7 @@ function notifications {
cp "$epicyonFollowFile" "$epicyonFollowNotificationsFile" cp "$epicyonFollowFile" "$epicyonFollowNotificationsFile"
chown ${PROJECT_NAME}:${PROJECT_NAME} "$epicyonFollowNotificationsFile" chown ${PROJECT_NAME}:${PROJECT_NAME} "$epicyonFollowNotificationsFile"
epicyonFollowMessage=$(notification_translate_text "New follow request")" ${EPICYON_DOMAIN_NAME}/users/${USERNAME}/followers" epicyonFollowMessage=$(notification_translate_text 'Approve follower requests')" ${EPICYON_DOMAIN_NAME}/users/${USERNAME}/followers"
sendNotification "$USERNAME" "Epicyon" "$epicyonFollowMessage" sendNotification "$USERNAME" "Epicyon" "$epicyonFollowMessage"
fi fi
fi fi

View File

@ -380,6 +380,9 @@ def _postToSpeakerJson(baseDir: str, nickname: str, domain: str,
content = urllib.parse.unquote_plus(postJsonObject['object']['content']) content = urllib.parse.unquote_plus(postJsonObject['object']['content'])
content = html.unescape(content) content = html.unescape(content)
content = content.replace('<p>', '').replace('</p>', ' ') content = content.replace('<p>', '').replace('</p>', ' ')
# replace some emoji before removing html
if ' <3' in content:
content = content.replace(' <3', ' ' + translate['heart'])
content = removeHtml(htmlReplaceQuoteMarks(content)) content = removeHtml(htmlReplaceQuoteMarks(content))
content = speakerReplaceLinks(content, translate, detectedLinks) content = speakerReplaceLinks(content, translate, detectedLinks)
content = _speakerPronounce(baseDir, content, translate) content = _speakerPronounce(baseDir, content, translate)

View File

@ -396,5 +396,8 @@
"Filtering and Blocking": "التصفية والحظر", "Filtering and Blocking": "التصفية والحظر",
"Role Assignment": "تعيين الدور", "Role Assignment": "تعيين الدور",
"Contact Details": "بيانات المتصل", "Contact Details": "بيانات المتصل",
"Background Images": "صور الخلفية" "Background Images": "صور الخلفية",
"heart": "قلب",
"counselor": "مستشار",
"Counselors": "المستشارين"
} }

View File

@ -396,5 +396,8 @@
"Filtering and Blocking": "Filtratge i bloqueig", "Filtering and Blocking": "Filtratge i bloqueig",
"Role Assignment": "Assignació de funcions", "Role Assignment": "Assignació de funcions",
"Contact Details": "Detalls de contacte", "Contact Details": "Detalls de contacte",
"Background Images": "Imatges de fons" "Background Images": "Imatges de fons",
"heart": "cor",
"counselor": "conseller",
"Counselors": "Consellers"
} }

View File

@ -396,5 +396,8 @@
"Filtering and Blocking": "Hidlo a Blocio", "Filtering and Blocking": "Hidlo a Blocio",
"Role Assignment": "Aseiniad Rôl", "Role Assignment": "Aseiniad Rôl",
"Background Images": "Delweddau Cefndir", "Background Images": "Delweddau Cefndir",
"Contact Details": "Manylion cyswllt" "Contact Details": "Manylion cyswllt",
"heart": "galon",
"counselor": "cynghorydd",
"Counselors": "Cynghorwyr"
} }

View File

@ -396,5 +396,8 @@
"Filtering and Blocking": "Filtern und Blockieren", "Filtering and Blocking": "Filtern und Blockieren",
"Role Assignment": "Rollenzuweisung", "Role Assignment": "Rollenzuweisung",
"Background Images": "Hintergrundbilder", "Background Images": "Hintergrundbilder",
"Contact Details": "Kontaktdetails" "Contact Details": "Kontaktdetails",
"heart": "herz",
"counselor": "Beraterin",
"Counselors": "Berater"
} }

View File

@ -396,5 +396,8 @@
"Filtering and Blocking": "Filtering and Blocking", "Filtering and Blocking": "Filtering and Blocking",
"Role Assignment": "Role Assignment", "Role Assignment": "Role Assignment",
"Contact Details": "Contact Details", "Contact Details": "Contact Details",
"Background Images": "Background Images" "Background Images": "Background Images",
"heart": "heart",
"counselor": "counselor",
"Counselors": "Counselors"
} }

View File

@ -396,5 +396,8 @@
"Filtering and Blocking": "Filtrado y bloqueo", "Filtering and Blocking": "Filtrado y bloqueo",
"Role Assignment": "Asignación de roles", "Role Assignment": "Asignación de roles",
"Background Images": "Imágenes de fondo", "Background Images": "Imágenes de fondo",
"Contact Details": "Detalles de contacto" "Contact Details": "Detalles de contacto",
"heart": "corazón",
"counselor": "Consejera",
"Counselors": "Consejeras"
} }

View File

@ -396,5 +396,8 @@
"Filtering and Blocking": "Filtrage et blocage", "Filtering and Blocking": "Filtrage et blocage",
"Role Assignment": "Attribution de rôle", "Role Assignment": "Attribution de rôle",
"Background Images": "Images d'arrière-plan", "Background Images": "Images d'arrière-plan",
"Contact Details": "Détails du contact" "Contact Details": "Détails du contact",
"heart": "cœur",
"counselor": "Conseillère",
"Counselors": "Conseillères"
} }

View File

@ -396,5 +396,8 @@
"Filtering and Blocking": "Scagadh agus Blocáil", "Filtering and Blocking": "Scagadh agus Blocáil",
"Role Assignment": "Sannadh Róil", "Role Assignment": "Sannadh Róil",
"Background Images": "Íomhánna Cúlra", "Background Images": "Íomhánna Cúlra",
"Contact Details": "Sonraí Teagmhála" "Contact Details": "Sonraí Teagmhála",
"heart": "chroí",
"counselor": "Comhairleoir",
"Counselors": "Comhairleoirí"
} }

View File

@ -396,5 +396,8 @@
"Filtering and Blocking": "छानना और अवरुद्ध करना", "Filtering and Blocking": "छानना और अवरुद्ध करना",
"Role Assignment": "भूमिका असाइनमेंट", "Role Assignment": "भूमिका असाइनमेंट",
"Background Images": "पृष्ठभूमि छवियों", "Background Images": "पृष्ठभूमि छवियों",
"Contact Details": "सम्पर्क करने का विवरण" "Contact Details": "सम्पर्क करने का विवरण",
"heart": "दिल",
"counselor": "काउंसलर",
"Counselors": "सलाहकार"
} }

View File

@ -396,5 +396,8 @@
"Filtering and Blocking": "Filtraggio e blocco", "Filtering and Blocking": "Filtraggio e blocco",
"Role Assignment": "Assegnazione del ruolo", "Role Assignment": "Assegnazione del ruolo",
"Background Images": "Immagini di sfondo", "Background Images": "Immagini di sfondo",
"Contact Details": "Dettagli del contatto" "Contact Details": "Dettagli del contatto",
"heart": "cuore",
"counselor": "Consulente",
"Counselors": "Consiglieri"
} }

View File

@ -396,5 +396,8 @@
"Filtering and Blocking": "フィルタリングとブロッキング", "Filtering and Blocking": "フィルタリングとブロッキング",
"Role Assignment": "役割の割り当て", "Role Assignment": "役割の割り当て",
"Background Images": "背景画像", "Background Images": "背景画像",
"Contact Details": "連絡先の詳細" "Contact Details": "連絡先の詳細",
"heart": "ハート",
"counselor": "カウンセラー",
"Counselors": "カウンセラー"
} }

View File

@ -396,5 +396,8 @@
"Filtering and Blocking": "Fîlterkirin û Astengkirin", "Filtering and Blocking": "Fîlterkirin û Astengkirin",
"Role Assignment": "Erk Rol", "Role Assignment": "Erk Rol",
"Contact Details": "Agahdariyên Têkiliyê", "Contact Details": "Agahdariyên Têkiliyê",
"Background Images": "Wêneyên Paşê" "Background Images": "Wêneyên Paşê",
"heart": "dil",
"counselor": "Pêşnîyarvan",
"Counselors": "Selêwirmendan"
} }

View File

@ -392,5 +392,8 @@
"Filtering and Blocking": "Filtering and Blocking", "Filtering and Blocking": "Filtering and Blocking",
"Role Assignment": "Role Assignment", "Role Assignment": "Role Assignment",
"Background Images": "Background Images", "Background Images": "Background Images",
"Contact Details": "Contact Details" "Contact Details": "Contact Details",
"heart": "heart",
"counselor": "Counselors",
"Counselors": "Counselors"
} }

View File

@ -396,5 +396,8 @@
"Filtering and Blocking": "Filtragem e Bloqueio", "Filtering and Blocking": "Filtragem e Bloqueio",
"Role Assignment": "Atribuição de Função", "Role Assignment": "Atribuição de Função",
"Background Images": "Imagens de fundo", "Background Images": "Imagens de fundo",
"Contact Details": "Detalhes do contato" "Contact Details": "Detalhes do contato",
"heart": "coração",
"counselor": "Conselheira",
"Counselors": "Conselheiras"
} }

View File

@ -396,5 +396,8 @@
"Filtering and Blocking": "Фильтрация и блокировка", "Filtering and Blocking": "Фильтрация и блокировка",
"Role Assignment": "Назначение ролей", "Role Assignment": "Назначение ролей",
"Background Images": "Фоновые изображения", "Background Images": "Фоновые изображения",
"Contact Details": "Контактная информация" "Contact Details": "Контактная информация",
"heart": "сердце",
"counselor": "Советник",
"Counselors": "Советники"
} }

View File

@ -396,5 +396,8 @@
"Filtering and Blocking": "过滤和阻止", "Filtering and Blocking": "过滤和阻止",
"Role Assignment": "角色分配", "Role Assignment": "角色分配",
"Background Images": "背景图片", "Background Images": "背景图片",
"Contact Details": "联系方式" "Contact Details": "联系方式",
"heart": "心",
"counselor": "顾问",
"Counselors": "辅导员"
} }

View File

@ -1387,6 +1387,20 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
' <textarea id="message" name="editors" placeholder="" ' + \ ' <textarea id="message" name="editors" placeholder="" ' + \
'style="height:200px" spellcheck="false">' + \ 'style="height:200px" spellcheck="false">' + \
editors + '</textarea>' editors + '</textarea>'
# counselors
counselors = ''
counselorsFile = baseDir + '/accounts/counselors.txt'
if os.path.isfile(counselorsFile):
with open(counselorsFile, "r") as f:
counselors = f.read()
roleAssignStr += ' <b><label class="labels">' + \
translate['Counselors'] + '</label></b><br>\n'
roleAssignStr += \
' <textarea id="message" name="counselors" ' + \
'placeholder="" ' + \
'style="height:200px" spellcheck="false">' + \
counselors + '</textarea>'
roleAssignStr += ' </div></details>\n' roleAssignStr += ' </div></details>\n'
# Video section # Video section