We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
add support for OIDC in account creation flow

### Observed behavior

currently SSO works for sign in but not account creation

### Expected behavior

the 'next' parameter needs to be passed from the sign in page to the account creation page and handled there

### User-facing consequences

The following flow is not supported:

> 1. User comes to SCE portal and click on login for one server, system would redirect to Kolibri portal.
> 2. On Kolibri portal, user decides to not login but register and clicks on register.
> 3. After registration, user is redirecting to Kolibri portal instead of returning back to SCE portal.



### Context

0.12.5

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `kolibri/core/theme_hook.py`
Content:
```
1 from __future__ import absolute_import
2 from __future__ import print_function
3 from __future__ import unicode_literals
4 
5 import logging
6 
7 from kolibri.plugins import hooks
8 import kolibri
9 from django.utils.six.moves.urllib import parse
10 from django.conf import settings
11 import os
12 
13 logger = logging.getLogger(__name__)
14 
15 
16 # Important for cache busting
17 THEME_NAME = "themeName"
18 THEME_VERSION = "themeVersion"
19 
20 # These constants are used by theme.js and the $theme mixin on the front-end
21 TOKEN_MAPPING = "tokenMapping"
22 BRAND_COLORS = "brandColors"
23 PRIMARY = "primary"
24 SECONDARY = "secondary"
25 COLOR_V50 = "v_50"
26 COLOR_V100 = "v_100"
27 COLOR_V200 = "v_200"
28 COLOR_V300 = "v_300"
29 COLOR_V400 = "v_400"
30 COLOR_V500 = "v_500"
31 COLOR_V600 = "v_600"
32 COLOR_V700 = "v_700"
33 COLOR_V800 = "v_800"
34 COLOR_V900 = "v_900"
35 SIGN_IN = "signIn"
36 SIDE_NAV = "sideNav"
37 APP_BAR = "appBar"
38 BACKGROUND = "background"
39 TITLE = "title"
40 TITLE_STYLE = "titleStyle"
41 TOP_LOGO = "topLogo"
42 IMG_SRC = "src"
43 IMG_STYLE = "style"
44 IMG_ALT = "alt"
45 SHOW_K_FOOTER_LOGO = "showKolibriFooterLogo"
46 
47 # This is the image file name that will be used when customizing the sign-in background
48 # image using the 'kolibri manage background' command. It does not attempt to use a file
49 # extension (like .jpg) because we don't know if it's a JPG, SVG, PNG, etc...
50 DEFAULT_BG_IMAGE_FILE = "background_image"
51 DEFAULT_BG_MD5_FILE = "background_image_md5"
52 
53 
54 def _isSet(theme, keys):
55     """
56     Given a theme dict, recursively check that all the keys are populated
57     and that the associated value is truthy
58     """
59     obj = theme
60     for key in keys:
61         if not obj or key not in obj:
62             return False
63         obj = obj[key]
64     return bool(obj)
65 
66 
67 def _validateMetadata(theme):
68     if THEME_NAME not in theme:
69         logger.error("a theme name must be set")
70     if THEME_VERSION not in theme:
71         logger.error("a theme version must be set")
72 
73 
74 def _validateBrandColors(theme):
75     if BRAND_COLORS not in theme:
76         logger.error("brand colors not defined by theme")
77         return
78 
79     required_colors = [PRIMARY, SECONDARY]
80     color_names = [
81         COLOR_V50,
82         COLOR_V100,
83         COLOR_V200,
84         COLOR_V300,
85         COLOR_V400,
86         COLOR_V500,
87         COLOR_V600,
88         COLOR_V700,
89         COLOR_V800,
90         COLOR_V900,
91     ]
92     for color in required_colors:
93         if color not in theme[BRAND_COLORS]:
94             logger.error("'{}' not defined by theme".format(color))
95         for name in color_names:
96             if name not in theme[BRAND_COLORS][color]:
97                 logger.error("{} '{}' not defined by theme".format(color, name))
98 
99 
100 def _initFields(theme):
101     """
102     set up top-level dicts if they don't exist
103     """
104     if SIGN_IN not in theme:
105         theme[SIGN_IN] = {}
106     if TOKEN_MAPPING not in theme:
107         theme[TOKEN_MAPPING] = {}
108     if SIDE_NAV not in theme:
109         theme[SIDE_NAV] = {}
110     if APP_BAR not in theme:
111         theme[APP_BAR] = {}
112 
113 
114 class ThemeHook(hooks.KolibriHook):
115     """
116     A hook to allow custom theming of Kolibri
117     Use this tool to help generate your brand colors: https://materialpalettes.com/
118     """
119 
120     class Meta:
121         abstract = True
122 
123     @property
124     @hooks.only_one_registered
125     def cacheKey(self):
126         theme = list(self.registered_hooks)[0].theme
127         return parse.quote(
128             "{}-{}-{}".format(
129                 kolibri.__version__, theme[THEME_NAME], theme[THEME_VERSION]
130             )
131         )
132 
133     @property
134     @hooks.only_one_registered
135     def theme(self):
136         theme = list(self.registered_hooks)[0].theme
137 
138         # some validation and initialization
139         _initFields(theme)
140         _validateMetadata(theme)
141         _validateBrandColors(theme)
142 
143         # set up cache busting
144         bust = "?" + self.cacheKey
145         if _isSet(theme, [SIGN_IN, BACKGROUND]):
146             theme[SIGN_IN][BACKGROUND] += bust
147         if _isSet(theme, [SIGN_IN, TOP_LOGO, IMG_SRC]):
148             theme[SIGN_IN][TOP_LOGO][IMG_SRC] += bust
149         if _isSet(theme, [SIDE_NAV, TOP_LOGO, IMG_SRC]):
150             theme[SIDE_NAV][TOP_LOGO][IMG_SRC] += bust
151         if _isSet(theme, [APP_BAR, TOP_LOGO, IMG_SRC]):
152             theme[APP_BAR][TOP_LOGO][IMG_SRC] += bust
153 
154         # if a background image has been locally set using the `manage background` command, use it
155         bg_img = os.path.join(settings.MEDIA_ROOT, DEFAULT_BG_IMAGE_FILE)
156         if os.path.exists(bg_img):
157             theme[SIGN_IN][BACKGROUND] = parse.urljoin(
158                 settings.MEDIA_URL, DEFAULT_BG_IMAGE_FILE
159             )
160             # add cache busting
161             md5_file = os.path.join(settings.MEDIA_ROOT, DEFAULT_BG_MD5_FILE)
162             if os.path.exists(md5_file):
163                 with open(md5_file) as f:
164                     theme[SIGN_IN][BACKGROUND] += "?{}".format(f.read())
165 
166         return theme
167
```

