Compare commits

..

4 Commits

Author SHA1 Message Date
github-actions[bot]
dfaeb41080 Merge dependabot/npm_and_yarn/engine.io-and-socket.io-6.4.2 into combine-prs-branch1 2023-05-12 07:03:36 +00:00
github-actions[bot]
16671c6e1e Merge dependabot/pip/django-3.2.19 into combine-prs-branch1 2023-05-12 07:03:36 +00:00
dependabot[bot]
0cd75cb313 Build(deps): Bump django from 3.2.18 to 3.2.19
Bumps [django](https://github.com/django/django) from 3.2.18 to 3.2.19.
- [Commits](https://github.com/django/django/compare/3.2.18...3.2.19)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-09 22:20:19 +00:00
dependabot[bot]
b2c16cefad Build(deps): Bump engine.io and socket.io
Bumps [engine.io](https://github.com/socketio/engine.io) and [socket.io](https://github.com/socketio/socket.io). These dependencies needed to be updated together.

Updates `engine.io` from 6.2.1 to 6.4.2
- [Release notes](https://github.com/socketio/engine.io/releases)
- [Changelog](https://github.com/socketio/engine.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/engine.io/compare/6.2.1...6.4.2)

Updates `socket.io` from 4.5.3 to 4.6.1
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/4.5.3...4.6.1)

---
updated-dependencies:
- dependency-name: engine.io
  dependency-type: indirect
- dependency-name: socket.io
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-04 00:56:05 +00:00
36 changed files with 1859 additions and 1939 deletions

View File

@@ -19,7 +19,7 @@ cssutils = "~=1.0.2"
dj-database-url = "~=0.5.0"
dj-static = "~=0.0.6"
Django = "~=3.2"
django-debug-toolbar = "~=4.0.0"
django-debug-toolbar = "~=3.2"
django-filter = "~=2.4.0"
django-ical = "~=1.7.1"
django-recurrence = "~=1.10.3"
@@ -79,7 +79,7 @@ django-hcaptcha = "*"
pikepdf = "*"
django-queryable-properties = "*"
django-mass-edit = "*"
selenium = "~=4.9.1"
selenium = "~=3.141.0"
[dev-packages]
pycodestyle = "~=2.9.1"

519
Pipfile.lock generated
View File

@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "fd57c06cb6fe93ee6b4af9d978b7185d76bc32c962a847a209539534dcd2fb2a"
"sha256": "2e2fb4b609c10fc42db6bbd69ca73800629fbcaceec664e1fcc79d4b37bc0eb1"
},
"pipfile-spec": 6,
"requires": {
@@ -32,20 +32,6 @@
"index": "pypi",
"version": "==3.3.4"
},
"async-generator": {
"hashes": [
"sha256:01c7bf666359b4967d2cda0000cc2e4af16a0ae098cbffcb8472fb9e8ad6585b",
"sha256:6ebb3d106c12920aaae42ccb6f787ef5eefdcdd166ea3d628fa8476abe712144"
],
"version": "==1.10"
},
"attrs": {
"hashes": [
"sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04",
"sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"
],
"version": "==23.1.0"
},
"backports.tempfile": {
"hashes": [
"sha256:05aa50940946f05759696156a8c39be118169a0e0f94a49d0bb106503891ff54",
@@ -172,6 +158,7 @@
"sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7",
"sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"
],
"markers": "python_version >= '3.6'",
"version": "==2023.5.7"
},
"chardet": {
@@ -211,6 +198,7 @@
"sha256:1ccd984dab89fc68955043aca4e1b03e0cf29cad9880f6e28e3ba7a74b14aa5a",
"sha256:fd23a65bfd444595913f02fc71f6b286c29261e354c41d722ca7a261a49b5969"
],
"markers": "python_version >= '3.7'",
"version": "==0.7.0"
},
"cssutils": {
@@ -230,11 +218,11 @@
},
"diff-match-patch": {
"hashes": [
"sha256:953019cdb9c9d2c9e47b5b12bcff3cf4746fc4598eb406076fa1fc27e6a1f15c",
"sha256:dce43505fb7b1b317de7195579388df0746d90db07015ed47a85e5e44930ef93"
"sha256:8bf9d9c4e059d917b5c6312bac0c137971a32815ddbda9c682b949f2986b4d34",
"sha256:da6f5a01aa586df23dfc89f3827e1cafbb5420be9d87769eeb079ddfd9477a18"
],
"index": "pypi",
"version": "==20230430"
"version": "==20200713"
},
"dj-database-url": {
"hashes": [
@@ -261,11 +249,11 @@
},
"django-debug-toolbar": {
"hashes": [
"sha256:89619f6e0ea1057dca47bfc429ed99b237ef70074dabc065a7faa5f00e1459cf",
"sha256:bad339d68520652ddc1580c76f136fcbc3e020fd5ed96510a89a02ec81bb3fb1"
"sha256:24ef1a7d44d25e60d7951e378454c6509bf536dce7e7d9d36e7c387db499bc27",
"sha256:879f8a4672d41621c06a4d322dcffa630fc4df056cada6e417ed01db0e5e0478"
],
"index": "pypi",
"version": "==4.0.0"
"version": "==3.8.1"
},
"django-filter": {
"hashes": [
@@ -308,11 +296,11 @@
},
"django-queryable-properties": {
"hashes": [
"sha256:4c2399847f5dd0a3eedabfc91865a0847aa58fc6cd80555151363943891ff4cd",
"sha256:ed2aac9168ecce664dd3c2a65cfb6fc9fd2e3aa9b2acc3a4d75a948a67b719d3"
"sha256:8d702a8c8cce65f6505826c4ecc22429dda06f132c952f51ded6b208ed2586b0",
"sha256:ededecd103998885b2ef3d4d5a04a3d29f79b3b3c086df89448efb4b3459d7ef"
],
"index": "pypi",
"version": "==1.8.4"
"version": "==1.8.3"
},
"django-recurrence": {
"hashes": [
@@ -324,11 +312,11 @@
},
"django-registration-redux": {
"hashes": [
"sha256:2213bbe8732be72724034f4146f0255a7bd666eb5a5e1b2d8d8aa633fe8af894",
"sha256:56fbc7b01a7f0f48812fe4d4e0729d2dac916e16f8aaed36b3f10129f2df9d0f"
"sha256:5079dd36980cc0faddf91a6e991129680410611b1059d8154d064cc0146744b2",
"sha256:88eb98530d98a7e3451bf728c0a5f6fe7ea2f45c65ef18f619ef37b940c854f5"
],
"index": "pypi",
"version": "==2.12"
"version": "==2.11"
},
"django-reversion": {
"hashes": [
@@ -353,25 +341,6 @@
"index": "pypi",
"version": "==0.2.0"
},
"exceptiongroup": {
"hashes": [
"sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e",
"sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"
],
"version": "==1.1.1"
},
"freetype-py": {
"hashes": [
"sha256:3a552265b06c2cb3fa54f86ed6fcbf045d8dc8176f9475bedddf9a1b31f5402f",
"sha256:89cee8f4e7cf0a37b73a43a08c88703d84e3b9f9243fc665d8dc0b72a5d206a8",
"sha256:b95ccd52ff7e9bef34505f8af724cee114a3c3cc9cf13e0fd406fa0cc92b988a",
"sha256:c8f17c3ac35dc7cc9571ac37a00a6daa428a1a6d0fe6926a77d16066865ed5ef",
"sha256:ca7155de937af6f26bfd9f9089a6e9b01fa8f9d3040a3ddc0aeb3a53cf88f428",
"sha256:ccdb1616794a8ad48beaa9e29d3494e6643d24d8e925cc39263de21c062ea5a7",
"sha256:f9b64ce3272a5c358dcee824800a32d70997fb872a0965a557adca20fce7a5d0"
],
"version": "==2.3.0"
},
"gunicorn": {
"hashes": [
"sha256:1904bb2b8a43658807108d59c3f3d56c2b6121a701161de0ddf9ad140073c626",
@@ -380,18 +349,12 @@
"index": "pypi",
"version": "==20.0.4"
},
"h11": {
"hashes": [
"sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d",
"sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"
],
"version": "==0.14.0"
},
"html5lib": {
"hashes": [
"sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d",
"sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==1.1"
},
"icalendar": {
@@ -412,12 +375,11 @@
},
"importlib-metadata": {
"hashes": [
"sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed",
"sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705"
"sha256:d5059f9f1e8e41f80e9c56c2ee58811450c31984dfa625329ffd7c0dad88a73b",
"sha256:d84d17e21670ec07990e1044a99efe8d615d860fd176fc29ef5c306068fda313"
],
"index": "pypi",
"markers": "python_version < '3.10'",
"version": "==6.6.0"
"version": "==5.1.0"
},
"lxml": {
"hashes": [
@@ -499,6 +461,7 @@
"sha256:f1496ea22ca2c830cbcbd473de8f114a320da308438ae65abad6bab7867fe38f",
"sha256:f49e52d174375a7def9915c9f06ec4e569d235ad428f70751765f48d5926678c"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==4.9.2"
},
"markdown": {
@@ -511,85 +474,68 @@
},
"msgpack": {
"hashes": [
"sha256:06f5174b5f8ed0ed919da0e62cbd4ffde676a374aba4020034da05fab67b9164",
"sha256:0c05a4a96585525916b109bb85f8cb6511db1c6f5b9d9cbcbc940dc6b4be944b",
"sha256:137850656634abddfb88236008339fdaba3178f4751b28f270d2ebe77a563b6c",
"sha256:17358523b85973e5f242ad74aa4712b7ee560715562554aa2134d96e7aa4cbbf",
"sha256:18334484eafc2b1aa47a6d42427da7fa8f2ab3d60b674120bce7a895a0a85bdd",
"sha256:1835c84d65f46900920b3708f5ba829fb19b1096c1800ad60bae8418652a951d",
"sha256:1967f6129fc50a43bfe0951c35acbb729be89a55d849fab7686004da85103f1c",
"sha256:1ab2f3331cb1b54165976a9d976cb251a83183631c88076613c6c780f0d6e45a",
"sha256:1c0f7c47f0087ffda62961d425e4407961a7ffd2aa004c81b9c07d9269512f6e",
"sha256:20a97bf595a232c3ee6d57ddaadd5453d174a52594bf9c21d10407e2a2d9b3bd",
"sha256:20c784e66b613c7f16f632e7b5e8a1651aa5702463d61394671ba07b2fc9e025",
"sha256:266fa4202c0eb94d26822d9bfd7af25d1e2c088927fe8de9033d929dd5ba24c5",
"sha256:28592e20bbb1620848256ebc105fc420436af59515793ed27d5c77a217477705",
"sha256:288e32b47e67f7b171f86b030e527e302c91bd3f40fd9033483f2cacc37f327a",
"sha256:3055b0455e45810820db1f29d900bf39466df96ddca11dfa6d074fa47054376d",
"sha256:332360ff25469c346a1c5e47cbe2a725517919892eda5cfaffe6046656f0b7bb",
"sha256:362d9655cd369b08fda06b6657a303eb7172d5279997abe094512e919cf74b11",
"sha256:366c9a7b9057e1547f4ad51d8facad8b406bab69c7d72c0eb6f529cf76d4b85f",
"sha256:36961b0568c36027c76e2ae3ca1132e35123dcec0706c4b7992683cc26c1320c",
"sha256:379026812e49258016dd84ad79ac8446922234d498058ae1d415f04b522d5b2d",
"sha256:382b2c77589331f2cb80b67cc058c00f225e19827dbc818d700f61513ab47bea",
"sha256:476a8fe8fae289fdf273d6d2a6cb6e35b5a58541693e8f9f019bfe990a51e4ba",
"sha256:48296af57cdb1d885843afd73c4656be5c76c0c6328db3440c9601a98f303d87",
"sha256:4867aa2df9e2a5fa5f76d7d5565d25ec76e84c106b55509e78c1ede0f152659a",
"sha256:4c075728a1095efd0634a7dccb06204919a2f67d1893b6aa8e00497258bf926c",
"sha256:4f837b93669ce4336e24d08286c38761132bc7ab29782727f8557e1eb21b2080",
"sha256:4f8d8b3bf1ff2672567d6b5c725a1b347fe838b912772aa8ae2bf70338d5a198",
"sha256:525228efd79bb831cf6830a732e2e80bc1b05436b086d4264814b4b2955b2fa9",
"sha256:5494ea30d517a3576749cad32fa27f7585c65f5f38309c88c6d137877fa28a5a",
"sha256:55b56a24893105dc52c1253649b60f475f36b3aa0fc66115bffafb624d7cb30b",
"sha256:56a62ec00b636583e5cb6ad313bbed36bb7ead5fa3a3e38938503142c72cba4f",
"sha256:57e1f3528bd95cc44684beda696f74d3aaa8a5e58c816214b9046512240ef437",
"sha256:586d0d636f9a628ddc6a17bfd45aa5b5efaf1606d2b60fa5d87b8986326e933f",
"sha256:5cb47c21a8a65b165ce29f2bec852790cbc04936f502966768e4aae9fa763cb7",
"sha256:6c4c68d87497f66f96d50142a2b73b97972130d93677ce930718f68828b382e2",
"sha256:821c7e677cc6acf0fd3f7ac664c98803827ae6de594a9f99563e48c5a2f27eb0",
"sha256:916723458c25dfb77ff07f4c66aed34e47503b2eb3188b3adbec8d8aa6e00f48",
"sha256:9e6ca5d5699bcd89ae605c150aee83b5321f2115695e741b99618f4856c50898",
"sha256:9f5ae84c5c8a857ec44dc180a8b0cc08238e021f57abdf51a8182e915e6299f0",
"sha256:a2b031c2e9b9af485d5e3c4520f4220d74f4d222a5b8dc8c1a3ab9448ca79c57",
"sha256:a61215eac016f391129a013c9e46f3ab308db5f5ec9f25811e811f96962599a8",
"sha256:a740fa0e4087a734455f0fc3abf5e746004c9da72fbd541e9b113013c8dc3282",
"sha256:a9985b214f33311df47e274eb788a5893a761d025e2b92c723ba4c63936b69b1",
"sha256:ab31e908d8424d55601ad7075e471b7d0140d4d3dd3272daf39c5c19d936bd82",
"sha256:ac9dd47af78cae935901a9a500104e2dea2e253207c924cc95de149606dc43cc",
"sha256:addab7e2e1fcc04bd08e4eb631c2a90960c340e40dfc4a5e24d2ff0d5a3b3edb",
"sha256:b1d46dfe3832660f53b13b925d4e0fa1432b00f5f7210eb3ad3bb9a13c6204a6",
"sha256:b2de4c1c0538dcb7010902a2b97f4e00fc4ddf2c8cda9749af0e594d3b7fa3d7",
"sha256:b5ef2f015b95f912c2fcab19c36814963b5463f1fb9049846994b007962743e9",
"sha256:b72d0698f86e8d9ddf9442bdedec15b71df3598199ba33322d9711a19f08145c",
"sha256:bae7de2026cbfe3782c8b78b0db9cbfc5455e079f1937cb0ab8d133496ac55e1",
"sha256:bf22a83f973b50f9d38e55c6aade04c41ddda19b00c4ebc558930d78eecc64ed",
"sha256:c075544284eadc5cddc70f4757331d99dcbc16b2bbd4849d15f8aae4cf36d31c",
"sha256:c396e2cc213d12ce017b686e0f53497f94f8ba2b24799c25d913d46c08ec422c",
"sha256:cb5aaa8c17760909ec6cb15e744c3ebc2ca8918e727216e79607b7bbce9c8f77",
"sha256:cdc793c50be3f01106245a61b739328f7dccc2c648b501e237f0699fe1395b81",
"sha256:d25dd59bbbbb996eacf7be6b4ad082ed7eacc4e8f3d2df1ba43822da9bfa122a",
"sha256:e42b9594cc3bf4d838d67d6ed62b9e59e201862a25e9a157019e171fbe672dd3",
"sha256:e57916ef1bd0fee4f21c4600e9d1da352d8816b52a599c46460e93a6e9f17086",
"sha256:ed40e926fa2f297e8a653c954b732f125ef97bdd4c889f243182299de27e2aa9",
"sha256:ef8108f8dedf204bb7b42994abf93882da1159728a2d4c5e82012edd92c9da9f",
"sha256:f933bbda5a3ee63b8834179096923b094b76f0c7a73c1cfe8f07ad608c58844b",
"sha256:fe5c63197c55bce6385d9aee16c4d0641684628f63ace85f73571e65ad1c1e8d"
"sha256:002b5c72b6cd9b4bafd790f364b8480e859b4712e91f43014fe01e4f957b8467",
"sha256:0a68d3ac0104e2d3510de90a1091720157c319ceeb90d74f7b5295a6bee51bae",
"sha256:0df96d6eaf45ceca04b3f3b4b111b86b33785683d682c655063ef8057d61fd92",
"sha256:0dfe3947db5fb9ce52aaea6ca28112a170db9eae75adf9339a1aec434dc954ef",
"sha256:0e3590f9fb9f7fbc36df366267870e77269c03172d086fa76bb4eba8b2b46624",
"sha256:11184bc7e56fd74c00ead4f9cc9a3091d62ecb96e97653add7a879a14b003227",
"sha256:112b0f93202d7c0fef0b7810d465fde23c746a2d482e1e2de2aafd2ce1492c88",
"sha256:1276e8f34e139aeff1c77a3cefb295598b504ac5314d32c8c3d54d24fadb94c9",
"sha256:1576bd97527a93c44fa856770197dec00d223b0b9f36ef03f65bac60197cedf8",
"sha256:1e91d641d2bfe91ba4c52039adc5bccf27c335356055825c7f88742c8bb900dd",
"sha256:26b8feaca40a90cbe031b03d82b2898bf560027160d3eae1423f4a67654ec5d6",
"sha256:2999623886c5c02deefe156e8f869c3b0aaeba14bfc50aa2486a0415178fce55",
"sha256:2a2df1b55a78eb5f5b7d2a4bb221cd8363913830145fad05374a80bf0877cb1e",
"sha256:2bb8cdf50dd623392fa75525cce44a65a12a00c98e1e37bf0fb08ddce2ff60d2",
"sha256:2cc5ca2712ac0003bcb625c96368fd08a0f86bbc1a5578802512d87bc592fe44",
"sha256:35bc0faa494b0f1d851fd29129b2575b2e26d41d177caacd4206d81502d4c6a6",
"sha256:3c11a48cf5e59026ad7cb0dc29e29a01b5a66a3e333dc11c04f7e991fc5510a9",
"sha256:449e57cc1ff18d3b444eb554e44613cffcccb32805d16726a5494038c3b93dab",
"sha256:462497af5fd4e0edbb1559c352ad84f6c577ffbbb708566a0abaaa84acd9f3ae",
"sha256:4733359808c56d5d7756628736061c432ded018e7a1dff2d35a02439043321aa",
"sha256:48f5d88c99f64c456413d74a975bd605a9b0526293218a3b77220a2c15458ba9",
"sha256:49565b0e3d7896d9ea71d9095df15b7f75a035c49be733051c34762ca95bbf7e",
"sha256:4ab251d229d10498e9a2f3b1e68ef64cb393394ec477e3370c457f9430ce9250",
"sha256:4d5834a2a48965a349da1c5a79760d94a1a0172fbb5ab6b5b33cbf8447e109ce",
"sha256:4dea20515f660aa6b7e964433b1808d098dcfcabbebeaaad240d11f909298075",
"sha256:545e3cf0cf74f3e48b470f68ed19551ae6f9722814ea969305794645da091236",
"sha256:63e29d6e8c9ca22b21846234913c3466b7e4ee6e422f205a2988083de3b08cae",
"sha256:6916c78f33602ecf0509cc40379271ba0f9ab572b066bd4bdafd7434dee4bc6e",
"sha256:6a4192b1ab40f8dca3f2877b70e63799d95c62c068c84dc028b40a6cb03ccd0f",
"sha256:6c9566f2c39ccced0a38d37c26cc3570983b97833c365a6044edef3574a00c08",
"sha256:76ee788122de3a68a02ed6f3a16bbcd97bc7c2e39bd4d94be2f1821e7c4a64e6",
"sha256:7760f85956c415578c17edb39eed99f9181a48375b0d4a94076d84148cf67b2d",
"sha256:77ccd2af37f3db0ea59fb280fa2165bf1b096510ba9fe0cc2bf8fa92a22fdb43",
"sha256:81fc7ba725464651190b196f3cd848e8553d4d510114a954681fd0b9c479d7e1",
"sha256:85f279d88d8e833ec015650fd15ae5eddce0791e1e8a59165318f371158efec6",
"sha256:9667bdfdf523c40d2511f0e98a6c9d3603be6b371ae9a238b7ef2dc4e7a427b0",
"sha256:a75dfb03f8b06f4ab093dafe3ddcc2d633259e6c3f74bb1b01996f5d8aa5868c",
"sha256:ac5bd7901487c4a1dd51a8c58f2632b15d838d07ceedaa5e4c080f7190925bff",
"sha256:aca0f1644d6b5a73eb3e74d4d64d5d8c6c3d577e753a04c9e9c87d07692c58db",
"sha256:b17be2478b622939e39b816e0aa8242611cc8d3583d1cd8ec31b249f04623243",
"sha256:c1683841cd4fa45ac427c18854c3ec3cd9b681694caf5bff04edb9387602d661",
"sha256:c23080fdeec4716aede32b4e0ef7e213c7b1093eede9ee010949f2a418ced6ba",
"sha256:d5b5b962221fa2c5d3a7f8133f9abffc114fe218eb4365e40f17732ade576c8e",
"sha256:d603de2b8d2ea3f3bcb2efe286849aa7a81531abc52d8454da12f46235092bcb",
"sha256:e83f80a7fec1a62cf4e6c9a660e39c7f878f603737a0cdac8c13131d11d97f52",
"sha256:eb514ad14edf07a1dbe63761fd30f89ae79b42625731e1ccf5e1f1092950eaa6",
"sha256:eba96145051ccec0ec86611fe9cf693ce55f2a3ce89c06ed307de0e085730ec1",
"sha256:ed6f7b854a823ea44cf94919ba3f727e230da29feb4a99711433f25800cf747f",
"sha256:f0029245c51fd9473dc1aede1160b0a29f4a912e6b1dd353fa6d317085b219da",
"sha256:f5d869c18f030202eb412f08b28d2afeea553d6613aee89e200d7aca7ef01f5f",
"sha256:fb62ea4b62bfcb0b380d5680f9a4b3f9a2d166d9394e9bbd9666c0ee09a3645c",
"sha256:fcb8a47f43acc113e24e910399376f7277cf8508b27e5b88499f053de6b115a8"
],
"index": "pypi",
"version": "==1.0.5"
},
"outcome": {
"hashes": [
"sha256:6f82bd3de45da303cf1f771ecafa1633750a358436a8bb60e06a1ceb745d2672",
"sha256:c4ab89a56575d6d38a05aa16daeaa333109c1f96167aba8901ab18b6b5e0f7f5"
],
"version": "==1.2.0"
"version": "==1.0.4"
},
"packaging": {
"hashes": [
"sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61",
"sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"
],
"markers": "python_version >= '3.7'",
"version": "==23.1"
},
"pep517": {
@@ -602,42 +548,45 @@
},
"pikepdf": {
"hashes": [
"sha256:0e1607fda03a53a29a4a8e3fbacbde788804c78167ff251e1c1006f89539f306",
"sha256:1cc8d0be5a62ed9011bb519abc34907b5965b392995043719effc4b6a00e2052",
"sha256:26b9bfb99265dfb6deb72574f8cd30e7ffbc2f53237988bb4e167e18d813f510",
"sha256:371eb23ac14e6c9947e59e5cea15ea93e61a5714c6b1f99fba948927809605ea",
"sha256:3c30776791fad8d57a43c392d8e190afded857c61e49dac471ab74e9e716c441",
"sha256:3efe4dd2cb417f42865b11e6fc9adb1b6252241bd7a8d891afcaeb2191c285c2",
"sha256:5155e1127dfe3aacf77a33552f128e9c04e8b61bf585ab2b155d062a524bfd06",
"sha256:6670efe5b9c1548d60348cdd5ce84ca363a3cde22e9cf695f1ce3b3f818e498d",
"sha256:677f04f02535ac398806970544c43c1e2b120d82b027437c467923a16c81d528",
"sha256:6790cf10da642d72703cbe887afb923daa2e0f7cb9467a79fe449dbe228f8942",
"sha256:6a150160f7ed97769f3c0e60de5cb031bce04e1f6708916ac1c936774a65cc0c",
"sha256:6dbe2b62e12ff2b47d4e56ebbe16697d0e25bc2c608f4ee5230cf179ebd2a8ab",
"sha256:70f1161dd22ccfcbfd1c460873c95b68b79cf234f0a4e9f37cb565bf436fd85e",
"sha256:7246789dd9071ebcf8c90baebe1eee34ac627e2ea22bf241eff31d32f5ca5df9",
"sha256:7a07f73f2aac48af46a546e285360d6e595b499075ab78c3b8ca9f5f13d9e876",
"sha256:99e483e037f6991be3c4c655454d57324c10ccf41960acd1edd899ebe9a314dd",
"sha256:9db8270c940f94d0049420f1a6c05b1f7d326d2abb20493c83f64fde3949404e",
"sha256:9fadd1a99754dcd925e37721485d4d1259c7ad3c9073c6b3b0ed12c6e2d2234c",
"sha256:ad82b836faed0376c725e19d0f8a7c7bef389e8c46683c11bbfc70410bc2e3ee",
"sha256:b148959f1ad51d236cf6bbc5343beef72c4c60569151221ec06b1d787909222e",
"sha256:b24b7520c7f40bba4f437ba5111dca99dbd0cca9d3cab0f0a33afa6150091ee3",
"sha256:c99838e86c0fc5a215a0588011344477e8f6ec2c5faf48ee3a9da1ba2c2cac5b",
"sha256:d0698a429948e613f810b487318ce88112bc71a67fd76645be140532130e6c86",
"sha256:d410028ef3435a459e55de520d29010ee91e4a40872d9eb2dab86e6730a24e9d",
"sha256:dc6a653f0f98076a1e86e4fe58fe36dcf403963ae55c65bfcd28aa1d2d9b1b18",
"sha256:e21bce4760c6e64c90b17601a8ce000219677adb264a3c038d2522de032169ca",
"sha256:e4559941b359beb0e90b7d0b8016397ab4700f075f7aa11f2561958a7ce0f8ea",
"sha256:ebc1b30d646ded58721a5594a5ca457e098fedfd9bcab28de79ad79a119e3537",
"sha256:f27a1aea4cae5484cffe4fc5fa761af11f384ca0fd4b2f9114f9ba9717fe4746",
"sha256:f325af78bfb63e305be7f31a3afea47fd33ba035ccb08e89d608d2e88b367349",
"sha256:f3c97acce9b66a41b2759dc30ef57de8f38c7239c9b0e7a5febc196b764a2567",
"sha256:f458c4161e76a882a15ade4125a2f92faa7e5ce120d2e6530dd995aa3308971c",
"sha256:f7451f176eb9828d8dd7cb3d4e00d4e0aa7f7d7d00331fe640bc20cf3328deb5"
"sha256:08ca2566c3ddcb633bbfb90c9e2b7134f222ab48f642f056c266fd69a4c0844e",
"sha256:15eff12d7b5dc4eeeb9fbe5148d5e93cdc9f632a352d7df5191409837cdada6f",
"sha256:24717a49cab8cf0ccb360ae38fefe4b09e23d394086ef6da740071165a2542d8",
"sha256:2c1a3a1ae0d787a6819ffb9d456b0ccbf2b8d48ad8b0748f765a6a306b92184b",
"sha256:2c653bc771cc6065642f5a734ecb771ff16b5412cf05a5c3435072ac01f84fbe",
"sha256:2e9c9cc68bc123b88007b321a494ab054c3ce378ee2f77bba1b90c8bdaaad59e",
"sha256:32a7775f8b2117e72fa101427edf4526f0886e785146a7bfdf2a877d27f94dbf",
"sha256:4675c743ac873d8a1ff9d06c1d5fab15e9ca66aa1abf73fcbca4b86c976b214e",
"sha256:4800fd878876d9a780e2d1125e971d680a0de466440bd6bcbc54ac7cfb925fd6",
"sha256:5b1271b200ece3e16ffa97c76ff93c057d3676f2ecee89ae52efd5e4804874ab",
"sha256:5b1c975d02e75aa8a0e09679ed23f85b6eddf91ac7c85189dc18f1ef8599ce70",
"sha256:5b295d9579081ab46ce7bb463eccbc62e0c60cbe546f29c0a9135abd5cf76a24",
"sha256:5f040aa7d9327b6d9087848dc8e35d2b8515bf17a04e2bdb20f8c51931810213",
"sha256:62d724e37a2f004f63615513d3f877334e679dd43b6c55cdfe9b8af56ff52400",
"sha256:6452fa9d10b15bb60b2343b7ac08123e0c5b87f852250538d32bf556f09b8c3a",
"sha256:66679ee6b364b3b9659a72697e053554e2f4c231371173745b59114f00a821e5",
"sha256:6b21fde29bd006cb0889e05a0407f0825b5650ae22272ba70720fc68a2e44a0e",
"sha256:788df6789df19a381976f6644b78a65da92c5d4fd45714682a1cffb0cd3ff410",
"sha256:7a6de8d04df3dc4f37ddbdfdbecdb4c3d20d479699260902ec06fa531cbfbae6",
"sha256:80a4546f59bb38121c20fc37305a388b8f9d561c6bbcc77a3415afdd8a7ab16d",
"sha256:856e527970fa2516858662906173004568a38f95b46ef95c8231c529f3e71581",
"sha256:8874d4d38b2da71837352576c5ec10c03b2a7976124b95721564d8c456c9824b",
"sha256:913437609c3e5b9109a2fe1100f52bdcead4e56e8c83ca8a9c3b520cd7720016",
"sha256:91fd023805733163927ae04b16d48374f04f03f204f2cfa45d442b052314de83",
"sha256:9d9fe5e3fbd54a45fe7678c08d24c1e8347a1e48adcb4f32c6c25ef380f056ca",
"sha256:a98fcebb4303b8b2f5cde0d56f2406a53e74a9ad4bc1e1bc12bdc2b3dd4def1f",
"sha256:aa7d3831fa016634f2ead255717644ba2dddf462117b8558b783ac2ba94583bb",
"sha256:ae0ba99841d80107becaec6ed067b63c455f51a9bb83b0e88efd3a098753735b",
"sha256:b77e2e134315d25dd004b4ffbd2d5032352da164b21bc3bd92768379610fa2b5",
"sha256:c5a2710aacb1fa25edd77feba51dcadf85a9b735f2190e8b45edf0e1e79b5d1d",
"sha256:c768e55caf96024218866a5b5f95fdded2ef001b2d5463d1c89e57d07bdab928",
"sha256:d55b1d8eb3b17e55682b91c042c48e2d0c67be4c1e30b7e539a82e03977eed29",
"sha256:d57a35b3ed3f8ef98aa528d4981d1376ccc1ba64ab937f2ac2ed0aadee1d5911",
"sha256:e35110f69406e5b9cf6330d16106877372f6aa955fdc1a920d53babcd6a5ae3d",
"sha256:e3ff858d504312ea07519121d3ecdf1b5bc40541f957d2b85d271a2ca6284b70",
"sha256:f721cd86d8ddf0624306fcd1fed3e086387fcb2e32baeafbd1ba92a7c40c5563"
],
"index": "pypi",
"version": "==7.2.0"
"version": "==6.2.5"
},
"pillow": {
"hashes": [
@@ -711,6 +660,7 @@
"sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159",
"sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"
],
"markers": "python_version >= '3.6'",
"version": "==1.0.0"
},
"premailer": {
@@ -783,22 +733,6 @@
"index": "pypi",
"version": "==2.8.6"
},
"pycairo": {
"hashes": [
"sha256:1a6d8e0f353062ad92954784e33dbbaf66c880c9c30e947996c542ed9748aaaf",
"sha256:2dec5378133778961993fb59d66df16070e03f4d491b67eb695ca9ad7a696008",
"sha256:3a71f758e461180d241e62ef52e85499c843bd2660fd6d87cec99c9833792bfa",
"sha256:564601e5f528531c6caec1c0177c3d0709081e1a2a5cccc13561f715080ae535",
"sha256:82e335774a17870bc038e0c2fb106c1e5e7ad0c764662023886dfcfce5bb5a52",
"sha256:87efd62a7b7afad9a0a420f05b6008742a6cfc59077697be65afe8dc73ae15ad",
"sha256:9b61ac818723adc04367301317eb2e814a83522f07bbd1f409af0dada463c44c",
"sha256:a4b1f525bbdf637c40f4d91378de36c01ec2b7f8ecc585b700a079b9ff83298e",
"sha256:d6bacff15d688ed135b4567965a4b664d9fb8de7417a7865bb138ad612043c9f",
"sha256:e7cde633986435d87a86b6118b7b6109c384266fd719ef959883e2729f6eafae",
"sha256:ec305fc7f2f0299df78aadec0eaf6eb9accb90eda242b5d3492544d3f2b28027"
],
"version": "==1.23.0"
},
"pygments": {
"hashes": [
"sha256:bc9591213a8f0e0ca1a5e68a479b4887fdc3e75d0774e5c71c31920c427de435",
@@ -831,14 +765,6 @@
"index": "pypi",
"version": "==2.2.4"
},
"pysocks": {
"hashes": [
"sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299",
"sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5",
"sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"
],
"version": "==1.7.1"
},
"python-barcode": {
"hashes": [
"sha256:241b34aa5c5cb6a9889882f9409b0182903a2c5d19b4218be3609cdbbd5ffdf9",
@@ -873,11 +799,54 @@
},
"reportlab": {
"hashes": [
"sha256:3ea3b2954cb434b024dac61e9f270f2a4c0f9e0cc8b2cf2e310273307b2ba05c",
"sha256:a1433a24cee3119fdc142487c6594d72621dd1d5d33df2d032c559aa0bb8b115"
"sha256:07fdd968df7941c2bfb67b9bb4532f424992dfafc71b72a4e4b291ff707e6b0e",
"sha256:090ea99ff829d918f7b6140594373b1340a34e1e6876eddae5aa06662ec10d64",
"sha256:109009b02fc225882ea766a5ed8be0ef473fa1356e252a3f651a6aa89b4a195f",
"sha256:1dd0307b2b13b0482ac8314fd793fbbce263a428b189371addf0466784e1d597",
"sha256:236a6483210049205f6180d7a7595d0ca2e4ce343d83cc94ca719a4145809c6f",
"sha256:26c25ea4afa8b92a2c14f4edc41c8fc30505745ce84cae86538e80cacadd7ae2",
"sha256:2a0bc7a1d64fe754b62e175ba0cf47a630b529c0488ec9ac4e4c7655e295ea4d",
"sha256:2c9b0861d8f40d7a24b094b8834f6a489b9e8c70bceaa7fa98237eed229671ce",
"sha256:39e92fa4ab2a8f0f2cc051d9c1e3acb881340c07ef59c0c8b627861343d653c0",
"sha256:3a62e51a4a47616896bd0f1e9cc3fbfb174b713794a5031a34b84f69dbe01775",
"sha256:3fd1ffdd5204301eb4c290a5752ac62f44d2d0b262e02e35a1e5234c13e14662",
"sha256:498b4ec7e73426de64c6bf6ec03c5b3f10dedf5db8a9e13fdf195f95a3d065aa",
"sha256:4c599645af9b5b2241a23e977a82c965a59c24cd94b2600b8d34373c66cad763",
"sha256:4fa3cdf490f3828b055381e8c7dc7819b3e5f7a442d7af7a8f90e9806a7fff51",
"sha256:55a070206580e161b6bbe1a96abf816c18d4c2c225d49916654714c93d842835",
"sha256:666bdba4958b348460a765c48b8c0640e7085540846ed9494f47d8651604b33c",
"sha256:69f41295d696c822224334f0994f1f107df7efed72211d45a1118696f1427c84",
"sha256:6dfcf7bd6db5d80711cbbd0996b6e7a79cc414ca81457960367df11d2860f92a",
"sha256:71cf73f9907c444ef663ea653dbac24af07c307079572c3ff8f20ad1463af3b7",
"sha256:72ec333f089b4fce5a6d740ed0a1963a3994146be195722da0d8e14d4a7e1600",
"sha256:759495c2b8c15cb0d6b539c246896029e4cde42a896c3956f77e311c5f6b0807",
"sha256:7a7c3369fa618eca79f9554ce06c618a5e738e592d61d96aa09b2457ca3ea410",
"sha256:8b1215facead57cc5325aef4229ef886e85d270b2ba02080fb5809ce9d2b81b4",
"sha256:907f7cd4832bb295d0c1573de15cc5aab5988282caf2ee7a2b1276fb6cdf502b",
"sha256:93e229519d046491b798f2c12dbbf2f3e237e89589aa5cbb5e1d8c1a978816db",
"sha256:a12049314497d872f6788f811e2b331654db207937f8a2fb34ff3e3cd9897faa",
"sha256:a8dddc52e0e486291be0ad39184da0607fae9cc665fdba1881211de9cfc0b332",
"sha256:adf78ccb2defad5b6ecb2e2e9f2a672719b0a8e2278592a7d77f6c220a042388",
"sha256:b13cebf4e397bba14542bcd023338b6ff2c151a3a12aabca89eecbf972cb361a",
"sha256:b3648f3c340b6b6aabf9352341478c708cee6f00c5cd5c902311fcf4ce870f3c",
"sha256:b6a1b685da0b9a8000bb980e02d9d5be202d0cc539af113b661c76c051fca6f1",
"sha256:b777ddc57b2d3366cbc540616034cdc1089ca0a31fefc907028e1dd62a6bf16c",
"sha256:bb83df8f7840321d34cb5b24c972c617a8c1716c8a36e5050fff56adf5891b8c",
"sha256:c07ec796a2a5d44bf787f2b623b6e668a389b0cafb78af34cf74554ff3bc532b",
"sha256:c40e108072379ff83dd7442159ebc249d12eb8eec15b70614953fecd2c403792",
"sha256:c4863c49602722237e35cbce5aa91af4539cc63a671f59504d2b3f3767d898cf",
"sha256:c56d701f7dc662e1d3d7fe364e66fa1339eafce54a488c2d16ec0ea49dc213c2",
"sha256:c84afd5bef6e407c80ba9f99b6abbe3ea78e8243b0f19897a871a7bcad1f749d",
"sha256:cdd206883e999278d2af656f988dfcc89eb0c175ce6d75e87b713cf1e792c0c4",
"sha256:ce85a204f46c871c8af6fa64b9bbed165456935c1d0bfb2f570a3194f6723ddb",
"sha256:cee3b6ebef5e4a8654ec5f0effeb1a2bb157ad87b0ac856871d25a805c0f2f90",
"sha256:d4cecfb48a6cfbfe2caf0fc280cecea999699e63bc98cb02254bd87b39eff677",
"sha256:db62bed0774778fdf82c609cb9efd0062f2fdcd285be527d01f6be9fd9755888",
"sha256:f51dcb39e910a853749250c0f82aced80bca3f7315e9c4ee14349eb7cab6a3f8",
"sha256:f5808e1dac6b66c109d6205ce2aebf84bb89e1a1493b7e6df38932df5ebfb9cf"
],
"index": "pypi",
"version": "==4.0.0"
"version": "==3.6.12"
},
"requests": {
"hashes": [
@@ -895,28 +864,29 @@
"index": "pypi",
"version": "==1.3.4"
},
"rlpycairo": {
"hashes": [
"sha256:7cd1eac30fe69d98f75d67a54892f9c10534a047b9a959ef17bb3926a196e50a",
"sha256:a88bce206c45d2180f944b8754c6e2e9245f80506c90fdfb94c7fbdd27805c25"
],
"version": "==0.2.0"
},
"selenium": {
"hashes": [
"sha256:3444f4376321530c36ce8355b6b357d8cf4a7d588ce5cf772183465930bbed0e",
"sha256:82aedaa85d55bc861f4c89ff9609e82f6c958e2e1e3da3ffcc36703f21d3ee16"
"sha256:2d7131d7bc5a5b99a2d9b04aaf2612c411b03b8ca1b1ee8d3de5845a9be2cb3c",
"sha256:deaf32b60ad91a4611b98d8002757f29e6f2c2d5fcaf202e1c9ad06d6772300d"
],
"index": "pypi",
"version": "==4.9.1"
"version": "==3.141.0"
},
"sentry-sdk": {
"hashes": [
"sha256:5932c092c6e6035584eb74d77064e4bce3b7935dfc4a331349719a40db265840",
"sha256:cf89a5063ef84278d186aceaed6fb595bfe67d099298e537634a323664265669"
"sha256:675f6279b6bb1fea09fd61751061f9a90dca3b5929ef631dd50dc8b3aeb245e9",
"sha256:8b4ff696c0bdcceb3f70bbb87a57ba84fd3168b1332d493fcd16c137f709578c"
],
"index": "pypi",
"version": "==1.22.2"
"version": "==1.11.1"
},
"setuptools": {
"hashes": [
"sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b",
"sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990"
],
"markers": "python_version >= '3.7'",
"version": "==67.7.2"
},
"simplejson": {
"hashes": [
@@ -993,36 +963,21 @@
"index": "pypi",
"version": "==1.15.0"
},
"sniffio": {
"hashes": [
"sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101",
"sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"
],
"version": "==1.3.0"
},
"sortedcontainers": {
"hashes": [
"sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88",
"sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"
],
"version": "==2.4.0"
},
"soupsieve": {
"hashes": [
"sha256:1c1bfee6819544a3447586c889157365a27e10d88cde3ad3da0cf0ddf646feb8",
"sha256:89d12b2d5dfcd2c9e8c22326da9d9aa9cb3dfab0a83a024f05704076ee8d35ea"
"sha256:3b2503d3c7084a42b1ebd08116e5f81aadfaea95863628c80a3b774a11b7c759",
"sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d"
],
"index": "pypi",
"markers": "python_version >= '3.0'",
"version": "==2.4.1"
"version": "==2.3.2.post1"
},
"sqlparse": {
"hashes": [
"sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3",
"sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"
"sha256:0323c0ec29cd52bceabc1b4d9d579e311f3e4961b98d174201d5622a23b85e34",
"sha256:69ca804846bb114d2ec380e4360a8a340db83f0ccf3afceeb1404df028f57268"
],
"index": "pypi",
"version": "==0.4.4"
"version": "==0.4.3"
},
"static3": {
"hashes": [
@@ -1042,6 +997,7 @@
"hashes": [
"sha256:3ae765d3a9409ee60c0fb4d24c2deb6a80617aa927054f5bcd7fc98f0695e587"
],
"markers": "python_version >= '3.7'",
"version": "==1.5.1"
},
"tini": {
@@ -1057,6 +1013,7 @@
"sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847",
"sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627"
],
"markers": "python_version >= '3.7'",
"version": "==1.2.1"
},
"toml": {
@@ -1064,46 +1021,33 @@
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.10.2"
},
"tornado": {
"hashes": [
"sha256:1285f0691143f7ab97150831455d4db17a267b59649f7bd9700282cba3d5e771",
"sha256:3455133b9ff262fd0a75630af0a8ee13564f25fb4fd3d9ce239b8a7d3d027bf8",
"sha256:5e2f49ad371595957c50e42dd7e5c14d64a6843a3cf27352b69c706d1b5918af",
"sha256:81c17e0cc396908a5e25dc8e9c5e4936e6dfd544c9290be48bd054c79bcad51e",
"sha256:90f569a35a8ec19bde53aa596952071f445da678ec8596af763b9b9ce07605e6",
"sha256:9661aa8bc0e9d83d757cd95b6f6d1ece8ca9fd1ccdd34db2de381e25bf818233",
"sha256:a27a1cfa9997923f80bdd962b3aab048ac486ad8cfb2f237964f8ab7f7eb824b",
"sha256:b4e7b956f9b5e6f9feb643ea04f07e7c6b49301e03e0023eedb01fa8cf52f579",
"sha256:d7117f3c7ba5d05813b17a1f04efc8e108a1b811ccfddd9134cc68553c414864",
"sha256:db181eb3df8738613ff0a26f49e1b394aade05034b01200a63e9662f347d4415",
"sha256:ffdce65a281fd708da5a9def3bfb8f364766847fa7ed806821a69094c9629e8a"
"sha256:1d54d13ab8414ed44de07efecb97d4ef7c39f7438cf5e976ccd356bebb1b5fca",
"sha256:20f638fd8cc85f3cbae3c732326e96addff0a15e22d80f049e00121651e82e72",
"sha256:5c87076709343557ef8032934ce5f637dbb552efa7b21d08e89ae7619ed0eb23",
"sha256:5f8c52d219d4995388119af7ccaa0bcec289535747620116a58d830e7c25d8a8",
"sha256:6fdfabffd8dfcb6cf887428849d30cf19a3ea34c2c248461e1f7d718ad30b66b",
"sha256:87dcafae3e884462f90c90ecc200defe5e580a7fbbb4365eda7c7c1eb809ebc9",
"sha256:9b630419bde84ec666bfd7ea0a4cb2a8a651c2d5cccdbdd1972a0c859dfc3c13",
"sha256:b8150f721c101abdef99073bf66d3903e292d851bee51910839831caba341a75",
"sha256:ba09ef14ca9893954244fd872798b4ccb2367c165946ce2dd7376aebdde8e3ac",
"sha256:d3a2f5999215a3a06a4fc218026cd84c61b8b2b40ac5296a6db1f1451ef04c1e",
"sha256:e5f923aa6a47e133d1cf87d60700889d7eae68988704e20c75fb2d65677a8e4b"
],
"index": "pypi",
"version": "==6.3.1"
},
"trio": {
"hashes": [
"sha256:ce68f1c5400a47b137c5a4de72c7c901bd4e7a24fbdebfe9b41de8c6c04eaacf",
"sha256:f1dd0780a89bfc880c7c7994519cb53f62aacb2c25ff487001c0052bd721cdf0"
],
"version": "==0.22.0"
},
"trio-websocket": {
"hashes": [
"sha256:0908435e4eecc49d830ae1c4d6c47b978a75f00594a2be2104d58b61a04cdb53",
"sha256:af13e9393f9051111300287947ec595d601758ce3d165328e7d36325135a8d62"
],
"version": "==0.10.2"
"version": "==6.2"
},
"urllib3": {
"hashes": [
"sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305",
"sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42"
"sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc",
"sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8"
],
"index": "pypi",
"version": "==1.26.15"
"version": "==1.26.13"
},
"webencodings": {
"hashes": [
@@ -1120,13 +1064,6 @@
"index": "pypi",
"version": "==5.2.0"
},
"wsproto": {
"hashes": [
"sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065",
"sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736"
],
"version": "==1.2.0"
},
"yolk": {
"hashes": [
"sha256:1c07eb4001dc133c08e66e38c5d58faa7616ae804f8d0ab02dd44a1044e7ddb8"
@@ -1176,11 +1113,11 @@
},
"zope.event": {
"hashes": [
"sha256:4ab47faac13163ca3c5d6d8a5595212e14770322e95c338d955e3688ba19082a",
"sha256:8cca6074a2bbca140d32704694e74098d5621f2c75ea6e3a9458240a3b5382a9"
"sha256:2666401939cdaa5f4e0c08cf7f20c9b21423b95e88f4675b1443973bdb080c42",
"sha256:5e76517f5b9b119acf37ca8819781db6c16ea433f7e2062c4afc2b6fbedb1330"
],
"index": "pypi",
"version": "==4.5.1"
"version": "==4.5.0"
},
"zope.hookable": {
"hashes": [
@@ -1347,6 +1284,7 @@
"sha256:01c7bf666359b4967d2cda0000cc2e4af16a0ae098cbffcb8472fb9e8ad6585b",
"sha256:6ebb3d106c12920aaae42ccb6f787ef5eefdcdd166ea3d628fa8476abe712144"
],
"markers": "python_version >= '3.5'",
"version": "==1.10"
},
"attrs": {
@@ -1354,6 +1292,7 @@
"sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04",
"sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"
],
"markers": "python_version >= '3.7'",
"version": "==23.1.0"
},
"certifi": {
@@ -1361,6 +1300,7 @@
"sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7",
"sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"
],
"markers": "python_version >= '3.6'",
"version": "==2023.5.7"
},
"charset-normalizer": {
@@ -1441,6 +1381,7 @@
"sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df",
"sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"
],
"markers": "python_version >= '3.7'",
"version": "==3.1.0"
},
"coverage": {
@@ -1496,6 +1437,7 @@
"sha256:f642e90754ee3e06b0e7e51bce3379590e76b7f76b708e1a71ff043f87025c84",
"sha256:fc2af30ed0d5ae0b1abdb4ebdce598eafd5b35397d4d75deb341a614d333d987"
],
"markers": "python_version >= '3.7'",
"version": "==6.5.0"
},
"coveralls": {
@@ -1525,6 +1467,7 @@
"sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e",
"sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"
],
"markers": "python_version < '3.11'",
"version": "==1.1.1"
},
"execnet": {
@@ -1532,6 +1475,7 @@
"sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5",
"sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==1.9.0"
},
"h11": {
@@ -1539,6 +1483,7 @@
"sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d",
"sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"
],
"markers": "python_version >= '3.7'",
"version": "==0.14.0"
},
"idna": {
@@ -1554,6 +1499,7 @@
"sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3",
"sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"
],
"markers": "python_version >= '3.7'",
"version": "==2.0.0"
},
"outcome": {
@@ -1561,6 +1507,7 @@
"sha256:6f82bd3de45da303cf1f771ecafa1633750a358436a8bb60e06a1ceb745d2672",
"sha256:c4ab89a56575d6d38a05aa16daeaa333109c1f96167aba8901ab18b6b5e0f7f5"
],
"markers": "python_version >= '3.7'",
"version": "==1.2.0"
},
"packaging": {
@@ -1568,6 +1515,7 @@
"sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61",
"sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"
],
"markers": "python_version >= '3.7'",
"version": "==23.1"
},
"pluggy": {
@@ -1575,6 +1523,7 @@
"sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159",
"sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"
],
"markers": "python_version >= '3.6'",
"version": "==1.0.0"
},
"psutil": {
@@ -1637,11 +1586,11 @@
},
"pytest": {
"hashes": [
"sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362",
"sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"
"sha256:892f933d339f068883b6fd5a459f03d85bfcb355e4981e146d2c7616c21fef71",
"sha256:c4014eb40e10f11f355ad4e3c2fb2c6c6d1919c73f3b5a433de4708202cade59"
],
"index": "pypi",
"version": "==7.3.1"
"version": "==7.2.0"
},
"pytest-cov": {
"hashes": [
@@ -1676,12 +1625,15 @@
"version": "==3.3.2"
},
"pytest-xdist": {
"extras": [
"psutil"
],
"hashes": [
"sha256:1849bd98d8b242b948e472db7478e090bf3361912a8fed87992ed94085f54727",
"sha256:37290d161638a20b672401deef1cba812d110ac27e35d213f091d15b8beb40c9"
"sha256:40fdb8f3544921c5dfcd486ac080ce22870e71d82ced6d2e78fa97c2addd480c",
"sha256:70a76f191d8a1d2d6be69fc440cdf85f3e4c03c08b520fd5dc5d338d6cf07d89"
],
"index": "pypi",
"version": "==3.2.1"
"version": "==3.1.0"
},
"requests": {
"hashes": [
@@ -1693,17 +1645,26 @@
},
"selenium": {
"hashes": [
"sha256:3444f4376321530c36ce8355b6b357d8cf4a7d588ce5cf772183465930bbed0e",
"sha256:82aedaa85d55bc861f4c89ff9609e82f6c958e2e1e3da3ffcc36703f21d3ee16"
"sha256:2d7131d7bc5a5b99a2d9b04aaf2612c411b03b8ca1b1ee8d3de5845a9be2cb3c",
"sha256:deaf32b60ad91a4611b98d8002757f29e6f2c2d5fcaf202e1c9ad06d6772300d"
],
"index": "pypi",
"version": "==4.9.1"
"version": "==3.141.0"
},
"setuptools": {
"hashes": [
"sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b",
"sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990"
],
"markers": "python_version >= '3.7'",
"version": "==67.7.2"
},
"sniffio": {
"hashes": [
"sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101",
"sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"
],
"markers": "python_version >= '3.7'",
"version": "==1.3.0"
},
"sortedcontainers": {
@@ -1725,6 +1686,7 @@
"sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
"sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"
],
"markers": "python_version < '3.11'",
"version": "==2.0.1"
},
"trio": {
@@ -1732,6 +1694,7 @@
"sha256:ce68f1c5400a47b137c5a4de72c7c901bd4e7a24fbdebfe9b41de8c6c04eaacf",
"sha256:f1dd0780a89bfc880c7c7994519cb53f62aacb2c25ff487001c0052bd721cdf0"
],
"markers": "python_version >= '3.7'",
"version": "==0.22.0"
},
"trio-websocket": {
@@ -1739,21 +1702,23 @@
"sha256:0908435e4eecc49d830ae1c4d6c47b978a75f00594a2be2104d58b61a04cdb53",
"sha256:af13e9393f9051111300287947ec595d601758ce3d165328e7d36325135a8d62"
],
"markers": "python_version >= '3.7'",
"version": "==0.10.2"
},
"urllib3": {
"hashes": [
"sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305",
"sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42"
"sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc",
"sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8"
],
"index": "pypi",
"version": "==1.26.15"
"version": "==1.26.13"
},
"wsproto": {
"hashes": [
"sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065",
"sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736"
],
"markers": "python_version >= '3.7'",
"version": "==1.2.0"
},
"zope.component": {
@@ -1766,11 +1731,11 @@
},
"zope.event": {
"hashes": [
"sha256:4ab47faac13163ca3c5d6d8a5595212e14770322e95c338d955e3688ba19082a",
"sha256:8cca6074a2bbca140d32704694e74098d5621f2c75ea6e3a9458240a3b5382a9"
"sha256:2666401939cdaa5f4e0c08cf7f20c9b21423b95e88f4675b1443973bdb080c42",
"sha256:5e76517f5b9b119acf37ca8819781db6c16ea433f7e2062c4afc2b6fbedb1330"
],
"index": "pypi",
"version": "==4.5.1"
"version": "==4.5.0"
},
"zope.hookable": {
"hashes": [

View File

@@ -64,7 +64,7 @@ INSTALLED_APPS = (
'assets',
'training',
# 'debug_toolbar',
'debug_toolbar',
'registration',
'reversion',
'widget_tweaks',
@@ -75,7 +75,7 @@ INSTALLED_APPS = (
MIDDLEWARE = (
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
# 'debug_toolbar.middleware.DebugToolbarMiddleware',
'debug_toolbar.middleware.DebugToolbarMiddleware',
'reversion.middleware.RevisionMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',

View File

@@ -48,7 +48,6 @@ class Index(generic.TemplateView): # Displays the current rig count along with
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['rig_count'] = models.Event.objects.rig_count()
context['now'] = models.Event.objects.events_in_bounds(timezone.now(), timezone.now())
return context

View File

@@ -20,7 +20,6 @@ admin.site.register(models.VatRate, VersionAdmin)
admin.site.register(models.Event, VersionAdmin)
admin.site.register(models.EventItem, VersionAdmin)
admin.site.register(models.Invoice, VersionAdmin)
admin.site.register(models.EventCheckIn)
@transaction.atomic() # Copied from django-extensions. GenericForeignKey support removed as unnecessary.
@@ -207,8 +206,3 @@ class RiskAssessmentAdmin(VersionAdmin):
@admin.register(models.EventChecklist)
class EventChecklistAdmin(VersionAdmin):
list_display = ('id', 'event', 'reviewed_at', 'reviewed_by')
@admin.register(models.PowerTestRecord)
class EventChecklistAdmin(VersionAdmin):
list_display = ('id', 'event', 'reviewed_at', 'reviewed_by')

View File

@@ -44,7 +44,7 @@ class EventForm(forms.ModelForm):
return simplejson.dumps(items)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
super(EventForm, self).__init__(*args, **kwargs)
self.fields['items_json'].initial = self._get_items_json
self.fields['start_date'].widget.format = '%Y-%m-%d'
@@ -200,41 +200,86 @@ class EventChecklistForm(forms.ModelForm):
related_models = {
'venue': models.Venue,
'power_mic': models.Profile,
}
# Two possible formats
def parsedatetime(self, date_string):
try:
return timezone.make_aware(datetime.strptime(date_string, '%Y-%m-%dT%H:%M:%S'))
except ValueError:
return timezone.make_aware(datetime.strptime(date_string, '%Y-%m-%dT%H:%M'))
# There's probably a thousand better ways to do this, but this one is mine
def clean(self):
vehicles = {key: val for key, val in self.data.items()
if key.startswith('vehicle')}
for key in vehicles:
pk = int(key.split('_')[1])
driver_key = 'driver_' + str(pk)
if (self.data[driver_key] == ''):
raise forms.ValidationError('Add a driver to vehicle ' + str(pk), code='vehicle_mismatch')
else:
try:
item = models.EventChecklistVehicle.objects.get(pk=pk)
except models.EventChecklistVehicle.DoesNotExist:
item = models.EventChecklistVehicle()
item.vehicle = vehicles['vehicle_' + str(pk)]
item.driver = models.Profile.objects.get(pk=self.data[driver_key])
item.full_clean('checklist')
# item does not have a database pk yet as it isn't saved
self.items['v' + str(pk)] = item
crewmembers = {key: val for key, val in self.data.items()
if key.startswith('crewmember')}
other_fields = ['start', 'role', 'end']
for key in crewmembers:
pk = int(key.split('_')[1])
for field in other_fields:
value = self.data[f'{field}_{pk}']
if value == '':
raise forms.ValidationError(f'Add a {field} to crewmember {pk}', code=f'{field}_mismatch')
try:
item = models.EventChecklistCrew.objects.get(pk=pk)
except models.EventChecklistCrew.DoesNotExist:
item = models.EventChecklistCrew()
item.crewmember = models.Profile.objects.get(pk=self.data['crewmember_' + str(pk)])
item.start = self.parsedatetime(self.data['start_' + str(pk)])
item.role = self.data['role_' + str(pk)]
item.end = self.parsedatetime(self.data['end_' + str(pk)])
item.full_clean('checklist')
# item does not have a database pk yet as it isn't saved
self.items['c' + str(pk)] = item
return super(EventChecklistForm, self).clean()
def save(self, commit=True):
checklist = super(EventChecklistForm, self).save(commit=False)
if (commit):
# Remove all existing, to be recreated from the form
checklist.vehicles.all().delete()
checklist.crew.all().delete()
checklist.save()
for key in self.items:
item = self.items[key]
reversion.add_to_revision(item)
# finish and save new database items
item.checklist = checklist
item.full_clean()
item.save()
self.items.clear()
return checklist
class Meta:
model = models.EventChecklist
fields = '__all__'
exclude = ['reviewed_at', 'reviewed_by']
class PowerTestRecordForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name, field in self.fields.items():
if field.__class__ == forms.NullBooleanField:
# Only display yes/no to user, the 'none' is only ever set in the background
field.widget = forms.CheckboxInput()
class Meta:
model = models.PowerTestRecord
fields = '__all__'
exclude = ['reviewed_at', 'reviewed_by']
class EventCheckInForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['time'].initial = timezone.now()
self.fields['role'].initial = "Crew"
class Meta:
model = models.EventCheckIn
fields = '__all__'
exclude = ['end_time']
class EditCheckInForm(forms.ModelForm):
class Meta:
model = models.EventCheckIn
fields = '__all__'

View File

@@ -278,7 +278,7 @@ class Command(BaseCommand):
suspended_structures=bool(random.getrandbits(1)),
outside=bool(random.getrandbits(1)))
if i == 0 or random.randint(0, 1) > 0: # Event 1 and 1 in 10 have a Checklist
models.EventChecklist.objects.create(event=new_event,
models.EventChecklist.objects.create(event=new_event, power_mic=random.choice(self.profiles),
safe_parking=bool(random.getrandbits(1)),
safe_packing=bool(random.getrandbits(1)),
exits=bool(random.getrandbits(1)),
@@ -287,4 +287,6 @@ class Command(BaseCommand):
ear_plugs=bool(random.getrandbits(1)),
hs_location="Locked away safely",
extinguishers_location="Somewhere, I forgot",
earthing=bool(random.getrandbits(1)),
pat=bool(random.getrandbits(1)),
date=timezone.now(), venue=random.choice(self.venues))

View File

@@ -1,71 +0,0 @@
# Generated by Django 3.2.16 on 2023-05-08 15:58
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import versioning.versioning
def migrate_old_data(apps, schema_editor):
EventChecklist = apps.get_model('RIGS', 'EventChecklist')
PowerTestRecord = apps.get_model('RIGS', 'PowerTestRecord')
for ec in EventChecklist.objects.all():
# New highscore for the most pythonic BS I've ever written.
PowerTestRecord.objects.create(event=ec.event, **{i.name:getattr(ec, i.attname) for i in PowerTestRecord._meta.get_fields() if not (i.is_relation or i.auto_created)})
def revert(apps, schema_editor):
apps.get_model('RIGS', 'PowerTestRecord').objects.all().delete()
class Migration(migrations.Migration):
dependencies = [
('RIGS', '0045_alter_profile_is_approved'),
]
operations = [
migrations.CreateModel(
name='PowerTestRecord',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='power_tests', to='RIGS.event')),
('notes', models.TextField(blank=True, default='')),
('venue', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='RIGS.venue')),
('reviewed_at', models.DateTimeField(null=True)),
('rcds', models.BooleanField(blank=True, help_text='RCDs installed where needed and tested?', null=True)),
('supply_test', models.BooleanField(blank=True, help_text='Electrical supplies tested?<br><small>(using socket tester)</small>', null=True)),
('earthing', models.BooleanField(blank=True, help_text='Equipment appropriately earthed?<br><small>(truss, stage, generators etc)</small>', null=True)),
('pat', models.BooleanField(blank=True, help_text='All equipment in PAT period?', null=True)),
('source_rcd', models.BooleanField(blank=True, help_text='Source RCD protected?<br><small>(if cable is more than 3m long) </small>', null=True)),
('labelling', models.BooleanField(blank=True, help_text='Appropriate and clear labelling on distribution and cabling?', null=True)),
('fd_voltage_l1', models.IntegerField(blank=True, help_text='L1 - N', null=True, verbose_name='First Distro Voltage L1-N')),
('fd_voltage_l2', models.IntegerField(blank=True, help_text='L2 - N', null=True, verbose_name='First Distro Voltage L2-N')),
('fd_voltage_l3', models.IntegerField(blank=True, help_text='L3 - N', null=True, verbose_name='First Distro Voltage L3-N')),
('fd_phase_rotation', models.BooleanField(blank=True, help_text='Phase Rotation<br><small>(if required)</small>', null=True, verbose_name='Phase Rotation')),
('fd_earth_fault', models.DecimalField(blank=True, decimal_places=2, help_text='Earth Fault Loop Impedance (Z<small>S</small>)', max_digits=5, null=True, verbose_name='Earth Fault Loop Impedance')),
('fd_pssc', models.IntegerField(blank=True, help_text='Prospective Short Circuit Current', null=True, verbose_name='PSCC')),
('w1_description', models.CharField(blank=True, default='', help_text='Description', max_length=255)),
('w1_polarity', models.BooleanField(blank=True, help_text='Polarity Checked?', null=True)),
('w1_voltage', models.IntegerField(blank=True, help_text='Voltage', null=True)),
('w1_earth_fault', models.DecimalField(blank=True, decimal_places=2, help_text='Earth Fault Loop Impedance (Z<small>S</small>)', max_digits=5, null=True, verbose_name='Earth Fault Loop Impedance')),
('w2_description', models.CharField(blank=True, default='', help_text='Description', max_length=255)),
('w2_polarity', models.BooleanField(blank=True, help_text='Polarity Checked?', null=True)),
('w2_voltage', models.IntegerField(blank=True, help_text='Voltage', null=True)),
('w2_earth_fault', models.DecimalField(blank=True, decimal_places=2, help_text='Earth Fault Loop Impedance (Z<small>S</small>)', max_digits=5, null=True, verbose_name='Earth Fault Loop Impedance')),
('w3_description', models.CharField(blank=True, default='', help_text='Description', max_length=255)),
('w3_polarity', models.BooleanField(blank=True, help_text='Polarity Checked?', null=True)),
('w3_voltage', models.IntegerField(blank=True, help_text='Voltage', null=True)),
('w3_earth_fault', models.DecimalField(blank=True, decimal_places=2, help_text='Earth Fault Loop Impedance (Z<small>S</small>)', max_digits=5, null=True, verbose_name='Earth Fault Loop Impedance')),
('all_rcds_tested', models.BooleanField(blank=True, help_text='All circuit RCDs tested?<br><small>(using test button)</small>', null=True)),
('public_sockets_tested', models.BooleanField(blank=True, help_text='Public/Performer accessible circuits tested?<br><small>(using socket tester)</small>', null=True)),
('reviewed_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Reviewer')),
],
options={
'abstract': False,
'ordering': ['event'],
'permissions': [('review_power', 'Can review Power Test Records')],
},
bases=(models.Model, versioning.versioning.RevisionMixin),
),
migrations.RunPython(migrate_old_data, reverse_code=revert),
]

View File

@@ -1,169 +0,0 @@
# Generated by Django 3.2.19 on 2023-05-17 08:44
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('RIGS', '0046_create_powertests'),
]
operations = [
migrations.CreateModel(
name='EventCheckIn',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('time', models.DateTimeField()),
('role', models.CharField(blank=True, max_length=50)),
('vehicle', models.CharField(blank=True, max_length=100)),
('end_time', models.DateTimeField(blank=True, null=True)),
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='crew', to='RIGS.event')),
('person', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='checkins', to=settings.AUTH_USER_MODEL)),
],
),
migrations.RemoveField(
model_name='eventchecklistvehicle',
name='checklist',
),
migrations.RemoveField(
model_name='eventchecklistvehicle',
name='driver',
),
migrations.RemoveField(
model_name='eventchecklist',
name='all_rcds_tested',
),
migrations.RemoveField(
model_name='eventchecklist',
name='earthing',
),
migrations.RemoveField(
model_name='eventchecklist',
name='fd_earth_fault',
),
migrations.RemoveField(
model_name='eventchecklist',
name='fd_phase_rotation',
),
migrations.RemoveField(
model_name='eventchecklist',
name='fd_pssc',
),
migrations.RemoveField(
model_name='eventchecklist',
name='fd_voltage_l1',
),
migrations.RemoveField(
model_name='eventchecklist',
name='fd_voltage_l2',
),
migrations.RemoveField(
model_name='eventchecklist',
name='fd_voltage_l3',
),
migrations.RemoveField(
model_name='eventchecklist',
name='labelling',
),
migrations.RemoveField(
model_name='eventchecklist',
name='pat',
),
migrations.RemoveField(
model_name='eventchecklist',
name='power_mic',
),
migrations.RemoveField(
model_name='eventchecklist',
name='public_sockets_tested',
),
migrations.RemoveField(
model_name='eventchecklist',
name='rcds',
),
migrations.RemoveField(
model_name='eventchecklist',
name='source_rcd',
),
migrations.RemoveField(
model_name='eventchecklist',
name='supply_test',
),
migrations.RemoveField(
model_name='eventchecklist',
name='w1_description',
),
migrations.RemoveField(
model_name='eventchecklist',
name='w1_earth_fault',
),
migrations.RemoveField(
model_name='eventchecklist',
name='w1_polarity',
),
migrations.RemoveField(
model_name='eventchecklist',
name='w1_voltage',
),
migrations.RemoveField(
model_name='eventchecklist',
name='w2_description',
),
migrations.RemoveField(
model_name='eventchecklist',
name='w2_earth_fault',
),
migrations.RemoveField(
model_name='eventchecklist',
name='w2_polarity',
),
migrations.RemoveField(
model_name='eventchecklist',
name='w2_voltage',
),
migrations.RemoveField(
model_name='eventchecklist',
name='w3_description',
),
migrations.RemoveField(
model_name='eventchecklist',
name='w3_earth_fault',
),
migrations.RemoveField(
model_name='eventchecklist',
name='w3_polarity',
),
migrations.RemoveField(
model_name='eventchecklist',
name='w3_voltage',
),
migrations.AddField(
model_name='powertestrecord',
name='power_mic',
field=models.ForeignKey(blank=True, help_text='Who is the Power MIC?', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='checklists', to=settings.AUTH_USER_MODEL, verbose_name='Power MIC'),
),
migrations.AlterField(
model_name='eventchecklist',
name='reviewed_at',
field=models.DateTimeField(blank=True, null=True),
),
migrations.AlterField(
model_name='powertestrecord',
name='reviewed_at',
field=models.DateTimeField(blank=True, null=True),
),
migrations.AlterField(
model_name='riskassessment',
name='reviewed_at',
field=models.DateTimeField(blank=True, null=True),
),
migrations.DeleteModel(
name='EventChecklistCrew',
),
migrations.DeleteModel(
name='EventChecklistVehicle',
),
]

