arthexis 0.1.10__py3-none-any.whl → 0.1.12__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.

Files changed (54) hide show
  1. {arthexis-0.1.10.dist-info → arthexis-0.1.12.dist-info}/METADATA +36 -26
  2. arthexis-0.1.12.dist-info/RECORD +102 -0
  3. config/context_processors.py +1 -0
  4. config/settings.py +31 -5
  5. config/urls.py +5 -4
  6. core/admin.py +430 -90
  7. core/apps.py +48 -2
  8. core/backends.py +38 -0
  9. core/environment.py +23 -5
  10. core/mailer.py +3 -1
  11. core/models.py +303 -31
  12. core/reference_utils.py +20 -9
  13. core/release.py +4 -0
  14. core/sigil_builder.py +7 -2
  15. core/sigil_resolver.py +35 -4
  16. core/system.py +250 -1
  17. core/tasks.py +92 -40
  18. core/temp_passwords.py +181 -0
  19. core/test_system_info.py +62 -2
  20. core/tests.py +169 -3
  21. core/user_data.py +51 -8
  22. core/views.py +371 -20
  23. nodes/admin.py +453 -8
  24. nodes/backends.py +21 -6
  25. nodes/dns.py +203 -0
  26. nodes/feature_checks.py +133 -0
  27. nodes/models.py +374 -31
  28. nodes/reports.py +411 -0
  29. nodes/tests.py +677 -38
  30. nodes/utils.py +32 -0
  31. nodes/views.py +14 -0
  32. ocpp/admin.py +278 -15
  33. ocpp/consumers.py +517 -16
  34. ocpp/evcs_discovery.py +158 -0
  35. ocpp/models.py +237 -4
  36. ocpp/reference_utils.py +42 -0
  37. ocpp/simulator.py +321 -22
  38. ocpp/store.py +110 -2
  39. ocpp/test_rfid.py +169 -7
  40. ocpp/tests.py +819 -6
  41. ocpp/transactions_io.py +17 -3
  42. ocpp/views.py +233 -19
  43. pages/admin.py +144 -4
  44. pages/context_processors.py +21 -7
  45. pages/defaults.py +13 -0
  46. pages/forms.py +38 -0
  47. pages/models.py +189 -15
  48. pages/tests.py +281 -8
  49. pages/urls.py +4 -0
  50. pages/views.py +137 -21
  51. arthexis-0.1.10.dist-info/RECORD +0 -95
  52. {arthexis-0.1.10.dist-info → arthexis-0.1.12.dist-info}/WHEEL +0 -0
  53. {arthexis-0.1.10.dist-info → arthexis-0.1.12.dist-info}/licenses/LICENSE +0 -0
  54. {arthexis-0.1.10.dist-info → arthexis-0.1.12.dist-info}/top_level.txt +0 -0
ocpp/test_rfid.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import io
2
+ import json
2
3
  import os
3
4
  import sys
4
5
  import types
@@ -17,12 +18,13 @@ from django.test import SimpleTestCase, TestCase
17
18
  from django.urls import reverse
18
19
  from django.contrib.auth import get_user_model
19
20
  from django.contrib.sites.models import Site
21
+ from django.utils import timezone
20
22
 
21
23
  from pages.models import Application, Module
22
24
  from nodes.models import Node, NodeRole
23
25
 
24
26
  from core.models import RFID
25
- from ocpp.rfid.reader import read_rfid, enable_deep_read
27
+ from ocpp.rfid.reader import read_rfid, enable_deep_read, validate_rfid_value
26
28
  from ocpp.rfid.detect import detect_scanner, main as detect_main
27
29
  from ocpp.rfid import background_reader
