Repository: learningequality/kolibri

Issue:
Temporary getting a 'Server Error (500)' after upgrading Kolibri 0.15.12 to Kolibri 0.16 beta 7
## Observed behavior
If I install Kolibri 0.15.12 and setup a facility and then upgrade Kolibri to Kolibri 0.16 beta 7 I am seeing a  'Server Error (500)' . On Windows if I restart the device the error disappears, on Ubuntu it seems that waiting for several minutes solves the problem.
This issue is also not being observed when upgrading to the previous beta 6 so must be the result of a recent change.

## Error details

```
ERROR 2023-11-10 17:38:53,583 django.request Internal Server Error: /en/device/
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/kolibri/dist/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/usr/lib/python3/dist-packages/kolibri/dist/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/lib/python3/dist-packages/kolibri/dist/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/lib/python3/dist-packages/kolibri/dist/django/views/generic/base.py", line 68, in view
    return self.dispatch(request, *args, **kwargs)
  File "/usr/lib/python3/dist-packages/kolibri/dist/django/utils/decorators.py", line 67, in _wrapper
    return bound_func(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/kolibri/dist/django/views/decorators/http.py", line 88, in inner
    res_etag = etag_func(request, *args, **kwargs) if etag_func else None
  File "/usr/lib/python3/dist-packages/kolibri/core/decorators.py", line 363, in calculate_spa_etag
    etag = render_and_cache(response, CACHE_KEY_TEMPLATE.format(request.path))
  File "/usr/lib/python3/dist-packages/kolibri/core/decorators.py", line 342, in render_and_cache
    response.render()
  File "/usr/lib/python3/dist-packages/kolibri/dist/django/template/response.py", line 107, in render
    self.content = self.rendered_content
  File "/usr/lib/python3/dist-packages/kolibri/dist/django/template/response.py", line 84, in rendered_content
    content = template.render(context, self._request)
  File "/usr/lib/python3/dist-packages/kolibri/dist/django/template/backends/django.py", line 66, in render
    return self.template.render(context)
  File "/usr/lib/python3/dist-packages/kolibri/dist/django/template/base.py", line 207, in render
    return self._render(context)
  File "/usr/lib/python3/dist-packages/kolibri/dist/django/template/base.py", line 199, in _render
    return self.nodelist.render(context)
  File "/usr/lib/python3/dist-packages/kolibri/dist/django/template/base.py", line 990, in render
    bit = node.render_annotated(context)
  File "/usr/lib/python3/dist-packages/kolibri/dist/django/template/base.py", line 957, in render_annotated
    return self.render(context)
  File "/usr/lib/python3/dist-packages/kolibri/dist/django/template/loader_tags.py", line 177, in render
    return compiled_parent._render(context)
  File "/usr/lib/python3/dist-packages/kolibri/dist/django/template/base.py", line 199, in _render
    return self.nodelist.render(context)
  File "/usr/lib/python3/dist-packages/kolibri/dist/django/template/base.py", line 990, in render
    bit = node.render_annotated(context)
  File "/usr/lib/python3/dist-packages/kolibri/dist/django/template/base.py", line 957, in render_annotated
    return self.render(context)
  File "/usr/lib/python3/dist-packages/kolibri/dist/django/template/loader_tags.py", line 72, in render
    result = block.nodelist.render(context)
  File "/usr/lib/python3/dist-packages/kolibri/dist/django/template/base.py", line 990, in render
    bit = node.render_annotated(context)
  File "/usr/lib/python3/dist-packages/kolibri/dist/django/template/base.py", line 957, in render_annotated
    return self.render(context)
  File "/usr/lib/python3/dist-packages/kolibri/dist/django/template/library.py", line 203, in render
    output = self.func(*resolved_args, **resolved_kwargs)
  File "/usr/lib/python3/dist-packages/kolibri/core/webpack/templatetags/webpack_tags.py", line 42, in webpack_asset
    return hook.render_to_page_load_sync_html()
  File "/usr/lib/python3/dist-packages/kolibri/core/kolibri_plugin.py", line 105, in render_to_page_load_sync_html
    + self.navigation_tags()
  File "/usr/lib/python3/dist-packages/kolibri/core/kolibri_plugin.py", line 90, in navigation_tags
    return [
  File "/usr/lib/python3/dist-packages/kolibri/core/kolibri_plugin.py", line 91, in <listcomp>
    hook.render_to_page_load_sync_html()
  File "/usr/lib/python3/dist-packages/kolibri/core/webpack/hooks.py", line 311, in render_to_page_load_sync_html
    self.plugin_data_tag()
  File "/usr/lib/python3/dist-packages/kolibri/core/webpack/hooks.py", line 220, in plugin_data_tag
    if self.plugin_data:
  File "/usr/lib/python3/dist-packages/kolibri/plugins/learn/kolibri_plugin.py", line 161, in plugin_data
    "allowLearnerDownloads": get_device_setting(
  File "/usr/lib/python3/dist-packages/kolibri/core/device/utils.py", line 64, in get_device_setting
    return getattr(device_settings, setting)
  File "/usr/lib/python3/dist-packages/kolibri/core/device/models.py", line 207, in allow_learner_download_resources
    return self._get_extra("allow_learner_download_resources")
  File "/usr/lib/python3/dist-packages/kolibri/core/device/models.py", line 195, in _get_extra
    return self.extra_settings.get(name, extra_settings_default_values[name])
  File "/usr/lib/python3/dist-packages/kolibri/dist/jsonfield/subclassing.py", line 36, in __get__
    return obj.__dict__[self.field.name]
KeyError: 'extra_settings'
INFO 2023-11-10 17:38:53,653 cherrypy.access 127.0.0.1 - - "GET /en/device/" 500 0 "" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"

```

