Importing themes

main
Bob Mottram 2021-05-29 12:04:03 +01:00
parent a8351756d2
commit e7ae1c0561
20 changed files with 107 additions and 21 deletions

View File

@ -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:

View File

@ -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]

View File

@ -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
"""

View File

@ -0,0 +1 @@
blue

View File

@ -0,0 +1 @@
debian

View File

@ -0,0 +1 @@
default

View File

@ -0,0 +1 @@
hacker

View File

@ -0,0 +1 @@
henge

View File

@ -0,0 +1 @@
indymediaclassic

View File

@ -0,0 +1 @@
indymediamodern

View File

@ -0,0 +1 @@
lcd

View File

@ -0,0 +1 @@
light

View File

@ -0,0 +1 @@
night

View File

@ -0,0 +1 @@
pixel

View File

@ -0,0 +1 @@
purple

View File

@ -0,0 +1 @@
rc3

View File

@ -0,0 +1 @@
solidaric

View File

@ -0,0 +1 @@
starlight

View File

@ -0,0 +1 @@
zen

View File

@ -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">' + \