df_config 1.2.55__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- df_config/__init__.py +22 -0
- df_config/__main__.py +3 -0
- df_config/application.py +24 -0
- df_config/apps/__init__.py +15 -0
- df_config/apps/allauth.py +28 -0
- df_config/apps/backends.py +72 -0
- df_config/apps/middleware.py +136 -0
- df_config/apps/pipeline.py +180 -0
- df_config/checks.py +26 -0
- df_config/config/__init__.py +15 -0
- df_config/config/base.py +27 -0
- df_config/config/defaults.py +675 -0
- df_config/config/dynamic_settings.py +598 -0
- df_config/config/fields.py +257 -0
- df_config/config/fields_providers.py +71 -0
- df_config/config/merger.py +250 -0
- df_config/config/url.py +292 -0
- df_config/config/values_providers.py +296 -0
- df_config/context_processors.py +29 -0
- df_config/extra/__init__.py +0 -0
- df_config/extra/loki.py +21 -0
- df_config/guesses/__init__.py +15 -0
- df_config/guesses/apps.py +235 -0
- df_config/guesses/auth.py +248 -0
- df_config/guesses/databases.py +244 -0
- df_config/guesses/djt.py +32 -0
- df_config/guesses/log.py +717 -0
- df_config/guesses/misc.py +513 -0
- df_config/guesses/pipeline.py +95 -0
- df_config/guesses/social_providers.py +258 -0
- df_config/guesses/staticfiles.py +207 -0
- df_config/iniconf.py +512 -0
- df_config/manage.py +152 -0
- df_config/management/__init__.py +15 -0
- df_config/management/commands/__init__.py +15 -0
- df_config/management/commands/collectstatic.py +29 -0
- df_config/management/commands/config.py +231 -0
- df_config/management/commands/server.py +156 -0
- df_config/models.py +45 -0
- df_config/root_urls.py +115 -0
- df_config/static/favicon/apple-touch-icon-precomposed.png +0 -0
- df_config/static/favicon/apple-touch-icon.png +0 -0
- df_config/static/favicon/favicon.ico +0 -0
- df_config/static/favicon/robots.txt +2 -0
- df_config/static/js/df_config.min.js +2 -0
- df_config/static/js/df_config.min.js.map +1 -0
- df_config/urls.py +1 -0
- df_config/utils.py +311 -0
- df_config-1.2.55.dist-info/LICENSE +515 -0
- df_config-1.2.55.dist-info/METADATA +296 -0
- df_config-1.2.55.dist-info/RECORD +52 -0
- df_config-1.2.55.dist-info/WHEEL +4 -0
df_config/__init__.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# #############################################################################
|
|
2
|
+
# This file is part of df_config #
|
|
3
|
+
# #
|
|
4
|
+
# Copyright (C) 2020 Matthieu Gallet <df_config@19pouces.net> #
|
|
5
|
+
# All Rights Reserved #
|
|
6
|
+
# #
|
|
7
|
+
# You may use, distribute and modify this code under the #
|
|
8
|
+
# terms of the (BSD-like) CeCILL-B license. #
|
|
9
|
+
# #
|
|
10
|
+
# You should have received a copy of the CeCILL-B license with #
|
|
11
|
+
# this file. If not, please visit: #
|
|
12
|
+
# https://cecill.info/licences/Licence_CeCILL-B_V1-en.txt (English) #
|
|
13
|
+
# or https://cecill.info/licences/Licence_CeCILL-B_V1-fr.txt (French) #
|
|
14
|
+
# #
|
|
15
|
+
# #############################################################################
|
|
16
|
+
"""__init__ file."""
|
|
17
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
__version__ = version("df_config")
|
|
21
|
+
except PackageNotFoundError:
|
|
22
|
+
__version__ = "1.0.0"
|
df_config/__main__.py
ADDED
df_config/application.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# ##############################################################################
|
|
2
|
+
# This file is part of df_config #
|
|
3
|
+
# #
|
|
4
|
+
# Copyright (C) 2020 Matthieu Gallet <df_config@19pouces.net> #
|
|
5
|
+
# All Rights Reserved #
|
|
6
|
+
# #
|
|
7
|
+
# You may use, distribute and modify this code under the #
|
|
8
|
+
# terms of the (BSD-like) CeCILL-B license. #
|
|
9
|
+
# #
|
|
10
|
+
# You should have received a copy of the CeCILL-B license with #
|
|
11
|
+
# this file. If not, please visit: #
|
|
12
|
+
# https://cecill.info/licences/Licence_CeCILL-B_V1-en.txt (English) #
|
|
13
|
+
# or https://cecill.info/licences/Licence_CeCILL-B_V1-fr.txt (French) #
|
|
14
|
+
# #
|
|
15
|
+
# ##############################################################################
|
|
16
|
+
from django.core.wsgi import get_wsgi_application
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
from django.core.asgi import get_asgi_application
|
|
20
|
+
except ImportError:
|
|
21
|
+
get_asgi_application = get_wsgi_application
|
|
22
|
+
|
|
23
|
+
wsgi_application = get_wsgi_application()
|
|
24
|
+
asgi_application = get_asgi_application()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# ##############################################################################
|
|
2
|
+
# This file is part of df_config #
|
|
3
|
+
# #
|
|
4
|
+
# Copyright (C) 2020 Matthieu Gallet <df_config@19pouces.net> #
|
|
5
|
+
# All Rights Reserved #
|
|
6
|
+
# #
|
|
7
|
+
# You may use, distribute and modify this code under the #
|
|
8
|
+
# terms of the (BSD-like) CeCILL-B license. #
|
|
9
|
+
# #
|
|
10
|
+
# You should have received a copy of the CeCILL-B license with #
|
|
11
|
+
# this file. If not, please visit: #
|
|
12
|
+
# https://cecill.info/licences/Licence_CeCILL-B_V1-en.txt (English) #
|
|
13
|
+
# or https://cecill.info/licences/Licence_CeCILL-B_V1-fr.txt (French) #
|
|
14
|
+
# #
|
|
15
|
+
# ##############################################################################
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# ##############################################################################
|
|
2
|
+
# This file is part of df_config #
|
|
3
|
+
# #
|
|
4
|
+
# Copyright (C) 2020 Matthieu Gallet <df_config@19pouces.net> #
|
|
5
|
+
# All Rights Reserved #
|
|
6
|
+
# #
|
|
7
|
+
# You may use, distribute and modify this code under the #
|
|
8
|
+
# terms of the (BSD-like) CeCILL-B license. #
|
|
9
|
+
# #
|
|
10
|
+
# You should have received a copy of the CeCILL-B license with #
|
|
11
|
+
# this file. If not, please visit: #
|
|
12
|
+
# https://cecill.info/licences/Licence_CeCILL-B_V1-en.txt (English) #
|
|
13
|
+
# or https://cecill.info/licences/Licence_CeCILL-B_V1-fr.txt (French) #
|
|
14
|
+
# #
|
|
15
|
+
# ##############################################################################
|
|
16
|
+
|
|
17
|
+
from django.conf import settings
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
from allauth.account.adapter import DefaultAccountAdapter
|
|
21
|
+
except ImportError:
|
|
22
|
+
DefaultAccountAdapter = object
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class AccountAdapter(DefaultAccountAdapter):
|
|
26
|
+
# noinspection PyMethodMayBeStatic,PyUnusedLocal
|
|
27
|
+
def is_open_for_signup(self, request):
|
|
28
|
+
return settings.DF_ALLOW_USER_CREATION and settings.DF_ALLOW_LOCAL_USERS
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# ##############################################################################
|
|
2
|
+
# This file is part of df_config #
|
|
3
|
+
# #
|
|
4
|
+
# Copyright (C) 2020 Matthieu Gallet <df_config@19pouces.net> #
|
|
5
|
+
# All Rights Reserved #
|
|
6
|
+
# #
|
|
7
|
+
# You may use, distribute and modify this code under the #
|
|
8
|
+
# terms of the (BSD-like) CeCILL-B license. #
|
|
9
|
+
# #
|
|
10
|
+
# You should have received a copy of the CeCILL-B license with #
|
|
11
|
+
# this file. If not, please visit: #
|
|
12
|
+
# https://cecill.info/licences/Licence_CeCILL-B_V1-en.txt (English) #
|
|
13
|
+
# or https://cecill.info/licences/Licence_CeCILL-B_V1-fr.txt (French) #
|
|
14
|
+
# #
|
|
15
|
+
# ##############################################################################
|
|
16
|
+
import logging
|
|
17
|
+
|
|
18
|
+
from django.conf import settings
|
|
19
|
+
from django.contrib.auth.backends import RemoteUserBackend
|
|
20
|
+
from django.contrib.auth.models import Group
|
|
21
|
+
from django.utils.functional import cached_property
|
|
22
|
+
|
|
23
|
+
logger = logging.getLogger("django.request")
|
|
24
|
+
|
|
25
|
+
_CACHED_GROUPS = {}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class DefaultGroupsRemoteUserBackend(RemoteUserBackend):
|
|
29
|
+
"""Add groups to new users.
|
|
30
|
+
Based on :class:`django.contrib.auth.backends.RemoteUserBackend`.
|
|
31
|
+
Only overrides the `configure_user` method to add the required groups.
|
|
32
|
+
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def create_unknown_user(self):
|
|
37
|
+
return settings.DF_ALLOW_USER_CREATION
|
|
38
|
+
|
|
39
|
+
@cached_property
|
|
40
|
+
def ldap_backend(self):
|
|
41
|
+
# noinspection PyUnresolvedReferences
|
|
42
|
+
from django_auth_ldap.backend import LDAPBackend
|
|
43
|
+
|
|
44
|
+
return LDAPBackend()
|
|
45
|
+
|
|
46
|
+
def authenticate(self, *args, **kwargs):
|
|
47
|
+
remote_user = kwargs.get("remote_user")
|
|
48
|
+
if (
|
|
49
|
+
remote_user
|
|
50
|
+
and settings.AUTH_LDAP_SERVER_URI
|
|
51
|
+
and settings.AUTH_LDAP_ALWAYS_UPDATE_USER
|
|
52
|
+
):
|
|
53
|
+
user = self.ldap_backend.populate_user(remote_user)
|
|
54
|
+
if user:
|
|
55
|
+
return user
|
|
56
|
+
return super().authenticate(*args, remote_user)
|
|
57
|
+
|
|
58
|
+
def configure_user(self, request, user=None, created=True):
|
|
59
|
+
"""
|
|
60
|
+
Configure a user after creation and returns the updated user.
|
|
61
|
+
|
|
62
|
+
By default, returns the user unmodified; only add it to the default group.
|
|
63
|
+
"""
|
|
64
|
+
if user is None: # compatibility
|
|
65
|
+
user = request
|
|
66
|
+
for group_name in settings.DF_DEFAULT_GROUPS:
|
|
67
|
+
if group_name not in _CACHED_GROUPS:
|
|
68
|
+
_CACHED_GROUPS[group_name] = Group.objects.get_or_create(
|
|
69
|
+
name=str(group_name)
|
|
70
|
+
)[0]
|
|
71
|
+
user.groups.add(_CACHED_GROUPS[group_name])
|
|
72
|
+
return user
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# ##############################################################################
|
|
2
|
+
# This file is part of df_config #
|
|
3
|
+
# #
|
|
4
|
+
# Copyright (C) 2020 Matthieu Gallet <df_config@19pouces.net> #
|
|
5
|
+
# All Rights Reserved #
|
|
6
|
+
# #
|
|
7
|
+
# You may use, distribute and modify this code under the #
|
|
8
|
+
# terms of the (BSD-like) CeCILL-B license. #
|
|
9
|
+
# #
|
|
10
|
+
# You should have received a copy of the CeCILL-B license with #
|
|
11
|
+
# this file. If not, please visit: #
|
|
12
|
+
# https://cecill.info/licences/Licence_CeCILL-B_V1-en.txt (English) #
|
|
13
|
+
# or https://cecill.info/licences/Licence_CeCILL-B_V1-fr.txt (French) #
|
|
14
|
+
# #
|
|
15
|
+
# ##############################################################################
|
|
16
|
+
import base64
|
|
17
|
+
import binascii
|
|
18
|
+
import logging
|
|
19
|
+
from functools import lru_cache
|
|
20
|
+
|
|
21
|
+
from django.conf import settings
|
|
22
|
+
from django.contrib import auth
|
|
23
|
+
from django.contrib.auth.middleware import (
|
|
24
|
+
RemoteUserMiddleware as BaseRemoteUserMiddleware,
|
|
25
|
+
)
|
|
26
|
+
from django.core.exceptions import ImproperlyConfigured
|
|
27
|
+
from django.http import HttpRequest
|
|
28
|
+
from django.utils.functional import cached_property
|
|
29
|
+
|
|
30
|
+
logger = logging.getLogger("django.request")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class DFConfigMiddleware(BaseRemoteUserMiddleware):
|
|
34
|
+
"""Like :class:`django.contrib.auth.middleware.RemoteUserMiddleware` but:
|
|
35
|
+
|
|
36
|
+
* can use any header defined by the setting `DF_REMOTE_USER_HEADER`,
|
|
37
|
+
* handle the HTTP_X_FORWARDED_FOR HTTP header (set the right client IP)
|
|
38
|
+
* handle HTTP basic authentication
|
|
39
|
+
* set response header for Internet Explorer (to use its most recent render engine)
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
@lru_cache()
|
|
43
|
+
def get_remoteuser_header(self):
|
|
44
|
+
# avoid cached_property to ease unittests
|
|
45
|
+
header = settings.DF_REMOTE_USER_HEADER
|
|
46
|
+
if header:
|
|
47
|
+
header = header.upper().replace("-", "_")
|
|
48
|
+
return header
|
|
49
|
+
|
|
50
|
+
def process_request(self, request: HttpRequest):
|
|
51
|
+
request.remote_username = None
|
|
52
|
+
|
|
53
|
+
if settings.USE_X_FORWARDED_FOR and "HTTP_X_FORWARDED_FOR" in request.META:
|
|
54
|
+
request.META["REMOTE_ADDR"] = (
|
|
55
|
+
request.META["HTTP_X_FORWARDED_FOR"].split(",")[0].strip()
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
if settings.USE_HTTP_BASIC_AUTH and "HTTP_AUTHORIZATION" in request.META:
|
|
59
|
+
authentication = request.META["HTTP_AUTHORIZATION"]
|
|
60
|
+
authmeth, sep, auth_data = authentication.partition(" ")
|
|
61
|
+
if sep == " " and authmeth.lower() == "basic":
|
|
62
|
+
try:
|
|
63
|
+
auth_data = base64.b64decode(auth_data.strip()).decode("utf-8")
|
|
64
|
+
except binascii.Error:
|
|
65
|
+
auth_data = ""
|
|
66
|
+
except UnicodeDecodeError:
|
|
67
|
+
auth_data = ""
|
|
68
|
+
username, sep, password = auth_data.partition(":")
|
|
69
|
+
if sep == ":":
|
|
70
|
+
user = auth.authenticate(username=username, password=password)
|
|
71
|
+
if user:
|
|
72
|
+
request.user = user
|
|
73
|
+
auth.login(request, user)
|
|
74
|
+
username = getattr(settings, "DF_FAKE_AUTHENTICATION_USERNAME", None)
|
|
75
|
+
|
|
76
|
+
header = self.get_remoteuser_header()
|
|
77
|
+
if header and username and settings.DEBUG:
|
|
78
|
+
remote_addr = request.META.get("REMOTE_ADDR")
|
|
79
|
+
if remote_addr in settings.INTERNAL_IPS:
|
|
80
|
+
request.META[header] = username
|
|
81
|
+
elif remote_addr:
|
|
82
|
+
logger.warning(
|
|
83
|
+
"Unable to use `settings.DF_FAKE_AUTHENTICATION_USERNAME`. "
|
|
84
|
+
"You should add %s to the list `settings.INTERNAL_IPS`."
|
|
85
|
+
% remote_addr
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
if header and header in request.META:
|
|
89
|
+
remote_username = request.META.get(header)
|
|
90
|
+
if (
|
|
91
|
+
not remote_username or remote_username == "(null)"
|
|
92
|
+
): # special case due to apache2+auth_mod_kerb :-(
|
|
93
|
+
return
|
|
94
|
+
remote_username = self.format_remote_username(remote_username)
|
|
95
|
+
# noinspection PyTypeChecker
|
|
96
|
+
self.remote_user_authentication(request, remote_username)
|
|
97
|
+
|
|
98
|
+
# noinspection PyUnusedLocal,PyMethodMayBeStatic
|
|
99
|
+
def process_response(self, request, response):
|
|
100
|
+
response["X-UA-Compatible"] = "IE=edge,chrome=1"
|
|
101
|
+
return response
|
|
102
|
+
|
|
103
|
+
def remote_user_authentication(self, request, username):
|
|
104
|
+
# AuthenticationMiddleware is required so that request.user exists.
|
|
105
|
+
# noinspection PyTypeChecker
|
|
106
|
+
if not hasattr(request, "user"):
|
|
107
|
+
raise ImproperlyConfigured(
|
|
108
|
+
"The Django remote user auth middleware requires the"
|
|
109
|
+
" authentication middleware to be installed. Edit your"
|
|
110
|
+
" MIDDLEWARE_CLASSES setting to insert"
|
|
111
|
+
" 'django.contrib.auth.middleware.AuthenticationMiddleware'"
|
|
112
|
+
" before the RemoteUserMiddleware class."
|
|
113
|
+
)
|
|
114
|
+
# If the user is already authenticated and that user is the user we are
|
|
115
|
+
# getting passed in the headers, then the correct user is already
|
|
116
|
+
# persisted in the session and we don't need to continue.
|
|
117
|
+
if request.user.is_authenticated:
|
|
118
|
+
cleaned_username = self.clean_username(username, request)
|
|
119
|
+
if request.user.get_username() == cleaned_username:
|
|
120
|
+
request.remote_username = cleaned_username
|
|
121
|
+
return
|
|
122
|
+
else:
|
|
123
|
+
self._remove_invalid_user(request)
|
|
124
|
+
# We are seeing this user for the first time in this session, attempt
|
|
125
|
+
# to authenticate the user.
|
|
126
|
+
user = auth.authenticate(remote_user=username)
|
|
127
|
+
if user:
|
|
128
|
+
# User is valid. Set request.user and persist user in the session
|
|
129
|
+
# by logging the user in.
|
|
130
|
+
request.user = user
|
|
131
|
+
auth.login(request, user)
|
|
132
|
+
request.remote_username = user.username
|
|
133
|
+
|
|
134
|
+
# noinspection PyMethodMayBeStatic
|
|
135
|
+
def format_remote_username(self, remote_username):
|
|
136
|
+
return remote_username.partition("@")[0]
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# ##############################################################################
|
|
2
|
+
# This file is part of df_config #
|
|
3
|
+
# #
|
|
4
|
+
# Copyright (C) 2020 Matthieu Gallet <df_config@19pouces.net> #
|
|
5
|
+
# All Rights Reserved #
|
|
6
|
+
# #
|
|
7
|
+
# You may use, distribute and modify this code under the #
|
|
8
|
+
# terms of the (BSD-like) CeCILL-B license. #
|
|
9
|
+
# #
|
|
10
|
+
# You should have received a copy of the CeCILL-B license with #
|
|
11
|
+
# this file. If not, please visit: #
|
|
12
|
+
# https://cecill.info/licences/Licence_CeCILL-B_V1-en.txt (English) #
|
|
13
|
+
# or https://cecill.info/licences/Licence_CeCILL-B_V1-fr.txt (French) #
|
|
14
|
+
# #
|
|
15
|
+
# ##############################################################################
|
|
16
|
+
"""Define extra compressors or compilers for django-pipeline."""
|
|
17
|
+
|
|
18
|
+
import os
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
from django.conf import settings
|
|
22
|
+
|
|
23
|
+
if settings.USE_PIPELINE:
|
|
24
|
+
from pipeline.compilers import SubProcessCompiler
|
|
25
|
+
from pipeline.compressors import SubProcessCompressor
|
|
26
|
+
from pipeline.storage import PipelineManifestStorage, PipelineMixin
|
|
27
|
+
else:
|
|
28
|
+
SubProcessCompressor = object
|
|
29
|
+
SubProcessCompiler = object
|
|
30
|
+
PipelineManifestStorage = None
|
|
31
|
+
PipelineMixin = None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
if settings.USE_WHITENOISE:
|
|
35
|
+
# noinspection PyPackageRequirements,PyUnresolvedReferences
|
|
36
|
+
from whitenoise.storage import CompressedManifestStaticFilesStorage
|
|
37
|
+
else:
|
|
38
|
+
CompressedManifestStaticFilesStorage = None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class RcssCompressor(SubProcessCompressor):
|
|
42
|
+
"""CSS compressor based on the Python library rcssmin.
|
|
43
|
+
|
|
44
|
+
(https://github.com/ndparker/rcssmin).
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
def filter_css(self, css):
|
|
48
|
+
"""Not implemented."""
|
|
49
|
+
raise NotImplementedError
|
|
50
|
+
|
|
51
|
+
def filter_js(self, js):
|
|
52
|
+
"""Not implemented."""
|
|
53
|
+
raise NotImplementedError
|
|
54
|
+
|
|
55
|
+
# noinspection PyMethodMayBeStatic
|
|
56
|
+
def compress_css(self, css):
|
|
57
|
+
"""Compress a block of CSS code using the "rcssmin" module."""
|
|
58
|
+
# noinspection PyUnresolvedReferences,PyPackageRequirements
|
|
59
|
+
from rcssmin import cssmin
|
|
60
|
+
|
|
61
|
+
return cssmin(css)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class CssNanoCompressor(SubProcessCompressor):
|
|
65
|
+
"""CSS compressor based on the "cssnano" command."""
|
|
66
|
+
|
|
67
|
+
def compress_css(self, css):
|
|
68
|
+
"""Compress a block of CSS code using the "cssnano" command."""
|
|
69
|
+
command = [settings.CSSNANO_BINARY] + settings.CSSNANO_ARGUMENTS
|
|
70
|
+
return self.execute_command(command, css)
|
|
71
|
+
|
|
72
|
+
def filter_css(self, css):
|
|
73
|
+
"""Not implemented."""
|
|
74
|
+
raise NotImplementedError
|
|
75
|
+
|
|
76
|
+
def filter_js(self, js):
|
|
77
|
+
"""Not implemented."""
|
|
78
|
+
raise NotImplementedError
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class TerserCompressor(SubProcessCompressor):
|
|
82
|
+
"""JavaScript compressor based on the "terser" command."""
|
|
83
|
+
|
|
84
|
+
def compress_js(self, js):
|
|
85
|
+
"""Compress a block of JavaScript code using the "terser" command."""
|
|
86
|
+
command = [settings.TERSER_BINARY, settings.TERSER_ARGUMENTS, "--"]
|
|
87
|
+
if self.verbose:
|
|
88
|
+
command += ["--verbose"]
|
|
89
|
+
return self.execute_command(command, js)
|
|
90
|
+
|
|
91
|
+
def filter_css(self, css):
|
|
92
|
+
"""Not implemented."""
|
|
93
|
+
raise NotImplementedError
|
|
94
|
+
|
|
95
|
+
def filter_js(self, js):
|
|
96
|
+
"""Not implemented."""
|
|
97
|
+
raise NotImplementedError
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class PyScssCompiler(SubProcessCompiler):
|
|
101
|
+
"""SASS (.scss) compiler based on the Python library pyScss.
|
|
102
|
+
|
|
103
|
+
(http://pyscss.readthedocs.io/en/latest/ ).
|
|
104
|
+
However, this compiler is limited to SASS 3.2 and cannot compile modern projets like Bootstrap 4.
|
|
105
|
+
Please use :class:`pipeline.compilers.sass.SASSCompiler` if you use modern SCSS files.
|
|
106
|
+
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
output_extension = "css"
|
|
110
|
+
|
|
111
|
+
# noinspection PyMethodMayBeStatic
|
|
112
|
+
def match_file(self, filename):
|
|
113
|
+
"""Return True if the file is a SASS file."""
|
|
114
|
+
return filename.endswith(".scss") or filename.endswith(".sass")
|
|
115
|
+
|
|
116
|
+
# noinspection PyUnusedLocal
|
|
117
|
+
def compile_file(self, infile, outfile, outdated=False, force=False):
|
|
118
|
+
"""Compile a SASS file using the "scss" command."""
|
|
119
|
+
# noinspection PyUnresolvedReferences,PyUnresolvedReferences,PyPackageRequirements
|
|
120
|
+
from scss import Compiler
|
|
121
|
+
|
|
122
|
+
root = Path(os.path.abspath(settings.STATIC_ROOT))
|
|
123
|
+
compiler = Compiler(root=root, search_path=("./",))
|
|
124
|
+
css_content = compiler.compile(infile)
|
|
125
|
+
with open(outfile, "w") as fd:
|
|
126
|
+
fd.write(css_content)
|
|
127
|
+
# noinspection PyUnresolvedReferences
|
|
128
|
+
if self.verbose:
|
|
129
|
+
print(css_content)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class TypescriptCompiler(SubProcessCompiler):
|
|
133
|
+
"""TypeScript (.ts) compiler using "tsc" (https://www.typescriptlang.org)."""
|
|
134
|
+
|
|
135
|
+
output_extension = "js"
|
|
136
|
+
|
|
137
|
+
# noinspection PyMethodMayBeStatic
|
|
138
|
+
def match_file(self, filename):
|
|
139
|
+
"""Return True if the file is a TypeScript file."""
|
|
140
|
+
return filename.endswith(".ts")
|
|
141
|
+
|
|
142
|
+
# noinspection PyMethodMayBeStatic,PyUnusedLocal
|
|
143
|
+
def compile_file(self, infile, outfile, outdated=False, force=False):
|
|
144
|
+
"""Compile a TypeScript file using the "tsc" command."""
|
|
145
|
+
command = (
|
|
146
|
+
[settings.TYPESCRIPT_BINARY]
|
|
147
|
+
+ settings.TYPESCRIPT_ARGUMENTS
|
|
148
|
+
+ ["--outFile", outfile, infile]
|
|
149
|
+
)
|
|
150
|
+
self.execute_command(command)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
if PipelineManifestStorage:
|
|
154
|
+
|
|
155
|
+
class NicerPipelineCachedStorage(PipelineManifestStorage):
|
|
156
|
+
"""Display a better exception."""
|
|
157
|
+
|
|
158
|
+
def hashed_name(self, name, content=None, filename=None):
|
|
159
|
+
"""Display a better exception if the file is not found."""
|
|
160
|
+
try:
|
|
161
|
+
return super().hashed_name(name, content=content)
|
|
162
|
+
except ValueError as e:
|
|
163
|
+
raise ValueError(
|
|
164
|
+
"%s. Did you run the command 'collectstatic'?" % e.args[0]
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
else:
|
|
168
|
+
NicerPipelineCachedStorage = None
|
|
169
|
+
|
|
170
|
+
if PipelineMixin and CompressedManifestStaticFilesStorage:
|
|
171
|
+
|
|
172
|
+
class PipelineCompressedManifestStaticFilesStorage(
|
|
173
|
+
PipelineMixin, CompressedManifestStaticFilesStorage
|
|
174
|
+
):
|
|
175
|
+
"""Mix django-pipeline and whitenoise."""
|
|
176
|
+
|
|
177
|
+
pass
|
|
178
|
+
|
|
179
|
+
else:
|
|
180
|
+
PipelineCompressedManifestStaticFilesStorage = None
|
df_config/checks.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# ##############################################################################
|
|
2
|
+
# This file is part of Interdiode #
|
|
3
|
+
# #
|
|
4
|
+
# Copyright (C) 2020 Matthieu Gallet <matthieu.gallet@19pouces.net> #
|
|
5
|
+
# All Rights Reserved #
|
|
6
|
+
# #
|
|
7
|
+
# ##############################################################################
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
from django.core.checks import Warning
|
|
12
|
+
|
|
13
|
+
settings_check_results = []
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def missing_package(package_name, desc=""):
|
|
17
|
+
if hasattr(sys, "real_prefix"): # inside a virtualenv
|
|
18
|
+
cmd = f"Try 'python -m pip install {package_name}' to install it."
|
|
19
|
+
elif __file__.startswith(os.environ.get("HOME", "/home")):
|
|
20
|
+
cmd = f"Try 'python3 -m pip install --user {package_name}' to install it."
|
|
21
|
+
else:
|
|
22
|
+
cmd = f"Try 'sudo python3 -m pip install {package_name}' to install it."
|
|
23
|
+
return Warning(
|
|
24
|
+
f"Python package '{package_name}' is required{desc}. {cmd}",
|
|
25
|
+
obj="configuration",
|
|
26
|
+
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# ##############################################################################
|
|
2
|
+
# This file is part of df_config #
|
|
3
|
+
# #
|
|
4
|
+
# Copyright (C) 2020 Matthieu Gallet <df_config@19pouces.net> #
|
|
5
|
+
# All Rights Reserved #
|
|
6
|
+
# #
|
|
7
|
+
# You may use, distribute and modify this code under the #
|
|
8
|
+
# terms of the (BSD-like) CeCILL-B license. #
|
|
9
|
+
# #
|
|
10
|
+
# You should have received a copy of the CeCILL-B license with #
|
|
11
|
+
# this file. If not, please visit: #
|
|
12
|
+
# https://cecill.info/licences/Licence_CeCILL-B_V1-en.txt (English) #
|
|
13
|
+
# or https://cecill.info/licences/Licence_CeCILL-B_V1-fr.txt (French) #
|
|
14
|
+
# #
|
|
15
|
+
# ##############################################################################
|
df_config/config/base.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# ##############################################################################
|
|
2
|
+
# This file is part of df_config #
|
|
3
|
+
# #
|
|
4
|
+
# Copyright (C) 2020 Matthieu Gallet <df_config@19pouces.net> #
|
|
5
|
+
# All Rights Reserved #
|
|
6
|
+
# #
|
|
7
|
+
# You may use, distribute and modify this code under the #
|
|
8
|
+
# terms of the (BSD-like) CeCILL-B license. #
|
|
9
|
+
# #
|
|
10
|
+
# You should have received a copy of the CeCILL-B license with #
|
|
11
|
+
# this file. If not, please visit: #
|
|
12
|
+
# https://cecill.info/licences/Licence_CeCILL-B_V1-en.txt (English) #
|
|
13
|
+
# or https://cecill.info/licences/Licence_CeCILL-B_V1-fr.txt (French) #
|
|
14
|
+
# #
|
|
15
|
+
# ##############################################################################
|
|
16
|
+
"""This module should be used as DJANGO_SETTINGS_MODULE.
|
|
17
|
+
|
|
18
|
+
Merge several sources of settings: env. variable, Python modules or .ini files.
|
|
19
|
+
"""
|
|
20
|
+
from df_config.manage import get_merger_from_env
|
|
21
|
+
|
|
22
|
+
merger = get_merger_from_env()
|
|
23
|
+
merger.process()
|
|
24
|
+
merger.post_process()
|
|
25
|
+
|
|
26
|
+
__settings = globals()
|
|
27
|
+
__settings.update(merger.settings)
|