## Expected behavior
Error free upgrade to Kolibri 0.16 beta 7

## Steps to reproduce the issue
1. Install Kolibri 0.15.12 and setup a facility.
2. Stop Kolibri and upgrade it by installing the [Beta 7 build](https://github.com/learningequality/kolibri/releases/tag/v0.16.0-beta7).

## Video

https://github.com/learningequality/kolibri/assets/79847249/804449bc-f488-4c0d-8da2-9fc393010a87

## Logs

[Windows10.zip](https://github.com/learningequality/kolibri/files/13321195/Windows10.zip)
[Ubuntu.zip](https://github.com/learningequality/kolibri/files/13321196/Ubuntu.zip)

## Usage Details
https://github.com/learningequality/kolibri/releases/tag/v0.16.0-beta7
Windows 10, Ubuntu 22  - Chrome, Firefox


Discussion:
@radinamatic 
I initially encountered this error when upgrading Kolibri 0.15.12 on Windows 10 to 0.16 with the [asset from this PR](https://github.com/learningequality/kolibri/pull/11508), and asked @pcenov to try to replicate (above).

<img width="801" alt="2023-11-09_4-29-39" src="https://github.com/learningequality/kolibri/assets/1457929/388e00e5-b9a0-47fd-82b2-003ef68b461b">


After the first fail with 500 error I closed the taskbar app and tried to start Kolibri from the command prompt, with the following output error:    [upgrade.txt](https://github.com/learningequality/kolibri/files/13322711/upgrade.txt)

As @pcenov mentioned, once the VM is restarted, Kolibri loads fine in the browser without errors, and I managed to sync a couple of LoDs. Server logs after the upgrade: [Windows10-logs.zip](https://github.com/learningequality/kolibri/files/13322708/Windows10-logs.zip)

Same result when upgrading to 0.16b8 from 0.15.12. No need to restart the device, just Kolibri, and the error resolves.


https://github.com/learningequality/kolibri/assets/1457929/b3790e5f-1a72-468b-a0bf-3a4b5fa71e8d



Resolving patch:
diff --git a/kolibri/core/device/models.py b/kolibri/core/device/models.py
--- a/kolibri/core/device/models.py
+++ b/kolibri/core/device/models.py
@@ -192,7 +192,10 @@ def _get_extra(self, name):
         :param name: A str name of the `extra_settings` field
         :return: mixed
         """
-        return self.extra_settings.get(name, extra_settings_default_values[name])
+        try:
+            return self.extra_settings.get(name, extra_settings_default_values[name])
+        except KeyError:
+            return extra_settings_default_values[name]
 
     @property
     def allow_download_on_metered_connection(self):


Test patch: