arthexis 0.1.26__py3-none-any.whl → 0.1.28__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.26.dist-info → arthexis-0.1.28.dist-info}/METADATA +16 -11
- {arthexis-0.1.26.dist-info → arthexis-0.1.28.dist-info}/RECORD +39 -38
- config/settings.py +7 -1
- config/settings_helpers.py +176 -1
- config/urls.py +18 -2
- core/admin.py +265 -23
- core/apps.py +6 -2
- core/celery_utils.py +73 -0
- core/models.py +307 -63
- core/system.py +17 -2
- core/tasks.py +304 -129
- core/test_system_info.py +43 -5
- core/tests.py +202 -2
- core/user_data.py +52 -19
- core/views.py +70 -3
- nodes/admin.py +348 -3
- nodes/apps.py +1 -1
- nodes/feature_checks.py +30 -0
- nodes/models.py +146 -18
- nodes/tasks.py +1 -1
- nodes/tests.py +181 -48
- nodes/views.py +148 -3
- ocpp/admin.py +1001 -10
- ocpp/consumers.py +572 -7
- ocpp/models.py +499 -33
- ocpp/store.py +406 -40
- ocpp/tasks.py +109 -145
- ocpp/test_rfid.py +73 -2
- ocpp/tests.py +982 -90
- ocpp/urls.py +5 -0
- ocpp/views.py +172 -70
- pages/context_processors.py +2 -0
- pages/models.py +9 -0
- pages/tests.py +166 -18
- pages/urls.py +1 -0
- pages/views.py +66 -3
- {arthexis-0.1.26.dist-info → arthexis-0.1.28.dist-info}/WHEEL +0 -0
- {arthexis-0.1.26.dist-info → arthexis-0.1.28.dist-info}/licenses/LICENSE +0 -0
- {arthexis-0.1.26.dist-info → arthexis-0.1.28.dist-info}/top_level.txt +0 -0
pages/views.py
CHANGED
|
@@ -41,7 +41,11 @@ from django.test import RequestFactory, signals as test_signals
|
|
|
41
41
|
from django.urls import NoReverseMatch, reverse
|
|
42
42
|
from django.utils import timezone
|
|
43
43
|
from django.utils.encoding import force_bytes, force_str
|
|
44
|
-
from django.utils.http import
|
|
44
|
+
from django.utils.http import (
|
|
45
|
+
url_has_allowed_host_and_scheme,
|
|
46
|
+
urlsafe_base64_decode,
|
|
47
|
+
urlsafe_base64_encode,
|
|
48
|
+
)
|
|
45
49
|
from core import mailer, public_wifi
|
|
46
50
|
from core.backends import TOTP_DEVICE_NAME
|
|
47
51
|
from django.utils.translation import get_language, gettext as _
|
|
@@ -69,12 +73,33 @@ from core.models import (
|
|
|
69
73
|
from ocpp.models import Charger
|
|
70
74
|
from .utils import get_original_referer
|
|
71
75
|
|
|
76
|
+
|
|
77
|
+
class _GraphvizDeprecationFilter(logging.Filter):
|
|
78
|
+
"""Filter out Graphviz debug logs about positional arg deprecations."""
|
|
79
|
+
|
|
80
|
+
_MESSAGE_PREFIX = "deprecate positional args:"
|
|
81
|
+
|
|
82
|
+
def filter(self, record: logging.LogRecord) -> bool: # pragma: no cover - logging hook
|
|
83
|
+
try:
|
|
84
|
+
message = record.getMessage()
|
|
85
|
+
except Exception: # pragma: no cover - defensive fallback
|
|
86
|
+
return True
|
|
87
|
+
return not message.startswith(self._MESSAGE_PREFIX)
|
|
88
|
+
|
|
89
|
+
|
|
72
90
|
try: # pragma: no cover - optional dependency guard
|
|
73
91
|
from graphviz import Digraph
|
|
74
92
|
from graphviz.backend import CalledProcessError, ExecutableNotFound
|
|
75
93
|
except ImportError: # pragma: no cover - handled gracefully in views
|
|
76
94
|
Digraph = None
|
|
77
95
|
CalledProcessError = ExecutableNotFound = None
|
|
96
|
+
else:
|
|
97
|
+
graphviz_logger = logging.getLogger("graphviz._tools")
|
|
98
|
+
if not any(
|
|
99
|
+
isinstance(existing_filter, _GraphvizDeprecationFilter)
|
|
100
|
+
for existing_filter in graphviz_logger.filters
|
|
101
|
+
):
|
|
102
|
+
graphviz_logger.addFilter(_GraphvizDeprecationFilter())
|
|
78
103
|
|
|
79
104
|
import markdown
|
|
80
105
|
from django.utils._os import safe_join
|
|
@@ -919,6 +944,17 @@ class CustomLoginView(LoginView):
|
|
|
919
944
|
"restricted_notice": restricted_notice,
|
|
920
945
|
}
|
|
921
946
|
)
|
|
947
|
+
node = Node.get_local()
|
|
948
|
+
has_rfid_scanner = False
|
|
949
|
+
if node:
|
|
950
|
+
try:
|
|
951
|
+
node.refresh_features()
|
|
952
|
+
except Exception:
|
|
953
|
+
logger.exception("Unable to refresh node features for login page")
|
|
954
|
+
has_rfid_scanner = node.has_feature("rfid-scanner")
|
|
955
|
+
context["show_rfid_login"] = has_rfid_scanner
|
|
956
|
+
if has_rfid_scanner:
|
|
957
|
+
context["rfid_login_url"] = reverse("pages:rfid-login")
|
|
922
958
|
return context
|
|
923
959
|
|
|
924
960
|
def get_success_url(self):
|
|
@@ -940,6 +976,31 @@ class CustomLoginView(LoginView):
|
|
|
940
976
|
login_view = CustomLoginView.as_view()
|
|
941
977
|
|
|
942
978
|
|
|
979
|
+
@ensure_csrf_cookie
|
|
980
|
+
def rfid_login_page(request):
|
|
981
|
+
node = Node.get_local()
|
|
982
|
+
if not node or not node.has_feature("rfid-scanner"):
|
|
983
|
+
raise Http404
|
|
984
|
+
if request.user.is_authenticated:
|
|
985
|
+
return redirect(reverse("admin:index") if request.user.is_staff else "/")
|
|
986
|
+
redirect_field_name = CustomLoginView.redirect_field_name
|
|
987
|
+
redirect_target = request.GET.get(redirect_field_name, "")
|
|
988
|
+
if redirect_target and not url_has_allowed_host_and_scheme(
|
|
989
|
+
redirect_target,
|
|
990
|
+
allowed_hosts={request.get_host()},
|
|
991
|
+
require_https=request.is_secure(),
|
|
992
|
+
):
|
|
993
|
+
redirect_target = ""
|
|
994
|
+
context = {
|
|
995
|
+
"login_api_url": reverse("rfid-login"),
|
|
996
|
+
"scan_api_url": reverse("rfid-scan-next"),
|
|
997
|
+
"redirect_field_name": redirect_field_name,
|
|
998
|
+
"redirect_target": redirect_target,
|
|
999
|
+
"back_url": reverse("pages:login"),
|
|
1000
|
+
}
|
|
1001
|
+
return render(request, "pages/rfid_login.html", context)
|
|
1002
|
+
|
|
1003
|
+
|
|
943
1004
|
@staff_member_required
|
|
944
1005
|
def authenticator_setup(request):
|
|
945
1006
|
"""Allow staff to enroll an authenticator app for TOTP logins."""
|
|
@@ -1493,15 +1554,17 @@ def client_report(request):
|
|
|
1493
1554
|
return HttpResponseRedirect(redirect_url)
|
|
1494
1555
|
download_url = None
|
|
1495
1556
|
download_param = request.GET.get("download")
|
|
1496
|
-
if download_param
|
|
1557
|
+
if download_param:
|
|
1497
1558
|
try:
|
|
1498
1559
|
download_id = int(download_param)
|
|
1499
1560
|
except (TypeError, ValueError):
|
|
1500
1561
|
download_id = None
|
|
1501
|
-
if download_id:
|
|
1562
|
+
if download_id and request.user.is_authenticated:
|
|
1502
1563
|
download_url = reverse(
|
|
1503
1564
|
"pages:client-report-download", args=[download_id]
|
|
1504
1565
|
)
|
|
1566
|
+
if download_url:
|
|
1567
|
+
setattr(request, "live_update_interval", None)
|
|
1505
1568
|
|
|
1506
1569
|
try:
|
|
1507
1570
|
login_url = reverse("pages:login")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|