Move to external css

merge-requests/30/head
Bob Mottram 2020-11-12 17:05:38 +00:00
parent 96ed5f2696
commit c9ef1cccb1
10 changed files with 395 additions and 492 deletions

126
webapp.py
View File

@ -8,7 +8,6 @@ __status__ = "Production"
import os import os
from shutil import copyfile from shutil import copyfile
from utils import getCSS
from utils import getNicknameFromActor from utils import getNicknameFromActor
from utils import getDomainFromActor from utils import getDomainFromActor
from utils import locatePost from utils import locatePost
@ -16,7 +15,7 @@ from utils import loadJson
from shares import getValidSharedItemID from shares import getValidSharedItemID
from webapp_utils import getAltPath from webapp_utils import getAltPath
from webapp_utils import getIconsDir from webapp_utils import getIconsDir
from webapp_utils import htmlHeader from webapp_utils import htmlHeaderWithExternalStyle
from webapp_utils import htmlFooter from webapp_utils import htmlFooter
from webapp_post import individualPostAsHtml from webapp_post import individualPostAsHtml
@ -34,15 +33,13 @@ def htmlFollowingList(cssCache: {}, baseDir: str,
if os.path.isfile(baseDir + '/epicyon.css'): if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css' cssFilename = baseDir + '/epicyon.css'
profileCSS = getCSS(baseDir, cssFilename, cssCache) followingListHtml = htmlHeaderWithExternalStyle(cssFilename)
if profileCSS: for followingAddress in followingList:
followingListHtml = htmlHeader(cssFilename, profileCSS) if followingAddress:
for followingAddress in followingList: followingListHtml += \
if followingAddress: '<h3>@' + followingAddress + '</h3>'
followingListHtml += \ followingListHtml += htmlFooter()
'<h3>@' + followingAddress + '</h3>' msg = followingListHtml
followingListHtml += htmlFooter()
msg = followingListHtml
return msg return msg
return '' return ''
@ -55,18 +52,16 @@ def htmlHashtagBlocked(cssCache: {}, baseDir: str, translate: {}) -> str:
if os.path.isfile(baseDir + '/suspended.css'): if os.path.isfile(baseDir + '/suspended.css'):
cssFilename = baseDir + '/suspended.css' cssFilename = baseDir + '/suspended.css'
blockedHashtagCSS = getCSS(baseDir, cssFilename, cssCache) blockedHashtagForm = htmlHeaderWithExternalStyle(cssFilename)
if blockedHashtagCSS: blockedHashtagForm += '<div><center>\n'
blockedHashtagForm = htmlHeader(cssFilename, blockedHashtagCSS) blockedHashtagForm += \
blockedHashtagForm += '<div><center>\n' ' <p class="screentitle">' + \
blockedHashtagForm += \ translate['Hashtag Blocked'] + '</p>\n'
' <p class="screentitle">' + \ blockedHashtagForm += \
translate['Hashtag Blocked'] + '</p>\n' ' <p>See <a href="/terms">' + \
blockedHashtagForm += \ translate['Terms of Service'] + '</a></p>\n'
' <p>See <a href="/terms">' + \ blockedHashtagForm += '</center></div>\n'
translate['Terms of Service'] + '</a></p>\n' blockedHashtagForm += htmlFooter()
blockedHashtagForm += '</center></div>\n'
blockedHashtagForm += htmlFooter()
return blockedHashtagForm return blockedHashtagForm
@ -108,8 +103,7 @@ def htmlRemoveSharedItem(cssCache: {}, translate: {}, baseDir: str,
if os.path.isfile(baseDir + '/follow.css'): if os.path.isfile(baseDir + '/follow.css'):
cssFilename = baseDir + '/follow.css' cssFilename = baseDir + '/follow.css'
profileStyle = getCSS(baseDir, cssFilename, cssCache) sharesStr = htmlHeaderWithExternalStyle(cssFilename)
sharesStr = htmlHeader(cssFilename, profileStyle)
sharesStr += '<div class="follow">\n' sharesStr += '<div class="follow">\n'
sharesStr += ' <div class="followAvatar">\n' sharesStr += ' <div class="followAvatar">\n'
sharesStr += ' <center>\n' sharesStr += ' <center>\n'
@ -179,45 +173,40 @@ def htmlDeletePost(cssCache: {},
if os.path.isfile(baseDir + '/epicyon.css'): if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css' cssFilename = baseDir + '/epicyon.css'
profileStyle = getCSS(baseDir, cssFilename, cssCache) deletePostStr = htmlHeaderWithExternalStyle(cssFilename)
if profileStyle: deletePostStr += \
if httpPrefix != 'https': individualPostAsHtml(True, recentPostsCache, maxRecentPosts,
profileStyle = profileStyle.replace('https://', iconsDir, translate, pageNumber,
httpPrefix + '://') baseDir, session, wfRequest, personCache,
deletePostStr = htmlHeader(cssFilename, profileStyle) nickname, domain, port, postJsonObject,
deletePostStr += \ None, True, False,
individualPostAsHtml(True, recentPostsCache, maxRecentPosts, httpPrefix, projectVersion, 'outbox',
iconsDir, translate, pageNumber, YTReplacementDomain,
baseDir, session, wfRequest, personCache, showPublishedDateOnly,
nickname, domain, port, postJsonObject, False, False, False, False, False)
None, True, False, deletePostStr += '<center>'
httpPrefix, projectVersion, 'outbox', deletePostStr += \
YTReplacementDomain, ' <p class="followText">' + \
showPublishedDateOnly, translate['Delete this post?'] + '</p>'
False, False, False, False, False)
deletePostStr += '<center>'
deletePostStr += \
' <p class="followText">' + \
translate['Delete this post?'] + '</p>'
postActor = getAltPath(actor, domainFull, callingDomain) postActor = getAltPath(actor, domainFull, callingDomain)
deletePostStr += \ deletePostStr += \
' <form method="POST" action="' + postActor + '/rmpost">\n' ' <form method="POST" action="' + postActor + '/rmpost">\n'
deletePostStr += \ deletePostStr += \
' <input type="hidden" name="pageNumber" value="' + \ ' <input type="hidden" name="pageNumber" value="' + \
str(pageNumber) + '">\n' str(pageNumber) + '">\n'
deletePostStr += \ deletePostStr += \
' <input type="hidden" name="messageId" value="' + \ ' <input type="hidden" name="messageId" value="' + \
messageId + '">\n' messageId + '">\n'
deletePostStr += \ deletePostStr += \
' <button type="submit" class="button" name="submitYes">' + \ ' <button type="submit" class="button" name="submitYes">' + \
translate['Yes'] + '</button>\n' translate['Yes'] + '</button>\n'
deletePostStr += \ deletePostStr += \
' <a href="' + actor + '/inbox"><button class="button">' + \ ' <a href="' + actor + '/inbox"><button class="button">' + \
translate['No'] + '</button></a>\n' translate['No'] + '</button></a>\n'
deletePostStr += ' </form>\n' deletePostStr += ' </form>\n'
deletePostStr += '</center>\n' deletePostStr += '</center>\n'
deletePostStr += htmlFooter() deletePostStr += htmlFooter()
return deletePostStr return deletePostStr
@ -238,8 +227,7 @@ def htmlFollowConfirm(cssCache: {}, translate: {}, baseDir: str,
if os.path.isfile(baseDir + '/follow.css'): if os.path.isfile(baseDir + '/follow.css'):
cssFilename = baseDir + '/follow.css' cssFilename = baseDir + '/follow.css'
profileStyle = getCSS(baseDir, cssFilename, cssCache) followStr = htmlHeaderWithExternalStyle(cssFilename)
followStr = htmlHeader(cssFilename, profileStyle)
followStr += '<div class="follow">\n' followStr += '<div class="follow">\n'
followStr += ' <div class="followAvatar">\n' followStr += ' <div class="followAvatar">\n'
followStr += ' <center>\n' followStr += ' <center>\n'
@ -283,9 +271,7 @@ def htmlUnfollowConfirm(cssCache: {}, translate: {}, baseDir: str,
if os.path.isfile(baseDir + '/follow.css'): if os.path.isfile(baseDir + '/follow.css'):
cssFilename = baseDir + '/follow.css' cssFilename = baseDir + '/follow.css'
profileStyle = getCSS(baseDir, cssFilename, cssCache) followStr = htmlHeaderWithExternalStyle(cssFilename)
followStr = htmlHeader(cssFilename, profileStyle)
followStr += '<div class="follow">\n' followStr += '<div class="follow">\n'
followStr += ' <div class="followAvatar">\n' followStr += ' <div class="followAvatar">\n'
followStr += ' <center>\n' followStr += ' <center>\n'
@ -330,9 +316,7 @@ def htmlUnblockConfirm(cssCache: {}, translate: {}, baseDir: str,
if os.path.isfile(baseDir + '/follow.css'): if os.path.isfile(baseDir + '/follow.css'):
cssFilename = baseDir + '/follow.css' cssFilename = baseDir + '/follow.css'
profileStyle = getCSS(baseDir, cssFilename, cssCache) blockStr = htmlHeaderWithExternalStyle(cssFilename)
blockStr = htmlHeader(cssFilename, profileStyle)
blockStr += '<div class="block">\n' blockStr += '<div class="block">\n'
blockStr += ' <div class="blockAvatar">\n' blockStr += ' <div class="blockAvatar">\n'
blockStr += ' <center>\n' blockStr += ' <center>\n'

View File

@ -8,9 +8,8 @@ __status__ = "Production"
import os import os
from shutil import copyfile from shutil import copyfile
from utils import getCSS
from utils import getConfigParam from utils import getConfigParam
from webapp_utils import htmlHeader from webapp_utils import htmlHeaderWithExternalStyle
from webapp_utils import htmlFooter from webapp_utils import htmlFooter
@ -38,25 +37,19 @@ def htmlAbout(cssCache: {}, baseDir: str, httpPrefix: str,
if os.path.isfile(baseDir + '/epicyon.css'): if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css' cssFilename = baseDir + '/epicyon.css'
aboutCSS = getCSS(baseDir, cssFilename, cssCache) aboutForm = htmlHeaderWithExternalStyle(cssFilename)
if aboutCSS: aboutForm += '<div class="container">' + aboutText + '</div>'
if httpPrefix != 'http': if onionDomain:
aboutCSS = aboutCSS.replace('https://', aboutForm += \
httpPrefix + '://') '<div class="container"><center>\n' + \
'<p class="administeredby">' + \
aboutForm = htmlHeader(cssFilename, aboutCSS) 'http://' + onionDomain + '</p>\n</center></div>\n'
aboutForm += '<div class="container">' + aboutText + '</div>' if adminNickname:
if onionDomain: adminActor = '/users/' + adminNickname
aboutForm += \ aboutForm += \
'<div class="container"><center>\n' + \ '<div class="container"><center>\n' + \
'<p class="administeredby">' + \ '<p class="administeredby">Administered by <a href="' + \
'http://' + onionDomain + '</p>\n</center></div>\n' adminActor + '">' + adminNickname + '</a></p>\n' + \
if adminNickname: '</center></div>\n'
adminActor = '/users/' + adminNickname aboutForm += htmlFooter()
aboutForm += \
'<div class="container"><center>\n' + \
'<p class="administeredby">Administered by <a href="' + \
adminActor + '">' + adminNickname + '</a></p>\n' + \
'</center></div>\n'
aboutForm += htmlFooter()
return aboutForm return aboutForm

View File

@ -14,11 +14,10 @@ from utils import getNicknameFromActor
from utils import getDomainFromActor from utils import getDomainFromActor
from utils import locatePost from utils import locatePost
from utils import loadJson from utils import loadJson
from utils import getCSS
from utils import weekDayOfMonthStart from utils import weekDayOfMonthStart
from happening import getTodaysEvents from happening import getTodaysEvents
from happening import getCalendarEvents from happening import getCalendarEvents
from webapp_utils import htmlHeader from webapp_utils import htmlHeaderWithExternalStyle
from webapp_utils import htmlFooter from webapp_utils import htmlFooter
from webapp_utils import getAltPath from webapp_utils import getAltPath
from webapp_utils import getIconsDir from webapp_utils import getIconsDir
@ -54,45 +53,40 @@ def htmlCalendarDeleteConfirm(cssCache: {}, translate: {}, baseDir: str,
if os.path.isfile(baseDir + '/epicyon.css'): if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css' cssFilename = baseDir + '/epicyon.css'
profileStyle = getCSS(baseDir, cssFilename, cssCache) deletePostStr = htmlHeaderWithExternalStyle(cssFilename)
if profileStyle: deletePostStr += \
if httpPrefix != 'https': '<center><h1>' + postTime + ' ' + str(year) + '/' + \
profileStyle = profileStyle.replace('https://', str(monthNumber) + \
httpPrefix + '://') '/' + str(dayNumber) + '</h1></center>'
deletePostStr = htmlHeader(cssFilename, profileStyle) deletePostStr += '<center>'
deletePostStr += \ deletePostStr += ' <p class="followText">' + \
'<center><h1>' + postTime + ' ' + str(year) + '/' + \ translate['Delete this event'] + '</p>'
str(monthNumber) + \
'/' + str(dayNumber) + '</h1></center>'
deletePostStr += '<center>'
deletePostStr += ' <p class="followText">' + \
translate['Delete this event'] + '</p>'
postActor = getAltPath(actor, domainFull, callingDomain) postActor = getAltPath(actor, domainFull, callingDomain)
deletePostStr += \ deletePostStr += \
' <form method="POST" action="' + postActor + '/rmpost">\n' ' <form method="POST" action="' + postActor + '/rmpost">\n'
deletePostStr += ' <input type="hidden" name="year" value="' + \ deletePostStr += ' <input type="hidden" name="year" value="' + \
str(year) + '">\n' str(year) + '">\n'
deletePostStr += ' <input type="hidden" name="month" value="' + \ deletePostStr += ' <input type="hidden" name="month" value="' + \
str(monthNumber) + '">\n' str(monthNumber) + '">\n'
deletePostStr += ' <input type="hidden" name="day" value="' + \ deletePostStr += ' <input type="hidden" name="day" value="' + \
str(dayNumber) + '">\n' str(dayNumber) + '">\n'
deletePostStr += \ deletePostStr += \
' <input type="hidden" name="pageNumber" value="1">\n' ' <input type="hidden" name="pageNumber" value="1">\n'
deletePostStr += \ deletePostStr += \
' <input type="hidden" name="messageId" value="' + \ ' <input type="hidden" name="messageId" value="' + \
messageId + '">\n' messageId + '">\n'
deletePostStr += \ deletePostStr += \
' <button type="submit" class="button" name="submitYes">' + \ ' <button type="submit" class="button" name="submitYes">' + \
translate['Yes'] + '</button>\n' translate['Yes'] + '</button>\n'
deletePostStr += \ deletePostStr += \
' <a href="' + actor + '/calendar?year=' + \ ' <a href="' + actor + '/calendar?year=' + \
str(year) + '?month=' + \ str(year) + '?month=' + \
str(monthNumber) + '"><button class="button">' + \ str(monthNumber) + '"><button class="button">' + \
translate['No'] + '</button></a>\n' translate['No'] + '</button></a>\n'
deletePostStr += ' </form>\n' deletePostStr += ' </form>\n'
deletePostStr += '</center>\n' deletePostStr += '</center>\n'
deletePostStr += htmlFooter() deletePostStr += htmlFooter()
return deletePostStr return deletePostStr
@ -112,13 +106,11 @@ def htmlCalendarDay(cssCache: {}, translate: {},
if os.path.isfile(baseDir + '/calendar.css'): if os.path.isfile(baseDir + '/calendar.css'):
cssFilename = baseDir + '/calendar.css' cssFilename = baseDir + '/calendar.css'
calendarStyle = getCSS(baseDir, cssFilename, cssCache)
calActor = actor calActor = actor
if '/users/' in actor: if '/users/' in actor:
calActor = '/users/' + actor.split('/users/')[1] calActor = '/users/' + actor.split('/users/')[1]
calendarStr = htmlHeader(cssFilename, calendarStyle) calendarStr = htmlHeaderWithExternalStyle(cssFilename)
calendarStr += '<main><table class="calendar">\n' calendarStr += '<main><table class="calendar">\n'
calendarStr += '<caption class="calendar__banner--month">\n' calendarStr += '<caption class="calendar__banner--month">\n'
calendarStr += \ calendarStr += \
@ -298,13 +290,11 @@ def htmlCalendar(cssCache: {}, translate: {},
if os.path.isfile(baseDir + '/calendar.css'): if os.path.isfile(baseDir + '/calendar.css'):
cssFilename = baseDir + '/calendar.css' cssFilename = baseDir + '/calendar.css'
calendarStyle = getCSS(baseDir, cssFilename, cssCache)
calActor = actor calActor = actor
if '/users/' in actor: if '/users/' in actor:
calActor = '/users/' + actor.split('/users/')[1] calActor = '/users/' + actor.split('/users/')[1]
calendarStr = htmlHeader(cssFilename, calendarStyle) calendarStr = htmlHeaderWithExternalStyle(cssFilename)
calendarStr += '<main><table class="calendar">\n' calendarStr += '<main><table class="calendar">\n'
calendarStr += '<caption class="calendar__banner--month">\n' calendarStr += '<caption class="calendar__banner--month">\n'
calendarStr += \ calendarStr += \

View File

@ -11,8 +11,7 @@ import time
from shutil import copyfile from shutil import copyfile
from utils import getConfigParam from utils import getConfigParam
from utils import noOfAccounts from utils import noOfAccounts
from utils import getCSS from webapp_utils import htmlHeaderWithExternalStyle
from webapp_utils import htmlHeader
from webapp_utils import htmlFooter from webapp_utils import htmlFooter
@ -100,11 +99,6 @@ def htmlLogin(cssCache: {}, translate: {},
if os.path.isfile(baseDir + '/login.css'): if os.path.isfile(baseDir + '/login.css'):
cssFilename = baseDir + '/login.css' cssFilename = baseDir + '/login.css'
loginCSS = getCSS(baseDir, cssFilename, cssCache)
if not loginCSS:
print('ERROR: login css file missing ' + cssFilename)
return None
# show the register button # show the register button
registerButtonStr = '' registerButtonStr = ''
if getConfigParam(baseDir, 'registration') == 'open': if getConfigParam(baseDir, 'registration') == 'open':
@ -135,7 +129,7 @@ def htmlLogin(cssCache: {}, translate: {},
if not autocomplete: if not autocomplete:
autocompleteStr = 'autocomplete="off" value=""' autocompleteStr = 'autocomplete="off" value=""'
loginForm = htmlHeader(cssFilename, loginCSS) loginForm = htmlHeaderWithExternalStyle(cssFilename)
loginForm += '<br>\n' loginForm += '<br>\n'
loginForm += '<form method="POST" action="/login">\n' loginForm += '<form method="POST" action="/login">\n'
loginForm += ' <div class="imgcontainer">\n' loginForm += ' <div class="imgcontainer">\n'

View File

@ -7,9 +7,8 @@ __email__ = "bob@freedombone.net"
__status__ = "Production" __status__ = "Production"
import os import os
from utils import getCSS
from webapp_timeline import htmlTimeline from webapp_timeline import htmlTimeline
from webapp_utils import htmlHeader from webapp_utils import htmlHeaderWithExternalStyle
from webapp_utils import htmlFooter from webapp_utils import htmlFooter
@ -56,56 +55,51 @@ def htmlModerationInfo(cssCache: {}, translate: {},
if os.path.isfile(baseDir + '/epicyon.css'): if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css' cssFilename = baseDir + '/epicyon.css'
infoCSS = getCSS(baseDir, cssFilename, cssCache) infoForm = htmlHeaderWithExternalStyle(cssFilename)
if infoCSS:
if httpPrefix != 'https':
infoCSS = infoCSS.replace('https://',
httpPrefix + '://')
infoForm = htmlHeader(cssFilename, infoCSS)
infoForm += \ infoForm += \
'<center><h1>' + \ '<center><h1>' + \
translate['Moderation Information'] + \ translate['Moderation Information'] + \
'</h1></center>' '</h1></center>'
infoShown = False infoShown = False
suspendedFilename = baseDir + '/accounts/suspended.txt' suspendedFilename = baseDir + '/accounts/suspended.txt'
if os.path.isfile(suspendedFilename): if os.path.isfile(suspendedFilename):
with open(suspendedFilename, "r") as f: with open(suspendedFilename, "r") as f:
suspendedStr = f.read() suspendedStr = f.read()
infoForm += '<div class="container">' infoForm += '<div class="container">'
infoForm += ' <br><b>' + \ infoForm += ' <br><b>' + \
translate['Suspended accounts'] + '</b>' translate['Suspended accounts'] + '</b>'
infoForm += ' <br>' + \ infoForm += ' <br>' + \
translate['These are currently suspended'] translate['These are currently suspended']
infoForm += \
' <textarea id="message" ' + \
'name="suspended" style="height:200px">' + \
suspendedStr + '</textarea>'
infoForm += '</div>'
infoShown = True
blockingFilename = baseDir + '/accounts/blocking.txt'
if os.path.isfile(blockingFilename):
with open(blockingFilename, "r") as f:
blockedStr = f.read()
infoForm += '<div class="container">'
infoForm += \
' <br><b>' + \
translate['Blocked accounts and hashtags'] + '</b>'
infoForm += \
' <br>' + \
translate[msgStr1]
infoForm += \
' <textarea id="message" ' + \
'name="blocked" style="height:700px">' + \
blockedStr + '</textarea>'
infoForm += '</div>'
infoShown = True
if not infoShown:
infoForm += \ infoForm += \
'<center><p>' + \ ' <textarea id="message" ' + \
translate[msgStr2] + \ 'name="suspended" style="height:200px">' + \
'</p></center>' suspendedStr + '</textarea>'
infoForm += htmlFooter() infoForm += '</div>'
infoShown = True
blockingFilename = baseDir + '/accounts/blocking.txt'
if os.path.isfile(blockingFilename):
with open(blockingFilename, "r") as f:
blockedStr = f.read()
infoForm += '<div class="container">'
infoForm += \
' <br><b>' + \
translate['Blocked accounts and hashtags'] + '</b>'
infoForm += \
' <br>' + \
translate[msgStr1]
infoForm += \
' <textarea id="message" ' + \
'name="blocked" style="height:700px">' + \
blockedStr + '</textarea>'
infoForm += '</div>'
infoShown = True
if not infoShown:
infoForm += \
'<center><p>' + \
translate[msgStr2] + \
'</p></center>'
infoForm += htmlFooter()
return infoForm return infoForm

View File

@ -13,11 +13,10 @@ from person import isPersonSnoozed
from posts import isModerator from posts import isModerator
from utils import getDomainFromActor from utils import getDomainFromActor
from utils import getNicknameFromActor from utils import getNicknameFromActor
from utils import getCSS
from blocking import isBlocked from blocking import isBlocked
from follow import isFollowingActor from follow import isFollowingActor
from followingCalendar import receivingCalendarEvents from followingCalendar import receivingCalendarEvents
from webapp_utils import htmlHeader from webapp_utils import htmlHeaderWithExternalStyle
from webapp_utils import htmlFooter from webapp_utils import htmlFooter
@ -83,19 +82,6 @@ def htmlPersonOptions(defaultTimeline: str,
if os.path.isfile(baseDir + '/options.css'): if os.path.isfile(baseDir + '/options.css'):
cssFilename = baseDir + '/options.css' cssFilename = baseDir + '/options.css'
profileStyle = getCSS(baseDir, cssFilename, cssCache)
if profileStyle:
profileStyle = \
profileStyle.replace('--follow-text-entry-width: 90%;',
'--follow-text-entry-width: 20%;')
if not os.path.isfile(baseDir + '/accounts/' +
'options-background.jpg'):
profileStyle = \
profileStyle.replace('background-image: ' +
'url("options-background.jpg");',
'background-image: none;')
# To snooze, or not to snooze? That is the question # To snooze, or not to snooze? That is the question
snoozeButtonStr = 'Snooze' snoozeButtonStr = 'Snooze'
if nickname: if nickname:
@ -109,7 +95,7 @@ def htmlPersonOptions(defaultTimeline: str,
'"><button class="button" name="submitDonate">' + \ '"><button class="button" name="submitDonate">' + \
translate['Donate'] + '</button></a>\n' translate['Donate'] + '</button></a>\n'
optionsStr = htmlHeader(cssFilename, profileStyle) optionsStr = htmlHeaderWithExternalStyle(cssFilename)
optionsStr += '<br><br>\n' optionsStr += '<br><br>\n'
optionsStr += '<div class="options">\n' optionsStr += '<div class="options">\n'
optionsStr += ' <div class="optionsAvatar">\n' optionsStr += ' <div class="optionsAvatar">\n'

View File

@ -25,7 +25,6 @@ from posts import downloadAnnounce
from posts import populateRepliesJson from posts import populateRepliesJson
from utils import locatePost from utils import locatePost
from utils import loadJson from utils import loadJson
from utils import getCSS
from utils import getCachedPostDirectory from utils import getCachedPostDirectory
from utils import getCachedPostFilename from utils import getCachedPostFilename
from utils import getProtocolPrefixes from utils import getProtocolPrefixes
@ -55,7 +54,7 @@ from webapp_utils import postContainsPublic
from webapp_utils import getContentWarningButton from webapp_utils import getContentWarningButton
from webapp_utils import getPostAttachmentsAsHtml from webapp_utils import getPostAttachmentsAsHtml
from webapp_utils import getIconsDir from webapp_utils import getIconsDir
from webapp_utils import htmlHeader from webapp_utils import htmlHeaderWithExternalStyle
from webapp_utils import htmlFooter from webapp_utils import htmlFooter
from webapp_media import addEmbeddedElements from webapp_media import addEmbeddedElements
from webapp_question import insertQuestion from webapp_question import insertQuestion
@ -1338,12 +1337,7 @@ def htmlIndividualPost(cssCache: {},
if os.path.isfile(baseDir + '/epicyon.css'): if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css' cssFilename = baseDir + '/epicyon.css'
postsCSS = getCSS(baseDir, cssFilename, cssCache) return htmlHeaderWithExternalStyle(cssFilename) + postStr + htmlFooter()
if postsCSS:
if httpPrefix != 'https':
postsCSS = postsCSS.replace('https://',
httpPrefix + '://')
return htmlHeader(cssFilename, postsCSS) + postStr + htmlFooter()
def htmlPostReplies(cssCache: {}, def htmlPostReplies(cssCache: {},
@ -1376,9 +1370,4 @@ def htmlPostReplies(cssCache: {},
if os.path.isfile(baseDir + '/epicyon.css'): if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css' cssFilename = baseDir + '/epicyon.css'
postsCSS = getCSS(baseDir, cssFilename, cssCache) return htmlHeaderWithExternalStyle(cssFilename) + repliesStr + htmlFooter()
if postsCSS:
if httpPrefix != 'https':
postsCSS = postsCSS.replace('https://',
httpPrefix + '://')
return htmlHeader(cssFilename, postsCSS) + repliesStr + htmlFooter()

View File

@ -10,7 +10,6 @@ import os
from pprint import pprint from pprint import pprint
from utils import getNicknameFromActor from utils import getNicknameFromActor
from utils import getDomainFromActor from utils import getDomainFromActor
from utils import getCSS
from utils import isSystemAccount from utils import isSystemAccount
from utils import removeHtml from utils import removeHtml
from utils import loadJson from utils import loadJson
@ -34,7 +33,7 @@ from tox import getToxAddress
from webapp_utils import scheduledPostsExist from webapp_utils import scheduledPostsExist
from webapp_utils import getPersonAvatarUrl from webapp_utils import getPersonAvatarUrl
from webapp_utils import getIconsDir from webapp_utils import getIconsDir
from webapp_utils import htmlHeader from webapp_utils import htmlHeaderWithExternalStyle
from webapp_utils import htmlFooter from webapp_utils import htmlFooter
from webapp_utils import addEmojiToDisplayName from webapp_utils import addEmojiToDisplayName
from webapp_utils import headerButtonsFrontScreen from webapp_utils import headerButtonsFrontScreen
@ -108,171 +107,165 @@ def htmlProfileAfterSearch(cssCache: {},
if os.path.isfile(baseDir + '/epicyon.css'): if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css' cssFilename = baseDir + '/epicyon.css'
profileStyle = getCSS(baseDir, cssFilename, cssCache) wf = \
if profileStyle: webfingerHandle(session,
wf = \ searchNickname + '@' + searchDomainFull,
webfingerHandle(session, httpPrefix, cachedWebfingers,
searchNickname + '@' + searchDomainFull, domain, projectVersion)
httpPrefix, cachedWebfingers, if not wf:
domain, projectVersion) print('DEBUG: Unable to webfinger ' +
if not wf: searchNickname + '@' + searchDomainFull)
print('DEBUG: Unable to webfinger ' + print('DEBUG: cachedWebfingers ' + str(cachedWebfingers))
searchNickname + '@' + searchDomainFull) print('DEBUG: httpPrefix ' + httpPrefix)
print('DEBUG: cachedWebfingers ' + str(cachedWebfingers)) print('DEBUG: domain ' + domain)
print('DEBUG: httpPrefix ' + httpPrefix) return None
print('DEBUG: domain ' + domain) if not isinstance(wf, dict):
return None print('WARN: Webfinger search for ' +
if not isinstance(wf, dict): searchNickname + '@' + searchDomainFull +
print('WARN: Webfinger search for ' + ' did not return a dict. ' +
searchNickname + '@' + searchDomainFull + str(wf))
' did not return a dict. ' + return None
str(wf))
return None
personUrl = None personUrl = None
if wf.get('errors'): if wf.get('errors'):
personUrl = httpPrefix + '://' + \ personUrl = httpPrefix + '://' + \
searchDomainFull + '/users/' + searchNickname searchDomainFull + '/users/' + searchNickname
profileStr = 'https://www.w3.org/ns/activitystreams' profileStr = 'https://www.w3.org/ns/activitystreams'
asHeader = {
'Accept': 'application/activity+json; profile="' + profileStr + '"'
}
if not personUrl:
personUrl = getUserUrl(wf)
if not personUrl:
# try single user instance
asHeader = { asHeader = {
'Accept': 'application/activity+json; profile="' + profileStr + '"' 'Accept': 'application/ld+json; profile="' + profileStr + '"'
}
personUrl = httpPrefix + '://' + searchDomainFull
profileJson = \
getJson(session, personUrl, asHeader, None,
projectVersion, httpPrefix, domain)
if not profileJson:
asHeader = {
'Accept': 'application/ld+json; profile="' + profileStr + '"'
} }
if not personUrl:
personUrl = getUserUrl(wf)
if not personUrl:
# try single user instance
asHeader = {
'Accept': 'application/ld+json; profile="' + profileStr + '"'
}
personUrl = httpPrefix + '://' + searchDomainFull
profileJson = \ profileJson = \
getJson(session, personUrl, asHeader, None, getJson(session, personUrl, asHeader, None,
projectVersion, httpPrefix, domain) projectVersion, httpPrefix, domain)
if not profileJson: if not profileJson:
asHeader = { print('DEBUG: No actor returned from ' + personUrl)
'Accept': 'application/ld+json; profile="' + profileStr + '"' return None
} avatarUrl = ''
profileJson = \ if profileJson.get('icon'):
getJson(session, personUrl, asHeader, None, if profileJson['icon'].get('url'):
projectVersion, httpPrefix, domain) avatarUrl = profileJson['icon']['url']
if not profileJson: if not avatarUrl:
print('DEBUG: No actor returned from ' + personUrl) avatarUrl = getPersonAvatarUrl(baseDir, personUrl,
return None personCache, True)
avatarUrl = '' displayName = searchNickname
if profileJson.get('icon'): if profileJson.get('name'):
if profileJson['icon'].get('url'): displayName = profileJson['name']
avatarUrl = profileJson['icon']['url'] profileDescription = ''
if not avatarUrl: if profileJson.get('summary'):
avatarUrl = getPersonAvatarUrl(baseDir, personUrl, profileDescription = profileJson['summary']
personCache, True) outboxUrl = None
displayName = searchNickname if not profileJson.get('outbox'):
if profileJson.get('name'): if debug:
displayName = profileJson['name'] pprint(profileJson)
profileDescription = '' print('DEBUG: No outbox found')
if profileJson.get('summary'): return None
profileDescription = profileJson['summary'] outboxUrl = profileJson['outbox']
outboxUrl = None
if not profileJson.get('outbox'):
if debug:
pprint(profileJson)
print('DEBUG: No outbox found')
return None
outboxUrl = profileJson['outbox']
profileBackgroundImage = ''
if profileJson.get('image'):
if profileJson['image'].get('url'):
profileBackgroundImage = profileJson['image']['url']
profileStyle = profileStyle.replace('image.png', # profileBackgroundImage = ''
profileBackgroundImage) # if profileJson.get('image'):
if httpPrefix != 'https': # if profileJson['image'].get('url'):
profileStyle = profileStyle.replace('https://', # profileBackgroundImage = profileJson['image']['url']
httpPrefix + '://')
# url to return to
backUrl = path
if not backUrl.endswith('/inbox'):
backUrl += '/inbox'
profileDescriptionShort = profileDescription # url to return to
if '\n' in profileDescription: backUrl = path
if len(profileDescription.split('\n')) > 2: if not backUrl.endswith('/inbox'):
profileDescriptionShort = '' backUrl += '/inbox'
else:
if '<br>' in profileDescription: profileDescriptionShort = profileDescription
if len(profileDescription.split('<br>')) > 2: if '\n' in profileDescription:
profileDescriptionShort = '' if len(profileDescription.split('\n')) > 2:
# keep the profile description short
if len(profileDescriptionShort) > 256:
profileDescriptionShort = '' profileDescriptionShort = ''
# remove formatting from profile description used on title else:
avatarDescription = '' if '<br>' in profileDescription:
if profileJson.get('summary'): if len(profileDescription.split('<br>')) > 2:
if isinstance(profileJson['summary'], str): profileDescriptionShort = ''
avatarDescription = \ # keep the profile description short
profileJson['summary'].replace('<br>', '\n') if len(profileDescriptionShort) > 256:
avatarDescription = avatarDescription.replace('<p>', '') profileDescriptionShort = ''
avatarDescription = avatarDescription.replace('</p>', '') # remove formatting from profile description used on title
if '<' in avatarDescription: avatarDescription = ''
avatarDescription = removeHtml(avatarDescription) if profileJson.get('summary'):
profileStr = ' <div class="hero-image">\n' if isinstance(profileJson['summary'], str):
profileStr += ' <div class="hero-text">\n' avatarDescription = \
if avatarUrl: profileJson['summary'].replace('<br>', '\n')
profileStr += \ avatarDescription = avatarDescription.replace('<p>', '')
' <img loading="lazy" src="' + avatarUrl + \ avatarDescription = avatarDescription.replace('</p>', '')
'" alt="' + avatarDescription + '" title="' + \ if '<' in avatarDescription:
avatarDescription + '" class="title">\n' avatarDescription = removeHtml(avatarDescription)
profileStr += ' <h1>' + displayName + '</h1>\n' profileStr = ' <div class="hero-image">\n'
profileStr += ' <p><b>@' + searchNickname + '@' + \ profileStr += ' <div class="hero-text">\n'
searchDomainFull + '</b></p>\n' if avatarUrl:
profileStr += ' <p>' + profileDescriptionShort + '</p>\n'
profileStr += ' </div>\n'
profileStr += '</div>\n'
profileStr += '<div class="container">\n'
profileStr += ' <form method="POST" action="' + \
backUrl + '/followconfirm">\n'
profileStr += ' <center>\n'
profileStr += \ profileStr += \
' <input type="hidden" name="actor" value="' + \ ' <img loading="lazy" src="' + avatarUrl + \
personUrl + '">\n' '" alt="' + avatarDescription + '" title="' + \
profileStr += \ avatarDescription + '" class="title">\n'
' <a href="' + backUrl + '"><button class="button">' + \ profileStr += ' <h1>' + displayName + '</h1>\n'
translate['Go Back'] + '</button></a>\n' profileStr += ' <p><b>@' + searchNickname + '@' + \
profileStr += \ searchDomainFull + '</b></p>\n'
' <button type="submit" class="button" name="submitYes">' + \ profileStr += ' <p>' + profileDescriptionShort + '</p>\n'
translate['Follow'] + '</button>\n' profileStr += ' </div>\n'
profileStr += \ profileStr += '</div>\n'
' <button type="submit" class="button" name="submitView">' + \ profileStr += '<div class="container">\n'
translate['View'] + '</button>\n' profileStr += ' <form method="POST" action="' + \
profileStr += ' </center>\n' backUrl + '/followconfirm">\n'
profileStr += ' </form>\n' profileStr += ' <center>\n'
profileStr += '</div>\n' profileStr += \
' <input type="hidden" name="actor" value="' + \
personUrl + '">\n'
profileStr += \
' <a href="' + backUrl + '"><button class="button">' + \
translate['Go Back'] + '</button></a>\n'
profileStr += \
' <button type="submit" class="button" name="submitYes">' + \
translate['Follow'] + '</button>\n'
profileStr += \
' <button type="submit" class="button" name="submitView">' + \
translate['View'] + '</button>\n'
profileStr += ' </center>\n'
profileStr += ' </form>\n'
profileStr += '</div>\n'
iconsDir = getIconsDir(baseDir) iconsDir = getIconsDir(baseDir)
i = 0 i = 0
for item in parseUserFeed(session, outboxUrl, asHeader, for item in parseUserFeed(session, outboxUrl, asHeader,
projectVersion, httpPrefix, domain): projectVersion, httpPrefix, domain):
if not item.get('type'): if not item.get('type'):
continue continue
if item['type'] != 'Create' and item['type'] != 'Announce': if item['type'] != 'Create' and item['type'] != 'Announce':
continue continue
if not item.get('object'): if not item.get('object'):
continue continue
profileStr += \ profileStr += \
individualPostAsHtml(True, recentPostsCache, maxRecentPosts, individualPostAsHtml(True, recentPostsCache, maxRecentPosts,
iconsDir, translate, None, baseDir, iconsDir, translate, None, baseDir,
session, cachedWebfingers, personCache, session, cachedWebfingers, personCache,
nickname, domain, port, nickname, domain, port,
item, avatarUrl, False, False, item, avatarUrl, False, False,
httpPrefix, projectVersion, 'inbox', httpPrefix, projectVersion, 'inbox',
YTReplacementDomain, YTReplacementDomain,
showPublishedDateOnly, showPublishedDateOnly,
False, False, False, False, False) False, False, False, False, False)
i += 1 i += 1
if i >= 20: if i >= 20:
break break
return htmlHeader(cssFilename, profileStyle) + profileStr + htmlFooter() return htmlHeaderWithExternalStyle(cssFilename) + profileStr + htmlFooter()
def htmlProfile(rssIconAtTop: bool, def htmlProfile(rssIconAtTop: bool,
@ -566,84 +559,79 @@ def htmlProfile(rssIconAtTop: bool,
if os.path.isfile(baseDir + '/epicyon.css'): if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css' cssFilename = baseDir + '/epicyon.css'
profileStyle = getCSS(baseDir, cssFilename, cssCache) if isSystemAccount(nickname):
if profileStyle: bannerFile, bannerFilename = \
profileStyle = \ getBannerFile(baseDir, nickname, domain)
profileStyle.replace('image.png', # profileStyle = \
profileJson['image']['url']) # profileStyle.replace('banner.png',
if isSystemAccount(nickname): # '/users/' + nickname + '/' + bannerFile)
bannerFile, bannerFilename = \
getBannerFile(baseDir, nickname, domain)
profileStyle = \
profileStyle.replace('banner.png',
'/users/' + nickname + '/' + bannerFile)
licenseStr = \ licenseStr = \
'<a href="https://gitlab.com/bashrc2/epicyon">' + \ '<a href="https://gitlab.com/bashrc2/epicyon">' + \
'<img loading="lazy" class="license" alt="' + \ '<img loading="lazy" class="license" alt="' + \
translate['Get the source code'] + '" title="' + \ translate['Get the source code'] + '" title="' + \
translate['Get the source code'] + '" src="/icons/agpl.png" /></a>' translate['Get the source code'] + '" src="/icons/agpl.png" /></a>'
if selected == 'posts': if selected == 'posts':
profileStr += \ profileStr += \
htmlProfilePosts(recentPostsCache, maxRecentPosts, htmlProfilePosts(recentPostsCache, maxRecentPosts,
translate, translate,
baseDir, httpPrefix, authorized, baseDir, httpPrefix, authorized,
nickname, domain, port, nickname, domain, port,
session, wfRequest, personCache, session, wfRequest, personCache,
projectVersion, projectVersion,
YTReplacementDomain, YTReplacementDomain,
showPublishedDateOnly) + licenseStr showPublishedDateOnly) + licenseStr
if selected == 'following': if selected == 'following':
profileStr += \ profileStr += \
htmlProfileFollowing(translate, baseDir, httpPrefix, htmlProfileFollowing(translate, baseDir, httpPrefix,
authorized, nickname, authorized, nickname,
domain, port, session, domain, port, session,
wfRequest, personCache, extraJson, wfRequest, personCache, extraJson,
projectVersion, ["unfollow"], selected, projectVersion, ["unfollow"], selected,
usersPath, pageNumber, maxItemsPerPage) usersPath, pageNumber, maxItemsPerPage)
if selected == 'followers': if selected == 'followers':
profileStr += \ profileStr += \
htmlProfileFollowing(translate, baseDir, httpPrefix, htmlProfileFollowing(translate, baseDir, httpPrefix,
authorized, nickname, authorized, nickname,
domain, port, session, domain, port, session,
wfRequest, personCache, extraJson, wfRequest, personCache, extraJson,
projectVersion, ["block"], projectVersion, ["block"],
selected, usersPath, pageNumber, selected, usersPath, pageNumber,
maxItemsPerPage) maxItemsPerPage)
if selected == 'roles': if selected == 'roles':
profileStr += \ profileStr += \
htmlProfileRoles(translate, nickname, domainFull, extraJson) htmlProfileRoles(translate, nickname, domainFull, extraJson)
if selected == 'skills': if selected == 'skills':
profileStr += \ profileStr += \
htmlProfileSkills(translate, nickname, domainFull, extraJson) htmlProfileSkills(translate, nickname, domainFull, extraJson)
if selected == 'shares': if selected == 'shares':
profileStr += \ profileStr += \
htmlProfileShares(actor, translate, htmlProfileShares(actor, translate,
nickname, domainFull, nickname, domainFull,
extraJson) + licenseStr extraJson) + licenseStr
# Footer which is only used for system accounts # Footer which is only used for system accounts
profileFooterStr = '' profileFooterStr = ''
if isSystemAccount(nickname): if isSystemAccount(nickname):
profileFooterStr = ' </td>\n' profileFooterStr = ' </td>\n'
profileFooterStr += ' <td valign="top" class="col-right">\n' profileFooterStr += ' <td valign="top" class="col-right">\n'
iconsDir = getIconsDir(baseDir) iconsDir = getIconsDir(baseDir)
profileFooterStr += \ profileFooterStr += \
getRightColumnContent(baseDir, 'news', domainFull, getRightColumnContent(baseDir, 'news', domainFull,
httpPrefix, translate, httpPrefix, translate,
iconsDir, False, False, iconsDir, False, False,
newswire, False, newswire, False,
False, None, False, False, False, None, False, False,
False, True, authorized, True) False, True, authorized, True)
profileFooterStr += ' </td>\n' profileFooterStr += ' </td>\n'
profileFooterStr += ' </tr>\n' profileFooterStr += ' </tr>\n'
profileFooterStr += ' </tbody>\n' profileFooterStr += ' </tbody>\n'
profileFooterStr += '</table>\n' profileFooterStr += '</table>\n'
profileStr = \ profileStr = \
htmlHeader(cssFilename, profileStyle) + \ htmlHeaderWithExternalStyle(cssFilename) + \
profileStr + profileFooterStr + htmlFooter() profileStr + profileFooterStr + htmlFooter()
return profileStr return profileStr
@ -989,12 +977,6 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
if os.path.isfile(baseDir + '/epicyon.css'): if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css' cssFilename = baseDir + '/epicyon.css'
editProfileCSS = getCSS(baseDir, cssFilename, cssCache)
if editProfileCSS:
if httpPrefix != 'https':
editProfileCSS = \
editProfileCSS.replace('https://', httpPrefix + '://')
moderatorsStr = '' moderatorsStr = ''
themesDropdown = '' themesDropdown = ''
instanceStr = '' instanceStr = ''
@ -1114,7 +1096,7 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
'<option value="' + themeName + '<option value="' + themeName +
'" selected>') '" selected>')
editProfileForm = htmlHeader(cssFilename, editProfileCSS) editProfileForm = htmlHeaderWithExternalStyle(cssFilename)
# top banner # top banner
editProfileForm += \ editProfileForm += \

View File

@ -7,8 +7,7 @@ __email__ = "bob@freedombone.net"
__status__ = "Production" __status__ = "Production"
import os import os
from utils import getCSS from webapp_utils import htmlHeaderWithExternalStyle
from webapp_utils import htmlHeader
from webapp_utils import htmlFooter from webapp_utils import htmlFooter
@ -20,12 +19,10 @@ def htmlSuspended(cssCache: {}, baseDir: str) -> str:
if os.path.isfile(baseDir + '/suspended.css'): if os.path.isfile(baseDir + '/suspended.css'):
cssFilename = baseDir + '/suspended.css' cssFilename = baseDir + '/suspended.css'
suspendedCSS = getCSS(baseDir, cssFilename, cssCache) suspendedForm = htmlHeaderWithExternalStyle(cssFilename)
if suspendedCSS: suspendedForm += '<div><center>\n'
suspendedForm = htmlHeader(cssFilename, suspendedCSS) suspendedForm += ' <p class="screentitle">Account Suspended</p>\n'
suspendedForm += '<div><center>\n' suspendedForm += ' <p>See <a href="/terms">Terms of Service</a></p>\n'
suspendedForm += ' <p class="screentitle">Account Suspended</p>\n' suspendedForm += '</center></div>\n'
suspendedForm += ' <p>See <a href="/terms">Terms of Service</a></p>\n' suspendedForm += htmlFooter()
suspendedForm += '</center></div>\n'
suspendedForm += htmlFooter()
return suspendedForm return suspendedForm

View File

@ -8,9 +8,8 @@ __status__ = "Production"
import os import os
from shutil import copyfile from shutil import copyfile
from utils import getCSS
from utils import getConfigParam from utils import getConfigParam
from webapp_utils import htmlHeader from webapp_utils import htmlHeaderWithExternalStyle
from webapp_utils import htmlFooter from webapp_utils import htmlFooter
@ -38,20 +37,15 @@ def htmlTermsOfService(cssCache: {}, baseDir: str,
if os.path.isfile(baseDir + '/epicyon.css'): if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css' cssFilename = baseDir + '/epicyon.css'
termsCSS = getCSS(baseDir, cssFilename, cssCache) TOSForm = htmlHeaderWithExternalStyle(cssFilename)
if termsCSS: TOSForm += '<div class="container">' + TOSText + '</div>\n'
if httpPrefix != 'https': if adminNickname:
termsCSS = termsCSS.replace('https://', httpPrefix+'://') adminActor = httpPrefix + '://' + domainFull + \
'/users/' + adminNickname
TOSForm = htmlHeader(cssFilename, termsCSS) TOSForm += \
TOSForm += '<div class="container">' + TOSText + '</div>\n' '<div class="container"><center>\n' + \
if adminNickname: '<p class="administeredby">Administered by <a href="' + \
adminActor = httpPrefix + '://' + domainFull + \ adminActor + '">' + adminNickname + '</a></p>\n' + \
'/users/' + adminNickname '</center></div>\n'
TOSForm += \ TOSForm += htmlFooter()
'<div class="container"><center>\n' + \
'<p class="administeredby">Administered by <a href="' + \
adminActor + '">' + adminNickname + '</a></p>\n' + \
'</center></div>\n'
TOSForm += htmlFooter()
return TOSForm return TOSForm