View File

@@ -81,10 +81,6 @@ class Profile(AbstractUser):
def __str__(self):
return self.name
def current_event(self):
q = EventCheckIn.objects.filter(person=self, end_time=None)
return q.latest('time') if q.exists() else None
class ContactableManager(models.Manager):
def search(self, query=None):
@@ -409,15 +405,7 @@ class Event(models.Model, RevisionMixin):
@property
def hs_done(self):
return self.riskassessment is not None and self.has_checklist and self.has_power
@property
def has_checklist(self):
return self.checklists.exists()
@property
def has_power(self):
return self.power_tests.exists()
return self.riskassessment is not None and len(self.checklists.all()) > 0
@property
def has_start_time(self):
@@ -490,15 +478,6 @@ class Event(models.Model, RevisionMixin):
else:
return bool(self.purchase_order)
@property
def can_check_in(self):
earliest = self.earliest_time
if isinstance(self.earliest_time, datetime.date):
earliest = datetime.datetime.combine(self.start_date, datetime.time(00, 00))
tz = pytz.timezone(settings.TIME_ZONE)
earliest = tz.localize(earliest)
return not self.dry_hire and earliest <= timezone.now()
objects = EventManager()
def get_absolute_url(self):
@@ -710,21 +689,8 @@ def validate_url(value):
raise ValidationError('URL must point to a location on the TEC Sharepoint')
class ReviewableModel(models.Model):
reviewed_at = models.DateTimeField(null=True, blank=True)
reviewed_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True,
verbose_name="Reviewer", on_delete=models.CASCADE)
class Meta:
abstract = True
@cached_property
def fieldz(self):
return [n.name for n in list(self._meta.get_fields()) if n.name != 'reviewed_at' and n.name != 'reviewed_by' and not n.is_relation and not n.auto_created]
@reversion.register
class RiskAssessment(ReviewableModel, RevisionMixin):
class RiskAssessment(models.Model, RevisionMixin):
SMALL = (0, 'Small')
MEDIUM = (1, 'Medium')
LARGE = (2, 'Large')
@@ -772,6 +738,10 @@ class RiskAssessment(ReviewableModel, RevisionMixin):
# Blimey that was a lot of options
reviewed_at = models.DateTimeField(null=True)
reviewed_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True,
verbose_name="Reviewer", on_delete=models.CASCADE)
supervisor_consulted = models.BooleanField(null=True)
expected_values = {
@@ -808,6 +778,10 @@ class RiskAssessment(ReviewableModel, RevisionMixin):
('review_riskassessment', 'Can review Risk Assessments')
]
@cached_property
def fieldz(self):
return [n.name for n in list(self._meta.get_fields()) if n.name != 'reviewed_at' and n.name != 'reviewed_by' and not n.is_relation and not n.auto_created]
@property
def event_size(self):
# Confirm event size. Check all except generators, since generators entails outside
@@ -821,12 +795,6 @@ class RiskAssessment(ReviewableModel, RevisionMixin):
def get_event_size_display(self):
return self.SIZES[self.event_size][1] + " Event"
def __str__(self):
return f"{self.pk} | {self.event}"
def get_absolute_url(self):
return reverse('ra_detail', kwargs={'pk': self.pk})
@property
def activity_feed_string(self):
return str(self.event)
@@ -835,12 +803,20 @@ class RiskAssessment(ReviewableModel, RevisionMixin):
def name(self):
return str(self)
def get_absolute_url(self):
return reverse('ra_detail', kwargs={'pk': self.pk})
@reversion.register
class EventChecklist(ReviewableModel, RevisionMixin):
def __str__(self):
return f"{self.pk} | {self.event}"
@reversion.register(follow=['vehicles', 'crew'])
class EventChecklist(models.Model, RevisionMixin):
event = models.ForeignKey('Event', related_name='checklists', on_delete=models.CASCADE)
# General
power_mic = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, related_name='checklists',
verbose_name="Power MIC", on_delete=models.CASCADE, help_text="Who is the Power MIC?")
venue = models.ForeignKey('Venue', on_delete=models.CASCADE)
date = models.DateField()
@@ -854,32 +830,6 @@ class EventChecklist(ReviewableModel, RevisionMixin):
hs_location = models.CharField(blank=True, default='', max_length=255, help_text="Location of Safety Bag/Box")
extinguishers_location = models.CharField(blank=True, default='', max_length=255, help_text="Location of fire extinguishers")
inverted_fields = []
class Meta:
ordering = ['event']
permissions = [
('review_eventchecklist', 'Can review Event Checklists')
]
def __str__(self):
return f"{self.pk} - {self.event}"
@property
def activity_feed_string(self):
return str(self.event)
def get_absolute_url(self):
return reverse('ec_detail', kwargs={'pk': self.pk})
@reversion.register
class PowerTestRecord(ReviewableModel, RevisionMixin):
event = models.ForeignKey('Event', related_name='power_tests', on_delete=models.CASCADE)
power_mic = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, related_name='checklists',
verbose_name="Power MIC", on_delete=models.CASCADE, help_text="Who is the Power MIC?")
venue = models.ForeignKey('Venue', on_delete=models.CASCADE)
notes = models.TextField(blank=True, default='')
# Small Electrical Checks
rcds = models.BooleanField(blank=True, null=True, help_text="RCDs installed where needed and tested?")
supply_test = models.BooleanField(blank=True, null=True, help_text="Electrical supplies tested?<br><small>(using socket tester)</small>")
@@ -915,40 +865,58 @@ class PowerTestRecord(ReviewableModel, RevisionMixin):
all_rcds_tested = models.BooleanField(blank=True, null=True, help_text="All circuit RCDs tested?<br><small>(using test button)</small>")
public_sockets_tested = models.BooleanField(blank=True, null=True, help_text="Public/Performer accessible circuits tested?<br><small>(using socket tester)</small>")
reviewed_at = models.DateTimeField(null=True)
reviewed_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True,
verbose_name="Reviewer", on_delete=models.CASCADE)
inverted_fields = []
class Meta:
ordering = ['event']
permissions = [
('review_power', 'Can review Power Test Records')
('review_eventchecklist', 'Can review Event Checklists')
]
def __str__(self):
return f"{self.pk} - {self.event}"
@cached_property
def fieldz(self):
return [n.name for n in list(self._meta.get_fields()) if n.name != 'reviewed_at' and n.name != 'reviewed_by' and not n.is_relation and not n.auto_created]
@property
def activity_feed_string(self):
return str(self.event)
class EventCheckIn(models.Model):
event = models.ForeignKey('Event', related_name='crew', on_delete=models.CASCADE)
person = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='checkins', on_delete=models.CASCADE)
time = models.DateTimeField()
role = models.CharField(max_length=50, blank=True)
vehicle = models.CharField(max_length=100, blank=True)
end_time = models.DateTimeField(null=True, blank=True)
def get_absolute_url(self):
return reverse('ec_detail', kwargs={'pk': self.pk})
def __str__(self):
return f"{self.person} on {self.event}"
return f"{self.pk} - {self.event}"
@reversion.register
class EventChecklistVehicle(models.Model, RevisionMixin):
checklist = models.ForeignKey('EventChecklist', related_name='vehicles', blank=True, on_delete=models.CASCADE)
vehicle = models.CharField(max_length=255)
driver = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='vehicles', on_delete=models.CASCADE)
reversion_hide = True
def __str__(self):
return f"{self.vehicle} driven by {self.driver}"
@reversion.register
class EventChecklistCrew(models.Model, RevisionMixin):
checklist = models.ForeignKey('EventChecklist', related_name='crew', blank=True, on_delete=models.CASCADE)
crewmember = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='crewed', on_delete=models.CASCADE)
role = models.CharField(max_length=255)
start = models.DateTimeField()
end = models.DateTimeField()
reversion_hide = True
def clean(self):
sass = " Please invent time travel and retry."
if self.time > timezone.now():
raise ValidationError("May not check in in the future." + sass)
if self.end_time and self.end_time < self.time:
raise ValidationError("May not check out before you've checked in." + sass)
if self.start > self.end:
raise ValidationError('Unless you\'ve invented time travel, crew can\'t finish before they have started.')
def get_absolute_url(self):
return reverse('event_detail', kwargs={'pk': self.event_id})
def active(self):
return end_time is not None
def __str__(self):
return f"{self.crewmember} ({self.role})"

