From 62ff00401abd1914b0499ca171bcc78e81d49427 Mon Sep 17 00:00:00 2001
From: Bob Mottram <bob@freedombone.net>
Date: Sat, 4 Dec 2021 19:39:00 +0000
Subject: [PATCH] Setting values from theme designer screen

---
 daemon.py               | 101 ++++++++++++++++++++++++++++++++++++++++
 theme.py                |  24 ++++++----
 webapp_themeDesigner.py |   3 +-
 3 files changed, 119 insertions(+), 9 deletions(-)

diff --git a/daemon.py b/daemon.py
index e6c3217c0..8cde5b1e5 100644
--- a/daemon.py
+++ b/daemon.py
@@ -317,6 +317,7 @@ from cache import storePersonInCache
 from cache import getPersonFromCache
 from cache import getPersonPubKey
 from httpsig import verifyPostHeaders
+from theme import setThemeFromDesigner
 from theme import scanThemesForScripts
 from theme import importTheme
 from theme import exportTheme
@@ -2110,6 +2111,77 @@ class PubServer(BaseHTTPRequestHandler):
         self.server.POSTbusy = False
         return
 
+    def _themeDesigner(self, path: str,
+                       callingDomain: str, cookie: str,
+                       baseDir: str, httpPrefix: str, nickname: str,
+                       domain: str, domainFull: str, port: int,
+                       onionDomain: str, i2pDomain: str,
+                       debug: bool, accessKeys: {},
+                       defaultTimeline: str, themeName: str,
+                       allowLocalNetworkAccess: bool) -> None:
+        """Receive POST from webapp_themeDesigner
+        """
+        usersPath = '/users/' + nickname
+        originPathStr = \
+            httpPrefix + '://' + domainFull + usersPath + '/' + defaultTimeline
+        length = int(self.headers['Content-length'])
+
+        try:
+            themeParams = self.rfile.read(length).decode('utf-8')
+        except SocketError as e:
+            if e.errno == errno.ECONNRESET:
+                print('WARN: POST accessKeysParams ' +
+                      'connection reset by peer')
+            else:
+                print('WARN: POST themeParams socket error')
+            self.send_response(400)
+            self.end_headers()
+            self.server.POSTbusy = False
+            return
+        except ValueError as e:
+            print('ERROR: POST themeParams rfile.read failed, ' + str(e))
+            self.send_response(400)
+            self.end_headers()
+            self.server.POSTbusy = False
+            return
+        themeParams = \
+            urllib.parse.unquote_plus(themeParams)
+
+        # theme designer screen, back button
+        # See htmlThemeDesigner
+        if 'submitThemeDesignerCancel=' in themeParams or \
+           'submitThemeDesigner=' not in themeParams:
+            if callingDomain.endswith('.onion') and onionDomain:
+                originPathStr = \
+                    'http://' + onionDomain + usersPath + '/' + defaultTimeline
+            elif callingDomain.endswith('.i2p') and i2pDomain:
+                originPathStr = \
+                    'http://' + i2pDomain + usersPath + '/' + defaultTimeline
+            self._redirect_headers(originPathStr, cookie, callingDomain)
+            self.server.POSTbusy = False
+            return
+
+        # get the parameters from the theme designer screen
+        themeDesignerParams = {}
+        for variableName, key in themeParams.items():
+            if variableName.startswith('themeSetting_'):
+                variableName = variableName.replace('themeSetting_', '')
+                themeDesignerParams[variableName] = key
+
+        setThemeFromDesigner(baseDir, themeName, themeDesignerParams,
+                             allowLocalNetworkAccess)
+
+        # redirect back from theme designer screen
+        if callingDomain.endswith('.onion') and onionDomain:
+            originPathStr = \
+                'http://' + onionDomain + usersPath + '/' + defaultTimeline
+        elif callingDomain.endswith('.i2p') and i2pDomain:
+            originPathStr = \
+                'http://' + i2pDomain + usersPath + '/' + defaultTimeline
+        self._redirect_headers(originPathStr, cookie, callingDomain)
+        self.server.POSTbusy = False
+        return
+
     def _personOptions(self, path: str,
                        callingDomain: str, cookie: str,
                        baseDir: str, httpPrefix: str,
@@ -17757,6 +17829,35 @@ class PubServer(BaseHTTPRequestHandler):
                                    self.server.defaultTimeline)
                 return
 
