mirror of https://gitlab.com/bashrc2/epicyon
Merge branch 'main' of ssh://code.freedombone.net:2222/bashrc/epicyon into main
commit
a9375537db
58
daemon.py
58
daemon.py
|
|
@ -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':
|
||||||
|
|
|
||||||
11
roles.py
11
roles.py
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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": "المستشارين"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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í"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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": "सलाहकार"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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": "カウンセラー"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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": "Советники"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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": "辅导员"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue