arthexis 0.1.15__py3-none-any.whl → 0.1.17__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.15.dist-info → arthexis-0.1.17.dist-info}/METADATA +1 -2
- {arthexis-0.1.15.dist-info → arthexis-0.1.17.dist-info}/RECORD +40 -39
- config/settings.py +3 -0
- config/urls.py +5 -0
- core/admin.py +242 -15
- core/admindocs.py +44 -3
- core/apps.py +1 -1
- core/backends.py +46 -8
- core/changelog.py +66 -5
- core/github_issues.py +12 -7
- core/mailer.py +9 -5
- core/models.py +121 -29
- core/release.py +107 -2
- core/system.py +209 -2
- core/tasks.py +5 -7
- core/test_system_info.py +16 -0
- core/tests.py +329 -0
- core/views.py +279 -40
- nodes/admin.py +25 -1
- nodes/models.py +70 -4
- nodes/rfid_sync.py +15 -0
- nodes/tests.py +119 -0
- nodes/utils.py +3 -0
- ocpp/admin.py +92 -10
- ocpp/consumers.py +38 -0
- ocpp/models.py +19 -4
- ocpp/tasks.py +156 -2
- ocpp/test_rfid.py +92 -5
- ocpp/tests.py +243 -1
- ocpp/views.py +23 -5
- pages/admin.py +126 -4
- pages/context_processors.py +20 -1
- pages/models.py +3 -1
- pages/module_defaults.py +156 -0
- pages/tests.py +241 -8
- pages/urls.py +1 -0
- pages/views.py +61 -4
- {arthexis-0.1.15.dist-info → arthexis-0.1.17.dist-info}/WHEEL +0 -0
- {arthexis-0.1.15.dist-info → arthexis-0.1.17.dist-info}/licenses/LICENSE +0 -0
- {arthexis-0.1.15.dist-info → arthexis-0.1.17.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: arthexis
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.17
|
|
4
4
|
Summary: Power & Energy Infrastructure
|
|
5
5
|
Author-email: "Rafael J. Guillén-Osorio" <tecnologia@gelectriic.com>
|
|
6
6
|
License-Expression: GPL-3.0-only
|
|
@@ -118,7 +118,6 @@ Dynamic: license-file
|
|
|
118
118
|
|
|
119
119
|
[](https://github.com/arthexis/arthexis/actions/workflows/coverage.yml) [](https://github.com/arthexis/arthexis/blob/main/docs/development/ocpp-user-manual.md)
|
|
120
120
|
|
|
121
|
-
For coding guidance, see [AGENTS.md](AGENTS.md).
|
|
122
121
|
|
|
123
122
|
## Purpose
|
|
124
123
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
arthexis-0.1.
|
|
1
|
+
arthexis-0.1.17.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
2
2
|
config/__init__.py,sha256=AwpOX7il-DAOmkdJ5dVfVJ3CWWebn1lHyQNmkw1EkDw,103
|
|
3
3
|
config/active_app.py,sha256=KJqYh-o91nPQjVXPEdbiJHzsI6cN9IZsBZ9O3iZ6Hyc,373
|
|
4
4
|
config/asgi.py,sha256=T-0QSbtieEWKPIDkEcEdd-q6qjK8ZCwwjCaISOBkWdM,1296
|
|
@@ -10,101 +10,102 @@ config/loadenv.py,sha256=CjXx-wBaTt1wixub4GJ5CMSMFqtiK5JURc7cPXpqO7s,287
|
|
|
10
10
|
config/logging.py,sha256=1cIbPgRshHuMKnVEEH0jKpRAlJSpewvLFbYDz7sCBG4,2104
|
|
11
11
|
config/middleware.py,sha256=mDU5tye8H4WCjpJqocwd0vmrzoVEYwdz9WTP4Hcr6dI,719
|
|
12
12
|
config/offline.py,sha256=X-yDcyoI4C44Y27lpkUwszY_09GwwFfazEsthKJpQ70,1382
|
|
13
|
-
config/settings.py,sha256=
|
|
13
|
+
config/settings.py,sha256=WFywFlWRTkEqDksWYAOd6DdSpHLEu2ETgLeeSGruwrA,21516
|
|
14
14
|
config/settings_helpers.py,sha256=0BdBciUHIkwsWa0vV_RKAd4wDuEzgE7G-42XYiES4YQ,3127
|
|
15
|
-
config/urls.py,sha256=
|
|
15
|
+
config/urls.py,sha256=lXl2KKsbIehjOW0W6FHAsxkZJ-3DAo37f2ICb1dvvz8,5320
|
|
16
16
|
config/wsgi.py,sha256=zU_mKlya6hejQ21PxKacTui3dUWd4ca_-YJNSYAoMX0,433
|
|
17
17
|
core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
|
-
core/admin.py,sha256=
|
|
18
|
+
core/admin.py,sha256=tEMop2REJ-P4o73ZWKZQuWm29zF3S-dWKu26wUDfvi4,145556
|
|
19
19
|
core/admin_history.py,sha256=XZ4b0ryufIka-xcwboK3DzmOL-INSx5Y2fJO-aJdV70,1783
|
|
20
|
-
core/admindocs.py,sha256=
|
|
21
|
-
core/apps.py,sha256=
|
|
20
|
+
core/admindocs.py,sha256=ycD0bJ_VE6rTGf9ebXTiKdYkD8Y8hD2oQ4HxxoBURCM,6756
|
|
21
|
+
core/apps.py,sha256=L_UMYI72-5jTo6nt8mfCbgdLhlP32D-8k76EZw0QyAA,14348
|
|
22
22
|
core/auto_upgrade.py,sha256=1EffHHFylgydWdZM_id6CppV0QqBtdNw7cwBYVdbNdk,1715
|
|
23
|
-
core/backends.py,sha256=
|
|
24
|
-
core/changelog.py,sha256=
|
|
23
|
+
core/backends.py,sha256=Mzv_0YYF3iNWYAaKAJHHk75X2im-Kihu1zsg8eBeW2c,10509
|
|
24
|
+
core/changelog.py,sha256=SRn37i5N-qb-RYV4Gpu9fg7Kv8gu4TH8ZwEmDRgN-Vo,12594
|
|
25
25
|
core/entity.py,sha256=o4VteOXePGEsIWJFZ3fpq3DZsdWr3hpQ9A6kFbKosSE,4844
|
|
26
26
|
core/environment.py,sha256=JLcvxAwU3OTL8O6kzwcUCFNZ3T28KanHrU_4mDBFamU,1584
|
|
27
27
|
core/fields.py,sha256=d-qGahdcv4SRcO4fwCJ6_-NnEAP5xW0k3kODdAAAHSA,5412
|
|
28
28
|
core/form_fields.py,sha256=h2xT8sO8EWbznsiARkxukFk69yoW6mQwqpgonA-d6aA,2496
|
|
29
29
|
core/github_helper.py,sha256=fkjoUPwOB19zbGuk39LNLJ5AbIVKFf3rNCtnu-JISIc,5733
|
|
30
|
-
core/github_issues.py,sha256=
|
|
30
|
+
core/github_issues.py,sha256=qIygOk1ZCki0eB-9o1poJ2BnaMnbHH4ewVE36hqHUuo,5223
|
|
31
31
|
core/github_repos.py,sha256=8KCxcEiO2Ltgde7UDTAFOyHTm_eBeZYUIZegEbrjkWA,1690
|
|
32
32
|
core/lcd_screen.py,sha256=WtHMlSoZXKOsdM0d-v-f8ul-LSA6FA1bEWFwho1t6s8,2573
|
|
33
33
|
core/liveupdate.py,sha256=22m0ueQ10-6b-9pQJHY0_5WRYA98fysXKEXOWzIr550,691
|
|
34
34
|
core/log_paths.py,sha256=lxvgXPgJtVNZ-kYrqV8VFle4GFQrSxG-yRTglqvclmU,3318
|
|
35
|
-
core/mailer.py,sha256=
|
|
35
|
+
core/mailer.py,sha256=JpW0RnD9uZ4O-wvlqeW7CMw95IFeCSkdvbankJDwHq0,2886
|
|
36
36
|
core/middleware.py,sha256=j19K9SX-Emkv7BDDtAacR9g6RWsxhKHwCc8w23JFvMM,3388
|
|
37
|
-
core/models.py,sha256=
|
|
37
|
+
core/models.py,sha256=Vl_Z_tLo93w2ZDgObFFIfLSzid3KXraByghMmJeCfNk,126647
|
|
38
38
|
core/notifications.py,sha256=LYktoKM5k4q7YYWAJuqdeKM-p0Q-3gXgfqdq71qLS68,3916
|
|
39
39
|
core/public_wifi.py,sha256=yydLgxOo9DmJJbM4X_23wGR3gxL3YzHno54v9GssuFA,7213
|
|
40
40
|
core/reference_utils.py,sha256=jeox3V4cZNxzM2Jj31g_mdb3O55zy9S2iXAZu70R1Zc,3627
|
|
41
|
-
core/release.py,sha256=
|
|
41
|
+
core/release.py,sha256=y5NRs0XwB7RQVvMEZoNWYjTBxuG68dOMizUXLRx7-x8,31561
|
|
42
42
|
core/rfid_import_export.py,sha256=petyhPvL0WUpehc6uGUDUhjYQ9AVvc6O49zuhDs6YFw,3516
|
|
43
43
|
core/sigil_builder.py,sha256=VLwbrrD7Zr3SHfIDYV-V7uv7LEGiIelCSkeGswHibuc,4843
|
|
44
44
|
core/sigil_context.py,sha256=GCzjfM6fcVvBtSbVNfmE6sx3HU8QnxnXrCIytnNpQzM,439
|
|
45
45
|
core/sigil_resolver.py,sha256=rCsypuX-0oWNfKyM1T9ZLWHY0Ezwhtk4VmI0L3krnsE,11098
|
|
46
|
-
core/system.py,sha256=
|
|
47
|
-
core/tasks.py,sha256=
|
|
46
|
+
core/system.py,sha256=tqx8-4kyViMGKI3EAaxztrbyes4TSTPQ9YsIKzdVs6c,35731
|
|
47
|
+
core/tasks.py,sha256=MtijKTtRHUEsTP4nVJFYx5B8Ls8EXmtzpBuq8FU5b9s,12302
|
|
48
48
|
core/temp_passwords.py,sha256=FieUnIUeQHmA1DoXvfJ5U6-Ayv3oDz-hSln5s_vNbA4,5271
|
|
49
|
-
core/test_system_info.py,sha256=
|
|
50
|
-
core/tests.py,sha256=
|
|
49
|
+
core/test_system_info.py,sha256=IMPz21KEs6OC5YbL7YaIBdmJVLjRY6MgPuZpldJB5OI,6935
|
|
50
|
+
core/tests.py,sha256=ojHab5JtcHuVDc1zXK_QVms1cID1XXjuRcHmPcqVqD0,98368
|
|
51
51
|
core/tests_liveupdate.py,sha256=IquU8ztk6zbzC1bQu3Nrr3RzGzuujtPwDkANJHbxg98,510
|
|
52
52
|
core/urls.py,sha256=YPippON1MAP2KeZZ8jHpcLO6mvbnKn1q7fdMv5Vm9dY,425
|
|
53
53
|
core/user_data.py,sha256=02CfvxayELWSWZJCxWpv1Yz7EGg08yEu5MM31Khsi0U,21083
|
|
54
|
-
core/views.py,sha256=
|
|
54
|
+
core/views.py,sha256=Gt2J51RyIOsR2gzl2q3ChPbbIVDzrscty3yIGRW07P8,87141
|
|
55
55
|
core/widgets.py,sha256=vlR9PlFfZGlkHm5X2cqNXuEBZSj8gmWaR6MO1mMy6kg,6904
|
|
56
56
|
core/workgroup_urls.py,sha256=XR9IqwsSBI8epW7_-hHhWFU9wsyJfZehHwNQBhCgmpM,407
|
|
57
57
|
core/workgroup_views.py,sha256=vtumF3-8YaTD-K6nSd8eYvUyq3ftpvWSEwtcp5B-P6o,2889
|
|
58
58
|
nodes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
59
|
-
nodes/admin.py,sha256=
|
|
59
|
+
nodes/admin.py,sha256=liGwvusPI3o0RAxhamA8Hs1CMev_DRiFbbNhHWNqIfk,62079
|
|
60
60
|
nodes/apps.py,sha256=AxK-sh9JBJZwNOLjqw9omCQGUQWw-45VRdYH07XhVJU,2732
|
|
61
61
|
nodes/backends.py,sha256=dmmbS0X2YIlCDz2KjoDf_L62dy--nuqZF1rEDoi2JHM,5921
|
|
62
62
|
nodes/dns.py,sha256=D5smXD7Rkh6E4MdL6TBL2WY8GgJg7Rx9z88LZrcMbTw,7048
|
|
63
63
|
nodes/feature_checks.py,sha256=27e4PCkZ8BGWnJCOwMcY2Bo9z7LoeZWiTZuISWGnrzk,3996
|
|
64
64
|
nodes/lcd.py,sha256=iKA8Wmq85KZD52aTzAU8ZmS144_gbdGMOXcE8yuECps,5758
|
|
65
|
-
nodes/models.py,sha256=
|
|
65
|
+
nodes/models.py,sha256=1aoifwRm_VHhYCcP4i7P7ZbiDFRLQkTO57FozknWd9A,62840
|
|
66
66
|
nodes/reports.py,sha256=NRYh3Y0SlZFhx31Zh2K03yO12ZrpxEHEY6T-dODA6WE,12059
|
|
67
|
-
nodes/rfid_sync.py,sha256=
|
|
67
|
+
nodes/rfid_sync.py,sha256=SP_BRUhgYMBH-zXrcM7uShgFSGYmmuIMb1OdcU1e-5U,6956
|
|
68
68
|
nodes/signals.py,sha256=PtOKdQfb08mV1LgSZvn7ZAcfOyy2c3Xkq4AOpBQyUdE,622
|
|
69
69
|
nodes/tasks.py,sha256=ur59ebu9z02idmvy_IvUQt3eu9LWRyyNpkg2szvIHCQ,1522
|
|
70
|
-
nodes/tests.py,sha256=
|
|
70
|
+
nodes/tests.py,sha256=deqjQVAt6sXyI_DdY9zj-Ha3ad1TlnVbhjGhJ-LFqKg,155932
|
|
71
71
|
nodes/urls.py,sha256=HmAxj6sr6nMf0lii_1UX7sNBJUcrkaiKm3R9ofUWhvM,677
|
|
72
|
-
nodes/utils.py,sha256=
|
|
72
|
+
nodes/utils.py,sha256=wt7UuSXGuq79A-g-B6EW3kK49QWJBb7zhhkw4pun4k8,4474
|
|
73
73
|
nodes/views.py,sha256=TyW7exkVaR-o2_XkJXSi9jQ_BygXOE2cQFs4xlI20Xc,22905
|
|
74
74
|
ocpp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
75
|
-
ocpp/admin.py,sha256=
|
|
75
|
+
ocpp/admin.py,sha256=gMxHkT5KSp4kPWJcDJ1Y65VqgrwFTZl8Y516FO8oi3g,34658
|
|
76
76
|
ocpp/apps.py,sha256=i3NqrmIamNEQBT33CIqh7HOSOPmJXCMKrZ-DUd3whqg,842
|
|
77
|
-
ocpp/consumers.py,sha256=
|
|
77
|
+
ocpp/consumers.py,sha256=LgplrJQOfs8CKCtmBcRQLcDVB4Tz7YZpb3I7r2lAorQ,66352
|
|
78
78
|
ocpp/evcs.py,sha256=q1mZrCVSZxXTrtYsDqH6lkeEcJ6tfSC7p9YxkDmpSCw,28883
|
|
79
79
|
ocpp/evcs_discovery.py,sha256=OmrzgaOHwveDRJs8AIhrM3apX8_k2PPXh_oYaYpNW3c,3876
|
|
80
|
-
ocpp/models.py,sha256=
|
|
80
|
+
ocpp/models.py,sha256=QjEaygY7Tl47Q6z2uxP6ftUn4JeD8-JQX2fcwrCaEEg,31631
|
|
81
81
|
ocpp/reference_utils.py,sha256=_UR82GfE93kv4766mHyVIfdhhyYvrT59660r3H6W55M,1072
|
|
82
82
|
ocpp/routing.py,sha256=3kQya-MdJ00778xDmX0esQLBP05P200V45asg-CGNoo,438
|
|
83
83
|
ocpp/simulator.py,sha256=vnyd59QffT79AaPhmfM_jipni_nqfG57X5tXyx1rBoc,28016
|
|
84
84
|
ocpp/status_display.py,sha256=YGFosd5HJETA0DcLdsjvx6EfhZSnI8Aa3cMnHG2WsBE,939
|
|
85
85
|
ocpp/store.py,sha256=rHrP2Iq2ycMFbal1UEJVXb7r4gDtI5yifaE3nT0tjJw,18855
|
|
86
|
-
ocpp/tasks.py,sha256=
|
|
86
|
+
ocpp/tasks.py,sha256=OxIaI4OSLz9AfwLexnXhiBILBimTs3gVrPd197Jguqg,5819
|
|
87
87
|
ocpp/test_export_import.py,sha256=Zp6xUBlRq7XkdKjOs78BhkujNQdklxi4RLxU8c-udWY,4530
|
|
88
|
-
ocpp/test_rfid.py,sha256=
|
|
89
|
-
ocpp/tests.py,sha256=
|
|
88
|
+
ocpp/test_rfid.py,sha256=0Zczbg1x_5vhIV5TITHeaUkNONMdx20pD4St7Zc-ghM,36524
|
|
89
|
+
ocpp/tests.py,sha256=BfOapD5vWrmA43Q4WI7or2lP2pmcBdrU5_YCK31JgHE,182621
|
|
90
90
|
ocpp/transactions_io.py,sha256=YnxI-Tv5UFxv0JuFK3XpoqFYP8eRT8sMuDiqkiMHPtU,7387
|
|
91
91
|
ocpp/urls.py,sha256=3T5O5DSwVk4PbhPx5p4D3UseCWvC5xV5HwJLSM6AfA8,1700
|
|
92
|
-
ocpp/views.py,sha256=
|
|
92
|
+
ocpp/views.py,sha256=wntIO3LHFoPAg40SFGMoRPAiA3xyDKPwNgIsCBSEOcI,57164
|
|
93
93
|
pages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
94
|
-
pages/admin.py,sha256=
|
|
94
|
+
pages/admin.py,sha256=f2IYr-nGg9FmafQfDmIRrv01UuXh4mdhFJbnw-ytzHU,27459
|
|
95
95
|
pages/apps.py,sha256=AzUNXQX0yRUX5jus-5EDReDb0nOEY8DBgYaM970u6Io,288
|
|
96
96
|
pages/checks.py,sha256=sM8_hUVM_HOIocvtTb2sY3AaSEvbTnOlO46UchGVd-0,1527
|
|
97
|
-
pages/context_processors.py,sha256=
|
|
97
|
+
pages/context_processors.py,sha256=oINGTI0owXz60FV-XFEjnTkY2xlSDE-W6X1TK8IK800,5072
|
|
98
98
|
pages/defaults.py,sha256=l36APPAZO4ub2A8Pp-lQGujKeOVYcyzU6t7-kOk8VoA,522
|
|
99
99
|
pages/forms.py,sha256=T0atqxdNds3IBP8N-9c5-ACf3iR9FzzmhzK4MOa24e8,7058
|
|
100
100
|
pages/middleware.py,sha256=6PMLiyuHAHbfLeHwwQxIVy2fJ32ramEO9SHAN05Set4,6967
|
|
101
|
-
pages/models.py,sha256=
|
|
101
|
+
pages/models.py,sha256=Sp8e2VB5a7yg4eSUlz_VcsSlAuDVap26xBKYYggxmLM,20952
|
|
102
|
+
pages/module_defaults.py,sha256=R8n6eQDjNRMpO-DW86OFGvyRarju5Bx7Fnb275R_z24,5411
|
|
102
103
|
pages/tasks.py,sha256=ivcba_3wSQ1-cku0oDplzw6vLeQ9hBq3R4TG-LmR5gs,1913
|
|
103
|
-
pages/tests.py,sha256=
|
|
104
|
-
pages/urls.py,sha256=
|
|
104
|
+
pages/tests.py,sha256=i1HLp8rNm63WuqFf9YgAEGWYowFC7SOyyg_7j17_buQ,126102
|
|
105
|
+
pages/urls.py,sha256=Ne6yYJxgUAMieDpppJ149E-yh-oVi92fARiRPe-n4-s,1166
|
|
105
106
|
pages/utils.py,sha256=CR4D1debgJLGgXsw9kap2ggpe7fIpSoWS_ivbgMNp2k,564
|
|
106
|
-
pages/views.py,sha256=
|
|
107
|
-
arthexis-0.1.
|
|
108
|
-
arthexis-0.1.
|
|
109
|
-
arthexis-0.1.
|
|
110
|
-
arthexis-0.1.
|
|
107
|
+
pages/views.py,sha256=Ye7qGlO7IwkZO0oR1SzCpkEDTtGCJPmDJT-x6QQ8vaQ,45848
|
|
108
|
+
arthexis-0.1.17.dist-info/METADATA,sha256=rvPpFn4fwAZGm0JJ6Esu1r1A80uFC-tWCYhJOj0UNd8,9998
|
|
109
|
+
arthexis-0.1.17.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
110
|
+
arthexis-0.1.17.dist-info/top_level.txt,sha256=J2a2q8_BWrCZ8H2WFUNMBfO2jz8j2gax6zZh-_1QDac,29
|
|
111
|
+
arthexis-0.1.17.dist-info/RECORD,,
|
config/settings.py
CHANGED
|
@@ -480,6 +480,9 @@ AUTHENTICATION_BACKENDS = [
|
|
|
480
480
|
"core.backends.RFIDBackend",
|
|
481
481
|
]
|
|
482
482
|
|
|
483
|
+
# Use the custom login view for all authentication redirects.
|
|
484
|
+
LOGIN_URL = "pages:login"
|
|
485
|
+
|
|
483
486
|
# Issuer name used when generating otpauth URLs for authenticator apps.
|
|
484
487
|
OTP_TOTP_ISSUER = os.environ.get("OTP_TOTP_ISSUER", "Arthexis")
|
|
485
488
|
|
config/urls.py
CHANGED
|
@@ -134,6 +134,11 @@ urlpatterns = [
|
|
|
134
134
|
core_views.todo_done,
|
|
135
135
|
name="todo-done",
|
|
136
136
|
),
|
|
137
|
+
path(
|
|
138
|
+
"admin/core/todos/<int:pk>/snapshot/",
|
|
139
|
+
core_views.todo_snapshot,
|
|
140
|
+
name="todo-snapshot",
|
|
141
|
+
),
|
|
137
142
|
path(
|
|
138
143
|
"admin/core/odoo-products/",
|
|
139
144
|
core_views.odoo_products,
|
core/admin.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from io import BytesIO
|
|
2
|
+
import os
|
|
2
3
|
|
|
3
4
|
from django import forms
|
|
4
5
|
from django.contrib import admin
|
|
@@ -34,7 +35,8 @@ from import_export.forms import (
|
|
|
34
35
|
from import_export.widgets import ForeignKeyWidget
|
|
35
36
|
from django.contrib.auth.models import Group
|
|
36
37
|
from django.templatetags.static import static
|
|
37
|
-
from django.utils import timezone
|
|
38
|
+
from django.utils import timezone, translation
|
|
39
|
+
from django.utils.formats import date_format
|
|
38
40
|
from django.utils.dateparse import parse_datetime
|
|
39
41
|
from django.utils.html import format_html
|
|
40
42
|
from django.utils.translation import gettext_lazy as _, ngettext
|
|
@@ -55,6 +57,8 @@ from reportlab.pdfbase import pdfmetrics
|
|
|
55
57
|
from reportlab.graphics import renderPDF
|
|
56
58
|
from reportlab.graphics.barcode import qr
|
|
57
59
|
from reportlab.graphics.shapes import Drawing
|
|
60
|
+
from reportlab.lib.styles import getSampleStyleSheet
|
|
61
|
+
from reportlab.platypus import Paragraph, SimpleDocTemplate, Spacer, Table, TableStyle
|
|
58
62
|
from ocpp.models import Transaction
|
|
59
63
|
from ocpp.rfid.utils import build_mode_toggle
|
|
60
64
|
from nodes.models import EmailOutbox
|
|
@@ -515,22 +519,39 @@ class ReleaseManagerAdmin(ProfileAdminMixin, SaveBeforeChangeAction, EntityModel
|
|
|
515
519
|
if not creds:
|
|
516
520
|
self.message_user(request, f"{manager} has no credentials", messages.ERROR)
|
|
517
521
|
return
|
|
518
|
-
|
|
522
|
+
env_url = os.environ.get("PYPI_REPOSITORY_URL", "").strip()
|
|
523
|
+
url = env_url or "https://upload.pypi.org/legacy/"
|
|
519
524
|
auth = (
|
|
520
525
|
("__token__", creds.token)
|
|
521
526
|
if creds.token
|
|
522
527
|
else (creds.username, creds.password)
|
|
523
528
|
)
|
|
524
529
|
try:
|
|
525
|
-
resp = requests.
|
|
526
|
-
|
|
530
|
+
resp = requests.post(
|
|
531
|
+
url,
|
|
532
|
+
auth=auth,
|
|
533
|
+
data={"verify_credentials": "1"},
|
|
534
|
+
timeout=10,
|
|
535
|
+
allow_redirects=False,
|
|
536
|
+
)
|
|
537
|
+
status = resp.status_code
|
|
538
|
+
if status in {401, 403}:
|
|
539
|
+
self.message_user(
|
|
540
|
+
request,
|
|
541
|
+
f"{manager} credentials invalid ({status})",
|
|
542
|
+
messages.ERROR,
|
|
543
|
+
)
|
|
544
|
+
elif status <= 400:
|
|
545
|
+
suffix = f" ({status})" if status != 200 else ""
|
|
527
546
|
self.message_user(
|
|
528
|
-
request,
|
|
547
|
+
request,
|
|
548
|
+
f"{manager} credentials valid{suffix}",
|
|
549
|
+
messages.SUCCESS,
|
|
529
550
|
)
|
|
530
551
|
else:
|
|
531
552
|
self.message_user(
|
|
532
553
|
request,
|
|
533
|
-
f"{manager} credentials
|
|
554
|
+
f"{manager} credentials check returned unexpected status {status}",
|
|
534
555
|
messages.ERROR,
|
|
535
556
|
)
|
|
536
557
|
except Exception as exc: # pragma: no cover - admin feedback
|
|
@@ -1288,11 +1309,11 @@ class AssistantProfileInlineForm(ProfileFormMixin, forms.ModelForm):
|
|
|
1288
1309
|
widget=forms.PasswordInput(render_value=True),
|
|
1289
1310
|
help_text="Provide a plain key to create or rotate credentials.",
|
|
1290
1311
|
)
|
|
1291
|
-
profile_fields = ("user_key", "scopes", "is_active")
|
|
1312
|
+
profile_fields = ("assistant_name", "user_key", "scopes", "is_active")
|
|
1292
1313
|
|
|
1293
1314
|
class Meta:
|
|
1294
1315
|
model = AssistantProfile
|
|
1295
|
-
fields = ("scopes", "is_active")
|
|
1316
|
+
fields = ("assistant_name", "scopes", "is_active")
|
|
1296
1317
|
|
|
1297
1318
|
def __init__(self, *args, **kwargs):
|
|
1298
1319
|
super().__init__(*args, **kwargs)
|
|
@@ -1454,7 +1475,7 @@ PROFILE_INLINE_CONFIG = {
|
|
|
1454
1475
|
},
|
|
1455
1476
|
AssistantProfile: {
|
|
1456
1477
|
"form": AssistantProfileInlineForm,
|
|
1457
|
-
"fields": ("user_key", "scopes", "is_active"),
|
|
1478
|
+
"fields": ("assistant_name", "user_key", "scopes", "is_active"),
|
|
1458
1479
|
"readonly_fields": ("user_key_hash", "created_at", "last_used_at"),
|
|
1459
1480
|
"template": "admin/edit_inline/profile_stacked.html",
|
|
1460
1481
|
},
|
|
@@ -1646,6 +1667,7 @@ class UserAdmin(UserDatumAdminMixin, DjangoUserAdmin):
|
|
|
1646
1667
|
class EmailCollectorInline(admin.TabularInline):
|
|
1647
1668
|
model = EmailCollector
|
|
1648
1669
|
extra = 0
|
|
1670
|
+
fields = ("name", "subject", "sender")
|
|
1649
1671
|
|
|
1650
1672
|
|
|
1651
1673
|
class EmailCollectorAdmin(EntityModelAdmin):
|
|
@@ -1994,7 +2016,7 @@ class EmailInboxAdmin(ProfileAdminMixin, SaveBeforeChangeAction, EntityModelAdmi
|
|
|
1994
2016
|
class AssistantProfileAdmin(
|
|
1995
2017
|
ProfileAdminMixin, SaveBeforeChangeAction, EntityModelAdmin
|
|
1996
2018
|
):
|
|
1997
|
-
list_display = ("owner", "created_at", "last_used_at", "is_active")
|
|
2019
|
+
list_display = ("assistant_name", "owner", "created_at", "last_used_at", "is_active")
|
|
1998
2020
|
readonly_fields = ("user_key_hash", "created_at", "last_used_at")
|
|
1999
2021
|
|
|
2000
2022
|
change_form_template = "admin/workgroupassistantprofile_change_form.html"
|
|
@@ -2006,7 +2028,15 @@ class AssistantProfileAdmin(
|
|
|
2006
2028
|
("Credentials", {"fields": ("user_key_hash",)}),
|
|
2007
2029
|
(
|
|
2008
2030
|
"Configuration",
|
|
2009
|
-
{
|
|
2031
|
+
{
|
|
2032
|
+
"fields": (
|
|
2033
|
+
"assistant_name",
|
|
2034
|
+
"scopes",
|
|
2035
|
+
"is_active",
|
|
2036
|
+
"created_at",
|
|
2037
|
+
"last_used_at",
|
|
2038
|
+
)
|
|
2039
|
+
},
|
|
2010
2040
|
),
|
|
2011
2041
|
)
|
|
2012
2042
|
|
|
@@ -2810,8 +2840,10 @@ class RFIDResource(resources.ModelResource):
|
|
|
2810
2840
|
"energy_accounts",
|
|
2811
2841
|
"reference",
|
|
2812
2842
|
"external_command",
|
|
2843
|
+
"post_auth_command",
|
|
2813
2844
|
"allowed",
|
|
2814
2845
|
"color",
|
|
2846
|
+
"endianness",
|
|
2815
2847
|
"kind",
|
|
2816
2848
|
"released",
|
|
2817
2849
|
"last_seen_on",
|
|
@@ -2823,8 +2855,10 @@ class RFIDResource(resources.ModelResource):
|
|
|
2823
2855
|
"energy_accounts",
|
|
2824
2856
|
"reference",
|
|
2825
2857
|
"external_command",
|
|
2858
|
+
"post_auth_command",
|
|
2826
2859
|
"allowed",
|
|
2827
2860
|
"color",
|
|
2861
|
+
"endianness",
|
|
2828
2862
|
"kind",
|
|
2829
2863
|
"released",
|
|
2830
2864
|
"last_seen_on",
|
|
@@ -2895,19 +2929,23 @@ class RFIDAdmin(EntityModelAdmin, ImportExportModelAdmin):
|
|
|
2895
2929
|
"user_data_flag",
|
|
2896
2930
|
"color",
|
|
2897
2931
|
"kind",
|
|
2932
|
+
"endianness",
|
|
2898
2933
|
"released",
|
|
2899
2934
|
"allowed",
|
|
2900
2935
|
"last_seen_on",
|
|
2901
2936
|
)
|
|
2902
|
-
list_filter = ("color", "released", "allowed")
|
|
2937
|
+
list_filter = ("color", "endianness", "released", "allowed")
|
|
2903
2938
|
search_fields = ("label_id", "rfid", "custom_label")
|
|
2904
2939
|
autocomplete_fields = ["energy_accounts"]
|
|
2905
2940
|
raw_id_fields = ["reference"]
|
|
2906
2941
|
actions = [
|
|
2907
2942
|
"scan_rfids",
|
|
2908
2943
|
"print_card_labels",
|
|
2944
|
+
"print_release_form",
|
|
2909
2945
|
"copy_rfids",
|
|
2910
2946
|
"toggle_selected_user_data",
|
|
2947
|
+
"toggle_selected_released",
|
|
2948
|
+
"toggle_selected_allowed",
|
|
2911
2949
|
]
|
|
2912
2950
|
readonly_fields = ("added_on", "last_seen_on")
|
|
2913
2951
|
form = RFIDForm
|
|
@@ -3005,6 +3043,50 @@ class RFIDAdmin(EntityModelAdmin, ImportExportModelAdmin):
|
|
|
3005
3043
|
level=messages.WARNING,
|
|
3006
3044
|
)
|
|
3007
3045
|
|
|
3046
|
+
@admin.action(description=_("Toggle Released flag"))
|
|
3047
|
+
def toggle_selected_released(self, request, queryset):
|
|
3048
|
+
manager = getattr(self.model, "all_objects", self.model.objects)
|
|
3049
|
+
toggled = 0
|
|
3050
|
+
for tag in queryset:
|
|
3051
|
+
new_state = not tag.released
|
|
3052
|
+
manager.filter(pk=tag.pk).update(released=new_state)
|
|
3053
|
+
tag.released = new_state
|
|
3054
|
+
toggled += 1
|
|
3055
|
+
|
|
3056
|
+
if toggled:
|
|
3057
|
+
self.message_user(
|
|
3058
|
+
request,
|
|
3059
|
+
ngettext(
|
|
3060
|
+
"Toggled released flag for %(count)d RFID.",
|
|
3061
|
+
"Toggled released flag for %(count)d RFIDs.",
|
|
3062
|
+
toggled,
|
|
3063
|
+
)
|
|
3064
|
+
% {"count": toggled},
|
|
3065
|
+
level=messages.SUCCESS,
|
|
3066
|
+
)
|
|
3067
|
+
|
|
3068
|
+
@admin.action(description=_("Toggle Allowed flag"))
|
|
3069
|
+
def toggle_selected_allowed(self, request, queryset):
|
|
3070
|
+
manager = getattr(self.model, "all_objects", self.model.objects)
|
|
3071
|
+
toggled = 0
|
|
3072
|
+
for tag in queryset:
|
|
3073
|
+
new_state = not tag.allowed
|
|
3074
|
+
manager.filter(pk=tag.pk).update(allowed=new_state)
|
|
3075
|
+
tag.allowed = new_state
|
|
3076
|
+
toggled += 1
|
|
3077
|
+
|
|
3078
|
+
if toggled:
|
|
3079
|
+
self.message_user(
|
|
3080
|
+
request,
|
|
3081
|
+
ngettext(
|
|
3082
|
+
"Toggled allowed flag for %(count)d RFID.",
|
|
3083
|
+
"Toggled allowed flag for %(count)d RFIDs.",
|
|
3084
|
+
toggled,
|
|
3085
|
+
)
|
|
3086
|
+
% {"count": toggled},
|
|
3087
|
+
level=messages.SUCCESS,
|
|
3088
|
+
)
|
|
3089
|
+
|
|
3008
3090
|
@admin.action(description=_("Copy RFID"))
|
|
3009
3091
|
def copy_rfids(self, request, queryset):
|
|
3010
3092
|
if queryset.count() != 1:
|
|
@@ -3047,6 +3129,7 @@ class RFIDAdmin(EntityModelAdmin, ImportExportModelAdmin):
|
|
|
3047
3129
|
"key_b_verified": source.key_b_verified,
|
|
3048
3130
|
"allowed": source.allowed,
|
|
3049
3131
|
"external_command": source.external_command,
|
|
3132
|
+
"post_auth_command": source.post_auth_command,
|
|
3050
3133
|
"color": source.color,
|
|
3051
3134
|
"kind": source.kind,
|
|
3052
3135
|
"reference": source.reference,
|
|
@@ -3262,6 +3345,141 @@ class RFIDAdmin(EntityModelAdmin, ImportExportModelAdmin):
|
|
|
3262
3345
|
|
|
3263
3346
|
print_card_labels.short_description = _("Print Card Labels")
|
|
3264
3347
|
|
|
3348
|
+
def _render_release_form(self, request, queryset, empty_message, redirect_url):
|
|
3349
|
+
tags = list(queryset)
|
|
3350
|
+
if not tags:
|
|
3351
|
+
self.message_user(request, empty_message, level=messages.WARNING)
|
|
3352
|
+
return HttpResponseRedirect(redirect_url)
|
|
3353
|
+
|
|
3354
|
+
language = getattr(request, "LANGUAGE_CODE", translation.get_language())
|
|
3355
|
+
if not language:
|
|
3356
|
+
language = settings.LANGUAGE_CODE
|
|
3357
|
+
|
|
3358
|
+
with translation.override(language):
|
|
3359
|
+
buffer = BytesIO()
|
|
3360
|
+
document = SimpleDocTemplate(
|
|
3361
|
+
buffer,
|
|
3362
|
+
pagesize=letter,
|
|
3363
|
+
leftMargin=36,
|
|
3364
|
+
rightMargin=36,
|
|
3365
|
+
topMargin=72,
|
|
3366
|
+
bottomMargin=36,
|
|
3367
|
+
)
|
|
3368
|
+
document.title = str(_("RFID Release Form"))
|
|
3369
|
+
|
|
3370
|
+
styles = getSampleStyleSheet()
|
|
3371
|
+
story = []
|
|
3372
|
+
story.append(Paragraph(_("RFID Release Form"), styles["Title"]))
|
|
3373
|
+
story.append(Spacer(1, 12))
|
|
3374
|
+
|
|
3375
|
+
generated_on = timezone.localtime()
|
|
3376
|
+
formatted_generated_on = date_format(generated_on, "DATETIME_FORMAT")
|
|
3377
|
+
if generated_on.tzinfo:
|
|
3378
|
+
formatted_generated_on = _("%(datetime)s %(timezone)s") % {
|
|
3379
|
+
"datetime": formatted_generated_on,
|
|
3380
|
+
"timezone": generated_on.tzname() or "",
|
|
3381
|
+
}
|
|
3382
|
+
generated_text = Paragraph(
|
|
3383
|
+
_("Generated on: %(date)s")
|
|
3384
|
+
% {"date": formatted_generated_on},
|
|
3385
|
+
styles["Normal"],
|
|
3386
|
+
)
|
|
3387
|
+
story.append(generated_text)
|
|
3388
|
+
story.append(Spacer(1, 24))
|
|
3389
|
+
|
|
3390
|
+
table_data = [
|
|
3391
|
+
[
|
|
3392
|
+
_("Label"),
|
|
3393
|
+
_("RFID"),
|
|
3394
|
+
_("Custom label"),
|
|
3395
|
+
_("Color"),
|
|
3396
|
+
_("Type"),
|
|
3397
|
+
]
|
|
3398
|
+
]
|
|
3399
|
+
|
|
3400
|
+
for tag in tags:
|
|
3401
|
+
table_data.append(
|
|
3402
|
+
[
|
|
3403
|
+
tag.label_id or "",
|
|
3404
|
+
tag.rfid or "",
|
|
3405
|
+
tag.custom_label or "",
|
|
3406
|
+
tag.get_color_display() if tag.color else "",
|
|
3407
|
+
tag.get_kind_display() if tag.kind else "",
|
|
3408
|
+
]
|
|
3409
|
+
)
|
|
3410
|
+
|
|
3411
|
+
table = Table(table_data, repeatRows=1, hAlign="LEFT")
|
|
3412
|
+
table.setStyle(
|
|
3413
|
+
TableStyle(
|
|
3414
|
+
[
|
|
3415
|
+
("BACKGROUND", (0, 0), (-1, 0), colors.lightgrey),
|
|
3416
|
+
("TEXTCOLOR", (0, 0), (-1, 0), colors.black),
|
|
3417
|
+
("GRID", (0, 0), (-1, -1), 0.5, colors.grey),
|
|
3418
|
+
("ALIGN", (0, 0), (-1, -1), "LEFT"),
|
|
3419
|
+
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
|
|
3420
|
+
("BOTTOMPADDING", (0, 0), (-1, 0), 8),
|
|
3421
|
+
]
|
|
3422
|
+
)
|
|
3423
|
+
)
|
|
3424
|
+
|
|
3425
|
+
story.append(table)
|
|
3426
|
+
story.append(Spacer(1, 36))
|
|
3427
|
+
|
|
3428
|
+
signature_lines = [
|
|
3429
|
+
[
|
|
3430
|
+
Paragraph(
|
|
3431
|
+
_("Issuer Signature: ______________________________"),
|
|
3432
|
+
styles["Normal"],
|
|
3433
|
+
),
|
|
3434
|
+
Paragraph(
|
|
3435
|
+
_("Receiver Signature: ______________________________"),
|
|
3436
|
+
styles["Normal"],
|
|
3437
|
+
),
|
|
3438
|
+
],
|
|
3439
|
+
[
|
|
3440
|
+
Paragraph(
|
|
3441
|
+
_("Issuer Name: ______________________________"),
|
|
3442
|
+
styles["Normal"],
|
|
3443
|
+
),
|
|
3444
|
+
Paragraph(
|
|
3445
|
+
_("Receiver Name: ______________________________"),
|
|
3446
|
+
styles["Normal"],
|
|
3447
|
+
),
|
|
3448
|
+
],
|
|
3449
|
+
]
|
|
3450
|
+
|
|
3451
|
+
signature_table = Table(
|
|
3452
|
+
signature_lines,
|
|
3453
|
+
colWidths=[document.width / 2.0, document.width / 2.0],
|
|
3454
|
+
hAlign="LEFT",
|
|
3455
|
+
)
|
|
3456
|
+
signature_table.setStyle(
|
|
3457
|
+
TableStyle(
|
|
3458
|
+
[
|
|
3459
|
+
("VALIGN", (0, 0), (-1, -1), "TOP"),
|
|
3460
|
+
("BOTTOMPADDING", (0, 0), (-1, -1), 12),
|
|
3461
|
+
]
|
|
3462
|
+
)
|
|
3463
|
+
)
|
|
3464
|
+
story.append(signature_table)
|
|
3465
|
+
|
|
3466
|
+
document.build(story)
|
|
3467
|
+
buffer.seek(0)
|
|
3468
|
+
|
|
3469
|
+
response = HttpResponse(buffer.getvalue(), content_type="application/pdf")
|
|
3470
|
+
response["Content-Disposition"] = "attachment; filename=rfid-release-form.pdf"
|
|
3471
|
+
return response
|
|
3472
|
+
|
|
3473
|
+
def print_release_form(self, request, queryset):
|
|
3474
|
+
return self._render_release_form(
|
|
3475
|
+
request,
|
|
3476
|
+
queryset,
|
|
3477
|
+
_("Select at least one RFID to print the release form."),
|
|
3478
|
+
request.get_full_path(),
|
|
3479
|
+
)
|
|
3480
|
+
|
|
3481
|
+
print_release_form.short_description = _("Print Release Form")
|
|
3482
|
+
|
|
3265
3483
|
def get_changelist_actions(self, request):
|
|
3266
3484
|
parent = getattr(super(), "get_changelist_actions", None)
|
|
3267
3485
|
actions = []
|
|
@@ -3336,6 +3554,7 @@ class RFIDAdmin(EntityModelAdmin, ImportExportModelAdmin):
|
|
|
3336
3554
|
context["title"] = _("Scan RFIDs")
|
|
3337
3555
|
context["opts"] = self.model._meta
|
|
3338
3556
|
context["show_release_info"] = True
|
|
3557
|
+
context["default_endianness"] = RFID.BIG_ENDIAN
|
|
3339
3558
|
return render(request, "admin/core/rfid/scan.html", context)
|
|
3340
3559
|
|
|
3341
3560
|
def scan_next(self, request):
|
|
@@ -3349,9 +3568,11 @@ class RFIDAdmin(EntityModelAdmin, ImportExportModelAdmin):
|
|
|
3349
3568
|
return JsonResponse({"error": "Invalid JSON payload"}, status=400)
|
|
3350
3569
|
rfid = payload.get("rfid") or payload.get("value")
|
|
3351
3570
|
kind = payload.get("kind")
|
|
3352
|
-
|
|
3571
|
+
endianness = payload.get("endianness")
|
|
3572
|
+
result = validate_rfid_value(rfid, kind=kind, endianness=endianness)
|
|
3353
3573
|
else:
|
|
3354
|
-
|
|
3574
|
+
endianness = request.GET.get("endianness")
|
|
3575
|
+
result = scan_sources(request, endianness=endianness)
|
|
3355
3576
|
status = 500 if result.get("error") else 200
|
|
3356
3577
|
return JsonResponse(result, status=status)
|
|
3357
3578
|
|
|
@@ -3542,7 +3763,7 @@ class PackageReleaseAdmin(SaveBeforeChangeAction, EntityModelAdmin):
|
|
|
3542
3763
|
list_display_links = ("version",)
|
|
3543
3764
|
actions = ["publish_release", "validate_releases", "test_pypi_connection"]
|
|
3544
3765
|
change_actions = ["publish_release_action", "test_pypi_connection_action"]
|
|
3545
|
-
changelist_actions = ["refresh_from_pypi", "prepare_next_release"]
|
|
3766
|
+
changelist_actions = ["edit_changelog", "refresh_from_pypi", "prepare_next_release"]
|
|
3546
3767
|
readonly_fields = ("pypi_url", "github_url", "release_on", "is_current", "revision")
|
|
3547
3768
|
fields = (
|
|
3548
3769
|
"package",
|
|
@@ -3565,6 +3786,12 @@ class PackageReleaseAdmin(SaveBeforeChangeAction, EntityModelAdmin):
|
|
|
3565
3786
|
|
|
3566
3787
|
revision_short.short_description = "revision"
|
|
3567
3788
|
|
|
3789
|
+
def edit_changelog(self, request, queryset=None):
|
|
3790
|
+
return redirect("admin:system-changelog-report")
|
|
3791
|
+
|
|
3792
|
+
edit_changelog.label = "Edit Changelog"
|
|
3793
|
+
edit_changelog.short_description = "Edit Changelog"
|
|
3794
|
+
|
|
3568
3795
|
def refresh_from_pypi(self, request, queryset):
|
|
3569
3796
|
package = Package.objects.filter(is_active=True).first()
|
|
3570
3797
|
if not package:
|