|
@@ -0,0 +1,225 @@
|
|
|
|
+import json
|
|
|
|
+import os
|
|
|
|
+import sys
|
|
|
|
+from collections import OrderedDict
|
|
|
|
+from pathlib import Path
|
|
|
|
+
|
|
|
|
+from django.core.management.utils import get_random_secret_key
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class File(type(Path())):
|
|
|
|
+ def __new__(cls, *pathsegments):
|
|
|
|
+ return super().__new__(cls, *pathsegments)
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class Directory(type(Path())):
|
|
|
|
+ def __new__(cls, *pathsegments):
|
|
|
|
+ return super().__new__(cls, *pathsegments)
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class DeferredSetting:
|
|
|
|
+ def __init__(self, function):
|
|
|
|
+ self.function = function
|
|
|
|
+
|
|
|
|
+ def __call__(self, settings):
|
|
|
|
+ return self.function(settings)
|
|
|
|
+
|
|
|
|
+"""
|
|
|
|
+# app setting file
|
|
|
|
+
|
|
|
|
+app_dir = AppDir(globals(), ALLOW_AUTO_LOGIN=False, )
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+"""
|
|
|
|
+
|
|
|
|
+disable_config_loader = False
|
|
|
|
+
|
|
|
|
+class NoConfigLoader:
|
|
|
|
+
|
|
|
|
+ def __enter__(self):
|
|
|
|
+ self.disable_config_loader = True
|
|
|
|
+
|
|
|
|
+ def __exit__(self, exc_type, exc_val, exc_tb):
|
|
|
|
+ self.disable_config_loader = False
|
|
|
|
+
|
|
|
|
+def get_option(x, name, **kwargs):
|
|
|
|
+ if name not in x and "default" not in kwargs:
|
|
|
|
+ print(f"Erreur l'option {name} n'est pas définie dans la config", file=sys.stderr)
|
|
|
|
+ exit(-1)
|
|
|
|
+ return x.get(name, kwargs.get("default"))
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class ConfigLoader:
|
|
|
|
+ SECRET = "secret"
|
|
|
|
+ DATA = "data"
|
|
|
|
+ BACKUP = "backup"
|
|
|
|
+ CONFIG = "config"
|
|
|
|
+ LOGS = "logs"
|
|
|
|
+ RUN = "run"
|
|
|
|
+ RUN_FILE = f"{RUN}/app.pid"
|
|
|
|
+ DJANGO_SECRET_FILE = f"{SECRET}/django_secret"
|
|
|
|
+ CONFIG_FILE = f"{CONFIG}/config.json"
|
|
|
|
+
|
|
|
|
+ OTHERS_PATH = {}
|
|
|
|
+ DEFAULT_OPTIONS = OrderedDict([
|
|
|
|
+ ("LANGUAGE_CODE", 'fr-fr'),
|
|
|
|
+ ("TIME_ZONE", "Europe/Paris"),
|
|
|
|
+ ("USE_I18N", True),
|
|
|
|
+ ("USE_TZ", True),
|
|
|
|
+ ("DEBUG", False),
|
|
|
|
+ ("STATIC_URL", 'static/'),
|
|
|
|
+ ("CRON", []),
|
|
|
|
+ ("STATICFILES_DIRS", DeferredSetting(lambda x: [get_option(x, "BASE_DIR") / "frontend" / "build" / "static"])),
|
|
|
|
+ ("TEMPLATES_DIR", DeferredSetting(lambda x: [get_option(x, "BASE_DIR") / "frontend" / "build"])),
|
|
|
|
+ ("ALLOWED_HOSTS", ["*"]),
|
|
|
|
+ ("ROOT_URLCONF", "djangotools.urls"),
|
|
|
|
+ ("CORS_ORIGIN_ALLOW_ALL", True),
|
|
|
|
+ ("DEFAULT_AUTO_FIELD", 'django.db.models.BigAutoField'),
|
|
|
|
+ ("AUTO_LOGIN", DeferredSetting(lambda x: os.environ["USER"])),
|
|
|
|
+ ("ALLOW_AUTO_LOGIN", DeferredSetting(lambda x: get_option(x, "DEBUG") and os.environ.get("ALLOW_AUTO_LOGIN", "False") != "False"))
|
|
|
|
+ ])
|
|
|
|
+
|
|
|
|
+ MANDATORY_OPTIONS = [
|
|
|
|
+ "BASE_DIR", "INSTALLED_APPS",
|
|
|
|
+ ]
|
|
|
|
+
|
|
|
|
+ def __init__(self, global_muodule, app_dir=None, **kwargs):
|
|
|
|
+ if disable_config_loader: return
|
|
|
|
+ self.kwargs = kwargs
|
|
|
|
+ self.global_muodule = global_muodule
|
|
|
|
+ if app_dir is not None:
|
|
|
|
+ self.app_dir = Directory(app_dir)
|
|
|
|
+ elif "APP_DIR" in os.environ:
|
|
|
|
+ self.app_dir = Directory(os.environ["APP_DIR"])
|
|
|
|
+ elif "app_dir" in global_muodule:
|
|
|
|
+ self.app_dir = Directory(global_muodule["app_dir"])
|
|
|
|
+ else:
|
|
|
|
+ raise ValueError("")
|
|
|
|
+
|
|
|
|
+ self.data_dir = Directory(self.app_dir / self.DATA)
|
|
|
|
+ self.secret_dir = Directory(self.app_dir / self.SECRET)
|
|
|
|
+ self.config_dir = Directory(self.app_dir / self.CONFIG)
|
|
|
|
+ self.config_file = File(self.app_dir / self.CONFIG_FILE)
|
|
|
|
+ self.backup_dir = Directory(self.app_dir / self.BACKUP)
|
|
|
|
+ self.logs_dir = Directory(self.app_dir / self.LOGS)
|
|
|
|
+ self.run_dir = Directory(self.app_dir / self.RUN)
|
|
|
|
+ self.run_file = File(self.app_dir / self.RUN_FILE)
|
|
|
|
+ self.django_secret_file = File(self.app_dir / self.DJANGO_SECRET_FILE)
|
|
|
|
+
|
|
|
|
+ for path in [self.app_dir, self.data_dir, self.backup_dir, self.secret_dir, self.config_dir, self.logs_dir]:
|
|
|
|
+ if not path.exists(): path.mkdir(parents=True)
|
|
|
|
+
|
|
|
|
+ if not self.config_file.is_file():
|
|
|
|
+ self.config_file.write_text("{}")
|
|
|
|
+
|
|
|
|
+ for name, path in self.OTHERS_PATH.items():
|
|
|
|
+ if isinstance(path, Directory):
|
|
|
|
+ path.mkdir(exist_ok=True, parents=True)
|
|
|
|
+ setattr(self, name, path)
|
|
|
|
+
|
|
|
|
+ def _absolutize(self, data, root=None):
|
|
|
|
+ if root is None: root = self.global_muodule["BASE_DIR"]
|
|
|
|
+ dirs = []
|
|
|
|
+ for x in data:
|
|
|
|
+ if not isinstance(x, Path):
|
|
|
|
+ x = Path(x)
|
|
|
|
+ if not x.is_absolute():
|
|
|
|
+ x = root / x
|
|
|
|
+ dirs.append(x)
|
|
|
|
+ return dirs
|
|
|
|
+
|
|
|
|
+ def process_checks(self):
|
|
|
|
+ errors = []
|
|
|
|
+ for x in self.MANDATORY_OPTIONS:
|
|
|
|
+ if x not in self.global_muodule:
|
|
|
|
+ errors.append(x)
|
|
|
|
+
|
|
|
|
+ if errors:
|
|
|
|
+ [print(f"Erreur de configuration, l'option '{x}' n'est pas passé dans les settings", file=sys.stderr) for x in errors]
|
|
|
|
+ exit(-1)
|
|
|
|
+
|
|
|
|
+ if "SECRET_KEY" not in self.global_muodule:
|
|
|
|
+ if not self.django_secret_file.is_file():
|
|
|
|
+ self.django_secret_file.write_text(get_random_secret_key())
|
|
|
|
+ self.global_muodule["SECRET_KEY"] = self.django_secret_file.read_text()
|
|
|
|
+
|
|
|
|
+ if "DATABASES" not in self.global_muodule:
|
|
|
|
+ self.global_muodule["DATABASES"] = {
|
|
|
|
+ 'default': {
|
|
|
|
+ 'ENGINE': 'django.db.backends.sqlite3',
|
|
|
|
+ 'NAME': self.data_dir / "db.sqlite3",
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if "AUTH_PASSWORD_VALIDATORS" not in self.global_muodule:
|
|
|
|
+ self.global_muodule["AUTH_PASSWORD_VALIDATORS"] = [
|
|
|
|
+ {
|
|
|
|
+ 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
|
|
|
+ },
|
|
|
|
+ ]
|
|
|
|
+
|
|
|
|
+ if "django.contrib.staticfiles" in self.global_muodule["INSTALLED_APPS"]:
|
|
|
|
+ self.global_muodule["STATICFILES_DIRS"] = self._absolutize(self.global_muodule["STATICFILES_DIRS"])
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ if "TEMPLATES" not in self.global_muodule:
|
|
|
|
+ templates_dirs = self._absolutize(self.global_muodule["TEMPLATES_DIR"])
|
|
|
|
+ self.global_muodule["TEMPLATES"] = [
|
|
|
|
+ {
|
|
|
|
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
|
|
|
+ 'DIRS': templates_dirs,
|
|
|
|
+ 'APP_DIRS': True,
|
|
|
|
+ 'OPTIONS': {
|
|
|
|
+ 'context_processors': [
|
|
|
|
+ 'django.template.context_processors.debug',
|
|
|
|
+ 'django.template.context_processors.request',
|
|
|
|
+ 'django.contrib.auth.context_processors.auth',
|
|
|
|
+ 'django.contrib.messages.context_processors.messages',
|
|
|
|
+ ],
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ ]
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ def init(self):
|
|
|
|
+ if disable_config_loader: return
|
|
|
|
+
|
|
|
|
+ for k, v in self.kwargs.items():
|
|
|
|
+ if k not in self.global_muodule:
|
|
|
|
+ self.global_muodule[k] = v
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ for k, v in self.DEFAULT_OPTIONS.items():
|
|
|
|
+ if isinstance(v, DeferredSetting):
|
|
|
|
+ v = v(self.global_muodule)
|
|
|
|
+ self.global_muodule.setdefault(k, v)
|
|
|
|
+
|
|
|
|
+ data = json.loads(self.config_file.read_text())
|
|
|
|
+ for k, v in data.items():
|
|
|
|
+ self.global_muodule[k] = v
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ self.process_checks()
|
|
|
|
+
|
|
|
|
+
|