+            # theme designer submit/cancel button
+            if usersInPath and \
+               self.path.endswith('/changeThemeSettings'):
+                nickname = self.path.split('/users/')[1]
+                if '/' in nickname:
+                    nickname = nickname.split('/')[0]
+
+                if not self.server.keyShortcuts.get(nickname):
+                    accessKeys = self.server.accessKeys
+                    self.server.keyShortcuts[nickname] = accessKeys.copy()
+                accessKeys = self.server.keyShortcuts[nickname]
+
+                self._themeDesigner(self.path,
+                                    callingDomain, cookie,
+                                    self.server.baseDir,
+                                    self.server.httpPrefix,
+                                    nickname,
+                                    self.server.domain,
+                                    self.server.domainFull,
+                                    self.server.port,
+                                    self.server.onionDomain,
+                                    self.server.i2pDomain,
+                                    self.server.debug,
+                                    accessKeys,
+                                    self.server.defaultTimeline,
+                                    self.server.themeName,
+                                    self.server.allowLocalNetworkAccess)
+                return
+
         # update the shared item federation token for the calling domain
         # if it is within the permitted federation
         if self.headers.get('Origin') and \
diff --git a/theme.py b/theme.py
index 273e54667..9a89e6356 100644
--- a/theme.py
+++ b/theme.py
@@ -492,14 +492,9 @@ def _setCustomFont(baseDir: str):
                 cssfile.write(css)
 
 
-def _readVariablesFile(baseDir: str, themeName: str,
-                       variablesFile: str,
-                       allowLocalNetworkAccess: bool) -> None:
-    """Reads variables from a file in the theme directory
-    """
-    themeParams = loadJson(variablesFile, 0)
-    if not themeParams:
-        return
+def setThemeFromDesigner(baseDir: str, themeName: str,
+                         themeParams: {},
+                         allowLocalNetworkAccess: bool):
     bgParams = {
         "login": "jpg",
         "follow": "jpg",
@@ -510,6 +505,19 @@ def _readVariablesFile(baseDir: str, themeName: str,
                       allowLocalNetworkAccess)
 
 
+def _readVariablesFile(baseDir: str, themeName: str,
+                       variablesFile: str,
+                       allowLocalNetworkAccess: bool) -> None:
+    """Reads variables from a file in the theme directory
+    """
+    themeParams = loadJson(variablesFile, 0)
+    if not themeParams:
+        return
+    setThemeFromDesigner(baseDir, themeName,
+                         themeParams,
+                         allowLocalNetworkAccess)
+
+
 def _setThemeDefault(baseDir: str, allowLocalNetworkAccess: bool):
     name = 'default'
     _removeTheme(baseDir)
diff --git a/webapp_themeDesigner.py b/webapp_themeDesigner.py
index bfdd8a675..fcb56e5af 100644
--- a/webapp_themeDesigner.py
+++ b/webapp_themeDesigner.py
@@ -57,7 +57,8 @@ def htmlThemeDesigner(cssCache: {}, baseDir: str,
     themeForm += \
         '    <center>\n' + \
         '    <button type="submit" class="button" ' + \
-        'name="submitThemeDesignerCancel" accesskey="' + timelineKey + '">' + \
+        'name="submitThemeDesignerCancel" ' + \
+        'accesskey="' + timelineKey + '">' + \
         translate['Go Back'] + '</button>\n' + \
         '    <button type="submit" class="button" ' + \
         'name="submitThemeDesigner" accesskey="' + submitKey + '">' + \