mirror of https://gitlab.com/bashrc2/epicyon
Importing themes
parent
a8351756d2
commit
e7ae1c0561
27
content.py
27
content.py
|
@ -948,7 +948,8 @@ def saveMediaInFormPOST(mediaBytes, debug: bool,
|
|||
'mp4': 'video/mp4',
|
||||
'ogv': 'video/ogv',
|
||||
'mp3': 'audio/mpeg',
|
||||
'ogg': 'audio/ogg'
|
||||
'ogg': 'audio/ogg',
|
||||
'zip': 'application/zip'
|
||||
}
|
||||
detectedExtension = None
|
||||
for extension, contentType in extensionList.items():
|
||||
|
@ -960,7 +961,8 @@ def saveMediaInFormPOST(mediaBytes, debug: bool,
|
|||
extension = 'jpg'
|
||||
elif extension == 'mpeg':
|
||||
extension = 'mp3'
|
||||
filename = filenameBase + '.' + extension
|
||||
if filenameBase:
|
||||
filename = filenameBase + '.' + extension
|
||||
attachmentMediaType = \
|
||||
searchStr.decode().split('/')[0].replace('Content-Type: ', '')
|
||||
detectedExtension = extension
|
||||
|
@ -979,16 +981,17 @@ def saveMediaInFormPOST(mediaBytes, debug: bool,
|
|||
break
|
||||
|
||||
# remove any existing image files with a different format
|
||||
extensionTypes = getImageExtensions()
|
||||
for ex in extensionTypes:
|
||||
if ex == detectedExtension:
|
||||
continue
|
||||
possibleOtherFormat = \
|
||||
filename.replace('.temp', '').replace('.' +
|
||||
detectedExtension, '.' +
|
||||
ex)
|
||||
if os.path.isfile(possibleOtherFormat):
|
||||
os.remove(possibleOtherFormat)
|
||||
if detectedExtension != 'zip':
|
||||
extensionTypes = getImageExtensions()
|
||||
for ex in extensionTypes:
|
||||
if ex == detectedExtension:
|
||||
continue
|
||||
possibleOtherFormat = \
|
||||
filename.replace('.temp', '').replace('.' +
|
||||
detectedExtension, '.' +
|
||||
ex)
|
||||
if os.path.isfile(possibleOtherFormat):
|
||||
os.remove(possibleOtherFormat)
|
||||
|
||||
fd = open(filename, 'wb')
|
||||
if not fd:
|
||||
|
|
33
daemon.py
33
daemon.py
|
@ -256,6 +256,7 @@ from cache import checkForChangedActor
|
|||
from cache import storePersonInCache
|
||||
from cache import getPersonFromCache
|
||||
from httpsig import verifyPostHeaders
|
||||
from theme import importTheme
|
||||
from theme import exportTheme
|
||||
from theme import isNewsThemeName
|
||||
from theme import getTextModeBanner
|
||||
|
@ -4042,7 +4043,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
profileMediaTypes = ('avatar', 'image',
|
||||
'banner', 'search_banner',
|
||||
'instanceLogo',
|
||||
'left_col_image', 'right_col_image')
|
||||
'left_col_image', 'right_col_image',
|
||||
'submitImportTheme')
|
||||
profileMediaTypesUploaded = {}
|
||||
for mType in profileMediaTypes:
|
||||
# some images can only be changed by the admin
|
||||
|
@ -4054,18 +4056,18 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
|
||||
if debug:
|
||||
print('DEBUG: profile update extracting ' + mType +
|
||||
' image or font from POST')
|
||||
' image, zip or font from POST')
|
||||
mediaBytes, postBytes = \
|
||||
extractMediaInFormPOST(postBytes, boundary, mType)
|
||||
if mediaBytes:
|
||||
if debug:
|
||||
print('DEBUG: profile update ' + mType +
|
||||
' image or font was found. ' +
|
||||
' image, zip or font was found. ' +
|
||||
str(len(mediaBytes)) + ' bytes')
|
||||
else:
|
||||
if debug:
|
||||
print('DEBUG: profile update, no ' + mType +
|
||||
' image or font was found in POST')
|
||||
' image, zip or font was found in POST')
|
||||
continue
|
||||
|
||||
# Note: a .temp extension is used here so that at no
|
||||
|
@ -4074,6 +4076,13 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
if mType == 'instanceLogo':
|
||||
filenameBase = \
|
||||
baseDir + '/accounts/login.temp'
|
||||
elif mType == 'submitImportTheme':
|
||||
if not os.path.isdir(baseDir + '/imports'):
|
||||
os.mkdir(baseDir + '/imports')
|
||||
filenameBase = \
|
||||
baseDir + '/imports/newtheme.zip'
|
||||
if os.path.isfile(filenameBase):
|
||||
os.remove(filenameBase)
|
||||
else:
|
||||
filenameBase = \
|
||||
baseDir + '/accounts/' + \
|
||||
|
@ -4085,10 +4094,19 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
filenameBase)
|
||||
if filename:
|
||||
print('Profile update POST ' + mType +
|
||||
' media or font filename is ' + filename)
|
||||
' media, zip or font filename is ' + filename)
|
||||
else:
|
||||
print('Profile update, no ' + mType +
|
||||
' media or font filename in POST')
|
||||
' media, zip or font filename in POST')
|
||||
continue
|
||||
|
||||
if mType == 'submitImportTheme':
|
||||
if nickname == adminNickname or \
|
||||
isArtist(baseDir, nickname):
|
||||
if importTheme(baseDir, filename):
|
||||
print(nickname + ' uploaded a theme')
|
||||
else:
|
||||
print('Only admin or artist can import a theme')
|
||||
continue
|
||||
|
||||
postImageFilename = filename.replace('.temp', '')
|
||||
|
@ -4108,7 +4126,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
filename, postImageFilename, city)
|
||||
if os.path.isfile(postImageFilename):
|
||||
print('profile update POST ' + mType +
|
||||
' image or font saved to ' + postImageFilename)
|
||||
' image, zip or font saved to ' +
|
||||
postImageFilename)
|
||||
if mType != 'instanceLogo':
|
||||
lastPartOfImageFilename = \
|
||||
postImageFilename.split('/')[-1]
|
||||
|
|
45
theme.py
45
theme.py
|
@ -10,11 +10,56 @@ import os
|
|||
from utils import loadJson
|
||||
from utils import saveJson
|
||||
from utils import getImageExtensions
|
||||
from utils import copytree
|
||||
from shutil import copyfile
|
||||
from shutil import make_archive
|
||||
from shutil import unpack_archive
|
||||
from content import dangerousCSS
|
||||
|
||||
|
||||
def importTheme(baseDir: str, filename: str) -> bool:
|
||||
"""Imports a theme
|
||||
"""
|
||||
if not os.path.isfile(filename):
|
||||
return False
|
||||
tempThemeDir = baseDir + '/imports/files'
|
||||
if not os.path.isdir(tempThemeDir):
|
||||
os.mkdir(tempThemeDir)
|
||||
unpack_archive(filename, tempThemeDir, 'zip')
|
||||
essentialThemeFiles = ('name.txt', 'theme.json')
|
||||
for themeFile in essentialThemeFiles:
|
||||
if not os.path.isfile(tempThemeDir + '/' + themeFile):
|
||||
print('WARN: ' + themeFile +
|
||||
' missing from imported theme')
|
||||
return False
|
||||
newThemeName = None
|
||||
with open(tempThemeDir + '/name.txt', 'r') as fp:
|
||||
newThemeName = fp.read().replace('\n', '').replace('\r', '')
|
||||
if len(newThemeName) > 20:
|
||||
print('WARN: Imported theme name is too long')
|
||||
return False
|
||||
if len(newThemeName) < 2:
|
||||
print('WARN: Imported theme name is too short')
|
||||
return False
|
||||
newThemeName = newThemeName.lower()
|
||||
forbiddenChars = (
|
||||
' ', ';', '/', '\\', '?', '!', '#', '@',
|
||||
':', '%', '&', '"', '+', '<', '>', '$'
|
||||
)
|
||||
for ch in forbiddenChars:
|
||||
if ch in newThemeName:
|
||||
print('WARN: theme name contains forbidden character')
|
||||
return False
|
||||
if not newThemeName:
|
||||
return False
|
||||
themeDir = baseDir + '/theme/' + newThemeName
|
||||
if not os.path.isdir(themeDir):
|
||||
os.mkdir(themeDir)
|
||||
copytree(tempThemeDir, themeDir)
|
||||
os.remove(tempThemeDir)
|
||||
return os.path.isfile(themeDir + '/theme.json')
|
||||
|
||||
|
||||
def exportTheme(baseDir: str, theme: str) -> bool:
|
||||
"""Exports a theme as a zip file
|
||||
"""
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
blue
|
|
@ -0,0 +1 @@
|
|||
debian
|
|
@ -0,0 +1 @@
|
|||
default
|
|
@ -0,0 +1 @@
|
|||
hacker
|
|
@ -0,0 +1 @@
|
|||
henge
|
|
@ -0,0 +1 @@
|
|||
indymediaclassic
|
|
@ -0,0 +1 @@
|
|||
indymediamodern
|
|
@ -0,0 +1 @@
|
|||
lcd
|
|
@ -0,0 +1 @@
|
|||
light
|
|
@ -0,0 +1 @@
|
|||
night
|
|
@ -0,0 +1 @@
|
|||
pixel
|
|
@ -0,0 +1 @@
|
|||
purple
|
|
@ -0,0 +1 @@
|
|||
rc3
|
|
@ -0,0 +1 @@
|
|||
solidaric
|
|
@ -0,0 +1 @@
|
|||
starlight
|
|
@ -0,0 +1 @@
|
|||
zen
|
|
@ -1317,9 +1317,12 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
|
|||
themesDropdown += ' <select id="themeDropdown" ' + \
|
||||
'name="themeDropdown" class="theme">'
|
||||
for themeName in themes:
|
||||
translatedThemeName = themeName
|
||||
if translate.get(themeName):
|
||||
translatedThemeName = translate[themeName]
|
||||
themesDropdown += ' <option value="' + \
|
||||
themeName.lower() + '">' + \
|
||||
translate[themeName] + '</option>'
|
||||
translatedThemeName + '</option>'
|
||||
themesDropdown += ' </select><br>'
|
||||
if os.path.isfile(baseDir + '/fonts/custom.woff') or \
|
||||
os.path.isfile(baseDir + '/fonts/custom.woff2') or \
|
||||
|
@ -1340,7 +1343,7 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
|
|||
' <label class="labels">' + \
|
||||
translate['Import Theme'] + '</label>\n'
|
||||
graphicsStr += ' <input type="file" id="importTheme" '
|
||||
graphicsStr += 'name="importTheme" '
|
||||
graphicsStr += 'name="submitImportTheme" '
|
||||
graphicsStr += 'accept="' + themeFormats + '">\n'
|
||||
graphicsStr += \
|
||||
' <label class="labels">' + \
|
||||
|
|
Loading…
Reference in New Issue