-
Notifications
You must be signed in to change notification settings - Fork 2
/
kolibri_utils.py
147 lines (111 loc) · 4.43 KB
/
kolibri_utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
from __future__ import annotations
import importlib.util
import json
import logging
import os
import platform
import tempfile
from gettext import gettext as _
from pathlib import Path
from kolibri_app.config import ENDLESS_KEY_DATA_DIR
from kolibri_app.globals import APP_AUTOMATIC_PROVISION
from .content_extensions_manager import ContentExtensionsManager
logger = logging.getLogger(__name__)
# These Kolibri plugins must be enabled for the application to function:
REQUIRED_PLUGINS = [
"kolibri.plugins.app",
"kolibri_explore_plugin",
]
# These Kolibri plugins will be automatically enabled if they are available:
OPTIONAL_PLUGINS = [
"kolibri_app_desktop_xdg_plugin",
"kolibri_desktop_auth_plugin",
"kolibri_dynamic_collections_plugin",
"kolibri_zim_plugin",
]
DISABLED_PLUGINS = [
"kolibri.plugins.learn",
]
# TODO: Automatically enable plugins from flatpak plugin extensions.
def init_kolibri(**kwargs):
_init_kolibri_env()
from kolibri.utils.main import initialize
for plugin_name in DISABLED_PLUGINS:
_disable_kolibri_plugin(plugin_name)
for plugin_name in REQUIRED_PLUGINS:
_enable_kolibri_plugin(plugin_name)
for plugin_name in OPTIONAL_PLUGINS:
_enable_kolibri_plugin(plugin_name, optional=True)
initialize(**kwargs)
if APP_AUTOMATIC_PROVISION:
_kolibri_automatic_provision()
def _init_kolibri_env():
os.environ["DJANGO_SETTINGS_MODULE"] = "kolibri_app.kolibri_settings"
os.environ["KOLIBRI_PROJECT"] = "endless-key-flatpak"
# Kolibri defaults to a very large thread pool. Because we expect this
# application to be used in a single user environment with a limited
# workload, we can use a smaller number of threads.
os.environ.setdefault("KOLIBRI_CHERRYPY_THREAD_POOL", "10")
os.environ.setdefault(
"KOLIBRI_APPS_BUNDLE_PATH", Path(ENDLESS_KEY_DATA_DIR, "apps-bundle").as_posix()
)
os.environ.setdefault(
"KOLIBRI_CONTENT_COLLECTIONS_PATH",
Path(ENDLESS_KEY_DATA_DIR, "collections").as_posix(),
)
content_extensions_manager = ContentExtensionsManager()
content_extensions_manager.apply(os.environ)
def _enable_kolibri_plugin(plugin_name: str, optional=False) -> bool:
from kolibri.plugins import config as plugins_config
from kolibri.plugins.utils import enable_plugin
if optional and not importlib.util.find_spec(plugin_name):
return False
if plugin_name not in plugins_config.ACTIVE_PLUGINS:
logger.info(f"Enabling plugin {plugin_name}")
enable_plugin(plugin_name)
return True
def _disable_kolibri_plugin(plugin_name: str, optional=False) -> bool:
from kolibri.plugins import config as plugins_config
from kolibri.plugins.utils import disable_plugin
if plugin_name in plugins_config.ACTIVE_PLUGINS:
logger.info(f"Disabling plugin {plugin_name}")
disable_plugin(plugin_name)
return True
def _kolibri_automatic_provision():
from kolibri.core.device.utils import device_provisioned
from kolibri.core.device.utils import provision_from_file
if device_provisioned():
return
# It is better to create a TemporaryDirectory containing a file, because
# provision_from_file deals with file paths instead of open files, and it
# deletes the provided file, which confuses tempfile.NamedTemporaryFile.
with tempfile.TemporaryDirectory() as directory:
file = Path(directory, "automatic_provision.json").open("w")
json.dump(_get_automatic_provision_data(), file)
file.flush()
provision_from_file(file.name)
def _get_automatic_provision_data() -> dict:
facility_name = _("Endless Key on {host}").format(
host=platform.node() or "localhost"
)
return {
"facility_name": facility_name,
"preset": "formal",
"facility_settings": {
"learner_can_login_with_no_password": False,
},
"device_settings": {
# Kolibri interprets None as "the system language at setup time",
# while an empty string causes Kolibri to always use the current
# browser language:
# <https://github.com/learningequality/kolibri/issues/11248>
"language_id": "",
"landing_page": "learn",
"allow_guest_access": False,
"allow_other_browsers_to_connect": False,
},
"superuser": {
"username": None,
"password": None,
},
}