Add and apply black formatter
This commit is contained in:
parent
0d34d4832a
commit
ecdd2f861c
1
Pipfile
1
Pipfile
@ -15,6 +15,7 @@ django-recurrence = "~=1.10"
|
|||||||
|
|
||||||
[dev-packages]
|
[dev-packages]
|
||||||
djlint = "~=0.7"
|
djlint = "~=0.7"
|
||||||
|
black = "*"
|
||||||
|
|
||||||
[requires]
|
[requires]
|
||||||
python_version = "3.9"
|
python_version = "3.9"
|
||||||
|
211
Pipfile.lock
generated
211
Pipfile.lock
generated
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"hash": {
|
"hash": {
|
||||||
"sha256": "38925606631e4d558d3539d27170aaaa686a4dc20fe8ee68f435b93c3ef7c12f"
|
"sha256": "4e1b5c33531624fa18bd7683e300a081a273442b3b1893f89f688ea3aed31da7"
|
||||||
},
|
},
|
||||||
"pipfile-spec": 6,
|
"pipfile-spec": 6,
|
||||||
"requires": {
|
"requires": {
|
||||||
@ -253,11 +253,11 @@
|
|||||||
},
|
},
|
||||||
"uvicorn": {
|
"uvicorn": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:0b89c91bb8fe84c4bded9996af13c4b8c0de799d29bffeaa0c8ad298f2be0934",
|
"sha256:60a149248181920a73b2e97aec1dacec5501618867f041a228b2519d91a62a91",
|
||||||
"sha256:192c2422b056a3beb512c6c260bf77a7a884204a4ae41856719c1913ead63bbb"
|
"sha256:fa166e6c3d58e23ff5a1a3543b079c7b28aa057ab1388201e4b34a49ec05da72"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==0.17.0"
|
"version": "==0.17.0.post1"
|
||||||
},
|
},
|
||||||
"webencodings": {
|
"webencodings": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@ -276,6 +276,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"develop": {
|
"develop": {
|
||||||
|
"black": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3",
|
||||||
|
"sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==21.12b0"
|
||||||
|
},
|
||||||
"click": {
|
"click": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3",
|
"sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3",
|
||||||
@ -294,11 +302,18 @@
|
|||||||
},
|
},
|
||||||
"djlint": {
|
"djlint": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:95715103781a4258ef91bdcb3702e1f5707ca075ceb49b58f0a8ce6b568115c6",
|
"sha256:68aad9ddfef883cc9d9e0d177387b74840af5ca12dcce6e4629eb7075c97dc05",
|
||||||
"sha256:d03cc3d6cd51db9f942211ffbdc85009d33f31e28ea1edbd22954af80d28141a"
|
"sha256:714ed457e022047149c8bff57d5be00ce30f8846b60e866791c66d27e7d11e7f"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==0.7.2"
|
"version": "==0.7.3"
|
||||||
|
},
|
||||||
|
"mypy-extensions": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d",
|
||||||
|
"sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"
|
||||||
|
],
|
||||||
|
"version": "==0.4.3"
|
||||||
},
|
},
|
||||||
"pathspec": {
|
"pathspec": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@ -307,6 +322,14 @@
|
|||||||
],
|
],
|
||||||
"version": "==0.9.0"
|
"version": "==0.9.0"
|
||||||
},
|
},
|
||||||
|
"platformdirs": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1d7385c7db91728b83efd0ca99a5afb296cab9d0ed8313a45ed8ba17967ecfca",
|
||||||
|
"sha256:440633ddfebcc36264232365d7840a970e75e1018d15b4327d11f91909045fda"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.7'",
|
||||||
|
"version": "==2.4.1"
|
||||||
|
},
|
||||||
"pyyaml": {
|
"pyyaml": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293",
|
"sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293",
|
||||||
@ -348,90 +371,98 @@
|
|||||||
},
|
},
|
||||||
"regex": {
|
"regex": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:0416f7399e918c4b0e074a0f66e5191077ee2ca32a0f99d4c187a62beb47aa05",
|
"sha256:04611cc0f627fc4a50bc4a9a2e6178a974c6a6a4aa9c1cca921635d2c47b9c87",
|
||||||
"sha256:05b7d6d7e64efe309972adab77fc2af8907bb93217ec60aa9fe12a0dad35874f",
|
"sha256:0b5d6f9aed3153487252d00a18e53f19b7f52a1651bc1d0c4b5844bc286dfa52",
|
||||||
"sha256:0617383e2fe465732af4509e61648b77cbe3aee68b6ac8c0b6fe934db90be5cc",
|
"sha256:0d2f5c3f7057530afd7b739ed42eb04f1011203bc5e4663e1e1d01bb50f813e3",
|
||||||
"sha256:07856afef5ffcc052e7eccf3213317fbb94e4a5cd8177a2caa69c980657b3cb4",
|
"sha256:11772be1eb1748e0e197a40ffb82fb8fd0d6914cd147d841d9703e2bef24d288",
|
||||||
"sha256:0f594b96fe2e0821d026365f72ac7b4f0b487487fb3d4aaf10dd9d97d88a9737",
|
"sha256:1333b3ce73269f986b1fa4d5d395643810074dc2de5b9d262eb258daf37dc98f",
|
||||||
"sha256:139a23d1f5d30db2cc6c7fd9c6d6497872a672db22c4ae1910be22d4f4b2068a",
|
"sha256:16f81025bb3556eccb0681d7946e2b35ff254f9f888cff7d2120e8826330315c",
|
||||||
"sha256:162abfd74e88001d20cb73ceaffbfe601469923e875caf9118333b1a4aaafdc4",
|
"sha256:1a171eaac36a08964d023eeff740b18a415f79aeb212169080c170ec42dd5184",
|
||||||
"sha256:2207ae4f64ad3af399e2d30dde66f0b36ae5c3129b52885f1bffc2f05ec505c8",
|
"sha256:1d6301f5288e9bdca65fab3de6b7de17362c5016d6bf8ee4ba4cbe833b2eda0f",
|
||||||
"sha256:2409b5c9cef7054dde93a9803156b411b677affc84fca69e908b1cb2c540025d",
|
"sha256:1e031899cb2bc92c0cf4d45389eff5b078d1936860a1be3aa8c94fa25fb46ed8",
|
||||||
"sha256:2fee3ed82a011184807d2127f1733b4f6b2ff6ec7151d83ef3477f3b96a13d03",
|
"sha256:1f8c0ae0a0de4e19fddaaff036f508db175f6f03db318c80bbc239a1def62d02",
|
||||||
"sha256:30ab804ea73972049b7a2a5c62d97687d69b5a60a67adca07eb73a0ddbc9e29f",
|
"sha256:2245441445099411b528379dee83e56eadf449db924648e5feb9b747473f42e3",
|
||||||
"sha256:3598893bde43091ee5ca0a6ad20f08a0435e93a69255eeb5f81b85e81e329264",
|
"sha256:22709d701e7037e64dae2a04855021b62efd64a66c3ceed99dfd684bfef09e38",
|
||||||
"sha256:3b5df18db1fccd66de15aa59c41e4f853b5df7550723d26aa6cb7f40e5d9da5a",
|
"sha256:24c89346734a4e4d60ecf9b27cac4c1fee3431a413f7aa00be7c4d7bbacc2c4d",
|
||||||
"sha256:3c5fb32cc6077abad3bbf0323067636d93307c9fa93e072771cf9a64d1c0f3ef",
|
"sha256:25716aa70a0d153cd844fe861d4f3315a6ccafce22b39d8aadbf7fcadff2b633",
|
||||||
"sha256:416c5f1a188c91e3eb41e9c8787288e707f7d2ebe66e0a6563af280d9b68478f",
|
"sha256:2dacb3dae6b8cc579637a7b72f008bff50a94cde5e36e432352f4ca57b9e54c4",
|
||||||
"sha256:42b50fa6666b0d50c30a990527127334d6b96dd969011e843e726a64011485da",
|
"sha256:34316bf693b1d2d29c087ee7e4bb10cdfa39da5f9c50fa15b07489b4ab93a1b5",
|
||||||
"sha256:432bd15d40ed835a51617521d60d0125867f7b88acf653e4ed994a1f8e4995dc",
|
"sha256:36b2d700a27e168fa96272b42d28c7ac3ff72030c67b32f37c05616ebd22a202",
|
||||||
"sha256:473e67837f786404570eae33c3b64a4b9635ae9f00145250851a1292f484c063",
|
"sha256:37978254d9d00cda01acc1997513f786b6b971e57b778fbe7c20e30ae81a97f3",
|
||||||
"sha256:4aaa4e0705ef2b73dd8e36eeb4c868f80f8393f5f4d855e94025ce7ad8525f50",
|
"sha256:38289f1690a7e27aacd049e420769b996826f3728756859420eeee21cc857118",
|
||||||
"sha256:50a7ddf3d131dc5633dccdb51417e2d1910d25cbcf842115a3a5893509140a3a",
|
"sha256:385ccf6d011b97768a640e9d4de25412204fbe8d6b9ae39ff115d4ff03f6fe5d",
|
||||||
"sha256:529801a0d58809b60b3531ee804d3e3be4b412c94b5d267daa3de7fadef00f49",
|
"sha256:3c7ea86b9ca83e30fa4d4cd0eaf01db3ebcc7b2726a25990966627e39577d729",
|
||||||
"sha256:537ca6a3586931b16a85ac38c08cc48f10fc870a5b25e51794c74df843e9966d",
|
"sha256:49810f907dfe6de8da5da7d2b238d343e6add62f01a15d03e2195afc180059ed",
|
||||||
"sha256:53db2c6be8a2710b359bfd3d3aa17ba38f8aa72a82309a12ae99d3c0c3dcd74d",
|
"sha256:519c0b3a6fbb68afaa0febf0d28f6c4b0a1074aefc484802ecb9709faf181607",
|
||||||
"sha256:5537f71b6d646f7f5f340562ec4c77b6e1c915f8baae822ea0b7e46c1f09b733",
|
"sha256:51f02ca184518702975b56affde6c573ebad4e411599005ce4468b1014b4786c",
|
||||||
"sha256:563d5f9354e15e048465061509403f68424fef37d5add3064038c2511c8f5e00",
|
"sha256:552a39987ac6655dad4bf6f17dd2b55c7b0c6e949d933b8846d2e312ee80005a",
|
||||||
"sha256:5d408a642a5484b9b4d11dea15a489ea0928c7e410c7525cd892f4d04f2f617b",
|
"sha256:596f5ae2eeddb79b595583c2e0285312b2783b0ec759930c272dbf02f851ff75",
|
||||||
"sha256:61600a7ca4bcf78a96a68a27c2ae9389763b5b94b63943d5158f2a377e09d29a",
|
"sha256:6014038f52b4b2ac1fa41a58d439a8a00f015b5c0735a0cd4b09afe344c94899",
|
||||||
"sha256:6650f16365f1924d6014d2ea770bde8555b4a39dc9576abb95e3cd1ff0263b36",
|
"sha256:61ebbcd208d78658b09e19c78920f1ad38936a0aa0f9c459c46c197d11c580a0",
|
||||||
"sha256:666abff54e474d28ff42756d94544cdfd42e2ee97065857413b72e8a2d6a6345",
|
"sha256:6213713ac743b190ecbf3f316d6e41d099e774812d470422b3a0f137ea635832",
|
||||||
"sha256:68a067c11463de2a37157930d8b153005085e42bcb7ad9ca562d77ba7d1404e0",
|
"sha256:637e27ea1ebe4a561db75a880ac659ff439dec7f55588212e71700bb1ddd5af9",
|
||||||
"sha256:6e1d2cc79e8dae442b3fa4a26c5794428b98f81389af90623ffcc650ce9f6732",
|
"sha256:6aa427c55a0abec450bca10b64446331b5ca8f79b648531138f357569705bc4a",
|
||||||
"sha256:74cbeac0451f27d4f50e6e8a8f3a52ca074b5e2da9f7b505c4201a57a8ed6286",
|
"sha256:6ca45359d7a21644793de0e29de497ef7f1ae7268e346c4faf87b421fea364e6",
|
||||||
"sha256:780b48456a0f0ba4d390e8b5f7c661fdd218934388cde1a974010a965e200e12",
|
"sha256:6db1b52c6f2c04fafc8da17ea506608e6be7086715dab498570c3e55e4f8fbd1",
|
||||||
"sha256:788aef3549f1924d5c38263104dae7395bf020a42776d5ec5ea2b0d3d85d6646",
|
"sha256:752e7ddfb743344d447367baa85bccd3629c2c3940f70506eb5f01abce98ee68",
|
||||||
"sha256:7ee1227cf08b6716c85504aebc49ac827eb88fcc6e51564f010f11a406c0a667",
|
"sha256:760c54ad1b8a9b81951030a7e8e7c3ec0964c1cb9fee585a03ff53d9e531bb8e",
|
||||||
"sha256:7f301b11b9d214f83ddaf689181051e7f48905568b0c7017c04c06dfd065e244",
|
"sha256:768632fd8172ae03852e3245f11c8a425d95f65ff444ce46b3e673ae5b057b74",
|
||||||
"sha256:83ee89483672b11f8952b158640d0c0ff02dc43d9cb1b70c1564b49abe92ce29",
|
"sha256:7a0b9f6a1a15d494b35f25ed07abda03209fa76c33564c09c9e81d34f4b919d7",
|
||||||
"sha256:85bfa6a5413be0ee6c5c4a663668a2cad2cbecdee367630d097d7823041bdeec",
|
"sha256:7e070d3aef50ac3856f2ef5ec7214798453da878bb5e5a16c16a61edf1817cc3",
|
||||||
"sha256:9345b6f7ee578bad8e475129ed40123d265464c4cfead6c261fd60fc9de00bcf",
|
"sha256:7e12949e5071c20ec49ef00c75121ed2b076972132fc1913ddf5f76cae8d10b4",
|
||||||
"sha256:93a5051fcf5fad72de73b96f07d30bc29665697fb8ecdfbc474f3452c78adcf4",
|
"sha256:7e26eac9e52e8ce86f915fd33380f1b6896a2b51994e40bb094841e5003429b4",
|
||||||
"sha256:962b9a917dd7ceacbe5cd424556914cb0d636001e393b43dc886ba31d2a1e449",
|
"sha256:85ffd6b1cb0dfb037ede50ff3bef80d9bf7fa60515d192403af6745524524f3b",
|
||||||
"sha256:96fc32c16ea6d60d3ca7f63397bff5c75c5a562f7db6dec7d412f7c4d2e78ec0",
|
"sha256:8618d9213a863c468a865e9d2ec50221015f7abf52221bc927152ef26c484b4c",
|
||||||
"sha256:98ba568e8ae26beb726aeea2273053c717641933836568c2a0278a84987b2a1a",
|
"sha256:8acef4d8a4353f6678fd1035422a937c2170de58a2b29f7da045d5249e934101",
|
||||||
"sha256:a3feefd5e95871872673b08636f96b61ebef62971eab044f5124fb4dea39919d",
|
"sha256:8d2f355a951f60f0843f2368b39970e4667517e54e86b1508e76f92b44811a8a",
|
||||||
"sha256:a955b747d620a50408b7fdf948e04359d6e762ff8a85f5775d907ceced715129",
|
"sha256:90b6840b6448203228a9d8464a7a0d99aa8fa9f027ef95fe230579abaf8a6ee1",
|
||||||
"sha256:b43c2b8a330a490daaef5a47ab114935002b13b3f9dc5da56d5322ff218eeadb",
|
"sha256:9187500d83fd0cef4669385cbb0961e227a41c0c9bc39219044e35810793edf7",
|
||||||
"sha256:b483c9d00a565633c87abd0aaf27eb5016de23fed952e054ecc19ce32f6a9e7e",
|
"sha256:93c20777a72cae8620203ac11c4010365706062aa13aaedd1a21bb07adbb9d5d",
|
||||||
"sha256:b9ed0b1e5e0759d6b7f8e2f143894b2a7f3edd313f38cf44e1e15d360e11749b",
|
"sha256:93cce7d422a0093cfb3606beae38a8e47a25232eea0f292c878af580a9dc7605",
|
||||||
"sha256:ba05430e819e58544e840a68b03b28b6d328aff2e41579037e8bab7653b37d83",
|
"sha256:94c623c331a48a5ccc7d25271399aff29729fa202c737ae3b4b28b89d2b0976d",
|
||||||
"sha256:ca49e1ab99593438b204e00f3970e7a5f70d045267051dfa6b5f4304fcfa1dbf",
|
"sha256:97f32dc03a8054a4c4a5ab5d761ed4861e828b2c200febd4e46857069a483916",
|
||||||
"sha256:ca5f18a75e1256ce07494e245cdb146f5a9267d3c702ebf9b65c7f8bd843431e",
|
"sha256:9a2bf98ac92f58777c0fafc772bf0493e67fcf677302e0c0a630ee517a43b949",
|
||||||
"sha256:cd410a1cbb2d297c67d8521759ab2ee3f1d66206d2e4328502a487589a2cb21b",
|
"sha256:a602bdc8607c99eb5b391592d58c92618dcd1537fdd87df1813f03fed49957a6",
|
||||||
"sha256:ce298e3d0c65bd03fa65ffcc6db0e2b578e8f626d468db64fdf8457731052942",
|
"sha256:a9d24b03daf7415f78abc2d25a208f234e2c585e5e6f92f0204d2ab7b9ab48e3",
|
||||||
"sha256:d5ca078bb666c4a9d1287a379fe617a6dccd18c3e8a7e6c7e1eb8974330c626a",
|
"sha256:abfcb0ef78df0ee9df4ea81f03beea41849340ce33a4c4bd4dbb99e23ec781b6",
|
||||||
"sha256:d5fd67df77bab0d3f4ea1d7afca9ef15c2ee35dfb348c7b57ffb9782a6e4db6e",
|
"sha256:b013f759cd69cb0a62de954d6d2096d648bc210034b79b1881406b07ed0a83f9",
|
||||||
"sha256:da1a90c1ddb7531b1d5ff1e171b4ee61f6345119be7351104b67ff413843fe94",
|
"sha256:b02e3e72665cd02afafb933453b0c9f6c59ff6e3708bd28d0d8580450e7e88af",
|
||||||
"sha256:dba70f30fd81f8ce6d32ddeef37d91c8948e5d5a4c63242d16a2b2df8143aafc",
|
"sha256:b52cc45e71657bc4743a5606d9023459de929b2a198d545868e11898ba1c3f59",
|
||||||
"sha256:dc07f021ee80510f3cd3af2cad5b6a3b3a10b057521d9e6aaeb621730d320c5a",
|
"sha256:ba37f11e1d020969e8a779c06b4af866ffb6b854d7229db63c5fdddfceaa917f",
|
||||||
"sha256:dd33eb9bdcfbabab3459c9ee651d94c842bc8a05fabc95edf4ee0c15a072495e",
|
"sha256:bb804c7d0bfbd7e3f33924ff49757de9106c44e27979e2492819c16972ec0da2",
|
||||||
"sha256:e0538c43565ee6e703d3a7c3bdfe4037a5209250e8502c98f20fea6f5fdf2965",
|
"sha256:bf594cc7cc9d528338d66674c10a5b25e3cde7dd75c3e96784df8f371d77a298",
|
||||||
"sha256:e1f54b9b4b6c53369f40028d2dd07a8c374583417ee6ec0ea304e710a20f80a0",
|
"sha256:c38baee6bdb7fe1b110b6b3aaa555e6e872d322206b7245aa39572d3fc991ee4",
|
||||||
"sha256:e32d2a2b02ccbef10145df9135751abea1f9f076e67a4e261b05f24b94219e36",
|
"sha256:c73d2166e4b210b73d1429c4f1ca97cea9cc090e5302df2a7a0a96ce55373f1c",
|
||||||
"sha256:e6096b0688e6e14af6a1b10eaad86b4ff17935c49aa774eac7c95a57a4e8c296",
|
"sha256:c9099bf89078675c372339011ccfc9ec310310bf6c292b413c013eb90ffdcafc",
|
||||||
"sha256:e71255ba42567d34a13c03968736c5d39bb4a97ce98188fafb27ce981115beec",
|
"sha256:cf0db26a1f76aa6b3aa314a74b8facd586b7a5457d05b64f8082a62c9c49582a",
|
||||||
"sha256:ed2e07c6a26ed4bea91b897ee2b0835c21716d9a469a96c3e878dc5f8c55bb23",
|
"sha256:d19a34f8a3429bd536996ad53597b805c10352a8561d8382e05830df389d2b43",
|
||||||
"sha256:eef2afb0fd1747f33f1ee3e209bce1ed582d1896b240ccc5e2697e3275f037c7",
|
"sha256:da80047524eac2acf7c04c18ac7a7da05a9136241f642dd2ed94269ef0d0a45a",
|
||||||
"sha256:f23222527b307970e383433daec128d769ff778d9b29343fb3496472dc20dabe",
|
"sha256:de2923886b5d3214be951bc2ce3f6b8ac0d6dfd4a0d0e2a4d2e5523d8046fdfb",
|
||||||
"sha256:f341ee2df0999bfdf7a95e448075effe0db212a59387de1a70690e4acb03d4c6",
|
"sha256:defa0652696ff0ba48c8aff5a1fac1eef1ca6ac9c660b047fc8e7623c4eb5093",
|
||||||
"sha256:f5be7805e53dafe94d295399cfbe5227f39995a997f4fd8539bf3cbdc8f47ca8",
|
"sha256:e54a1eb9fd38f2779e973d2f8958fd575b532fe26013405d1afb9ee2374e7ab8",
|
||||||
"sha256:f7f325be2804246a75a4f45c72d4ce80d2443ab815063cdf70ee8fb2ca59ee1b",
|
"sha256:e5c31d70a478b0ca22a9d2d76d520ae996214019d39ed7dd93af872c7f301e52",
|
||||||
"sha256:f8af619e3be812a2059b212064ea7a640aff0568d972cd1b9e920837469eb3cb",
|
"sha256:ebaeb93f90c0903233b11ce913a7cb8f6ee069158406e056f884854c737d2442",
|
||||||
"sha256:fa8c626d6441e2d04b6ee703ef2d1e17608ad44c7cb75258c09dd42bacdfc64b",
|
"sha256:ecfe51abf7f045e0b9cdde71ca9e153d11238679ef7b5da6c82093874adf3338",
|
||||||
"sha256:fbb9dc00e39f3e6c0ef48edee202f9520dafb233e8b51b06b8428cfcb92abd30",
|
"sha256:f99112aed4fb7cee00c7f77e8b964a9b10f69488cdff626ffd797d02e2e4484f",
|
||||||
"sha256:fff55f3ce50a3ff63ec8e2a8d3dd924f1941b250b0aac3d3d42b687eeff07a8e"
|
"sha256:fd914db437ec25bfa410f8aa0aa2f3ba87cdfc04d9919d608d02330947afaeab"
|
||||||
],
|
],
|
||||||
"version": "==2021.11.10"
|
"version": "==2022.1.18"
|
||||||
|
},
|
||||||
|
"tomli": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f",
|
||||||
|
"sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.6'",
|
||||||
|
"version": "==1.2.3"
|
||||||
},
|
},
|
||||||
"tomlkit": {
|
"tomlkit": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:173ad840fa5d2aac140528ca1933c29791b79a374a0861a80347f42ec9328117",
|
"sha256:29e84a855712dfe0e88a48f6d05c21118dbafb283bb2eed614d46f80deb8e9a1",
|
||||||
"sha256:d7a454f319a7e9bd2e249f239168729327e4dd2d27b17dc68be264ad1ce36754"
|
"sha256:b824e3466f1d475b2b5f1c392954c6cb7ea04d64354ff7300dc7c14257dc85db"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
"markers": "python_version >= '3.6' and python_version < '4.0'",
|
||||||
"version": "==0.7.2"
|
"version": "==0.8.0"
|
||||||
},
|
},
|
||||||
"tqdm": {
|
"tqdm": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
@ -440,6 +471,14 @@
|
|||||||
],
|
],
|
||||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
"version": "==4.62.3"
|
"version": "==4.62.3"
|
||||||
|
},
|
||||||
|
"typing-extensions": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e",
|
||||||
|
"sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.6'",
|
||||||
|
"version": "==4.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import sys
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Run administrative tasks."""
|
"""Run administrative tasks."""
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'recmaint.settings.dev')
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "recmaint.settings.dev")
|
||||||
try:
|
try:
|
||||||
from django.core.management import execute_from_command_line
|
from django.core.management import execute_from_command_line
|
||||||
except ImportError as exc:
|
except ImportError as exc:
|
||||||
@ -18,5 +18,5 @@ def main():
|
|||||||
execute_from_command_line(sys.argv)
|
execute_from_command_line(sys.argv)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
@ -11,6 +11,6 @@ import os
|
|||||||
|
|
||||||
from django.core.asgi import get_asgi_application
|
from django.core.asgi import get_asgi_application
|
||||||
|
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'recmaint.settings')
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "recmaint.settings")
|
||||||
|
|
||||||
application = get_asgi_application()
|
application = get_asgi_application()
|
||||||
|
@ -22,61 +22,61 @@ ALLOWED_HOSTS = []
|
|||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
'tasks.apps.TasksConfig',
|
"tasks.apps.TasksConfig",
|
||||||
'rentals.apps.RentalsConfig',
|
"rentals.apps.RentalsConfig",
|
||||||
'widget_tweaks',
|
"widget_tweaks",
|
||||||
'markdownx',
|
"markdownx",
|
||||||
'markdownify',
|
"markdownify",
|
||||||
'recurrence',
|
"recurrence",
|
||||||
'django.contrib.admin',
|
"django.contrib.admin",
|
||||||
'django.contrib.auth',
|
"django.contrib.auth",
|
||||||
'django.contrib.contenttypes',
|
"django.contrib.contenttypes",
|
||||||
'django.contrib.sessions',
|
"django.contrib.sessions",
|
||||||
'django.contrib.messages',
|
"django.contrib.messages",
|
||||||
'django.contrib.staticfiles',
|
"django.contrib.staticfiles",
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
'django.middleware.security.SecurityMiddleware',
|
"django.middleware.security.SecurityMiddleware",
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||||
'django.middleware.common.CommonMiddleware',
|
"django.middleware.common.CommonMiddleware",
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
"django.middleware.csrf.CsrfViewMiddleware",
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
]
|
]
|
||||||
|
|
||||||
ROOT_URLCONF = 'recmaint.urls'
|
ROOT_URLCONF = "recmaint.urls"
|
||||||
|
|
||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
{
|
{
|
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||||
'DIRS': [os.path.join(BASE_DIR, 'templates')],
|
"DIRS": [os.path.join(BASE_DIR, "templates")],
|
||||||
'APP_DIRS': True,
|
"APP_DIRS": True,
|
||||||
'OPTIONS': {
|
"OPTIONS": {
|
||||||
'context_processors': [
|
"context_processors": [
|
||||||
'django.template.context_processors.debug',
|
"django.template.context_processors.debug",
|
||||||
'django.template.context_processors.request',
|
"django.template.context_processors.request",
|
||||||
'django.contrib.auth.context_processors.auth',
|
"django.contrib.auth.context_processors.auth",
|
||||||
'django.contrib.messages.context_processors.messages',
|
"django.contrib.messages.context_processors.messages",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||||
|
|
||||||
WSGI_APPLICATION = 'recmaint.wsgi.application'
|
WSGI_APPLICATION = "recmaint.wsgi.application"
|
||||||
|
|
||||||
|
|
||||||
# Default URL to redirect to after authentication
|
# Default URL to redirect to after authentication
|
||||||
LOGIN_REDIRECT_URL = '/'
|
LOGIN_REDIRECT_URL = "/"
|
||||||
|
|
||||||
# Internationalization
|
# Internationalization
|
||||||
# https://docs.djangoproject.com/en/3.1/topics/i18n/
|
# https://docs.djangoproject.com/en/3.1/topics/i18n/
|
||||||
|
|
||||||
LANGUAGE_CODE = 'en-us'
|
LANGUAGE_CODE = "en-us"
|
||||||
TIME_ZONE = 'America/New_York'
|
TIME_ZONE = "America/New_York"
|
||||||
USE_I18N = False
|
USE_I18N = False
|
||||||
USE_L10N = True
|
USE_L10N = True
|
||||||
USE_TZ = True
|
USE_TZ = True
|
||||||
@ -85,4 +85,4 @@ USE_TZ = True
|
|||||||
# Static files (CSS, JavaScript, Images)
|
# Static files (CSS, JavaScript, Images)
|
||||||
# https://docs.djangoproject.com/en/3.1/howto/static-files/
|
# https://docs.djangoproject.com/en/3.1/howto/static-files/
|
||||||
|
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = "/static/"
|
||||||
|
@ -4,7 +4,7 @@ from .base import *
|
|||||||
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
|
||||||
|
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
SECRET_KEY = 'g&zqf68eks@z$ctb%3_5+retmt%_i0=)7-y$i^gvc6p#s1+*ng'
|
SECRET_KEY = "g&zqf68eks@z$ctb%3_5+retmt%_i0=)7-y$i^gvc6p#s1+*ng"
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
@ -13,8 +13,8 @@ DEBUG = True
|
|||||||
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
|
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
|
||||||
|
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {
|
"default": {
|
||||||
'ENGINE': 'django.db.backends.sqlite3',
|
"ENGINE": "django.db.backends.sqlite3",
|
||||||
'NAME': BASE_DIR / 'db.sqlite3',
|
"NAME": BASE_DIR / "db.sqlite3",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,26 +11,26 @@ DEBUG = False
|
|||||||
# "AUTH_LDAP_SERVER_URI", "AUTH_LDAP_BIND_DN", and "AUTH_LDAP_BIND_PASSWORD" set in prod.py
|
# "AUTH_LDAP_SERVER_URI", "AUTH_LDAP_BIND_DN", and "AUTH_LDAP_BIND_PASSWORD" set in prod.py
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = [
|
AUTHENTICATION_BACKENDS = [
|
||||||
'django_auth_ldap.backend.LDAPBackend',
|
"django_auth_ldap.backend.LDAPBackend",
|
||||||
'django.contrib.auth.backends.ModelBackend',
|
"django.contrib.auth.backends.ModelBackend",
|
||||||
]
|
]
|
||||||
|
|
||||||
AUTH_LDAP_USER_SEARCH = LDAPSearch(
|
AUTH_LDAP_USER_SEARCH = LDAPSearch(
|
||||||
'cn=users,dc=sawtooth,dc=claremontmakerspace,dc=org',
|
"cn=users,dc=sawtooth,dc=claremontmakerspace,dc=org",
|
||||||
ldap.SCOPE_SUBTREE,
|
ldap.SCOPE_SUBTREE,
|
||||||
'(uid=%(user)s)',
|
"(uid=%(user)s)",
|
||||||
)
|
)
|
||||||
|
|
||||||
AUTH_LDAP_USER_ATTR_MAP = {
|
AUTH_LDAP_USER_ATTR_MAP = {
|
||||||
'first_name': 'givenName',
|
"first_name": "givenName",
|
||||||
'last_name': 'sn',
|
"last_name": "sn",
|
||||||
'email': 'mail',
|
"email": "mail",
|
||||||
}
|
}
|
||||||
|
|
||||||
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
|
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
|
||||||
'cn=groups,dc=sawtooth,dc=claremontmakerspace,dc=org',
|
"cn=groups,dc=sawtooth,dc=claremontmakerspace,dc=org",
|
||||||
ldap.SCOPE_SUBTREE,
|
ldap.SCOPE_SUBTREE,
|
||||||
'(objectClass=posixGroup)',
|
"(objectClass=posixGroup)",
|
||||||
)
|
)
|
||||||
AUTH_LDAP_GROUP_TYPE = PosixGroupType()
|
AUTH_LDAP_GROUP_TYPE = PosixGroupType()
|
||||||
AUTH_LDAP_MIRROR_GROUPS = True
|
AUTH_LDAP_MIRROR_GROUPS = True
|
||||||
|
@ -19,17 +19,30 @@ from django.urls import include, path
|
|||||||
from django.contrib.auth.views import LoginView, LogoutView
|
from django.contrib.auth.views import LoginView, LogoutView
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', lambda request: redirect('/tasks/')),
|
path("", lambda request: redirect("/tasks/")),
|
||||||
path('tasks/', include('tasks.urls')),
|
path("tasks/", include("tasks.urls")),
|
||||||
path('rentals/', include('rentals.urls')),
|
path("rentals/", include("rentals.urls")),
|
||||||
path('admin/', admin.site.urls),
|
path("admin/", admin.site.urls),
|
||||||
path('auth/', include([
|
path(
|
||||||
path('login/', LoginView.as_view(
|
"auth/",
|
||||||
template_name="auth/login.dj.html",
|
include(
|
||||||
redirect_authenticated_user=True), name='login'),
|
[
|
||||||
path('logout/', LogoutView.as_view(template_name="auth/logout.dj.html"), name='logout'),
|
path(
|
||||||
])),
|
"login/",
|
||||||
path('markdownx/', include('markdownx.urls')),
|
LoginView.as_view(
|
||||||
|
template_name="auth/login.dj.html",
|
||||||
|
redirect_authenticated_user=True,
|
||||||
|
),
|
||||||
|
name="login",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"logout/",
|
||||||
|
LogoutView.as_view(template_name="auth/logout.dj.html"),
|
||||||
|
name="logout",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
),
|
||||||
|
path("markdownx/", include("markdownx.urls")),
|
||||||
]
|
]
|
||||||
|
@ -11,6 +11,6 @@ import os
|
|||||||
|
|
||||||
from django.core.wsgi import get_wsgi_application
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'recmaint.settings')
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "recmaint.settings")
|
||||||
|
|
||||||
application = get_wsgi_application()
|
application = get_wsgi_application()
|
||||||
|
@ -2,13 +2,16 @@ from django.contrib import admin
|
|||||||
|
|
||||||
from .models import LockerBank, LockerRental
|
from .models import LockerBank, LockerRental
|
||||||
|
|
||||||
|
|
||||||
class LockerRentalInline(admin.TabularInline):
|
class LockerRentalInline(admin.TabularInline):
|
||||||
model = LockerRental
|
model = LockerRental
|
||||||
extra = 0
|
extra = 0
|
||||||
|
|
||||||
|
|
||||||
@admin.register(LockerBank)
|
@admin.register(LockerBank)
|
||||||
class LockerBankAdmin(admin.ModelAdmin):
|
class LockerBankAdmin(admin.ModelAdmin):
|
||||||
inlines = [LockerRentalInline]
|
inlines = [LockerRentalInline]
|
||||||
prepopulated_fields = {"slug": ("name",)}
|
prepopulated_fields = {"slug": ("name",)}
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(LockerRental)
|
admin.site.register(LockerRental)
|
||||||
|
@ -2,5 +2,5 @@ from django.apps import AppConfig
|
|||||||
|
|
||||||
|
|
||||||
class RentalsConfig(AppConfig):
|
class RentalsConfig(AppConfig):
|
||||||
default_auto_field = 'django.db.models.BigAutoField'
|
default_auto_field = "django.db.models.BigAutoField"
|
||||||
name = 'rentals'
|
name = "rentals"
|
||||||
|
@ -22,11 +22,15 @@ class LockerBank(models.Model):
|
|||||||
for row in range(self.rows):
|
for row in range(self.rows):
|
||||||
for column in range(self.columns):
|
for column in range(self.columns):
|
||||||
# TODO: filter could be optimized
|
# TODO: filter could be optimized
|
||||||
yield chr(row + ord('A')), column + 1, self.rentals.filter(row=row, column=column)
|
yield chr(row + ord("A")), column + 1, self.rentals.filter(
|
||||||
|
row=row, column=column
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class LockerRental(models.Model):
|
class LockerRental(models.Model):
|
||||||
locker_bank = models.ForeignKey(LockerBank, on_delete=models.CASCADE, related_name="rentals")
|
locker_bank = models.ForeignKey(
|
||||||
|
LockerBank, on_delete=models.CASCADE, related_name="rentals"
|
||||||
|
)
|
||||||
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
|
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
|
||||||
row = models.PositiveIntegerField()
|
row = models.PositiveIntegerField()
|
||||||
column = models.PositiveIntegerField()
|
column = models.PositiveIntegerField()
|
||||||
|
@ -2,4 +2,4 @@ from django.apps import AppConfig
|
|||||||
|
|
||||||
|
|
||||||
class TasksConfig(AppConfig):
|
class TasksConfig(AppConfig):
|
||||||
name = 'tasks'
|
name = "tasks"
|
||||||
|
@ -5,20 +5,21 @@ from markdownx.widgets import MarkdownxWidget
|
|||||||
|
|
||||||
from .models import Event
|
from .models import Event
|
||||||
|
|
||||||
|
|
||||||
class EventForm(forms.ModelForm):
|
class EventForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Event
|
model = Event
|
||||||
fields = ['date', 'user', 'notes']
|
fields = ["date", "user", "notes"]
|
||||||
widgets = {
|
widgets = {
|
||||||
'notes': MarkdownxWidget(attrs={'rows': 2}),
|
"notes": MarkdownxWidget(attrs={"rows": 2}),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
user = kwargs.pop('user')
|
user = kwargs.pop("user")
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
self.fields['date'].initial = datetime.now()
|
self.fields["date"].initial = datetime.now()
|
||||||
self.fields['user'].initial = user
|
self.fields["user"].initial = user
|
||||||
if not user.is_staff:
|
if not user.is_staff:
|
||||||
print(list(self.fields['user'].choices))
|
print(list(self.fields["user"].choices))
|
||||||
self.fields['user'].choices = [(user.id, user)]
|
self.fields["user"].choices = [(user.id, user)]
|
||||||
|
@ -4,13 +4,13 @@ from django_auth_ldap.backend import LDAPBackend
|
|||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = 'Import a user from LDAP by username'
|
help = "Import a user from LDAP by username"
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
parser.add_argument('username', type=str)
|
parser.add_argument("username", type=str)
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
username = options['username']
|
username = options["username"]
|
||||||
user = LDAPBackend().populate_user(username)
|
user = LDAPBackend().populate_user(username)
|
||||||
if user is None:
|
if user is None:
|
||||||
raise Exception(f"No user named {username}")
|
raise Exception(f"No user named {username}")
|
||||||
|
@ -8,7 +8,7 @@ from tasks.models import Tool, Task, Event, GroupToolSubscription, GroupTaskSubs
|
|||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = 'Sends any notifications for upcoming and overdue tasks'
|
help = "Sends any notifications for upcoming and overdue tasks"
|
||||||
|
|
||||||
def _active_task_subscriptions(self):
|
def _active_task_subscriptions(self):
|
||||||
for subscription in GroupTaskSubscription.objects.all():
|
for subscription in GroupTaskSubscription.objects.all():
|
||||||
@ -34,29 +34,40 @@ class Command(BaseCommand):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
template = loader.get_template('tasks/notificationEmail.txt.dtl')
|
template = loader.get_template("tasks/notificationEmail.txt.dtl")
|
||||||
|
|
||||||
group_subscriptions = self._active_task_subscriptions()
|
group_subscriptions = self._active_task_subscriptions()
|
||||||
subscriptions_per_user = self._expand_group_subscriptions_to_users(group_subscriptions)
|
subscriptions_per_user = self._expand_group_subscriptions_to_users(
|
||||||
|
group_subscriptions
|
||||||
|
)
|
||||||
|
|
||||||
for user, subscriptions in subscriptions_per_user.items():
|
for user, subscriptions in subscriptions_per_user.items():
|
||||||
if not user.email:
|
if not user.email:
|
||||||
self.stdout.write(self.style.ERROR(
|
self.stdout.write(
|
||||||
f"Can't send email, user '{user}' is missing an email address"))
|
self.style.ERROR(
|
||||||
|
f"Can't send email, user '{user}' is missing an email address"
|
||||||
|
)
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self.stdout.write(self.style.SUCCESS(
|
self.stdout.write(
|
||||||
f'Sending notification for {len(subscriptions)} task(s) to {user}'))
|
self.style.SUCCESS(
|
||||||
|
f"Sending notification for {len(subscriptions)} task(s) to {user}"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
send_mail(
|
send_mail(
|
||||||
subject=f'[CMS Tool Maintenance] {len(subscriptions)} tasks are upcoming or overdue!',
|
subject=f"[CMS Tool Maintenance] {len(subscriptions)} tasks are upcoming or overdue!",
|
||||||
message=template.render({'subscriptions': subscriptions}).strip(),
|
message=template.render({"subscriptions": subscriptions}).strip(),
|
||||||
from_email='adam@adamgoldsmith.name',
|
from_email="adam@adamgoldsmith.name",
|
||||||
recipient_list=[user.email],
|
recipient_list=[user.email],
|
||||||
fail_silently=False
|
fail_silently=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.stdout.write(self.style.ERROR(
|
self.stdout.write(
|
||||||
f"Failed to send mail for user '{user}': {type(e).__name__}: {e}"))
|
self.style.ERROR(
|
||||||
|
f"Failed to send mail for user '{user}': {type(e).__name__}: {e}"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
@ -7,6 +7,7 @@ from django.urls import reverse
|
|||||||
from markdownx.models import MarkdownxField
|
from markdownx.models import MarkdownxField
|
||||||
from recurrence.fields import RecurrenceField
|
from recurrence.fields import RecurrenceField
|
||||||
|
|
||||||
|
|
||||||
class Tool(models.Model):
|
class Tool(models.Model):
|
||||||
name = models.CharField(max_length=200)
|
name = models.CharField(max_length=200)
|
||||||
slug = models.SlugField(unique=True)
|
slug = models.SlugField(unique=True)
|
||||||
@ -16,7 +17,7 @@ class Tool(models.Model):
|
|||||||
return f"{self.name}{(' - ' + self.asset_tag) if self.asset_tag else ''}"
|
return f"{self.name}{(' - ' + self.asset_tag) if self.asset_tag else ''}"
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('toolDetail', args=[self.slug])
|
return reverse("toolDetail", args=[self.slug])
|
||||||
|
|
||||||
|
|
||||||
class Task(models.Model):
|
class Task(models.Model):
|
||||||
@ -34,21 +35,23 @@ class Task(models.Model):
|
|||||||
return f"{self.tool.name}: {self.name}"
|
return f"{self.tool.name}: {self.name}"
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('taskDetail', args=[self.tool.slug, self.slug])
|
return reverse("taskDetail", args=[self.tool.slug, self.slug])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def last_event(self):
|
def last_event(self):
|
||||||
return self.event_set.latest('date')
|
return self.event_set.latest("date")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def next_recurrence(self):
|
def next_recurrence(self):
|
||||||
def _date_to_datetime(date):
|
def _date_to_datetime(date):
|
||||||
return datetime.datetime.combine(date, datetime.time.min)
|
return datetime.datetime.combine(date, datetime.time.min)
|
||||||
|
|
||||||
if self.recurrence_base is None: # relative date
|
if self.recurrence_base is None: # relative date
|
||||||
try:
|
try:
|
||||||
return self.recurrence.after(
|
return self.recurrence.after(
|
||||||
_date_to_datetime(self.last_event.date),
|
_date_to_datetime(self.last_event.date),
|
||||||
dtstart=_date_to_datetime(self.last_event.date))
|
dtstart=_date_to_datetime(self.last_event.date),
|
||||||
|
)
|
||||||
except Event.DoesNotExist:
|
except Event.DoesNotExist:
|
||||||
return None
|
return None
|
||||||
else: # absolute date
|
else: # absolute date
|
||||||
@ -83,9 +86,8 @@ class GroupToolSubscription(SubscriptionSettings):
|
|||||||
def get_task_subscriptions(self):
|
def get_task_subscriptions(self):
|
||||||
for task in self.tool.task_set.all():
|
for task in self.tool.task_set.all():
|
||||||
yield GroupTaskSubscription(
|
yield GroupTaskSubscription(
|
||||||
days_before=self.days_before,
|
days_before=self.days_before, group=self.group, task=task
|
||||||
group=self.group,
|
)
|
||||||
task=task)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = (("group", "tool"),)
|
unique_together = (("group", "tool"),)
|
||||||
|
@ -4,11 +4,14 @@ from django.urls import path
|
|||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', views.index, name='index'),
|
path("", views.index, name="index"),
|
||||||
# ex: /CMS00001/
|
# ex: /CMS00001/
|
||||||
path('<str:tool_slug>/', views.toolDetail, name='toolDetail'),
|
path("<str:tool_slug>/", views.toolDetail, name="toolDetail"),
|
||||||
# ex: /CMS00001/tasks/
|
# ex: /CMS00001/tasks/
|
||||||
path('<str:tool_slug>/tasks/', lambda request, tool_slug: redirect('toolDetail', tool_slug)),
|
path(
|
||||||
|
"<str:tool_slug>/tasks/",
|
||||||
|
lambda request, tool_slug: redirect("toolDetail", tool_slug),
|
||||||
|
),
|
||||||
# ex: /CMS00001/tasks/task_name/
|
# ex: /CMS00001/tasks/task_name/
|
||||||
path('<str:tool_slug>/tasks/<str:task_slug>', views.taskDetail, name='taskDetail'),
|
path("<str:tool_slug>/tasks/<str:task_slug>", views.taskDetail, name="taskDetail"),
|
||||||
]
|
]
|
||||||
|
@ -7,10 +7,10 @@ from .forms import EventForm
|
|||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
context = {
|
context = {
|
||||||
'tools': Tool.objects.all(),
|
"tools": Tool.objects.all(),
|
||||||
'tasks': Task.objects.all(),
|
"tasks": Task.objects.all(),
|
||||||
}
|
}
|
||||||
return render(request, 'tasks/index.dj.html', context)
|
return render(request, "tasks/index.dj.html", context)
|
||||||
|
|
||||||
|
|
||||||
def toolDetail(request, tool_slug):
|
def toolDetail(request, tool_slug):
|
||||||
@ -18,11 +18,11 @@ def toolDetail(request, tool_slug):
|
|||||||
tasks = tool.task_set.all()
|
tasks = tool.task_set.all()
|
||||||
events = Event.objects.filter(task__tool=tool)
|
events = Event.objects.filter(task__tool=tool)
|
||||||
context = {
|
context = {
|
||||||
'tool': tool,
|
"tool": tool,
|
||||||
'tasks': tasks,
|
"tasks": tasks,
|
||||||
'events': events,
|
"events": events,
|
||||||
}
|
}
|
||||||
return render(request, 'tasks/toolDetail.dj.html', context)
|
return render(request, "tasks/toolDetail.dj.html", context)
|
||||||
|
|
||||||
|
|
||||||
def taskDetail(request, tool_slug, task_slug):
|
def taskDetail(request, tool_slug, task_slug):
|
||||||
@ -30,7 +30,7 @@ def taskDetail(request, tool_slug, task_slug):
|
|||||||
task = get_object_or_404(tool.task_set, slug=task_slug)
|
task = get_object_or_404(tool.task_set, slug=task_slug)
|
||||||
events = task.event_set.all()
|
events = task.event_set.all()
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == "POST":
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
event = Event(task=task)
|
event = Event(task=task)
|
||||||
form = EventForm(request.POST, user=request.user, instance=event)
|
form = EventForm(request.POST, user=request.user, instance=event)
|
||||||
@ -44,15 +44,21 @@ def taskDetail(request, tool_slug, task_slug):
|
|||||||
form = EventForm(user=request.user)
|
form = EventForm(user=request.user)
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'tool': tool,
|
"tool": tool,
|
||||||
'task': task,
|
"task": task,
|
||||||
'events': events,
|
"events": events,
|
||||||
'form': form,
|
"form": form,
|
||||||
}
|
}
|
||||||
|
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
context.update({
|
context.update(
|
||||||
'task_subs': task.grouptasksubscription_set.filter(group__user=request.user),
|
{
|
||||||
'tool_subs': tool.grouptoolsubscription_set.filter(group__user=request.user),
|
"task_subs": task.grouptasksubscription_set.filter(
|
||||||
})
|
group__user=request.user
|
||||||
return render(request, 'tasks/taskDetail.dj.html', context)
|
),
|
||||||
|
"tool_subs": tool.grouptoolsubscription_set.filter(
|
||||||
|
group__user=request.user
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return render(request, "tasks/taskDetail.dj.html", context)
|
||||||
|
Loading…
Reference in New Issue
Block a user