Path: `kolibri/plugins/default_theme/kolibri_plugin.py`
Content:
```
1 from __future__ import absolute_import
2 from __future__ import print_function
3 from __future__ import unicode_literals
4 
5 from django.contrib.staticfiles.templatetags.staticfiles import static
6 
7 from kolibri.plugins.base import KolibriPluginBase
8 
9 from kolibri.core import theme_hook
10 
11 
12 class DefaultThemePlugin(KolibriPluginBase):
13     pass
14 
15 
16 class DefaultThemeHook(theme_hook.ThemeHook):
17     @property
18     def theme(self):
19         return {
20             # metadata
21             theme_hook.THEME_NAME: "Default theme",
22             theme_hook.THEME_VERSION: 1,  # increment when changes are made
23             # specify primary and secondary brand colors
24             theme_hook.BRAND_COLORS: {
25                 theme_hook.PRIMARY: {
26                     theme_hook.COLOR_V50: "#f0e7ed",
27                     theme_hook.COLOR_V100: "#dbc3d4",
28                     theme_hook.COLOR_V200: "#c59db9",
29                     theme_hook.COLOR_V300: "#ac799d",
30                     theme_hook.COLOR_V400: "#996189",
31                     theme_hook.COLOR_V500: "#874e77",
32                     theme_hook.COLOR_V600: "#7c4870",
33                     theme_hook.COLOR_V700: "#6e4167",
34                     theme_hook.COLOR_V800: "#5f3b5c",
35                     theme_hook.COLOR_V900: "#4b2e4d",
36                 },
37                 theme_hook.SECONDARY: {
38                     theme_hook.COLOR_V50: "#e3f0ed",
39                     theme_hook.COLOR_V100: "#badbd2",
40                     theme_hook.COLOR_V200: "#8dc5b6",
41                     theme_hook.COLOR_V300: "#62af9a",
42                     theme_hook.COLOR_V400: "#479e86",
43                     theme_hook.COLOR_V500: "#368d74",
44                     theme_hook.COLOR_V600: "#328168",
45                     theme_hook.COLOR_V700: "#2c715a",
46                     theme_hook.COLOR_V800: "#26614d",
47                     theme_hook.COLOR_V900: "#1b4634",
48                 },
49             },
50             # sign-in page config
51             theme_hook.SIGN_IN: {
52                 theme_hook.BACKGROUND: static("background.jpg"),
53                 theme_hook.TITLE: None,  # use default: "Kolibri"
54                 theme_hook.TOP_LOGO: {
55                     theme_hook.IMG_SRC: None,  # use default Kolibri bird
56                     theme_hook.IMG_STYLE: "padding-left: 64px; padding-right: 64px; margin-bottom: 8px; margin-top: 8px",
57                     theme_hook.IMG_ALT: None,
58                 },
59                 theme_hook.SHOW_K_FOOTER_LOGO: False,
60             },
61             # side-nav config
62             theme_hook.SIDE_NAV: {theme_hook.SHOW_K_FOOTER_LOGO: True},
63             # app bar config
64             theme_hook.APP_BAR: {theme_hook.TOP_LOGO: None},
65         }
66
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/kolibri/core/theme_hook.py b/kolibri/core/theme_hook.py
--- a/kolibri/core/theme_hook.py
+++ b/kolibri/core/theme_hook.py
@@ -42,7 +42,10 @@
 IMG_SRC = "src"
 IMG_STYLE = "style"
 IMG_ALT = "alt"
+SHOW_TITLE = "showTitle"
 SHOW_K_FOOTER_LOGO = "showKolibriFooterLogo"
+SHOW_POWERED_BY = "showPoweredBy"
+POWERED_BY_STYLE = "poweredByStyle"
 
 # This is the image file name that will be used when customizing the sign-in background
 # image using the 'kolibri manage background' command. It does not attempt to use a file
diff --git a/kolibri/plugins/default_theme/kolibri_plugin.py b/kolibri/plugins/default_theme/kolibri_plugin.py
--- a/kolibri/plugins/default_theme/kolibri_plugin.py
+++ b/kolibri/plugins/default_theme/kolibri_plugin.py
@@ -56,6 +56,8 @@
                     theme_hook.IMG_STYLE: "padding-left: 64px; padding-right: 64px; margin-bottom: 8px; margin-top: 8px",
                     theme_hook.IMG_ALT: None,
                 },
+                theme_hook.SHOW_POWERED_BY: False,
+                theme_hook.SHOW_TITLE: True,
                 theme_hook.SHOW_K_FOOTER_LOGO: False,
             },
             # side-nav config

{"golden_diff": "diff --git a/kolibri/core/theme_hook.py b/kolibri/core/theme_hook.py\n--- a/kolibri/core/theme_hook.py\n+++ b/kolibri/core/theme_hook.py\n@@ -42,7 +42,10 @@\n IMG_SRC = \"src\"\n IMG_STYLE = \"style\"\n IMG_ALT = \"alt\"\n+SHOW_TITLE = \"showTitle\"\n SHOW_K_FOOTER_LOGO = \"showKolibriFooterLogo\"\n+SHOW_POWERED_BY = \"showPoweredBy\"\n+POWERED_BY_STYLE = \"poweredByStyle\"\n \n # This is the image file name that will be used when customizing the sign-in background\n # image using the 'kolibri manage background' command. It does not attempt to use a file\ndiff --git a/kolibri/plugins/default_theme/kolibri_plugin.py b/kolibri/plugins/default_theme/kolibri_plugin.py\n--- a/kolibri/plugins/default_theme/kolibri_plugin.py\n+++ b/kolibri/plugins/default_theme/kolibri_plugin.py\n@@ -56,6 +56,8 @@\n                     theme_hook.IMG_STYLE: \"padding-left: 64px; padding-right: 64px; margin-bottom: 8px; margin-top: 8px\",\n                     theme_hook.IMG_ALT: None,\n                 },\n+                theme_hook.SHOW_POWERED_BY: False,\n+                theme_hook.SHOW_TITLE: True,\n                 theme_hook.SHOW_K_FOOTER_LOGO: False,\n             },\n             # side-nav config\n", "issue": "add support for OIDC in account creation flow\n\r\n### Observed behavior\r\n\r\ncurrently SSO works for sign in but not account creation\r\n\r\n### Expected behavior\r\n\r\nthe 'next' parameter needs to be passed from the sign in page to the account creation page and handled there\r\n\r\n### User-facing consequences\r\n\r\nThe following flow is not supported:\r\n\r\n> 1. User comes to SCE portal and click on login for one server, system would redirect to Kolibri portal.\r\n> 2. On Kolibri portal, user decides to not login but register and clicks on register.\r\n> 3. After registration, user is redirecting to Kolibri portal instead of returning back to SCE portal.\r\n\r\n\r\n\r\n### Context\r\n\r\n0.12.5\n", "before_files": [{"content": "from __future__ import absolute_import\nfrom __future__ import print_function\nfrom __future__ import unicode_literals\n\nimport logging\n\nfrom kolibri.plugins import hooks\nimport kolibri\nfrom django.utils.six.moves.urllib import parse\nfrom django.conf import settings\nimport os\n\nlogger = logging.getLogger(__name__)\n\n\n# Important for cache busting\nTHEME_NAME = \"themeName\"\nTHEME_VERSION = \"themeVersion\"\n\n# These constants are used by theme.js and the $theme mixin on the front-end\nTOKEN_MAPPING = \"tokenMapping\"\nBRAND_COLORS = \"brandColors\"\nPRIMARY = \"primary\"\nSECONDARY = \"secondary\"\nCOLOR_V50 = \"v_50\"\nCOLOR_V100 = \"v_100\"\nCOLOR_V200 = \"v_200\"\nCOLOR_V300 = \"v_300\"\nCOLOR_V400 = \"v_400\"\nCOLOR_V500 = \"v_500\"\nCOLOR_V600 = \"v_600\"\nCOLOR_V700 = \"v_700\"\nCOLOR_V800 = \"v_800\"\nCOLOR_V900 = \"v_900\"\nSIGN_IN = \"signIn\"\nSIDE_NAV = \"sideNav\"\nAPP_BAR = \"appBar\"\nBACKGROUND = \"background\"\nTITLE = \"title\"\nTITLE_STYLE = \"titleStyle\"\nTOP_LOGO = \"topLogo\"\nIMG_SRC = \"src\"\nIMG_STYLE = \"style\"\nIMG_ALT = \"alt\"\nSHOW_K_FOOTER_LOGO = \"showKolibriFooterLogo\"\n\n# This is the image file name that will be used when customizing the sign-in background\n# image using the 'kolibri manage background' command. It does not attempt to use a file\n# extension (like .jpg) because we don't know if it's a JPG, SVG, PNG, etc...\nDEFAULT_BG_IMAGE_FILE = \"background_image\"\nDEFAULT_BG_MD5_FILE = \"background_image_md5\"\n\n\ndef _isSet(theme, keys):\n    \"\"\"\n    Given a theme dict, recursively check that all the keys are populated\n    and that the associated value is truthy\n    \"\"\"\n    obj = theme\n    for key in keys:\n        if not obj or key not in obj:\n            return False\n        obj = obj[key]\n    return bool(obj)\n\n\ndef _validateMetadata(theme):\n    if THEME_NAME not in theme:\n        logger.error(\"a theme name must be set\")\n    if THEME_VERSION not in theme:\n        logger.error(\"a theme version must be set\")\n\n\ndef _validateBrandColors(theme):\n    if BRAND_COLORS not in theme:\n        logger.error(\"brand colors not defined by theme\")\n        return\n\n    required_colors = [PRIMARY, SECONDARY]\n    color_names = [\n        COLOR_V50,\n        COLOR_V100,\n        COLOR_V200,\n        COLOR_V300,\n        COLOR_V400,\n        COLOR_V500,\n        COLOR_V600,\n        COLOR_V700,\n        COLOR_V800,\n        COLOR_V900,\n    ]\n    for color in required_colors:\n        if color not in theme[BRAND_COLORS]:\n            logger.error(\"'{}' not defined by theme\".format(color))\n        for name in color_names:\n            if name not in theme[BRAND_COLORS][color]:\n                logger.error(\"{} '{}' not defined by theme\".format(color, name))\n\n\ndef _initFields(theme):\n    \"\"\"\n    set up top-level dicts if they don't exist\n    \"\"\"\n    if SIGN_IN not in theme:\n        theme[SIGN_IN] = {}\n    if TOKEN_MAPPING not in theme:\n        theme[TOKEN_MAPPING] = {}\n    if SIDE_NAV not in theme:\n        theme[SIDE_NAV] = {}\n    if APP_BAR not in theme:\n        theme[APP_BAR] = {}\n\n\nclass ThemeHook(hooks.KolibriHook):\n    \"\"\"\n    A hook to allow custom theming of Kolibri\n    Use this tool to help generate your brand colors: https://materialpalettes.com/\n    \"\"\"\n\n    class Meta:\n        abstract = True\n\n    @property\n    @hooks.only_one_registered\n    def cacheKey(self):\n        theme = list(self.registered_hooks)[0].theme\n        return parse.quote(\n            \"{}-{}-{}\".format(\n                kolibri.__version__, theme[THEME_NAME], theme[THEME_VERSION]\n            )\n        )\n\n    @property\n    @hooks.only_one_registered\n    def theme(self):\n        theme = list(self.registered_hooks)[0].theme\n\n        # some validation and initialization\n        _initFields(theme)\n        _validateMetadata(theme)\n        _validateBrandColors(theme)\n\n        # set up cache busting\n        bust = \"?\" + self.cacheKey\n        if _isSet(theme, [SIGN_IN, BACKGROUND]):\n            theme[SIGN_IN][BACKGROUND] += bust\n        if _isSet(theme, [SIGN_IN, TOP_LOGO, IMG_SRC]):\n            theme[SIGN_IN][TOP_LOGO][IMG_SRC] += bust\n        if _isSet(theme, [SIDE_NAV, TOP_LOGO, IMG_SRC]):\n            theme[SIDE_NAV][TOP_LOGO][IMG_SRC] += bust\n        if _isSet(theme, [APP_BAR, TOP_LOGO, IMG_SRC]):\n            theme[APP_BAR][TOP_LOGO][IMG_SRC] += bust\n\n        # if a background image has been locally set using the `manage background` command, use it\n        bg_img = os.path.join(settings.MEDIA_ROOT, DEFAULT_BG_IMAGE_FILE)\n        if os.path.exists(bg_img):\n            theme[SIGN_IN][BACKGROUND] = parse.urljoin(\n                settings.MEDIA_URL, DEFAULT_BG_IMAGE_FILE\n            )\n            # add cache busting\n            md5_file = os.path.join(settings.MEDIA_ROOT, DEFAULT_BG_MD5_FILE)\n            if os.path.exists(md5_file):\n                with open(md5_file) as f:\n                    theme[SIGN_IN][BACKGROUND] += \"?{}\".format(f.read())\n\n        return theme\n", "path": "kolibri/core/theme_hook.py"}, {"content": "from __future__ import absolute_import\nfrom __future__ import print_function\nfrom __future__ import unicode_literals\n\nfrom django.contrib.staticfiles.templatetags.staticfiles import static\n\nfrom kolibri.plugins.base import KolibriPluginBase\n\nfrom kolibri.core import theme_hook\n\n\nclass DefaultThemePlugin(KolibriPluginBase):\n    pass\n\n\nclass DefaultThemeHook(theme_hook.ThemeHook):\n    @property\n    def theme(self):\n        return {\n            # metadata\n            theme_hook.THEME_NAME: \"Default theme\",\n            theme_hook.THEME_VERSION: 1,  # increment when changes are made\n            # specify primary and secondary brand colors\n            theme_hook.BRAND_COLORS: {\n                theme_hook.PRIMARY: {\n                    theme_hook.COLOR_V50: \"#f0e7ed\",\n                    theme_hook.COLOR_V100: \"#dbc3d4\",\n                    theme_hook.COLOR_V200: \"#c59db9\",\n                    theme_hook.COLOR_V300: \"#ac799d\",\n                    theme_hook.COLOR_V400: \"#996189\",\n                    theme_hook.COLOR_V500: \"#874e77\",\n                    theme_hook.COLOR_V600: \"#7c4870\",\n                    theme_hook.COLOR_V700: \"#6e4167\",\n                    theme_hook.COLOR_V800: \"#5f3b5c\",\n                    theme_hook.COLOR_V900: \"#4b2e4d\",\n                },\n                theme_hook.SECONDARY: {\n                    theme_hook.COLOR_V50: \"#e3f0ed\",\n                    theme_hook.COLOR_V100: \"#badbd2\",\n                    theme_hook.COLOR_V200: \"#8dc5b6\",\n                    theme_hook.COLOR_V300: \"#62af9a\",\n                    theme_hook.COLOR_V400: \"#479e86\",\n                    theme_hook.COLOR_V500: \"#368d74\",\n                    theme_hook.COLOR_V600: \"#328168\",\n                    theme_hook.COLOR_V700: \"#2c715a\",\n                    theme_hook.COLOR_V800: \"#26614d\",\n                    theme_hook.COLOR_V900: \"#1b4634\",\n                },\n            },\n            # sign-in page config\n            theme_hook.SIGN_IN: {\n                theme_hook.BACKGROUND: static(\"background.jpg\"),\n                theme_hook.TITLE: None,  # use default: \"Kolibri\"\n                theme_hook.TOP_LOGO: {\n                    theme_hook.IMG_SRC: None,  # use default Kolibri bird\n                    theme_hook.IMG_STYLE: \"padding-left: 64px; padding-right: 64px; margin-bottom: 8px; margin-top: 8px\",\n                    theme_hook.IMG_ALT: None,\n                },\n                theme_hook.SHOW_K_FOOTER_LOGO: False,\n            },\n            # side-nav config\n            theme_hook.SIDE_NAV: {theme_hook.SHOW_K_FOOTER_LOGO: True},\n            # app bar config\n            theme_hook.APP_BAR: {theme_hook.TOP_LOGO: None},\n        }\n", "path": "kolibri/plugins/default_theme/kolibri_plugin.py"}], "after_files": [{"content": "from __future__ import absolute_import\nfrom __future__ import print_function\nfrom __future__ import unicode_literals\n\nimport logging\n\nfrom kolibri.plugins import hooks\nimport kolibri\nfrom django.utils.six.moves.urllib import parse\nfrom django.conf import settings\nimport os\n\nlogger = logging.getLogger(__name__)\n\n\n# Important for cache busting\nTHEME_NAME = \"themeName\"\nTHEME_VERSION = \"themeVersion\"\n\n# These constants are used by theme.js and the $theme mixin on the front-end\nTOKEN_MAPPING = \"tokenMapping\"\nBRAND_COLORS = \"brandColors\"\nPRIMARY = \"primary\"\nSECONDARY = \"secondary\"\nCOLOR_V50 = \"v_50\"\nCOLOR_V100 = \"v_100\"\nCOLOR_V200 = \"v_200\"\nCOLOR_V300 = \"v_300\"\nCOLOR_V400 = \"v_400\"\nCOLOR_V500 = \"v_500\"\nCOLOR_V600 = \"v_600\"\nCOLOR_V700 = \"v_700\"\nCOLOR_V800 = \"v_800\"\nCOLOR_V900 = \"v_900\"\nSIGN_IN = \"signIn\"\nSIDE_NAV = \"sideNav\"\nAPP_BAR = \"appBar\"\nBACKGROUND = \"background\"\nTITLE = \"title\"\nTITLE_STYLE = \"titleStyle\"\nTOP_LOGO = \"topLogo\"\nIMG_SRC = \"src\"\nIMG_STYLE = \"style\"\nIMG_ALT = \"alt\"\nSHOW_TITLE = \"showTitle\"\nSHOW_K_FOOTER_LOGO = \"showKolibriFooterLogo\"\nSHOW_POWERED_BY = \"showPoweredBy\"\nPOWERED_BY_STYLE = \"poweredByStyle\"\n\n# This is the image file name that will be used when customizing the sign-in background\n# image using the 'kolibri manage background' command. It does not attempt to use a file\n# extension (like .jpg) because we don't know if it's a JPG, SVG, PNG, etc...\nDEFAULT_BG_IMAGE_FILE = \"background_image\"\nDEFAULT_BG_MD5_FILE = \"background_image_md5\"\n\n\ndef _isSet(theme, keys):\n    \"\"\"\n    Given a theme dict, recursively check that all the keys are populated\n    and that the associated value is truthy\n    \"\"\"\n    obj = theme\n    for key in keys:\n        if not obj or key not in obj:\n            return False\n        obj = obj[key]\n    return bool(obj)\n\n\ndef _validateMetadata(theme):\n    if THEME_NAME not in theme:\n        logger.error(\"a theme name must be set\")\n    if THEME_VERSION not in theme:\n        logger.error(\"a theme version must be set\")\n\n\ndef _validateBrandColors(theme):\n    if BRAND_COLORS not in theme:\n        logger.error(\"brand colors not defined by theme\")\n        return\n\n    required_colors = [PRIMARY, SECONDARY]\n    color_names = [\n        COLOR_V50,\n        COLOR_V100,\n        COLOR_V200,\n        COLOR_V300,\n        COLOR_V400,\n        COLOR_V500,\n        COLOR_V600,\n        COLOR_V700,\n        COLOR_V800,\n        COLOR_V900,\n    ]\n    for color in required_colors:\n        if color not in theme[BRAND_COLORS]:\n            logger.error(\"'{}' not defined by theme\".format(color))\n        for name in color_names:\n            if name not in theme[BRAND_COLORS][color]:\n                logger.error(\"{} '{}' not defined by theme\".format(color, name))\n\n\ndef _initFields(theme):\n    \"\"\"\n    set up top-level dicts if they don't exist\n    \"\"\"\n    if SIGN_IN not in theme:\n        theme[SIGN_IN] = {}\n    if TOKEN_MAPPING not in theme:\n        theme[TOKEN_MAPPING] = {}\n    if SIDE_NAV not in theme:\n        theme[SIDE_NAV] = {}\n    if APP_BAR not in theme:\n        theme[APP_BAR] = {}\n\n\nclass ThemeHook(hooks.KolibriHook):\n    \"\"\"\n    A hook to allow custom theming of Kolibri\n    Use this tool to help generate your brand colors: https://materialpalettes.com/\n    \"\"\"\n\n    class Meta:\n        abstract = True\n\n    @property\n    @hooks.only_one_registered\n    def cacheKey(self):\n        theme = list(self.registered_hooks)[0].theme\n        return parse.quote(\n            \"{}-{}-{}\".format(\n                kolibri.__version__, theme[THEME_NAME], theme[THEME_VERSION]\n            )\n        )\n\n    @property\n    @hooks.only_one_registered\n    def theme(self):\n        theme = list(self.registered_hooks)[0].theme\n\n        # some validation and initialization\n        _initFields(theme)\n        _validateMetadata(theme)\n        _validateBrandColors(theme)\n\n        # set up cache busting\n        bust = \"?\" + self.cacheKey\n        if _isSet(theme, [SIGN_IN, BACKGROUND]):\n            theme[SIGN_IN][BACKGROUND] += bust\n        if _isSet(theme, [SIGN_IN, TOP_LOGO, IMG_SRC]):\n            theme[SIGN_IN][TOP_LOGO][IMG_SRC] += bust\n        if _isSet(theme, [SIDE_NAV, TOP_LOGO, IMG_SRC]):\n            theme[SIDE_NAV][TOP_LOGO][IMG_SRC] += bust\n        if _isSet(theme, [APP_BAR, TOP_LOGO, IMG_SRC]):\n            theme[APP_BAR][TOP_LOGO][IMG_SRC] += bust\n\n        # if a background image has been locally set using the `manage background` command, use it\n        bg_img = os.path.join(settings.MEDIA_ROOT, DEFAULT_BG_IMAGE_FILE)\n        if os.path.exists(bg_img):\n            theme[SIGN_IN][BACKGROUND] = parse.urljoin(\n                settings.MEDIA_URL, DEFAULT_BG_IMAGE_FILE\n            )\n            # add cache busting\n            md5_file = os.path.join(settings.MEDIA_ROOT, DEFAULT_BG_MD5_FILE)\n            if os.path.exists(md5_file):\n                with open(md5_file) as f:\n                    theme[SIGN_IN][BACKGROUND] += \"?{}\".format(f.read())\n\n        return theme\n", "path": "kolibri/core/theme_hook.py"}, {"content": "from __future__ import absolute_import\nfrom __future__ import print_function\nfrom __future__ import unicode_literals\n\nfrom django.contrib.staticfiles.templatetags.staticfiles import static\n\nfrom kolibri.plugins.base import KolibriPluginBase\n\nfrom kolibri.core import theme_hook\n\n\nclass DefaultThemePlugin(KolibriPluginBase):\n    pass\n\n\nclass DefaultThemeHook(theme_hook.ThemeHook):\n    @property\n    def theme(self):\n        return {\n            # metadata\n            theme_hook.THEME_NAME: \"Default theme\",\n            theme_hook.THEME_VERSION: 1,  # increment when changes are made\n            # specify primary and secondary brand colors\n            theme_hook.BRAND_COLORS: {\n                theme_hook.PRIMARY: {\n                    theme_hook.COLOR_V50: \"#f0e7ed\",\n                    theme_hook.COLOR_V100: \"#dbc3d4\",\n                    theme_hook.COLOR_V200: \"#c59db9\",\n                    theme_hook.COLOR_V300: \"#ac799d\",\n                    theme_hook.COLOR_V400: \"#996189\",\n                    theme_hook.COLOR_V500: \"#874e77\",\n                    theme_hook.COLOR_V600: \"#7c4870\",\n                    theme_hook.COLOR_V700: \"#6e4167\",\n                    theme_hook.COLOR_V800: \"#5f3b5c\",\n                    theme_hook.COLOR_V900: \"#4b2e4d\",\n                },\n                theme_hook.SECONDARY: {\n                    theme_hook.COLOR_V50: \"#e3f0ed\",\n                    theme_hook.COLOR_V100: \"#badbd2\",\n                    theme_hook.COLOR_V200: \"#8dc5b6\",\n                    theme_hook.COLOR_V300: \"#62af9a\",\n                    theme_hook.COLOR_V400: \"#479e86\",\n                    theme_hook.COLOR_V500: \"#368d74\",\n                    theme_hook.COLOR_V600: \"#328168\",\n                    theme_hook.COLOR_V700: \"#2c715a\",\n                    theme_hook.COLOR_V800: \"#26614d\",\n                    theme_hook.COLOR_V900: \"#1b4634\",\n                },\n            },\n            # sign-in page config\n            theme_hook.SIGN_IN: {\n                theme_hook.BACKGROUND: static(\"background.jpg\"),\n                theme_hook.TITLE: None,  # use default: \"Kolibri\"\n                theme_hook.TOP_LOGO: {\n                    theme_hook.IMG_SRC: None,  # use default Kolibri bird\n                    theme_hook.IMG_STYLE: \"padding-left: 64px; padding-right: 64px; margin-bottom: 8px; margin-top: 8px\",\n                    theme_hook.IMG_ALT: None,\n                },\n                theme_hook.SHOW_POWERED_BY: False,\n                theme_hook.SHOW_TITLE: True,\n                theme_hook.SHOW_K_FOOTER_LOGO: False,\n            },\n            # side-nav config\n            theme_hook.SIDE_NAV: {theme_hook.SHOW_K_FOOTER_LOGO: True},\n            # app bar config\n            theme_hook.APP_BAR: {theme_hook.TOP_LOGO: None},\n        }\n", "path": "kolibri/plugins/default_theme/kolibri_plugin.py"}]}