28
30
  from ocpp.rfid.constants import (
@@ -71,6 +73,11 @@ class BackgroundReaderConfigurationTests(SimpleTestCase):
71
73
 
72
74
 
73
75
  class ScanNextViewTests(TestCase):
76
+ def setUp(self):
77
+ User = get_user_model()
78
+ self.user = User.objects.create_user("rfid-user", password="pwd")
79
+ self.client.force_login(self.user)
80
+
74
81
  @patch("config.middleware.Node.get_local", return_value=None)
75
82
  @patch("config.middleware.get_site")
76
83
  @patch(
@@ -103,6 +110,62 @@ class ScanNextViewTests(TestCase):
103
110
  self.assertEqual(resp.status_code, 500)
104
111
  self.assertEqual(resp.json(), {"error": "boom"})
105
112
 
113
+ @patch("config.middleware.Node.get_local", return_value=None)
114
+ @patch("config.middleware.get_site")
115
+ @patch(
116
+ "ocpp.rfid.views.validate_rfid_value",
117
+ return_value={"rfid": "ABCD1234", "label_id": 1, "created": False},
118
+ )
119
+ def test_scan_next_post_validates(self, mock_validate, mock_site, mock_node):
120
+ User = get_user_model()
121
+ user = User.objects.create_user("scanner", password="pwd")
122
+ self.client.force_login(user)
123
+ resp = self.client.post(
124
+ reverse("rfid-scan-next"),
125
+ data=json.dumps({"rfid": "ABCD1234"}),
126
+ content_type="application/json",
127
+ )
128
+ self.assertEqual(resp.status_code, 200)
129
+ self.assertEqual(
130
+ resp.json(), {"rfid": "ABCD1234", "label_id": 1, "created": False}
131
+ )
132
+ mock_validate.assert_called_once_with("ABCD1234", kind=None)
133
+
134
+ @patch("config.middleware.Node.get_local", return_value=None)
135
+ @patch("config.middleware.get_site")
136
+ @patch("ocpp.rfid.views.validate_rfid_value")
137
+ def test_scan_next_post_requires_authentication(
138
+ self, mock_validate, mock_site, mock_node
139
+ ):
140
+ resp = self.client.post(
141
+ reverse("rfid-scan-next"),
142
+ data=json.dumps({"rfid": "ABCD1234"}),
143
+ content_type="application/json",
144
+ )
145
+ self.assertEqual(resp.status_code, 401)
146
+ self.assertEqual(resp.json(), {"error": "Authentication required"})
147
+ mock_validate.assert_not_called()
148
+
149
+ @patch("config.middleware.Node.get_local", return_value=None)
150
+ @patch("config.middleware.get_site")
151
+ def test_scan_next_post_invalid_json(self, mock_site, mock_node):
152
+ User = get_user_model()
153
+ user = User.objects.create_user("invalid-json", password="pwd")
154
+ self.client.force_login(user)
155
+ resp = self.client.post(
156
+ reverse("rfid-scan-next"),
157
+ data="{",
158
+ content_type="application/json",
159
+ )
160
+ self.assertEqual(resp.status_code, 400)
161
+ self.assertEqual(resp.json(), {"error": "Invalid JSON payload"})
162
+
163
+ def test_scan_next_requires_authentication(self):
164
+ self.client.logout()
165
+ resp = self.client.get(reverse("rfid-scan-next"))
166
+ self.assertEqual(resp.status_code, 302)
167
+ self.assertIn(reverse("pages:login"), resp.url)
168
+
106
169
 
107
170
  class ReaderNotificationTests(TestCase):
108
171
  def _mock_reader(self):
@@ -171,6 +234,74 @@ class ReaderNotificationTests(TestCase):
171
234
  self.assertTrue(getattr(reader, "stop_called", False))
172
235
 
173
236
 
237
+ class ValidateRfidValueTests(SimpleTestCase):
238
+ @patch("ocpp.rfid.reader.timezone.now")
239
+ @patch("ocpp.rfid.reader.notify_async")
240
+ @patch("ocpp.rfid.reader.RFID.objects.get_or_create")
241
+ def test_creates_new_tag(self, mock_get, mock_notify, mock_now):
242
+ fake_now = object()
243
+ mock_now.return_value = fake_now
244
+ tag = MagicMock()
245
+ tag.pk = 1
246
+ tag.label_id = 1
247
+ tag.allowed = True
248
+ tag.color = "B"
249
+ tag.released = False
250
+ tag.reference = None
251
+ tag.kind = RFID.CLASSIC
252
+ mock_get.return_value = (tag, True)
253
+
254
+ result = validate_rfid_value("abcd1234")
255
+
256
+ mock_get.assert_called_once_with(rfid="ABCD1234", defaults={})
257
+ tag.save.assert_called_once_with(update_fields=["last_seen_on"])
258
+ self.assertIs(tag.last_seen_on, fake_now)
259
+ mock_notify.assert_called_once_with("RFID 1 OK", "ABCD1234 B")
260
+ self.assertTrue(result["created"])
261
+ self.assertEqual(result["rfid"], "ABCD1234")
262
+
263
+ @patch("ocpp.rfid.reader.timezone.now")
264
+ @patch("ocpp.rfid.reader.notify_async")
265
+ @patch("ocpp.rfid.reader.RFID.objects.get_or_create")
266
+ def test_updates_existing_tag_kind(self, mock_get, mock_notify, mock_now):
267
+ fake_now = object()
268
+ mock_now.return_value = fake_now
269
+ tag = MagicMock()
270
+ tag.pk = 5
271
+ tag.label_id = 5
272
+ tag.allowed = False
273
+ tag.color = "G"
274
+ tag.released = True
275
+ tag.reference = None
276
+ tag.kind = RFID.CLASSIC
277
+ mock_get.return_value = (tag, False)
278
+
279
+ result = validate_rfid_value("abcd", kind=RFID.NTAG215)
280
+
281
+ mock_get.assert_called_once_with(
282
+ rfid="ABCD", defaults={"kind": RFID.NTAG215}
283
+ )
284
+ tag.save.assert_called_once_with(update_fields=["kind", "last_seen_on"])
285
+ self.assertIs(tag.last_seen_on, fake_now)
286
+ self.assertEqual(tag.kind, RFID.NTAG215)
287
+ mock_notify.assert_called_once_with("RFID 5 BAD", "ABCD G")
288
+ self.assertFalse(result["allowed"])
289
+ self.assertFalse(result["created"])
290
+ self.assertEqual(result["kind"], RFID.NTAG215)
291
+
292
+ def test_rejects_invalid_value(self):
293
+ result = validate_rfid_value("invalid!")
294
+ self.assertEqual(result, {"error": "RFID must be hexadecimal digits"})
295
+
296
+ def test_rejects_non_string_values(self):
297
+ result = validate_rfid_value(12345)
298
+ self.assertEqual(result, {"error": "RFID must be a string"})
299
+
300
+ def test_rejects_missing_value(self):
301
+ result = validate_rfid_value(None)
302
+ self.assertEqual(result, {"error": "RFID value is required"})
303
+
304
+
174
305
  class CardTypeDetectionTests(TestCase):
175
306
  def _mock_ntag_reader(self):
176
307
  class MockReader:
@@ -301,7 +432,12 @@ class RFIDDetectionScriptTests(SimpleTestCase):
301
432
  mock_detect.assert_called_once()
302
433
 
303
434
 
304
- class RestartViewTests(SimpleTestCase):
435
+ class RestartViewTests(TestCase):
436
+ def setUp(self):
437
+ User = get_user_model()
438
+ self.user = User.objects.create_user("restart-user", password="pwd")
439
+ self.client.force_login(self.user)
440
+
305
441
  @patch("config.middleware.Node.get_local", return_value=None)
306
442
  @patch("config.middleware.get_site")
307
443
  @patch("ocpp.rfid.views.restart_sources", return_value={"status": "restarted"})
@@ -311,8 +447,19 @@ class RestartViewTests(SimpleTestCase):
311
447
  self.assertEqual(resp.json(), {"status": "restarted"})
312
448
  mock_restart.assert_called_once()
313
449
 
450
+ def test_restart_requires_authentication(self):
451
+ self.client.logout()
452
+ resp = self.client.post(reverse("rfid-scan-restart"))
453
+ self.assertEqual(resp.status_code, 302)
454
+ self.assertIn(reverse("pages:login"), resp.url)
455
+
456
+
457
+ class ScanTestViewTests(TestCase):
458
+ def setUp(self):
459
+ User = get_user_model()
460
+ self.user = User.objects.create_user("scan-test-user", password="pwd")
461
+ self.client.force_login(self.user)
314
462
 
315
- class ScanTestViewTests(SimpleTestCase):
316
463
  @patch("config.middleware.Node.get_local", return_value=None)
317
464
  @patch("config.middleware.get_site")
318
465
  @patch("ocpp.rfid.views.test_sources", return_value={"irq_pin": 7})
@@ -332,6 +479,12 @@ class ScanTestViewTests(SimpleTestCase):
332
479
  self.assertEqual(resp.status_code, 500)
333
480
  self.assertEqual(resp.json(), {"error": "no scanner detected"})
334
481
 
482
+ def test_scan_test_requires_authentication(self):
483
+ self.client.logout()
484
+ resp = self.client.get(reverse("rfid-scan-test"))
485
+ self.assertEqual(resp.status_code, 302)
486
+ self.assertIn(reverse("pages:login"), resp.url)
487
+
335
488
 
336
489
  class RFIDLandingTests(TestCase):
337
490
  def test_scanner_view_registered_as_landing(self):
@@ -352,6 +505,8 @@ class RFIDLandingTests(TestCase):
352
505
  class ScannerTemplateTests(TestCase):
353
506
  def setUp(self):
354
507
  self.url = reverse("rfid-reader")
508
+ User = get_user_model()
509
+ self.user = User.objects.create_user("scanner-user", password="pwd")
355
510
 
356
511
  def test_configure_link_for_staff(self):
357
512
  User = get_user_model()
@@ -360,9 +515,11 @@ class ScannerTemplateTests(TestCase):
360
515
  resp = self.client.get(self.url)
361
516
  self.assertContains(resp, 'id="rfid-configure"')
362
517
 
363
- def test_no_link_for_anonymous(self):
518
+ def test_redirect_for_anonymous(self):
519
+ self.client.logout()
364
520
  resp = self.client.get(self.url)
365
- self.assertNotContains(resp, 'id="rfid-configure"')
521
+ self.assertEqual(resp.status_code, 302)
522
+ self.assertIn(reverse("pages:login"), resp.url)
366
523
 
367
524
  def test_advanced_fields_for_staff(self):
368
525
  User = get_user_model()
@@ -374,9 +531,12 @@ class ScannerTemplateTests(TestCase):
374
531
  self.assertContains(resp, 'id="rfid-released"')
375
532
  self.assertContains(resp, 'id="rfid-reference"')
376
533
 
377
- def test_basic_fields_for_public(self):
534
+ def test_basic_fields_for_authenticated_user(self):
535
+ self.client.logout()
536
+ self.client.force_login(self.user)
378
537
  resp = self.client.get(self.url)
379
538
  self.assertContains(resp, 'id="rfid-kind"')
539
+ self.assertNotContains(resp, 'id="rfid-connect-local"')
380
540
  self.assertNotContains(resp, 'id="rfid-rfid"')
381
541
  self.assertNotContains(resp, 'id="rfid-released"')
382
542
  self.assertNotContains(resp, 'id="rfid-reference"')
@@ -388,7 +548,9 @@ class ScannerTemplateTests(TestCase):
388
548
  resp = self.client.get(self.url)
389
549
  self.assertContains(resp, 'id="rfid-deep-read"')
390
550
 
391
- def test_no_deep_read_button_for_public(self):
551
+ def test_no_deep_read_button_for_authenticated_user(self):
552
+ self.client.logout()
553
+ self.client.force_login(self.user)
392
554
  resp = self.client.get(self.url)
393
555
  self.assertNotContains(resp, 'id="rfid-deep-read"')
394
556