View File

@@ -34,7 +34,16 @@
</div>
</li>
{% if perms.RIGS.view_riskassessment %}
<li class="nav-item"><a class="nav-link" href="{% url 'hs_list' %}">H&S</a></li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownHS" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
H&S
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdownHS">
<a class="dropdown-item" href="{% url 'hs_list' %}"><span class="fas fa-eye"></span> Overview</a>
<a class="dropdown-item" href="{% url 'ra_list' %}"><span class="fas fa-file-medical"></span> Risk Assessments</a>
<a class="dropdown-item" href="{% url 'ec_list' %}"><span class="fas fa-tasks"></span> Event Checklists</a>
</div>
</li>
{% endif %}
{% if perms.RIGS.view_invoice %}
<li class="nav-item dropdown">

View File

@@ -1,8 +1,6 @@
{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %}
{% load markdown_tags %}
{% load button from filters %}
{% load static %}
{% block content %}
<div class="row my-3 py-3">
@@ -54,43 +52,6 @@
</div>
</div>
</div>
{% if event.can_check_in %}
<div class="col-sm-12">
<div class="card mt-3">
<div class="card-header">Crew Record</div>
<div class="table-responsive">
<table class="table table-sm">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Vehicle</th>
<th scope="col">Start Time</th>
<th scope="col">Role</th>
<th scope="col">End Time</th>
<th scope="col">{% if request.user.pk is event.mic.pk %}<a href="{% url 'event_checkin_override' event.pk %}" class="btn btn-sm btn-success"><span class="fas fa-plus"></span> Add</a>{% endif %}</th>
</tr>
</thead>
<tbody id="crewmembers">
{% for crew in object.crew.all %}
<tr>
<td>{{crew.person}}</td>
<td>{{crew.vehicle|default:"None"}}</td>
<td>{{crew.time}}</td>
<td>{{crew.role}}</td>
<td>{% if crew.end_time %}{{crew.end_time}}{% else %}<span class="text-success fas fa-clock" data-toggle="tooltip" title="This person is currently checked into this event"></span>{% endif %}</td>
<td>{% if crew.end_time %}{% if crew.person.pk == request.user.pk or event.mic.pk == request.user.pk %}{% button 'edit' 'edit_checkin' crew.pk clazz='btn-sm modal-href' %}{% endif %}{%endif%}</td>
</tr>
{% empty %}
<tr>
<td colspan="6" class="text-center bg-warning">Apparently this event happened by magic...</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %}
</div>
{% if not request.is_ajax and perms.RIGS.view_event %}
<div class="col-sm-12 text-right">
{% include 'partials/event_detail_buttons.html' %}

