arthexis 0.1.13__py3-none-any.whl → 0.1.14__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.
Potentially problematic release.
This version of arthexis might be problematic. Click here for more details.
- {arthexis-0.1.13.dist-info → arthexis-0.1.14.dist-info}/METADATA +222 -221
- arthexis-0.1.14.dist-info/RECORD +109 -0
- {arthexis-0.1.13.dist-info → arthexis-0.1.14.dist-info}/licenses/LICENSE +674 -674
- config/__init__.py +5 -5
- config/active_app.py +15 -15
- config/asgi.py +43 -43
- config/auth_app.py +7 -7
- config/celery.py +32 -32
- config/context_processors.py +67 -69
- config/horologia_app.py +7 -7
- config/loadenv.py +11 -11
- config/logging.py +59 -48
- config/middleware.py +25 -25
- config/offline.py +49 -49
- config/settings.py +691 -682
- config/settings_helpers.py +109 -109
- config/urls.py +171 -166
- config/wsgi.py +17 -17
- core/admin.py +3771 -2809
- core/admin_history.py +50 -50
- core/admindocs.py +151 -151
- core/apps.py +356 -272
- core/auto_upgrade.py +57 -57
- core/backends.py +265 -236
- core/changelog.py +342 -0
- core/entity.py +133 -133
- core/environment.py +61 -61
- core/fields.py +168 -168
- core/form_fields.py +75 -75
- core/github_helper.py +188 -25
- core/github_issues.py +178 -172
- core/github_repos.py +72 -0
- core/lcd_screen.py +78 -78
- core/liveupdate.py +25 -25
- core/log_paths.py +100 -100
- core/mailer.py +85 -85
- core/middleware.py +91 -91
- core/models.py +3609 -2795
- core/notifications.py +105 -105
- core/public_wifi.py +267 -227
- core/reference_utils.py +108 -108
- core/release.py +721 -368
- core/rfid_import_export.py +113 -0
- core/sigil_builder.py +149 -149
- core/sigil_context.py +20 -20
- core/sigil_resolver.py +315 -315
- core/system.py +752 -493
- core/tasks.py +408 -394
- core/temp_passwords.py +181 -181
- core/test_system_info.py +186 -139
- core/tests.py +2095 -1521
- core/tests_liveupdate.py +17 -17
- core/urls.py +11 -11
- core/user_data.py +641 -633
- core/views.py +2175 -1417
- core/widgets.py +213 -94
- core/workgroup_urls.py +17 -17
- core/workgroup_views.py +94 -94
- nodes/admin.py +1720 -1161
- nodes/apps.py +87 -85
- nodes/backends.py +160 -160
- nodes/dns.py +203 -203
- nodes/feature_checks.py +133 -133
- nodes/lcd.py +165 -165
- nodes/models.py +1737 -1597
- nodes/reports.py +411 -411
- nodes/rfid_sync.py +195 -0
- nodes/signals.py +18 -0
- nodes/tasks.py +46 -46
- nodes/tests.py +3810 -3116
- nodes/urls.py +15 -14
- nodes/utils.py +121 -105
- nodes/views.py +683 -619
- ocpp/admin.py +948 -948
- ocpp/apps.py +25 -25
- ocpp/consumers.py +1565 -1459
- ocpp/evcs.py +844 -844
- ocpp/evcs_discovery.py +158 -158
- ocpp/models.py +917 -917
- ocpp/reference_utils.py +42 -42
- ocpp/routing.py +11 -11
- ocpp/simulator.py +745 -745
- ocpp/status_display.py +26 -26
- ocpp/store.py +601 -541
- ocpp/tasks.py +31 -31
- ocpp/test_export_import.py +130 -130
- ocpp/test_rfid.py +913 -702
- ocpp/tests.py +4445 -4094
- ocpp/transactions_io.py +189 -189
- ocpp/urls.py +50 -50
- ocpp/views.py +1479 -1251
- pages/admin.py +708 -539
- pages/apps.py +10 -10
- pages/checks.py +40 -40
- pages/context_processors.py +127 -119
- pages/defaults.py +13 -13
- pages/forms.py +198 -198
- pages/middleware.py +205 -153
- pages/models.py +607 -426
- pages/tests.py +2612 -2200
- pages/urls.py +25 -25
- pages/utils.py +12 -12
- pages/views.py +1165 -1128
- arthexis-0.1.13.dist-info/RECORD +0 -105
- nodes/actions.py +0 -70
- {arthexis-0.1.13.dist-info → arthexis-0.1.14.dist-info}/WHEEL +0 -0
- {arthexis-0.1.13.dist-info → arthexis-0.1.14.dist-info}/top_level.txt +0 -0
pages/apps.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
from django.apps import AppConfig
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class PagesConfig(AppConfig):
|
|
5
|
-
default_auto_field = "django.db.models.BigAutoField"
|
|
6
|
-
name = "pages"
|
|
7
|
-
verbose_name = "7. Experience"
|
|
8
|
-
|
|
9
|
-
def ready(self): # pragma: no cover - import for side effects
|
|
10
|
-
from . import checks # noqa: F401
|
|
1
|
+
from django.apps import AppConfig
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class PagesConfig(AppConfig):
|
|
5
|
+
default_auto_field = "django.db.models.BigAutoField"
|
|
6
|
+
name = "pages"
|
|
7
|
+
verbose_name = "7. Experience"
|
|
8
|
+
|
|
9
|
+
def ready(self): # pragma: no cover - import for side effects
|
|
10
|
+
from . import checks # noqa: F401
|
pages/checks.py
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
import inspect
|
|
2
|
-
|
|
3
|
-
from django.core.checks import Warning, register
|
|
4
|
-
from django.urls.resolvers import URLPattern, URLResolver
|
|
5
|
-
|
|
6
|
-
from config import urls as project_urls
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def _collect_checks(resolver: URLResolver, errors: list, prefix: str = ""):
|
|
10
|
-
for pattern in resolver.url_patterns:
|
|
11
|
-
if isinstance(pattern, URLResolver):
|
|
12
|
-
_collect_checks(pattern, errors, prefix + pattern.pattern._route)
|
|
13
|
-
elif isinstance(pattern, URLPattern):
|
|
14
|
-
view = pattern.callback
|
|
15
|
-
if getattr(view, "landing", False):
|
|
16
|
-
sig = inspect.signature(view)
|
|
17
|
-
params = list(sig.parameters.values())
|
|
18
|
-
if params and params[0].name == "request":
|
|
19
|
-
params = params[1:]
|
|
20
|
-
has_required = any(
|
|
21
|
-
p.default is inspect._empty
|
|
22
|
-
and p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD)
|
|
23
|
-
for p in params
|
|
24
|
-
)
|
|
25
|
-
if has_required:
|
|
26
|
-
errors.append(
|
|
27
|
-
Warning(
|
|
28
|
-
f'Landing view "{view.__module__}.{view.__name__}" requires URL parameters and cannot be a landing page.',
|
|
29
|
-
id="pages.W001",
|
|
30
|
-
)
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
@register()
|
|
35
|
-
def landing_views_have_no_args(app_configs, **kwargs):
|
|
36
|
-
errors: list = []
|
|
37
|
-
for p in project_urls.urlpatterns:
|
|
38
|
-
if isinstance(p, URLResolver):
|
|
39
|
-
_collect_checks(p, errors, p.pattern._route)
|
|
40
|
-
return errors
|
|
1
|
+
import inspect
|
|
2
|
+
|
|
3
|
+
from django.core.checks import Warning, register
|
|
4
|
+
from django.urls.resolvers import URLPattern, URLResolver
|
|
5
|
+
|
|
6
|
+
from config import urls as project_urls
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _collect_checks(resolver: URLResolver, errors: list, prefix: str = ""):
|
|
10
|
+
for pattern in resolver.url_patterns:
|
|
11
|
+
if isinstance(pattern, URLResolver):
|
|
12
|
+
_collect_checks(pattern, errors, prefix + pattern.pattern._route)
|
|
13
|
+
elif isinstance(pattern, URLPattern):
|
|
14
|
+
view = pattern.callback
|
|
15
|
+
if getattr(view, "landing", False):
|
|
16
|
+
sig = inspect.signature(view)
|
|
17
|
+
params = list(sig.parameters.values())
|
|
18
|
+
if params and params[0].name == "request":
|
|
19
|
+
params = params[1:]
|
|
20
|
+
has_required = any(
|
|
21
|
+
p.default is inspect._empty
|
|
22
|
+
and p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD)
|
|
23
|
+
for p in params
|
|
24
|
+
)
|
|
25
|
+
if has_required:
|
|
26
|
+
errors.append(
|
|
27
|
+
Warning(
|
|
28
|
+
f'Landing view "{view.__module__}.{view.__name__}" requires URL parameters and cannot be a landing page.',
|
|
29
|
+
id="pages.W001",
|
|
30
|
+
)
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@register()
|
|
35
|
+
def landing_views_have_no_args(app_configs, **kwargs):
|
|
36
|
+
errors: list = []
|
|
37
|
+
for p in project_urls.urlpatterns:
|
|
38
|
+
if isinstance(p, URLResolver):
|
|
39
|
+
_collect_checks(p, errors, p.pattern._route)
|
|
40
|
+
return errors
|
pages/context_processors.py
CHANGED
|
@@ -1,119 +1,127 @@
|
|
|
1
|
-
from utils.sites import get_site
|
|
2
|
-
from django.urls import Resolver404, resolve
|
|
3
|
-
from django.conf import settings
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
from types import SimpleNamespace
|
|
6
|
-
from nodes.models import Node
|
|
7
|
-
from core.models import Reference
|
|
8
|
-
from core.reference_utils import filter_visible_references
|
|
9
|
-
from .models import Module
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
f"data:image/png;base64,{
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
else
|
|
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
|
-
|
|
1
|
+
from utils.sites import get_site
|
|
2
|
+
from django.urls import Resolver404, resolve
|
|
3
|
+
from django.conf import settings
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from types import SimpleNamespace
|
|
6
|
+
from nodes.models import Node
|
|
7
|
+
from core.models import Reference
|
|
8
|
+
from core.reference_utils import filter_visible_references
|
|
9
|
+
from .models import Module
|
|
10
|
+
|
|
11
|
+
_FAVICON_DIR = Path(settings.BASE_DIR) / "pages" / "fixtures" / "data"
|
|
12
|
+
_FAVICON_FILENAMES = {
|
|
13
|
+
"default": "favicon.txt",
|
|
14
|
+
"Constellation": "favicon_constellation.txt",
|
|
15
|
+
"Control": "favicon_control.txt",
|
|
16
|
+
"Satellite": "favicon_satellite.txt",
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _load_favicon(filename: str) -> str:
|
|
21
|
+
path = _FAVICON_DIR / filename
|
|
22
|
+
try:
|
|
23
|
+
return f"data:image/png;base64,{path.read_text().strip()}"
|
|
24
|
+
except OSError:
|
|
25
|
+
return ""
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
_DEFAULT_FAVICON = _load_favicon(_FAVICON_FILENAMES["default"])
|
|
29
|
+
_ROLE_FAVICONS = {
|
|
30
|
+
role: (_load_favicon(filename) or _DEFAULT_FAVICON)
|
|
31
|
+
for role, filename in _FAVICON_FILENAMES.items()
|
|
32
|
+
if role != "default"
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def nav_links(request):
|
|
37
|
+
"""Provide navigation links for the current site."""
|
|
38
|
+
site = get_site(request)
|
|
39
|
+
node = Node.get_local()
|
|
40
|
+
role = node.role if node else None
|
|
41
|
+
if role:
|
|
42
|
+
modules = (
|
|
43
|
+
Module.objects.filter(node_role=role, is_deleted=False)
|
|
44
|
+
.select_related("application")
|
|
45
|
+
.prefetch_related("landings")
|
|
46
|
+
)
|
|
47
|
+
else:
|
|
48
|
+
modules = []
|
|
49
|
+
|
|
50
|
+
valid_modules = []
|
|
51
|
+
datasette_enabled = False
|
|
52
|
+
current_module = None
|
|
53
|
+
for module in modules:
|
|
54
|
+
landings = []
|
|
55
|
+
for landing in module.landings.filter(enabled=True):
|
|
56
|
+
try:
|
|
57
|
+
match = resolve(landing.path)
|
|
58
|
+
except Resolver404:
|
|
59
|
+
continue
|
|
60
|
+
view_func = match.func
|
|
61
|
+
requires_login = bool(getattr(view_func, "login_required", False))
|
|
62
|
+
if not requires_login and hasattr(view_func, "login_url"):
|
|
63
|
+
requires_login = True
|
|
64
|
+
staff_only = getattr(view_func, "staff_required", False)
|
|
65
|
+
if requires_login and not request.user.is_authenticated:
|
|
66
|
+
setattr(landing, "requires_login", True)
|
|
67
|
+
if staff_only and not request.user.is_staff:
|
|
68
|
+
continue
|
|
69
|
+
landings.append(landing)
|
|
70
|
+
if landings:
|
|
71
|
+
app_name = getattr(module.application, "name", "").lower()
|
|
72
|
+
if app_name == "awg":
|
|
73
|
+
module.menu = "Calculate"
|
|
74
|
+
elif module.path.rstrip("/").lower() == "/man":
|
|
75
|
+
module.menu = "Manual"
|
|
76
|
+
module.enabled_landings = landings
|
|
77
|
+
valid_modules.append(module)
|
|
78
|
+
if request.path.startswith(module.path):
|
|
79
|
+
if current_module is None or len(module.path) > len(
|
|
80
|
+
current_module.path
|
|
81
|
+
):
|
|
82
|
+
current_module = module
|
|
83
|
+
|
|
84
|
+
datasette_lock = Path(settings.BASE_DIR) / "locks" / "datasette.lck"
|
|
85
|
+
if datasette_lock.exists():
|
|
86
|
+
datasette_enabled = True
|
|
87
|
+
datasette_module = SimpleNamespace(
|
|
88
|
+
menu_label="Data",
|
|
89
|
+
path="/data/",
|
|
90
|
+
enabled_landings=[SimpleNamespace(path="/data/", label="Datasette")],
|
|
91
|
+
)
|
|
92
|
+
valid_modules.append(datasette_module)
|
|
93
|
+
|
|
94
|
+
valid_modules.sort(key=lambda m: m.menu_label.lower())
|
|
95
|
+
|
|
96
|
+
if current_module and current_module.favicon:
|
|
97
|
+
favicon_url = current_module.favicon.url
|
|
98
|
+
else:
|
|
99
|
+
favicon_url = None
|
|
100
|
+
if site:
|
|
101
|
+
try:
|
|
102
|
+
if site.badge.favicon:
|
|
103
|
+
favicon_url = site.badge.favicon.url
|
|
104
|
+
except Exception:
|
|
105
|
+
pass
|
|
106
|
+
if not favicon_url:
|
|
107
|
+
role_name = getattr(getattr(node, "role", None), "name", "")
|
|
108
|
+
favicon_url = _ROLE_FAVICONS.get(role_name, _DEFAULT_FAVICON) or _DEFAULT_FAVICON
|
|
109
|
+
|
|
110
|
+
header_refs_qs = (
|
|
111
|
+
Reference.objects.filter(show_in_header=True)
|
|
112
|
+
.exclude(value="")
|
|
113
|
+
.prefetch_related("roles", "features", "sites")
|
|
114
|
+
)
|
|
115
|
+
header_references = filter_visible_references(
|
|
116
|
+
header_refs_qs,
|
|
117
|
+
request=request,
|
|
118
|
+
site=site,
|
|
119
|
+
node=node,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
"nav_modules": valid_modules,
|
|
124
|
+
"favicon_url": favicon_url,
|
|
125
|
+
"header_references": header_references,
|
|
126
|
+
"datasette_enabled": datasette_enabled,
|
|
127
|
+
}
|
pages/defaults.py
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
"""Default configuration for the pages application."""
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
|
|
4
|
-
from typing import Dict
|
|
5
|
-
|
|
6
|
-
DEFAULT_APPLICATION_DESCRIPTIONS: Dict[str, str] = {
|
|
7
|
-
"awg": "Power, Energy and Cost calculations.",
|
|
8
|
-
"core": "Support for Business Processes and monetization.",
|
|
9
|
-
"ocpp": "Compatibility with Standards and Good Practices.",
|
|
10
|
-
"nodes": "System and Node-level operations,",
|
|
11
|
-
"pages": "User QA, Continuity Design and Chaos Testing.",
|
|
12
|
-
"teams": "Identity, Entitlements and Access Controls.",
|
|
13
|
-
}
|
|
1
|
+
"""Default configuration for the pages application."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import Dict
|
|
5
|
+
|
|
6
|
+
DEFAULT_APPLICATION_DESCRIPTIONS: Dict[str, str] = {
|
|
7
|
+
"awg": "Power, Energy and Cost calculations.",
|
|
8
|
+
"core": "Support for Business Processes and monetization.",
|
|
9
|
+
"ocpp": "Compatibility with Standards and Good Practices.",
|
|
10
|
+
"nodes": "System and Node-level operations,",
|
|
11
|
+
"pages": "User QA, Continuity Design and Chaos Testing.",
|
|
12
|
+
"teams": "Identity, Entitlements and Access Controls.",
|
|
13
|
+
}
|