View File

@@ -30,7 +30,21 @@
</a>
{% endif %}
</dd>
<dt class="col-6">{{ object|help_text:'power_mic' }}</dt>
<dd class="col-6">
{% if object.power_mic %}
<a href="{% url 'profile_detail' object.power_mic.pk %}">{{ object.power_mic.name }}</a>
{% else %}
None
{% endif %}
</dd>
</dl>
<p>List vehicles and their drivers</p>
<ul>
{% for i in object.vehicles.all %}
<li>{{i}}</li>
{% endfor %}
</ul>
</div>
</div>
</div>
@@ -68,6 +82,165 @@
</div>
</div>
</div>
<div class="card mb-3">
<div class="card-header">Crew Record</div>
<div class="table-responsive">
<table class="table table-sm">
<thead>
<tr>
<th scope="col">Crewmember</th>
<th scope="col">Start Time</th>
<th scope="col">Role</th>
<th scope="col">End Time</th>
</tr>
</thead>
<tbody id="crewmemberst">
{% for crew in object.crew.all %}
<tr>
<td>{{crew.crewmember}}</td>
<td>{{crew.start}}</td>
<td>{{crew.role}}</td>
<td>{{crew.end}}</td>
</tr>
{% empty %}
<tr>
<td colspan="4" class="text-center bg-warning">Apparently this event happened by magic...</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="card mb-3">
<div class="card-header">Power {% include 'partials/event_size.html' with object=object.event.riskassessment %}</div>
<div class="card-body">
{% if object.event.riskassessment.event_size == 0 %}
<dl class="row">
<dt class="col-10">{{ object|help_text:'rcds'|safe }}</dt>
<dd class="col-2">
{{ object.rcds|yesnoi }}
</dd>
<dt class="col-10">{{ object|help_text:'supply_test'|safe }}</dt>
<dd class="col-2">
{{ object.supply_test|yesnoi }}
</dd>
<dt class="col-10">{{ object|help_text:'earthing'|safe }}</dt>
<dd class="col-2">
{{ object.earthing|yesnoi }}
</dd>
<dt class="col-10">{{ object|help_text:'pat'|safe }}</dt>
<dd class="col-2">
{{ object.pat|yesnoi }}
</dd>
</dl>
{% else %}
<dl class="row">
<dt class="col-10">{{ object|help_text:'source_rcd'|safe }}</dt>
<dd class="col-2">
{{ object.source_rcd|yesnoi }}
</dd>
<dt class="col-10">{{ object|help_text:'labelling'|safe }}</dt>
<dd class="col-2">
{{ object.labelling|yesnoi }}
</dd>
<dt class="col-10">{{ object|help_text:'earthing'|safe }}</dt>
<dd class="col-2">
{{ object.earthing|yesnoi }}
</dd>
<dt class="col-10">{{ object|help_text:'pat'|safe }}</dt>
<dd class="col-2">
{{ object.pat|yesnoi }}
</dd>
</dl>
<hr>
<p>Tests at first distro</p>
<table class="table table-bordered">
<thead>
<tr>
<th scope="col" class="text-center">Test</th>
<th scope="col" colspan="3" class="text-center">Value</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row" rowspan="2">Voltage<br><small>(cube meter)</small></th>
<th>{{ object|help_text:'fd_voltage_l1' }}</th>
<th>{{ object|help_text:'fd_voltage_l2' }}</th>
<th>{{ object|help_text:'fd_voltage_l3' }}</th>
</tr>
<tr>
<td>{{ object.fd_voltage_l1 }}</td>
<td>{{ object.fd_voltage_l2 }}</td>
<td>{{ object.fd_voltage_l3 }}</td>
</tr>
<tr>
<th scope="row">{{ object|help_text:'fd_phase_rotation'|safe }}</th>
<td colspan="3">{{ object.fd_phase_rotation|yesnoi }}</td>
</tr>
<tr>
<th scope="row">{{ object|help_text:'fd_earth_fault'|safe}}</th>
<td colspan="3">{{ object.fd_earth_fault }}</td>
</tr>
<tr>
<th scope="row">{{ object|help_text:'fd_pssc'}}</th>
<td colspan="3">{{ object.fd_pssc }}</td>
</tr>
</tbody>
</table>
<hr>
<p>Tests at 'Worst Case' points (at least 1 point required)</p>
<table class="table table-bordered">
<thead>
<tr>
<th scope="col" class="text-center">Test</th>
<th scope="col" class="text-center">Point 1</th>
<th scope="col" class="text-center">Point 2</th>
<th scope="col" class="text-center">Point 3</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">{{ object|help_text:'w1_description'|safe}}</th>
<td>{{ object.w1_description }}</td>
<td>{{ object.w2_description|default:'' }}</td>
<td>{{ object.w3_description|default:'' }}</td>
</tr>
<tr>
<th scope="row">{{ object|help_text:'w1_polarity'|safe}}</th>
<td>{{ object.w1_polarity|yesnoi }}</td>
<td>{{ object.w2_polarity|default:''|yesnoi }}</td>
<td>{{ object.w3_polarity|default:''|yesnoi }}</td>
</tr>
<tr>
<th scope="row">{{ object|help_text:'w1_voltage'|safe}}</th>
<td>{{ object.w1_voltage }}</td>
<td>{{ object.w2_voltage|default:'' }}</td>
<td>{{ object.w3_voltage|default:'' }}</td>
</tr>
<tr>
<th scope="row">{{ object|help_text:'w1_earth_fault'|safe}}</th>
<td>{{ object.w1_earth_fault }}</td>
<td>{{ object.w2_earth_fault|default:'' }}</td>
<td>{{ object.w3_earth_fault|default:'' }}</td>
</tr>
</tbody>
</table>
<hr>
<dl class="row">
<dt class="col-10">{{ object|help_text:'all_rcds_tested'|safe }}</dt>
<dd class="col-2">
{{ object.all_rcds_tested|yesnoi }}
</dd>
<dt class="col-10">{{ object|help_text:'public_sockets_tested'|safe }}</dt>
<dd class="col-2">
{{ object.public_sockets_tested|yesnoi }}
</dd>
</dl>
<hr>
{% include 'partials/ec_power_info.html' %}
{% endif %}
</div>
</div>
<div class="col-12 text-right">
{% button 'edit' url='ec_edit' pk=object.pk %}
{% button 'view' url='event_detail' pk=object.pk text="Event" %}

View File

@@ -13,19 +13,57 @@
{% block preload_js %}
{{ block.super }}
<script src="{% static 'js/selects.js' %}"></script>
<script src="{% static 'js/interaction.js' %}"></script>
{% endblock %}
{% block js %}
{{ block.super }}
<script src="{% static 'js/autocompleter.js' %}"></script>
<script src="{% static 'js/tooltip.js' %}"></script>
<script>
$(document).ready(function () {
$('button[data-action=add]').on('click', function (event) {
event.preventDefault();
let target = $($(this).attr('data-target'));
let newID = Number(target.attr('data-pk'));
let newRow = $($(this).attr('data-clone'))
.clone().attr('style', "")
.attr('id', function(i, val){
return val.split("_")[0] + '_' + newID;
})
.appendTo(target);
newRow.find('select,input').attr('name', function(i, val){
return val.split("_")[0] + '_' + newID;
})//Disabled is to prevent the hidden row being sent to the form
.removeAttr('disabled');
newRow.find('button[data-action=delete]').attr('data-id', newID);
newRow.find('select').addClass('selectpicker');
newRow.find('.selectpicker').selectpicker('refresh');
$(".selectpicker").each(function(){initPicker($(this))});
initDatetime();
$(target).attr('data-pk', newID - 1);
});
$(document).on('click', 'button[data-action=delete]', function(event) {
event.preventDefault();
$(this).closest('tr').remove();
});
//Somewhat rudimentary way of ensuring people fill in completely (if it hits the database validation the whole table row disappears when the page reloads...)
//the not is to avoid adding it to some of bootstrap-selects extra crap
$('#vehiclest,#crewmemberst').on('change', 'select,input', function () {
$(this).closest('tr').find("select,input").not(':input[type=search]').attr('required', 'true');
});
});
</script>
{% endblock %}
{% block content %}
<div class="col-12">
{% include 'form_errors.html' %}
<form role="form" method="POST" action="{% if edit %}{% url 'ec_edit' pk=object.pk %}{% else %}{% url 'event_ec' pk=event.pk %}{% endif %}">
{% if edit %}
<form role="form" method="POST" action="{% url 'ec_edit' pk=object.pk %}">
{% else %}
<form role="form" method="POST" action="{% url 'event_ec' pk=event.pk %}">
{% endif %}
<input type="hidden" name="{{ form.event.name }}" id="{{ form.event.id_for_label }}"
value="{{event.pk}}"/>
{% csrf_token %}
@@ -56,7 +94,7 @@
<div class="form-group form-row" id="{{ form.venue.id_for_label }}-group">
<label for="{{ form.venue.id_for_label }}"
class="col-4 col-form-label">{{ form.venue.label }}</label>
<select id="{{ form.venue.id_for_label }}" name="{{ form.venue.name }}" class="selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='venue' %}">
<select id="{{ form.venue.id_for_label }}" name="{{ form.venue.name }}" class="form-control selectpicker col-8" data-live-search="true" data-sourceurl="{% url 'api_secure' model='venue' %}">
{% if venue %}
<option value="{{venue.pk}}" selected="selected">{{ venue.name }}</option>
{% elif event.venue %}
@@ -64,6 +102,52 @@
{% endif %}
</select>
</div>
<div class="form-group form-row" id="{{ form.power_mic.id_for_label }}-group">
<label for="{{ form.power_mic.id_for_label }}"
class="col-4 col-form-label">{{ form.power_mic.help_text }}</label>
<select id="{{ form.power_mic.id_for_label }}" name="{{ form.power_mic.name }}" class="form-control selectpicker col-8" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials" required="true">
{% if power_mic %}
<option value="{{power_mic.pk}}" selected="selected">{{ power_mic.name }}</option>
{% elif event.riskassessment.power_mic %}
<option value="{{event.riskassessment.power_mic.pk}}" selected="selected">{{ event.riskassessment.power_mic.name }}</option>
{% endif %}
</select>
</div>
<p class="pt-3 font-weight-bold">List vehicles and their drivers</p>
<div class="table-responsive">
<table class="table table-sm">
<thead>
<tr>
<th scope="col">Vehicle</th>
<th scope="col">Driver</th>
<th scope="col"></th>
</tr>
</thead>
<tbody id="vehiclest" data-pk="-1">
<tr id="vehicles_new" style="display: none;">
<td><input type="text" class="form-control" name="vehicle_new" disabled="true"/></td>
<td><select data-container="body" class="form-control" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials" name="driver_new" disabled="true"></select></td>
<td><button type="button" class="btn btn-danger btn-sm mt-1" data-action='delete' data-target='#vehicle'><span class="fas fa-times"></span></button></td>
</tr>
{% for i in object.vehicles.all %}
<tr id="vehicles_{{i.pk}}">
<td><input name="vehicle_{{i.pk}}" type="text" class="form-control" value="{{ i.vehicle }}"/></td>
<td>
<select data-container="body" name="driver_{{i.pk}}" class="form-control selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials">
{% if i.driver != '' %}
<option value="{{i.driver.pk}}" selected="selected">{{ i.driver.name }}</option>
{% endif %}
</select>
</td>
<td><button type="button" class="btn btn-danger btn-sm mt-1" data-id='{{i.pk}}' data-action='delete' data-target='#vehicle'><span class="fas fa-times"></span></button></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="text-right">
<button type="button" class="btn btn-secondary" id="vehicle-add" data-action='add' data-target='#vehiclest' data-clone='#vehicles_new'><span class="fas fa-plus"></span> Add Vehicle</button>
</div>
</div>
</div>
</div>
@@ -91,6 +175,176 @@
</div>
</div>
</div>
<div class="row my-3">
<div class="col-12">
<div class="card">
<div class="card-header">Crew Record</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-sm">
<thead>
<tr>
<th scope="col">Person</th>
<th scope="col">Start Time</th>
<th scope="col">Role</th>
<th scope="col">End Time</th>
<th scope="col"></th>
</tr>
</thead>
<tbody id="crewmemberst" data-pk="-1">
<tr id="crew_new" style="display: none;">
<td>
<select name="crewmember_new" class="form-control" data-container="body" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials" disabled="true"></select>
</td>
<td style="min-width: 15ch"><input name="start_new" type="datetime-local" class="form-control" value="{{ i.start }}" disabled=""/></td>
<td style="min-width: 15ch"><input name="role_new" type="text" class="form-control" value="{{ i.role }}" disabled="true"/></td>
<td style="min-width: 15ch"><input name="end_new" type="datetime-local" class="form-control" value="{{ i.end }}" disabled="true" /></td>
<td><button type="button" class="btn btn-danger btn-sm mt-1" data-id='{{crew.pk}}' data-action='delete' data-target='#crewmember'><span class="fas fa-times"></span></button></td>
</tr>
{% for crew in object.crew.all %}
<tr id="crew_{{crew.pk}}">
<td>
<select data-container="body" name="crewmember_{{crew.pk}}" class="form-control selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials">
{% if crew.crewmember != '' %}
<option value="{{crew.crewmember.pk}}" selected="selected">{{ crew.crewmember.name }}</option>
{% endif %}
</select>
</td>
<td><input name="start_{{crew.pk}}" type="datetime-local" class="form-control" value="{{ crew.start|date:'Y-m-d' }}T{{ crew.start|date:'H:i:s' }}"/></td>
<td><input name="role_{{crew.pk}}" type="text" class="form-control" value="{{ crew.role }}"/></td>
<td><input name="end_{{crew.pk}}" type="datetime-local" class="form-control" value="{{ crew.end|date:'Y-m-d' }}T{{ crew.end|date:'H:i:s' }}"/></td>
<td><button type="button" class="btn btn-danger btn-sm mt-1" data-id='{{crew.pk}}' data-action='delete' data-target='#crewmember'><span class="fas fa-times"></span></button></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="card-footer">
<div class="text-right">
<button type="button" class="btn btn-secondary" data-action='add' data-target='#crewmemberst' data-clone='#crew_new'><span class="fas fa-plus"></span> Add Crewmember</button>
</div>
</div>
</div>
</div>
</div>
{% if event.riskassessment.event_size == 0 %}
<div class="row my-3" id="size-0">
<div class="col-12">
<div class="card border-success">
<div class="card-header">Electrical Checks <small>for Small TEC Events <6kVA (approx. 26A)</small></div>
<div class="card-body">
{% include 'partials/checklist_checkbox.html' with formitem=form.rcds %}
{% include 'partials/checklist_checkbox.html' with formitem=form.supply_test %}
{% include 'partials/checklist_checkbox.html' with formitem=form.earthing %}
{% include 'partials/checklist_checkbox.html' with formitem=form.pat %}
</div>
</div>
</div>
</div>
{% else %}
<div class="row my-3" id="size-1">
<div class="col-12">
{% if event.riskassessment.event_size == 1 %}
<div class="card border-warning">
<div class="card-header">Electrical Checks <small>for Medium TEC Events </small></div>
<div class="card-body">
{% else %}
<div class="card border-danger">
<div class="card-header">Electrical Checks <small>for Large TEC Events</small></div>
<div class="card-body">
<div class="alert alert-danger"><strong>Here be dragons. Ensure you have appeased the Power Gods before continuing... (If you didn't check with a Supervisor, <em>you cannot continue your event!</em>)</strong></div>
{% endif %}
{% include 'partials/checklist_checkbox.html' with formitem=form.source_rcd %}
{% include 'partials/checklist_checkbox.html' with formitem=form.labelling %}
{% include 'partials/checklist_checkbox.html' with formitem=form.earthing %}
{% include 'partials/checklist_checkbox.html' with formitem=form.pat %}
<hr>
<p>Tests at first distro</p>
<div class="table-responsive">
<table class="table table-bordered table-sm">
<thead>
<tr>
<th scope="col" class="text-center">Test</th>
<th scope="col" colspan="3" class="text-center">Value</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row" rowspan="2">Voltage<br><small>(cube meter)</small></th>
<th class="text-center">{{ form.fd_voltage_l1.help_text }}</th>
<th class="text-center">{{ form.fd_voltage_l2.help_text }}</th>
<th class="text-center">{{ form.fd_voltage_l3.help_text }}</th>
</tr>
<tr>
<td>{% render_field form.fd_voltage_l1 class+="form-control" style="min-width: 5rem;" %}</td>
<td>{% render_field form.fd_voltage_l2 class+="form-control" style="min-width: 5rem;" %}</td>
<td>{% render_field form.fd_voltage_l3 class+="form-control" style="min-width: 5rem;" %}</td>
</tr>
<tr>
<th scope="row">{{form.fd_phase_rotation.help_text|safe}}</th>
<td colspan="3">{% include 'partials/checklist_checkbox.html' with formitem=form.fd_phase_rotation %}</td>
</tr>
<tr>
<th scope="row">{{form.fd_earth_fault.help_text|safe}}</th>
<td colspan="3">{% render_field form.fd_earth_fault class+="form-control" %}</td>
</tr>
<tr>
<th scope="row">{{form.fd_pssc.help_text|safe}}</th>
<td colspan="3">{% render_field form.fd_pssc class+="form-control" %}</td>
</tr>
</tbody>
</table>
</div>
<hr>
<p>Tests at 'Worst Case' points (at least 1 point required)</p>
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th scope="col" class="text-center">Test</th>
<th scope="col" class="text-center">Point 1</th>
<th scope="col" class="text-center">Point 2</th>
<th scope="col" class="text-center">Point 3</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">{{form.w1_description.help_text|safe}}</th>
<td>{% render_field form.w1_description class+="form-control" style="min-width: 5rem;" %}</td>
<td>{% render_field form.w2_description class+="form-control" style="min-width: 5rem;" %}</td>
<td>{% render_field form.w3_description class+="form-control" style="min-width: 5rem;" %}</td>
</tr>
<tr>
<th scope="row">{{form.w1_polarity.help_text|safe}}</th>
<td>{% render_field form.w1_polarity %}</td>
<td>{% render_field form.w2_polarity %}</td>
<td>{% render_field form.w3_polarity %}</td>
</tr>
<tr>
<th scope="row">{{form.w1_voltage.help_text|safe}}</th>
<td>{% render_field form.w1_voltage class+="form-control" %}</td>
<td>{% render_field form.w2_voltage class+="form-control" %}</td>
<td>{% render_field form.w3_voltage class+="form-control" %}</td>
</tr>
<tr>
<th scope="row">{{form.w1_earth_fault.help_text|safe}}</th>
<td>{% render_field form.w1_earth_fault class+="form-control" %}</td>
<td>{% render_field form.w2_earth_fault class+="form-control" %}</td>
<td>{% render_field form.w3_earth_fault class+="form-control" %}</td>
</tr>
</tbody>
</table>
</div>
<hr/>
{% include 'partials/checklist_checkbox.html' with formitem=form.all_rcds_tested %}
{% include 'partials/checklist_checkbox.html' with formitem=form.public_sockets_tested %}
{% include 'partials/ec_power_info.html' %}
</div>
</div>
</div>
</div>
{% endif %}
<div class="row mt-3">
<div class="col-sm-12 text-right">
{% button 'submit' %}

View File

@@ -1,105 +0,0 @@
{% extends request.is_ajax|yesno:'base_ajax.html,base_rigs.html' %}
{% load widget_tweaks %}
{% load static %}
{% load button from filters %}
{% block css %}
{{ block.super }}
<link rel="stylesheet" type="text/css" href="{% static 'css/selects.css' %}"/>
<link rel="stylesheet" type="text/css" href="{% static 'css/easymde.min.css' %}">
{% endblock %}
{% block preload_js %}
{{ block.super }}
<script src="{% static 'js/selects.js' %}"></script>
<script src="{% static 'js/easymde.min.js' %}"></script>
{% endblock %}
{% block js %}
{{ block.super }}
<script src="{% static 'js/autocompleter.js' %}"></script>
<script src="{% static 'js/interaction.js' %}"></script>
<script src="{% static 'js/tooltip.js' %}"></script>
{% endblock %}
{% block content %}
<div class="col-12">
{% include 'form_errors.html' %}
<form id="checkin" role="form" method="POST" action="{{ form.action|default:request.path }}">
<input type="hidden" name="{{ form.event.name }}" id="{{ form.event.id_for_label }}"
value="{{event.pk}}"/>
{% if not request.is_ajax and self.request.user.pk is form.event.mic.pk %}
<div class="form-group">
<label for="{{ form.person.id_for_label }}"
class="col-sm-4 col-form-label">{{ form.person.label }}</label>
<div class="col-sm-8">
<select id="{{ form.person.id_for_label }}" name="{{ form.person.name }}" class="px-0 selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials">
{% if person %}
<option value="{{form.person.value}}" selected="selected" >{{ person.name }}</option>
{% endif %}
</select>
</div>
</div>
{% else %}
<input type="hidden" name="{{ form.person.name }}" id="{{ form.person.id_for_label }}"
value="{{request.user.pk}}"/>
{% endif %}
{% csrf_token %}
<div class="form-group">
<label for="{{ form.time.id_for_label }}"
class="col-sm-4 col-form-label">Start Time</label>
<div class="col-sm-8">
{% render_field form.time class+="form-control" %}
</div>
</div>
<div class="form-group">
<label for="{{ form.role.id_for_label }}" class="col col-form-label">Role</label>
<div class="row pl-3">
<div class="col-md-6 col-sm-12">
<button type="button" class="btn btn-primary" onclick="document.getElementById('id_role').value='MIC'">MIC</button>
<button type="button" class="btn btn-danger" onclick="document.getElementById('id_role').value='Power MIC'">Power MIC</button>
<button type="button" class="btn btn-info" onclick="document.getElementById('id_role').value='Crew'">Crew</button>
</div>
<div class="col-md-6 mt-2">
{% render_field form.role class+="form-control" placeholder="Other (enter text)" %}
</div>
</div>
</div>
<div class="form-group">
<label for="{{ form.vehicle.id_for_label }}" class="col col-form-label">Vehicle (if applicable)</label>
<div class="row pl-3">
<div class="col-md-6 col-sm-12">
<button type="button" class="btn btn-primary" onclick="document.getElementById('id_vehicle').value='Virgil'"><span class="fas fa-truck-moving"></span> Virgil</button>
<button type="button" class="btn btn-secondary" onclick="document.getElementById('id_vehicle').value='Virgil + Erms'"><span class="fas fa-trailer"></span><span class="fas fa-truck-moving"></span> Virgil + Erms</button>
</div>
<div class="col-md-6 mt-2">
{% render_field form.vehicle class+="form-control" placeholder="Other (enter text)" %}
</div>
</div>
</div>
{% if edit or manual %}
<div class="form-group">
<label for="{{ form.end_time.id_for_label }}"
class="col-sm-4 col-form-label">End Time</label>
<div class="col-sm-8">
{% render_field form.end_time class+="form-control" %}
</div>
</div>
{% endif %}
{% if not request.is_ajax %}
<div class="row mt-3">
<div class="col-sm-12 text-right">
{% button 'submit' %}
</div>
</div>
{% endif %}
</form>
</div>
{% endblock %}
{% block footer %}
<div class="col-sm-12 text-right pr-0">
<button type="submit" class="btn btn-primary" title="Save" form="checkin"
><span class="fas fa-save align-middle"></span> <span class="d-none d-sm-inline align-middle">Save</span></button>
</div>
{% endblock %}

View File

@@ -12,7 +12,6 @@
<th scope="col">Dates</th>
<th scope="col">RA</th>
<th scope="col">Checklists</th>
<th scope="col">Power Records</th>
</tr>
</thead>
<tbody>
@@ -36,14 +35,6 @@
<a href="{% url 'event_ec' event.pk %}" class="btn btn-info"><span class="fas fa-paperclip"></span> <span
class="d-none d-sm-inline">Create</span></a>
</td>
<td>
{% for record in event.power_tests.all %}
{% include 'partials/hs_status.html' with event=event object=record view='pt_detail' edit='pt_edit' create='event_pt' review='pt_review' perm=perms.RIGS.review_power %}
<br/>
{% endfor %}
<a href="{% url 'event_pt' event.pk %}" class="btn btn-info"><span class="fas fa-paperclip"></span> <span
class="hidden-xs">Create</span></a>
</td>
</tr>
{% empty %}
<tr class="bg-warning text-dark">

View File

@@ -0,0 +1,59 @@
{% extends 'base_rigs.html' %}
{% load paginator from filters %}
{% load help_text from filters %}
{% load verbose_name from filters %}
{% load get_field from filters %}
{% block title %}{{ title }} List{% endblock %}
{% block content %}
<div class="row">
<div class="col-12">
<h2>{{title}} List</h2>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="table-responsive">
<table class="table mb-0 table-sm">
<thead>
<tr>
<th scope="col">Event</th>
{# mmm hax #}
{% if object_list.0 != None %}
{% for field in object_list.0.fieldz %}
<th scope="col">{{ object_list.0|verbose_name:field|title }}</th>
{% endfor %}
{% endif %}
<th scope="col"></th>
</tr>
</thead>
<tbody>
{% for object in object_list %}
<tr class="{% if object.reviewed_by %}table-success{%endif%}">
{# General #}
<th scope="row"><a href="{% url 'event_detail' object.event.pk %}">{{ object.event }}</a><br><small>{{ object.event.get_status_display }}</small></th>
{% for field in object_list.0.fieldz %}
<td>{{ object|get_field:field }}</td>
{% endfor %}
{# Buttons #}
<td>
{% include 'partials/hs_status.html' %}
</td>
</tr>
{% empty %}
<tr class="bg-warning">
<td colspan="6">Nothing found</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% if is_paginated %}
<div class="row justify-content-center">
{% paginator %}
</div>
{% endif %}
{% endblock %}

View File

@@ -1,175 +0,0 @@
{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %}
{% load help_text from filters %}
{% load profile_by_index from filters %}
{% load yesnoi from filters %}
{% load button from filters %}
{% block content %}
<div class="row">
<div class="col-12 text-right my-3">
{% button 'edit' url='pt_edit' pk=object.pk %}
{% button 'view' url='event_detail' pk=object.event.pk text="Event" %}
{% include 'partials/review_status.html' with perm=perms.RIGS.review_power review='pt_review' %}
</div>
</div>
<div class="card mb-3">
<div class="card-header">{% include 'partials/event_size.html' with object=object.event.riskassessment %}</div>
<div class="card-body">
<dl class="row">
<dt class="col-6">{{ object|help_text:'power_mic' }}</dt>
<dd class="col-6">
{% if object.power_mic %}
<a href="{% url 'profile_detail' object.power_mic.pk %}">{{ object.power_mic.name }}</a>
{% else %}
None
{% endif %}
</dd>
<dt class="col-6">Venue</dt>
<dd class="col-6">
{% if object.venue %}
<a href="{% url 'venue_detail' object.venue.pk %}" class="modal-href">
{{ object.venue }}
</a>
{% endif %}
</dd>
<dt class="col-6">Notes</dt>
<dd class="col-6">
{{ object.notes }}
</dd>
</dl>
{% if object.event.riskassessment.event_size == 0 %}
<dl class="row">
<dt class="col-10">{{ object|help_text:'rcds'|safe }}</dt>
<dd class="col-2">
{{ object.rcds|yesnoi }}
</dd>
<dt class="col-10">{{ object|help_text:'supply_test'|safe }}</dt>
<dd class="col-2">
{{ object.supply_test|yesnoi }}
</dd>
<dt class="col-10">{{ object|help_text:'earthing'|safe }}</dt>
<dd class="col-2">
{{ object.earthing|yesnoi }}
</dd>
<dt class="col-10">{{ object|help_text:'pat'|safe }}</dt>
<dd class="col-2">
{{ object.pat|yesnoi }}
</dd>
</dl>
{% else %}
<dl class="row">
<dt class="col-10">{{ object|help_text:'source_rcd'|safe }}</dt>
<dd class="col-2">
{{ object.source_rcd|yesnoi }}
</dd>
<dt class="col-10">{{ object|help_text:'labelling'|safe }}</dt>
<dd class="col-2">
{{ object.labelling|yesnoi }}
</dd>
<dt class="col-10">{{ object|help_text:'earthing'|safe }}</dt>
<dd class="col-2">
{{ object.earthing|yesnoi }}
</dd>
<dt class="col-10">{{ object|help_text:'pat'|safe }}</dt>
<dd class="col-2">
{{ object.pat|yesnoi }}
</dd>
</dl>
<hr>
<p>Tests at first distro</p>
<table class="table table-bordered">
<thead>
<tr>
<th scope="col" class="text-center">Test</th>
<th scope="col" colspan="3" class="text-center">Value</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row" rowspan="2">Voltage<br><small>(cube meter)</small></th>
<th>{{ object|help_text:'fd_voltage_l1' }}</th>
<th>{{ object|help_text:'fd_voltage_l2' }}</th>
<th>{{ object|help_text:'fd_voltage_l3' }}</th>
</tr>
<tr>
<td>{{ object.fd_voltage_l1 }}</td>
<td>{{ object.fd_voltage_l2 }}</td>
<td>{{ object.fd_voltage_l3 }}</td>
</tr>
<tr>
<th scope="row">{{ object|help_text:'fd_phase_rotation'|safe }}</th>
<td colspan="3">{{ object.fd_phase_rotation|yesnoi }}</td>
</tr>
<tr>
<th scope="row">{{ object|help_text:'fd_earth_fault'|safe}}</th>
<td colspan="3">{{ object.fd_earth_fault }}</td>
</tr>
<tr>
<th scope="row">{{ object|help_text:'fd_pssc'}}</th>
<td colspan="3">{{ object.fd_pssc }}</td>
</tr>
</tbody>
</table>
<hr>
<p>Tests at 'Worst Case' points (at least 1 point required)</p>
<table class="table table-bordered">
<thead>
<tr>
<th scope="col" class="text-center">Test</th>
<th scope="col" class="text-center">Point 1</th>
<th scope="col" class="text-center">Point 2</th>
<th scope="col" class="text-center">Point 3</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">{{ object|help_text:'w1_description'|safe}}</th>
<td>{{ object.w1_description }}</td>
<td>{{ object.w2_description|default:'' }}</td>
<td>{{ object.w3_description|default:'' }}</td>
</tr>
<tr>
<th scope="row">{{ object|help_text:'w1_polarity'|safe}}</th>
<td>{{ object.w1_polarity|yesnoi }}</td>
<td>{{ object.w2_polarity|default:''|yesnoi }}</td>
<td>{{ object.w3_polarity|default:''|yesnoi }}</td>
</tr>
<tr>
<th scope="row">{{ object|help_text:'w1_voltage'|safe}}</th>
<td>{{ object.w1_voltage }}</td>
<td>{{ object.w2_voltage|default:'' }}</td>
<td>{{ object.w3_voltage|default:'' }}</td>
</tr>
<tr>
<th scope="row">{{ object|help_text:'w1_earth_fault'|safe}}</th>
<td>{{ object.w1_earth_fault }}</td>
<td>{{ object.w2_earth_fault|default:'' }}</td>
<td>{{ object.w3_earth_fault|default:'' }}</td>
</tr>
</tbody>
</table>
<hr>
<dl class="row">
<dt class="col-10">{{ object|help_text:'all_rcds_tested'|safe }}</dt>
<dd class="col-2">
{{ object.all_rcds_tested|yesnoi }}
</dd>
<dt class="col-10">{{ object|help_text:'public_sockets_tested'|safe }}</dt>
<dd class="col-2">
{{ object.public_sockets_tested|yesnoi }}
</dd>
</dl>
<hr>
{% include 'partials/ec_power_info.html' %}
{% endif %}
</div>
</div>
<div class="col-12 text-right">
{% button 'edit' url='ec_edit' pk=object.pk %}
{% button 'view' url='event_detail' pk=object.pk text="Event" %}
{% include 'partials/review_status.html' with perm=perms.RIGS.review_eventchecklist review='ec_review' %}
</div>
<div class="col-12 text-right">
{% include 'partials/last_edited.html' with target="eventchecklist_history" %}
</div>
{% endblock %}

View File

@@ -1,203 +0,0 @@
{% extends request.is_ajax|yesno:'base_ajax.html,base_rigs.html' %}
{% load widget_tweaks %}
{% load static %}
{% load help_text from filters %}
{% load profile_by_index from filters %}
{% load button from filters %}
{% block css %}
{{ block.super }}
<link rel="stylesheet" href="{% static 'css/selects.css' %}"/>
{% endblock %}
{% block preload_js %}
{{ block.super }}
<script src="{% static 'js/selects.js' %}"></script>
{% endblock %}
{% block js %}
{{ block.super }}
<script src="{% static 'js/autocompleter.js' %}"></script>
<script src="{% static 'js/tooltip.js' %}"></script>
{% endblock %}
{% block content %}
<div class="col-12">
{% include 'form_errors.html' %}
{% if edit %}
<form role="form" method="POST" action="{% url 'pt_edit' pk=object.pk %}">
{% else %}
<form role="form" method="POST" action="{% url 'event_pt' pk=event.pk %}">
{% endif %}
<input type="hidden" name="{{ form.event.name }}" id="{{ form.event.id_for_label }}"
value="{{event.pk}}"/>
{% csrf_token %}
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">Event Information</div>
<div class="card-body">
<dl class="row">
<dt class="col-4">Event Date</dt>
<dd class="col-8">{{ event.start_date}}{%if event.end_date %}-{{ event.end_date}}{%endif%}</dd>
<dt class="col-4">Event Name</dt>
<dd class="col-8">{{ event.name }}</dd>
<dt class="col-4">Client</dt>
<dd class="col-8">{{ event.person }}</dd>
<dt class="col-4">Event Size</dt>
<dd class="col-8">{% include 'partials/event_size.html' with object=event.riskassessment %}</dd>
</dl>
<hr>
<div class="form-group form-row" id="{{ form.power_mic.id_for_label }}-group">
<label for="{{ form.power_mic.id_for_label }}"
class="col-4 col-form-label">{{ form.power_mic.help_text }}</label>
<select id="{{ form.power_mic.id_for_label }}" name="{{ form.power_mic.name }}" class="form-control selectpicker col-8" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials" required="true">
{% if power_mic %}
<option value="{{power_mic.pk}}" selected="selected">{{ power_mic.name }}</option>
{% elif event.riskassessment.power_mic %}
<option value="{{event.riskassessment.power_mic.pk}}" selected="selected">{{ event.riskassessment.power_mic.name }}</option>
{% endif %}
</select>
</div>
<div class="form-group form-row" id="{{ form.venue.id_for_label }}-group">
<label for="{{ form.venue.id_for_label }}"
class="col-4 col-form-label">{{ form.venue.label }}</label>
<select id="{{ form.venue.id_for_label }}" name="{{ form.venue.name }}" class="form-control selectpicker col-8" data-live-search="true" data-sourceurl="{% url 'api_secure' model='venue' %}">
{% if venue %}
<option value="{{venue.pk}}" selected="selected">{{ venue.name }}</option>
{% elif event.venue %}
<option value="{{event.venue.pk}}" selected="selected">{{ event.venue.name }}</option>
{% endif %}
</select>
</div>
<label for="{{ form.notes.id_for_label }}">Notes</label>
{% render_field form.notes class+="form-control" %}
</div>
</div>
</div>
</div>
{% if event.riskassessment.event_size == 0 %}
<div class="row my-3" id="size-0">
<div class="col-12">
<div class="card border-success">
<div class="card-header">Electrical Checks <small>for Small TEC Events <6kVA (approx. 26A)</small></div>
<div class="card-body">
{% include 'partials/checklist_checkbox.html' with formitem=form.rcds %}
{% include 'partials/checklist_checkbox.html' with formitem=form.supply_test %}
{% include 'partials/checklist_checkbox.html' with formitem=form.earthing %}
{% include 'partials/checklist_checkbox.html' with formitem=form.pat %}
</div>
</div>
</div>
</div>
{% else %}
<div class="row my-3" id="size-1">
<div class="col-12">
{% if event.riskassessment.event_size == 1 %}
<div class="card border-warning">
<div class="card-header">Electrical Checks <small>for Medium TEC Events </small></div>
<div class="card-body">
{% else %}
<div class="card border-danger">
<div class="card-header">Electrical Checks <small>for Large TEC Events</small></div>
<div class="card-body">
<div class="alert alert-danger"><strong>Here be dragons. Ensure you have appeased the Power Gods before continuing... (If you didn't check with a Supervisor, <em>you cannot continue your event!</em>)</strong></div>
{% endif %}
{% include 'partials/checklist_checkbox.html' with formitem=form.source_rcd %}
{% include 'partials/checklist_checkbox.html' with formitem=form.labelling %}
{% include 'partials/checklist_checkbox.html' with formitem=form.earthing %}
{% include 'partials/checklist_checkbox.html' with formitem=form.pat %}
<hr>
<p>Tests at first distro</p>
<div class="table-responsive">
<table class="table table-bordered table-sm">
<thead>
<tr>
<th scope="col" class="text-center">Test</th>
<th scope="col" colspan="3" class="text-center">Value</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row" rowspan="2">Voltage<br><small>(cube meter)</small></th>
<th class="text-center">{{ form.fd_voltage_l1.help_text }}</th>
<th class="text-center">{{ form.fd_voltage_l2.help_text }}</th>
<th class="text-center">{{ form.fd_voltage_l3.help_text }}</th>
</tr>
<tr>
<td>{% render_field form.fd_voltage_l1 class+="form-control" style="min-width: 5rem;" %}</td>
<td>{% render_field form.fd_voltage_l2 class+="form-control" style="min-width: 5rem;" %}</td>
<td>{% render_field form.fd_voltage_l3 class+="form-control" style="min-width: 5rem;" %}</td>
</tr>
<tr>
<th scope="row">{{form.fd_phase_rotation.help_text|safe}}</th>
<td colspan="3">{% include 'partials/checklist_checkbox.html' with formitem=form.fd_phase_rotation %}</td>
</tr>
<tr>
<th scope="row">{{form.fd_earth_fault.help_text|safe}}</th>
<td colspan="3">{% render_field form.fd_earth_fault class+="form-control" %}</td>
</tr>
<tr>
<th scope="row">{{form.fd_pssc.help_text|safe}}</th>
<td colspan="3">{% render_field form.fd_pssc class+="form-control" %}</td>
</tr>
</tbody>
</table>
</div>
<hr>
<p>Tests at 'Worst Case' points (at least 1 point required)</p>
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th scope="col" class="text-center">Test</th>
<th scope="col" class="text-center">Point 1</th>
<th scope="col" class="text-center">Point 2</th>
<th scope="col" class="text-center">Point 3</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">{{form.w1_description.help_text|safe}}</th>
<td>{% render_field form.w1_description class+="form-control" style="min-width: 5rem;" %}</td>
<td>{% render_field form.w2_description class+="form-control" style="min-width: 5rem;" %}</td>
<td>{% render_field form.w3_description class+="form-control" style="min-width: 5rem;" %}</td>
</tr>
<tr>
<th scope="row">{{form.w1_polarity.help_text|safe}}</th>
<td>{% render_field form.w1_polarity %}</td>
<td>{% render_field form.w2_polarity %}</td>
<td>{% render_field form.w3_polarity %}</td>
</tr>
<tr>
<th scope="row">{{form.w1_voltage.help_text|safe}}</th>
<td>{% render_field form.w1_voltage class+="form-control" %}</td>
<td>{% render_field form.w2_voltage class+="form-control" %}</td>
<td>{% render_field form.w3_voltage class+="form-control" %}</td>
</tr>
<tr>
<th scope="row">{{form.w1_earth_fault.help_text|safe}}</th>
<td>{% render_field form.w1_earth_fault class+="form-control" %}</td>
<td>{% render_field form.w2_earth_fault class+="form-control" %}</td>
<td>{% render_field form.w3_earth_fault class+="form-control" %}</td>
</tr>
</tbody>
</table>
</div>
<hr/>
{% include 'partials/checklist_checkbox.html' with formitem=form.all_rcds_tested %}
{% include 'partials/checklist_checkbox.html' with formitem=form.public_sockets_tested %}
{% include 'partials/ec_power_info.html' %}
</div>
</div>
</div>
</div>
{% endif %}
<div class="row mt-3">
<div class="col-sm-12 text-right">
{% button 'submit' %}
</div>
</div>
</form>
</div>
{% endblock %}

View File

@@ -47,6 +47,6 @@
</tr>
</tbody>
</table>
<p><strong>Voltage Drop on Circuit:</strong> &#8804;5% (approx. 12v)</p>
<p><strong>Voltage Drop on Circuit:</strong> 5% (approx. 12v)</p>
</div>
</div>

View File

@@ -49,13 +49,5 @@
{% endif %}
<a href="https://docs.google.com/forms/d/e/1FAIpQLSf-TBOuJZCTYc2L8DWdAaC3_Werq0ulsUs8-6G85I6pA9WVsg/viewform" class="btn btn-danger"><span class="fas fa-file-invoice-dollar"></span> <span class="d-none d-sm-inline">Subhire Insurance Form</span></a>
{% if event.can_check_in %}
{% if request.user.current_event %}
<a href="{% url 'event_checkout' %}" class="btn btn-warning">Check Out</a>
{% else %}
<a href="{% url 'event_checkin' event.pk %}" class="btn btn-success modal-href"><span class="fas fa-user-clock"></span> <span class="d-none d-sm-inline">Check In</span></a>
{% endif %}
{% endif %}
{% endif %}
</div>

View File

@@ -15,21 +15,19 @@
{% endif %}
{% endif %}
{% if not event.dry_hire %}
{% if event.has_checklist %}
{% if event.riskassessment %}
<a href="{{ event.riskassessment.get_absolute_url }}"><span class="badge badge-success">RA: <span class="fas fa-check{% if event.riskassessment.reviewed_by %}-double{%endif%}"></span></a>
{% else %}
<span class="badge badge-danger">RA: <span class="fas fa-times"></span></span>
{% endif %}
{% if event.has_checklist %}
<span class="badge badge-success">Checklist: <span class="fas fa-check"></span> {% if event.checklists.count > 1 %}({{event.checklists.count}}){% endif %}</span>
{% endif %}
{% if not event.dry_hire %}
{% if event.hs_done %}
{# TODO Display status of all checklists #}
<span class="badge badge-success">Checklist: <span class="fas fa-check"></span></span>
{% else %}
<span class="badge badge-danger">Checklist: <span class="fas fa-times"></span></span>
{% endif %}
{% if event.has_power %}
<span class="badge badge-success">Power Record: <span class="fas fa-check"></span> {% if event.power_tests.count > 1 %}({{event.power_tests.count}}){% endif %}</span>
{% else %}
<span class="badge badge-danger">Power Record: <span class="fas fa-times"></span></span>
{% endif %}
{% endif %}
{% if perms.RIGS.view_invoice %}
{% if event.invoice %}

View File

@@ -10,18 +10,10 @@
<hr>
<h5>Event Checklists:</h5>
{% for checklist in event.checklists.all %}
{% include 'partials/hs_status.html' with event=event object=checklist view='ec_detail' edit='ec_edit' create='event_ec' review='ec_review' perm=perms.RIGS.review_eventchecklist %}
<br/>
{% endfor %}
<a href="{% url 'event_ec' event.pk %}" class="btn btn-info mt-2"><span class="fas fa-paperclip"></span> <span
class="hidden-xs">Create</span></a>
<hr>
<h5>Power Test Records:</h5>
{% for record in event.power_tests.all %}
{% include 'partials/hs_status.html' with event=event object=record view='pt_detail' edit='pt_edit' create='event_pt' review='pt_review' perm=perms.RIGS.review_power %}
<br/>
{% endfor %}
<a href="{% url 'event_pt' event.pk %}" class="btn btn-info mt-2"><span class="fas fa-paperclip"></span> <span
class="hidden-xs">Create</span></a>
{% include 'partials/hs_status.html' with event=event object=checklist view='ec_detail' edit='ec_edit' create='event_ec' review='ec_review' perm=perms.RIGS.review_eventchecklist %}
<br/>
{% endfor %}
<a href="{% url 'event_ec' event.pk %}" class="btn btn-info mt-2"><span class="fas fa-paperclip"></span> <span
class="hidden-xs">Create</span></a>
</div>
</div>

View File

@@ -43,22 +43,15 @@ def venue(db):
@pytest.fixture # TODO parameterise with Event sizes
def checklist(basic_event, venue, admin_user, ra):
checklist = models.EventChecklist.objects.create(event=basic_event, safe_parking=False,
checklist = models.EventChecklist.objects.create(event=basic_event, power_mic=admin_user, safe_parking=False,
safe_packing=False, exits=False, trip_hazard=False, warning_signs=False,
ear_plugs=False, hs_location="Locked away safely",
extinguishers_location="Somewhere, I forgot",
extinguishers_location="Somewhere, I forgot", earthing=False, pat=False,
date=timezone.now(), venue=venue)
yield checklist
checklist.delete()
@pytest.fixture
def power_test(basic_event, venue, admin_user, ra):
power_test = models.PowerTestRecord.objects.create(event=basic_event, venue=venue)
yield power_test
power_test.delete()
@pytest.fixture
def many_events(db, admin_user, scope="class"):
many_events = {

View File

@@ -230,6 +230,11 @@ class CreateEventChecklist(FormPage):
URL_TEMPLATE = 'event/{event_id}/checklist'
_submit_locator = (By.XPATH, "//button[@type='submit' and contains(., 'Save')]")
_power_mic_selector = (By.XPATH, "//div[select[@id='id_power_mic']]")
_add_vehicle_locator = (By.XPATH, "//button[contains(., 'Vehicle')]")
_add_crew_locator = (By.XPATH, "//button[contains(., 'Crew')]")
_vehicle_row_locator = ('xpath', "//tr[@id[starts-with(., 'vehicle') and not(contains(.,'new'))]]")
_crew_row_locator = ('xpath', "//tr[@id[starts-with(., 'crew') and not(contains(.,'new'))]]")
form_items = {
'safe_parking': (regions.CheckBox, (By.ID, 'id_safe_parking')),
@@ -240,20 +245,6 @@ class CreateEventChecklist(FormPage):
'ear_plugs': (regions.CheckBox, (By.ID, 'id_ear_plugs')),
'hs_location': (regions.TextBox, (By.ID, 'id_hs_location')),
'extinguishers_location': (regions.TextBox, (By.ID, 'id_extinguishers_location')),
}
@property
def success(self):
return '{event_id}' not in self.driver.current_url
class CreatePowerTestRecord(FormPage):
URL_TEMPLATE = 'event/{event_id}/power'
_submit_locator = (By.XPATH, "//button[@type='submit' and contains(., 'Save')]")
_power_mic_selector = (By.XPATH, "//div[select[@id='id_power_mic']]")
form_items = {
'rcds': (regions.CheckBox, (By.ID, 'id_rcds')),
'supply_test': (regions.CheckBox, (By.ID, 'id_supply_test')),
'earthing': (regions.CheckBox, (By.ID, 'id_earthing')),
@@ -272,10 +263,58 @@ class CreatePowerTestRecord(FormPage):
'w1_earth_fault': (regions.TextBox, (By.ID, 'id_w1_earth_fault')),
}
def add_vehicle(self):
self.find_element(*self._add_vehicle_locator).click()
def add_crew(self):
self.find_element(*self._add_crew_locator).click()
@property
def power_mic(self):
return regions.BootstrapSelectElement(self, self.find_element(*self._power_mic_selector))
@property
def vehicles(self):
return [self.VehicleRow(self, el) for el in self.find_elements(*self._vehicle_row_locator)]
class VehicleRow(Region):
_name_locator = ('xpath', ".//input")
_select_locator = ('xpath', ".//div[contains(@class,'bootstrap-select')]/..")
@property
def name(self):
return regions.TextBox(self, self.root.find_element(*self._name_locator))
@property
def vehicle(self):
return regions.BootstrapSelectElement(self, self.root.find_element(*self._select_locator))
@property
def crew(self):
return [self.CrewRow(self, el) for el in self.find_elements(*self._crew_row_locator)]
class CrewRow(Region):
_select_locator = ('xpath', ".//div[contains(@class,'bootstrap-select')]/..")
_start_time_locator = ('xpath', ".//input[@name[starts-with(., 'start') and not(contains(.,'new'))]]")
_end_time_locator = ('xpath', ".//input[@name[starts-with(., 'end') and not(contains(.,'new'))]]")
_role_locator = ('xpath', ".//input[@name[starts-with(., 'role') and not(contains(.,'new'))]]")
@property
def crewmember(self):
return regions.BootstrapSelectElement(self, self.root.find_element(*self._select_locator))
@property
def start_time(self):
return regions.DateTimePicker(self, self.root.find_element(*self._start_time_locator))
@property
def end_time(self):
return regions.DateTimePicker(self, self.root.find_element(*self._end_time_locator))
@property
def role(self):
return regions.TextBox(self, self.root.find_element(*self._role_locator))
@property
def success(self):
return '{event_id}' not in self.driver.current_url

View File

@@ -6,7 +6,7 @@ from PyRIGS.tests.regions import TextBox, Modal, SimpleMDETextArea
class Header(Region):
def find_link(self, link_text):
return self.driver.find_element(By.PARTIAL_LINK_TEXT, link_text)
return self.driver.find_element_by_partial_link_text(link_text)
class ItemRow(Region):

View File

@@ -318,7 +318,7 @@ class TestEventDuplicate(BaseRigboardTest):
self.assertFalse(newEvent.authorised)
self.assertNotIn("N%05d" % self.testEvent.pk, self.driver.find_element(By.XPATH, '//h2').text)
self.assertNotIn("N%05d" % self.testEvent.pk, self.driver.find_element_by_xpath('//h2').text)
self.assertNotIn("Event data duplicated but not yet saved", self.page.warning) # Check info message not visible
# Check the new items are visible
@@ -327,25 +327,26 @@ class TestEventDuplicate(BaseRigboardTest):
self.assertIn("Test Item 2", table.text)
self.assertIn("Test Item 3", table.text)
infoPanel = self.driver.find_element(By.XPATH, '//div[contains(text(), "Event Info")]/..')
self.assertIn("N%05d" % self.testEvent.pk, infoPanel.find_element(By.XPATH, '//dt[text()="Based On"]/following-sibling::dd[1]').text)
infoPanel = self.driver.find_element_by_xpath('//div[contains(text(), "Event Info")]/..')
self.assertIn("N%05d" % self.testEvent.pk,
infoPanel.find_element_by_xpath('//dt[text()="Based On"]/following-sibling::dd[1]').text)
# Check the PO hasn't carried through
self.assertNotIn("TESTPO", infoPanel.find_element(By.XPATH, '//dt[text()="PO"]/following-sibling::dd[1]').text)
self.assertNotIn("TESTPO", infoPanel.find_element_by_xpath('//dt[text()="PO"]/following-sibling::dd[1]').text)
self.assertIn("N%05d" % self.testEvent.pk,
infoPanel.find_element(By.XPATH, '//dt[text()="Based On"]/following-sibling::dd[1]').text)
infoPanel.find_element_by_xpath('//dt[text()="Based On"]/following-sibling::dd[1]').text)
self.driver.get(self.live_server_url + '/event/' + str(self.testEvent.pk)) # Go back to the old event
# Check that based-on hasn't crept into the old event
infoPanel = self.driver.find_element(By.XPATH, '//div[contains(text(), "Event Info")]/..')
infoPanel = self.driver.find_element_by_xpath('//div[contains(text(), "Event Info")]/..')
self.assertNotIn("N%05d" % self.testEvent.pk,
infoPanel.find_element(By.XPATH, '//dt[text()="Based On"]/following-sibling::dd[1]').text)
infoPanel.find_element_by_xpath('//dt[text()="Based On"]/following-sibling::dd[1]').text)
# Check the PO remains on the old event
self.assertIn("TESTPO", infoPanel.find_element(By.XPATH, '//dt[text()="PO"]/following-sibling::dd[1]').text)
self.assertIn("TESTPO", infoPanel.find_element_by_xpath('//dt[text()="PO"]/following-sibling::dd[1]').text)
self.assertNotIn("N%05d" % self.testEvent.pk,
infoPanel.find_element(By.XPATH, '//dt[text()="Based On"]/following-sibling::dd[1]').text)
infoPanel.find_element_by_xpath('//dt[text()="Based On"]/following-sibling::dd[1]').text)
# Check the items are as they were
table = self.page.item_table # ID number is known, see above
@@ -676,6 +677,14 @@ def small_ec(page, admin_user):
page.ear_plugs = True
page.hs_location = "The Moon"
page.extinguishers_location = "With the rest of the fire"
# If we do this first the search fails, for ... reasons
page.power_mic.search(admin_user.name)
page.power_mic.toggle()
assert not page.power_mic.is_open
page.earthing = True
page.rcds = True
page.supply_test = True
page.pat = True
def test_ec_create_small(logged_in_browser, live_server, admin_user, ra):
@@ -696,15 +705,14 @@ def test_ec_create_medium(logged_in_browser, live_server, admin_user, medium_ra)
page.ear_plugs = True
page.hs_location = "Death Valley"
page.extinguishers_location = "With the rest of the fire"
# If we do this first the search fails, for ... reasons
page.power_mic.search(admin_user.name)
page.power_mic.toggle()
assert not page.power_mic.is_open
# Gotta scroll to make the button clickable
logged_in_browser.driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
page.submit()
assert page.success
def test_power_checklist(logged_in_browser, live_server, admin_user, power_test, medium_ra):
page = pages.CreatePowerTestRecord(logged_in_browser.driver, live_server.url, event_id=medium_ra.event.pk).open()
page.earthing = True
page.pat = True
page.source_rcd = True
@@ -719,15 +727,56 @@ def test_power_checklist(logged_in_browser, live_server, admin_user, power_test,
page.w1_polarity = True
page.w1_voltage = 240
page.w1_earth_fault = "0.42"
# If we do this first the search fails, for ... reasons
page.power_mic.search(admin_user.name)
page.power_mic.toggle()
assert not page.power_mic.is_open
page.submit()
assert page.success
def test_ec_create_vehicle(logged_in_browser, live_server, admin_user, checklist):
page = pages.EditEventChecklist(logged_in_browser.driver, live_server.url, pk=checklist.pk).open()
small_ec(page, admin_user)
page.add_vehicle()
assert len(page.vehicles) == 1
vehicle_name = 'Brian'
page.vehicles[0].name.set_value(vehicle_name)
# Appears we're moving too fast for javascript...
t.sleep(1)
page.vehicles[0].vehicle.search(admin_user.first_name)
t.sleep(1)
page.submit()
assert page.success
# Check data is correct
checklist.refresh_from_db()
vehicle = models.EventChecklistVehicle.objects.get(checklist=checklist.pk)
assert vehicle_name == vehicle.vehicle
# TODO Test validation of end before start
def test_ec_create_crew(logged_in_browser, live_server, admin_user, checklist):
page = pages.EditEventChecklist(logged_in_browser.driver, live_server.url, pk=checklist.pk).open()
small_ec(page, admin_user)
page.add_crew()
assert len(page.crew) == 1
role = "MIC"
start_time = timezone.make_aware(datetime.datetime(2015, 1, 1, 9, 0))
end_time = timezone.make_aware(datetime.datetime(2015, 1, 1, 10, 30))
crew = page.crew[0]
t.sleep(2)
crew.crewmember.search(admin_user.first_name)
t.sleep(2)
crew.role.set_value(role)
crew.start_time.set_value(start_time)
crew.end_time.set_value(end_time)
page.submit()
assert page.success
# Check data is correct
crew_obj = models.EventChecklistCrew.objects.get(checklist=checklist.pk)
assert admin_user.pk == crew_obj.crewmember.pk
assert role == crew_obj.role
assert start_time == crew_obj.start
assert end_time == crew_obj.end
# TODO Can I loop through all the boolean fields and test them at once?
def test_ra_creation(logged_in_browser, live_server, admin_user, basic_event):
page = pages.CreateRiskAssessment(logged_in_browser.driver, live_server.url, event_id=basic_event.pk).open()

View File

@@ -79,8 +79,10 @@ urlpatterns = [
name='ra_detail'),
path('event/ra/<int:pk>/edit/', permission_required_with_403('RIGS.change_riskassessment')(views.EventRiskAssessmentEdit.as_view()),
name='ra_edit'),
path('event/ra/<int:pk>/review/', permission_required_with_403('RIGS.review_riskassessment')(views.MarkReviewed.as_view()),
name='ra_review', kwargs={'model': 'RiskAssessment'}),
path('event/ra/list', permission_required_with_403('RIGS.view_riskassessment')(views.EventRiskAssessmentList.as_view()),
name='ra_list'),
path('event/ra/<int:pk>/review/', permission_required_with_403('RIGS.review_riskassessment')(views.EventRiskAssessmentReview.as_view()),
name='ra_review'),
path('event/ra/<int:pk>/print/', permission_required_with_403('RIGS.view_riskassessment')(views.RAPrint.as_view()), name='ra_print'),
path('event/<int:pk>/checklist/', permission_required_with_403('RIGS.add_eventchecklist')(views.EventChecklistCreate.as_view()),
@@ -89,26 +91,10 @@ urlpatterns = [
name='ec_detail'),
path('event/checklist/<int:pk>/edit/', permission_required_with_403('RIGS.change_eventchecklist')(views.EventChecklistEdit.as_view()),
name='ec_edit'),
path('event/checklist/<int:pk>/review/', permission_required_with_403('RIGS.review_eventchecklist')(views.MarkReviewed.as_view()),
name='ec_review', kwargs={'model': 'EventChecklist'}),
path('event/<int:pk>/power/', permission_required_with_403('RIGS.add_powertestrecord')(views.PowerTestCreate.as_view()),
name='event_pt'),
path('event/power/<int:pk>/', login_required(views.PowerTestDetail.as_view()),
name='pt_detail'),
path('event/power/<int:pk>/edit/', permission_required_with_403('RIGS.change_powertestrecord')(views.PowerTestEdit.as_view()),
name='pt_edit'),
path('event/power/<int:pk>/review/', permission_required_with_403('RIGS.review_power')(views.MarkReviewed.as_view()),
name='pt_review', kwargs={'model': 'PowerTestRecord'}),
path('event/<int:pk>/checkin/', permission_required_with_403('RIGS.add_eventcheckin')(views.EventCheckIn.as_view()),
name='event_checkin'),
path('event/checkout/', permission_required_with_403('RIGS.change_eventcheckin')(views.EventCheckOut.as_view()),
name='event_checkout'),
path('event/<int:pk>/checkin/edit/', permission_required_with_403('RIGS.change_eventcheckin')(views.EventCheckInEdit.as_view()),
name='edit_checkin'),
path('event/<int:pk>/checkin/add/', permission_required_with_403('RIGS.add_eventcheckin')(views.EventCheckInOverride.as_view()),
name='event_checkin_override'),
path('event/checklist/list', permission_required_with_403('RIGS.view_eventchecklist')(views.EventChecklistList.as_view()),
name='ec_list'),
path('event/checklist/<int:pk>/review/', permission_required_with_403('RIGS.review_eventchecklist')(views.EventChecklistReview.as_view()),
name='ec_review'),
# Finance
path('invoice/', permission_required_with_403('RIGS.view_invoice')(views.InvoiceIndex.as_view()),

View File

@@ -1,46 +1,16 @@
from django.apps import apps
from django.contrib import messages
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.urls import reverse_lazy
from django.utils import timezone
from django.views import generic
from reversion import revisions as reversion
from RIGS import models, forms
from RIGS.views.rigboard import get_related
from PyRIGS.views import PrintView, ModalURLMixin
from django.shortcuts import redirect
from PyRIGS.views import PrintView
class HSCreateView(generic.CreateView):
def get_form(self, **kwargs):
form = super().get_form(**kwargs)
epk = self.kwargs.get('pk')
event = models.Event.objects.get(pk=epk)
form.instance.event = event
return form
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
epk = self.kwargs.get('pk')
event = models.Event.objects.get(pk=epk)
context['event'] = event
context['page_title'] = f'Create {self.model.__name__} for Event {event.display_id}'
return context
class MarkReviewed(generic.View):
def get(self, *args, **kwargs):
obj = apps.get_model('RIGS', kwargs.get('model')).objects.get(pk=kwargs.get('pk'))
with reversion.create_revision():
reversion.set_user(self.request.user)
obj.reviewed_by = self.request.user
obj.reviewed_at = timezone.now()
obj.save()
return HttpResponseRedirect(reverse('hs_list'))
class EventRiskAssessmentCreate(HSCreateView):
class EventRiskAssessmentCreate(generic.CreateView):
model = models.RiskAssessment
template_name = 'hs/risk_assessment_form.html'
form_class = forms.EventRiskAssessmentForm
@@ -53,12 +23,28 @@ class EventRiskAssessmentCreate(HSCreateView):
ra = models.RiskAssessment.objects.filter(event=event).first()
if ra is not None:
return HttpResponseRedirect(reverse('ra_edit', kwargs={'pk': ra.pk}))
return HttpResponseRedirect(reverse_lazy('ra_edit', kwargs={'pk': ra.pk}))
return super(EventRiskAssessmentCreate, self).get(self)
def get_form(self, **kwargs):
form = super(EventRiskAssessmentCreate, self).get_form(**kwargs)
epk = self.kwargs.get('pk')
event = models.Event.objects.get(pk=epk)
form.instance.event = event
return form
def get_context_data(self, **kwargs):
context = super(EventRiskAssessmentCreate, self).get_context_data(**kwargs)
epk = self.kwargs.get('pk')
event = models.Event.objects.get(pk=epk)
context['event'] = event
context['page_title'] = f'Create Risk Assessment for Event {event.display_id}'
get_related(context['form'], context)
return context
def get_success_url(self):
return reverse('ra_detail', kwargs={'pk': self.object.pk})
return reverse_lazy('ra_detail', kwargs={'pk': self.object.pk})
class EventRiskAssessmentEdit(generic.UpdateView):
@@ -71,7 +57,7 @@ class EventRiskAssessmentEdit(generic.UpdateView):
ra.reviewed_by = None
ra.reviewed_at = None
ra.save()
return reverse('ra_detail', kwargs={'pk': self.object.pk})
return reverse_lazy('ra_detail', kwargs={'pk': self.object.pk})
def get_context_data(self, **kwargs):
context = super(EventRiskAssessmentEdit, self).get_context_data(**kwargs)
@@ -94,6 +80,36 @@ class EventRiskAssessmentDetail(generic.DetailView):
return context
class EventRiskAssessmentList(generic.ListView):
paginate_by = 20
model = models.RiskAssessment
template_name = 'hs/hs_object_list.html'
def get_queryset(self):
return self.model.objects.exclude(event__status=models.Event.CANCELLED).order_by('reviewed_at').select_related('event')
def get_context_data(self, **kwargs):
context = super(EventRiskAssessmentList, self).get_context_data(**kwargs)
context['title'] = 'Risk Assessment'
context['view'] = 'ra_detail'
context['edit'] = 'ra_edit'
context['review'] = 'ra_review'
context['perm'] = 'perms.RIGS.review_riskassessment'
return context
class EventRiskAssessmentReview(generic.View):
def get(self, *args, **kwargs):
rpk = kwargs.get('pk')
ra = models.RiskAssessment.objects.get(pk=rpk)
with reversion.create_revision():
reversion.set_user(self.request.user)
ra.reviewed_by = self.request.user
ra.reviewed_at = timezone.now()
ra.save()
return HttpResponseRedirect(reverse_lazy('ra_list'))
class EventChecklistDetail(generic.DetailView):
model = models.EventChecklist
template_name = 'hs/event_checklist_detail.html'
@@ -114,7 +130,7 @@ class EventChecklistEdit(generic.UpdateView):
ec.reviewed_by = None
ec.reviewed_at = None
ec.save()
return reverse('ec_detail', kwargs={'pk': self.object.pk})
return reverse_lazy('ec_detail', kwargs={'pk': self.object.pk})
def get_context_data(self, **kwargs):
context = super(EventChecklistEdit, self).get_context_data(**kwargs)
@@ -127,7 +143,7 @@ class EventChecklistEdit(generic.UpdateView):
return context
class EventChecklistCreate(HSCreateView):
class EventChecklistCreate(generic.CreateView):
model = models.EventChecklist
template_name = 'hs/event_checklist_form.html'
form_class = forms.EventChecklistForm
@@ -142,67 +158,57 @@ class EventChecklistCreate(HSCreateView):
if ra is None:
messages.error(self.request, f'A Risk Assessment must exist prior to creating any Event Checklists for {event}! Please create one now.')
return HttpResponseRedirect(reverse('event_ra', kwargs={'pk': epk}))
return HttpResponseRedirect(reverse_lazy('event_ra', kwargs={'pk': epk}))
return super(EventChecklistCreate, self).get(self)
def get_success_url(self):
return reverse('ec_detail', kwargs={'pk': self.object.pk})
class PowerTestDetail(generic.DetailView):
model = models.PowerTestRecord
template_name = 'hs/power_detail.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['page_title'] = f"Power Test Record for Event <a href='{self.object.event.get_absolute_url()}'>{self.object.event.display_id} {self.object.event.name}</a>"
return context
class PowerTestEdit(generic.UpdateView):
model = models.PowerTestRecord
template_name = 'hs/power_form.html'
form_class = forms.PowerTestRecordForm
def get_success_url(self):
ec = self.get_object()
ec.reviewed_by = None
ec.reviewed_at = None
ec.save()
return reverse('ec_detail', kwargs={'pk': self.object.pk})
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
pk = self.kwargs.get('pk')
ec = models.PowerTestRecord.objects.get(pk=pk)
context['event'] = ec.event
context['edit'] = True
context['page_title'] = f'Edit Power Test Record for Event {ec.event.display_id}'
# get_related(context['form'], context)
return context
class PowerTestCreate(HSCreateView):
model = models.PowerTestRecord
template_name = 'hs/power_form.html'
form_class = forms.PowerTestRecordForm
def get(self, *args, **kwargs):
epk = kwargs.get('pk')
def get_form(self, **kwargs):
form = super(EventChecklistCreate, self).get_form(**kwargs)
epk = self.kwargs.get('pk')
event = models.Event.objects.get(pk=epk)
form.instance.event = event
return form
# Check if RA exists
ra = models.RiskAssessment.objects.filter(event=event).first()
if ra is None:
messages.error(self.request, f'A Risk Assessment must exist prior to creating any Power Test Records for {event}! Please create one now.')
return HttpResponseRedirect(reverse('event_ra', kwargs={'pk': epk}))
return super().get(self)
def get_context_data(self, **kwargs):
context = super(EventChecklistCreate, self).get_context_data(**kwargs)
epk = self.kwargs.get('pk')
event = models.Event.objects.get(pk=epk)
context['event'] = event
context['page_title'] = f'Create Event Checklist for Event {event.display_id}'
return context
def get_success_url(self):
return reverse('pt_detail', kwargs={'pk': self.object.pk})
return reverse_lazy('ec_detail', kwargs={'pk': self.object.pk})
class EventChecklistList(generic.ListView):
paginate_by = 20
model = models.EventChecklist
template_name = 'hs/hs_object_list.html'
def get_queryset(self):
return self.model.objects.exclude(event__status=models.Event.CANCELLED).order_by('reviewed_at').select_related('event')
def get_context_data(self, **kwargs):
context = super(EventChecklistList, self).get_context_data(**kwargs)
context['title'] = 'Event Checklist'
context['view'] = 'ec_detail'
context['edit'] = 'ec_edit'
context['review'] = 'ec_review'
context['perm'] = 'perms.RIGS.review_eventchecklist'
return context
class EventChecklistReview(generic.View):
def get(self, *args, **kwargs):
rpk = kwargs.get('pk')
ec = models.EventChecklist.objects.get(pk=rpk)
with reversion.create_revision():
reversion.set_user(self.request.user)
ec.reviewed_by = self.request.user
ec.reviewed_at = timezone.now()
ec.save()
return HttpResponseRedirect(reverse_lazy('ec_list'))
class HSList(generic.ListView):
@@ -227,58 +233,3 @@ class RAPrint(PrintView):
context = super().get_context_data(**kwargs)
context['filename'] = f"EventSpecificRiskAssessment_for_{context['object'].event.display_id}.pdf"
return context
class EventCheckIn(generic.CreateView, ModalURLMixin):
model = models.EventCheckIn
template_name = 'hs/eventcheckin_form.html'
form_class = forms.EventCheckInForm
def get_success_url(self):
return self.get_close_url('event_detail', 'event_detail') # Well, that's one way of doing that...!
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['event'] = models.Event.objects.get(pk=self.kwargs.get('pk'))
context['page_title'] = f'Check In to Event {context["event"].display_id}'
# get_related(context['form'], context)
return context
class EventCheckInOverride(generic.CreateView):
model = models.EventCheckIn
template_name = 'hs/eventcheckin_form.html'
form_class = forms.EditCheckInForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['event'] = models.Event.objects.get(pk=self.kwargs.get('pk'))
context['page_title'] = f'Manually add Check In to Event {context["event"].display_id}'
context['manual'] = True
return context
class EventCheckInEdit(generic.UpdateView, ModalURLMixin):
model = models.EventCheckIn
template_name = 'hs/eventcheckin_form.html'
form_class = forms.EditCheckInForm
def get_success_url(self):
return self.get_close_url('event_detail', 'event_detail') # Well, that's one way of doing that...!
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['event'] = self.object.event
context['page_title'] = f'Edit Check In for Event {context["event"].display_id}'
context['edit'] = True
# get_related(context['form'], context)
return context
class EventCheckOut(generic.RedirectView):
def get_redirect_url(self, *args, **kwargs):
checkin = self.request.user.current_event()
if checkin:
checkin.end_time = timezone.now()
checkin.save()
return self.request.META.get('HTTP_REFERER', '/')

View File

@@ -195,7 +195,7 @@ class TestAssetForm(AutoLoginTest):
# self.assertTrue(self.page.parent_selector.options[0].selected)
self.page.parent_selector.toggle()
self.assertFalse(self.driver.find_element(By.ID, 'cable-table').is_displayed())
self.assertFalse(self.driver.find_element_by_id('cable-table').is_displayed())
self.page.submit()
self.assertTrue(self.page.success)
@@ -350,7 +350,7 @@ class TestAssetAudit(AutoLoginTest):
self.wait.until(ec.visibility_of_element_located((By.ID, 'modal')))
self.assertEqual(self.page.modal.asset_id, asset_row.id)
self.page.modal.close()
self.assertFalse(self.driver.find_element(By.ID, 'modal').is_displayed())
self.assertFalse(self.driver.find_element_by_id('modal').is_displayed())
# Make sure audit log was NOT filled out
audited = models.Asset.objects.get(asset_id=asset_row.id)
assert audited.last_audited_by is None

1167
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -73,7 +73,7 @@ function initPicker(obj) {
return array;
}
};
//console.log(obj.data);
console.log(obj.data);
if (!obj.data('noclear')) {
obj.prepend($("<option></option>")
.attr("value",'')

View File

@@ -30,9 +30,6 @@
<body>
<a class="skip-link" href='#main'>Skip to content</a>
{% block navbar %}
{% if request.user.current_event %}
<div class="bg-primary d-flex justify-content-between align-items-center"><span class="ml-2">You are currently checked in to <a href="{{request.user.current_event.event.get_absolute_url}}" class="text-white">{{request.user.current_event.event}}</a></span><a href="{% url 'event_checkout'%}" class="btn btn-warning">Check Out</a></div>
{% endif %}
<nav class="navbar navbar-expand-lg navbar-dark bg-dark" role="navigation">
<div class="container">
<a class="navbar-brand" style="position: absolute; left:0.5em; top: 2px;" href="{% if request.user.is_authenticated %}https://rigs.nottinghamtec.co.uk{%else%}https://nottinghamtec.co.uk{%endif%}">

View File

@@ -8,13 +8,6 @@
<div class="row">
<h1 class="col-sm-12 pb-3">R<small class="text-muted">ig</small> I<small class="text-muted">nformation</small> G<small class="text-muted">athering</small> S<small class="text-muted">ystem</small></h1>
<h2 class="col-sm-12 pb-3">Welcome back {{ user.get_full_name }}, there {%if rig_count == 1 %}is one rig coming up{%else%}are {{ rig_count|apnumber }} rigs coming up.{%endif%}</h2>
{% if now %}
<div class="col-sm-12 alert alert-primary rounded-0 mx-auto">
{% for event in now %}
Event {{ event }} is happening now! <a href="{% url 'event_checkin' event.pk %}" class="btn btn-success btn-sm modal-href align-baseline {% if request.user.current_event %}disabled{%endif%}"><span class="fas fa-user-clock"></span> <span class="d-none d-sm-inline">Check In</span></a><br/>
{% endfor %}
</div>
{% endif %}
<div class="col-sm-4 mb-3">
<div class="card">
<img class="card-img-top d-none d-sm-block" src="{% static 'imgs/rigs.jpg' %}" alt="Some lights and haze, very purple" style="height: 150px; object-fit: cover;">
@@ -31,6 +24,7 @@
</div>
<div class="col-sm-4 mb-3">
<div class="card">
{% now "m-d" as todays_date %}
<img class="card-img-top d-none d-sm-block" src="{% if todays_date == '04-01' %}{% static 'imgs/tappytaptap.gif' %}{%else%}{% static 'imgs/assets.jpg' %}{%endif%}" alt="M32 sound desk close up of the faders" style="height: 150px; object-fit: cover;">
<h4 class="card-header">Asset Database</h4>
<div class="list-group list-group-flush">

View File

@@ -50,7 +50,10 @@ class Command(BaseCommand):
"add_supplier", "view_cabletype", "change_cabletype",
"add_cabletype", "view_eventchecklist", "change_eventchecklist",
"add_eventchecklist", "view_riskassessment", "change_riskassessment",
"add_riskassessment"]
"add_riskassessment", "add_eventchecklistcrew", "change_eventchecklistcrew",
"delete_eventchecklistcrew", "view_eventchecklistcrew", "add_eventchecklistvehicle",
"change_eventchecklistvehicle",
"delete_eventchecklistvehicle", "view_eventchecklistvehicle", ]
finance_perms = keyholder_perms + ["add_invoice", "change_invoice", "view_invoice",
"add_payment", "change_payment", "delete_payment"]
hs_perms = keyholder_perms + ["review_riskassessment", "review_eventchecklist"]

View File

@@ -6,7 +6,6 @@ from django.core import mail
from django.test import LiveServerTestCase
from django.test.utils import override_settings
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from PyRIGS.tests.base import create_browser
from RIGS import models
@@ -25,31 +24,31 @@ class UserRegistrationTest(LiveServerTestCase):
def test_registration(self):
# Navigate to the registration page
self.browser.get(self.live_server_url + '/user/register/')
title_text = self.browser.find_element(By.TAG_NAME, 'h3').text
title_text = self.browser.find_element_by_tag_name('h3').text
self.assertIn("User Registration", title_text)
# Check the form invites correctly
username = self.browser.find_element(By.ID, 'id_username')
username = self.browser.find_element_by_id('id_username')
self.assertEqual(username.get_attribute('placeholder'), 'Username')
email = self.browser.find_element(By.ID, 'id_email')
email = self.browser.find_element_by_id('id_email')
self.assertEqual(email.get_attribute('placeholder'), 'E-mail')
# If this is correct we don't need to test it later
self.assertEqual(email.get_attribute('type'), 'email')
password1 = self.browser.find_element(By.ID, 'id_password1')
password1 = self.browser.find_element_by_id('id_password1')
self.assertEqual(password1.get_attribute('placeholder'), 'Password')
self.assertEqual(password1.get_attribute('type'), 'password')
password2 = self.browser.find_element(By.ID, 'id_password2')
password2 = self.browser.find_element_by_id('id_password2')
self.assertEqual(
password2.get_attribute('placeholder'), 'Password confirmation')
self.assertEqual(password2.get_attribute('type'), 'password')
first_name = self.browser.find_element(By.ID, 'id_first_name')
first_name = self.browser.find_element_by_id('id_first_name')
self.assertEqual(first_name.get_attribute('placeholder'), 'First name')
last_name = self.browser.find_element(By.ID, 'id_last_name')
last_name = self.browser.find_element_by_id('id_last_name')
self.assertEqual(last_name.get_attribute('placeholder'), 'Last name')
initials = self.browser.find_element(By.ID, 'id_initials')
initials = self.browser.find_element_by_id('id_initials')
self.assertEqual(initials.get_attribute('placeholder'), 'Initials')
# No longer required for new users
# phone = self.browser.find_element(By.ID, 'id_phone')
# phone = self.browser.find_element_by_id('id_phone')
# self.assertEqual(phone.get_attribute('placeholder'), 'Phone')
# Fill the form out incorrectly
@@ -63,20 +62,21 @@ class UserRegistrationTest(LiveServerTestCase):
initials.send_keys('JS')
# phone.send_keys('0123456789')
time.sleep(1)
self.browser.switch_to.frame(self.browser.find_element(By.TAG_NAME, "iframe"))
self.browser.find_element(By.ID, 'anchor').click()
self.browser.switch_to.frame(self.browser.find_element_by_tag_name("iframe"))
self.browser.find_element_by_id('anchor').click()
self.browser.switch_to.default_content()
time.sleep(3)
# Submit incorrect form
submit = self.browser.find_element(By.XPATH, "//input[@type='submit']")
submit = self.browser.find_element_by_xpath("//input[@type='submit']")
submit.click()
# Restablish error fields
password1 = self.browser.find_element(By.ID, 'id_password1')
password2 = self.browser.find_element(By.ID, 'id_password2')
password1 = self.browser.find_element_by_id('id_password1')
password2 = self.browser.find_element_by_id('id_password2')
# Read what the error is
alert = self.browser.find_element(By.CSS_SELECTOR, '.alert-danger').text
alert = self.browser.find_element_by_css_selector(
'div.alert-danger').text
# TODO Use regex matching to handle smart/unsmart quotes...
self.assertIn("password fields didn", alert)
@@ -92,7 +92,8 @@ class UserRegistrationTest(LiveServerTestCase):
password2.send_keys(Keys.ENTER)
# Check we have a success message
alert = self.browser.find_element(By.CSS_SELECTOR, '.alert-success').text
alert = self.browser.find_element_by_css_selector(
'div.alert-success').text
self.assertIn('register', alert)
self.assertIn('email', alert)
@@ -110,14 +111,14 @@ class UserRegistrationTest(LiveServerTestCase):
self.browser.get(urls[0]) # go to the first link
# Complete registration
title_text = self.browser.find_element(By.TAG_NAME, 'h2').text
title_text = self.browser.find_element_by_tag_name('h2').text
self.assertIn('Complete', title_text)
# Test login
self.browser.get(self.live_server_url + '/user/login')
username = self.browser.find_element(By.ID, 'id_username')
username = self.browser.find_element_by_id('id_username')
self.assertEqual(username.get_attribute('placeholder'), 'Username')
password = self.browser.find_element(By.ID, 'id_password')
password = self.browser.find_element_by_id('id_password')
self.assertEqual(password.get_attribute('placeholder'), 'Password')
self.assertEqual(password.get_attribute('type'), 'password')
@@ -131,7 +132,8 @@ class UserRegistrationTest(LiveServerTestCase):
self.assertFalse(profileObject.is_approved)
# Read what the error is
alert = self.browser.find_element(By.CSS_SELECTOR, 'div.alert-danger').text
alert = self.browser.find_element_by_css_selector(
'div.alert-danger').text
self.assertIn("approved", alert)
# Approve the user so we can proceed
@@ -140,14 +142,14 @@ class UserRegistrationTest(LiveServerTestCase):
# Retry login
self.browser.get(self.live_server_url + '/user/login')
username = self.browser.find_element(By.ID, 'id_username')
username = self.browser.find_element_by_id('id_username')
username.send_keys('TestUsername')
password = self.browser.find_element(By.ID, 'id_password')
password = self.browser.find_element_by_id('id_password')
password.send_keys('correcthorsebatterystaple')
password.send_keys(Keys.ENTER)
# Check we are logged in
udd = self.browser.find_element(By.CLASS_NAME, 'navbar').text
udd = self.browser.find_element_by_class_name('navbar').text
self.assertIn('Hi John', udd)
# Check all the data actually got saved