Merge pull request #2 from lemeow125/feature/geofencing

Feature/geofencing
This commit is contained in:
lemeow125 2023-07-19 15:51:20 +08:00 committed by GitHub
commit 7d47cf79d9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
66 changed files with 1331 additions and 498 deletions

View file

@ -11,6 +11,11 @@ djoser = "*"
pillow = "*" pillow = "*"
whitenoise = "*" whitenoise = "*"
djangochannelsrestframework = "*" djangochannelsrestframework = "*"
daphne = "*"
psycopg2 = "*"
gdal = {path = "./packages/GDAL-3.4.3-cp311-cp311-win_amd64.whl"}
django-leaflet = "*"
django-extra-fields = "*"
[dev-packages] [dev-packages]

551
Pipfile.lock generated
View file

@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "231f11224ec1ef1ad1406ac5644ebcdfac020af9478f407d577553bb05c637df" "sha256": "975af7eaaedebb1c31a1828fdf307574edc293e0de15ecfd9cf7107f98d642f5"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
@ -24,6 +24,28 @@
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==3.7.2" "version": "==3.7.2"
}, },
"attrs": {
"hashes": [
"sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04",
"sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"
],
"markers": "python_version >= '3.7'",
"version": "==23.1.0"
},
"autobahn": {
"hashes": [
"sha256:ec9421c52a2103364d1ef0468036e6019ee84f71721e86b36fe19ad6966c1181"
],
"markers": "python_version >= '3.9'",
"version": "==23.6.2"
},
"automat": {
"hashes": [
"sha256:c3164f8742b9dc440f3682482d32aaff7bb53f71740dd018533f9de286b64180",
"sha256:e56beb84edad19dcc11d30e8d9b895f75deeb5ef5e96b84a467066b3b84bb04e"
],
"version": "==22.10.0"
},
"certifi": { "certifi": {
"hashes": [ "hashes": [
"sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7", "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7",
@ -111,109 +133,128 @@
}, },
"charset-normalizer": { "charset-normalizer": {
"hashes": [ "hashes": [
"sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6", "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96",
"sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1", "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c",
"sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e", "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710",
"sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373", "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706",
"sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62", "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020",
"sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230", "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252",
"sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be", "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad",
"sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c", "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329",
"sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0", "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a",
"sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448", "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f",
"sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f", "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6",
"sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649", "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4",
"sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d", "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a",
"sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0", "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46",
"sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706", "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2",
"sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a", "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23",
"sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59", "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace",
"sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23", "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd",
"sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5", "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982",
"sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb", "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10",
"sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e", "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2",
"sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e", "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea",
"sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c", "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09",
"sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28", "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5",
"sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d", "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149",
"sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41", "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489",
"sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974", "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9",
"sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce", "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80",
"sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f", "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592",
"sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1", "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3",
"sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d", "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6",
"sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8", "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed",
"sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017", "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c",
"sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31", "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200",
"sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7", "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a",
"sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8", "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e",
"sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e", "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d",
"sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14", "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6",
"sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd", "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623",
"sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d", "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669",
"sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795", "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3",
"sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b", "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa",
"sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b", "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9",
"sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b", "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2",
"sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203", "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f",
"sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f", "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1",
"sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19", "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4",
"sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1", "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a",
"sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a", "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8",
"sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac", "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3",
"sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9", "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029",
"sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0", "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f",
"sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137", "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959",
"sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f", "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22",
"sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6", "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7",
"sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5", "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952",
"sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909", "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346",
"sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f", "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e",
"sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0", "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d",
"sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324", "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299",
"sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755", "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd",
"sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb", "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a",
"sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854", "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3",
"sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c", "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037",
"sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60", "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94",
"sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84", "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c",
"sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0", "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858",
"sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b", "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a",
"sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1", "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449",
"sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531", "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c",
"sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1", "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918",
"sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11", "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1",
"sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326", "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c",
"sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df", "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac",
"sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab" "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"
], ],
"markers": "python_full_version >= '3.7.0'", "markers": "python_full_version >= '3.7.0'",
"version": "==3.1.0" "version": "==3.2.0"
},
"constantly": {
"hashes": [
"sha256:586372eb92059873e29eba4f9dec8381541b4d3834660707faf8ba59146dfc35",
"sha256:dd2fa9d6b1a51a83f0d7dd76293d734046aa176e384bf6e33b7e44880eb37c5d"
],
"version": "==15.1.0"
}, },
"cryptography": { "cryptography": {
"hashes": [ "hashes": [
"sha256:059e348f9a3c1950937e1b5d7ba1f8e968508ab181e75fc32b879452f08356db", "sha256:01f1d9e537f9a15b037d5d9ee442b8c22e3ae11ce65ea1f3316a41c78756b711",
"sha256:1a5472d40c8f8e91ff7a3d8ac6dfa363d8e3138b961529c996f3e2df0c7a411a", "sha256:079347de771f9282fbfe0e0236c716686950c19dee1b76240ab09ce1624d76d7",
"sha256:1a8e6c2de6fbbcc5e14fd27fb24414507cb3333198ea9ab1258d916f00bc3039", "sha256:182be4171f9332b6741ee818ec27daff9fb00349f706629f5cbf417bd50e66fd",
"sha256:1fee5aacc7367487b4e22484d3c7e547992ed726d14864ee33c0176ae43b0d7c", "sha256:192255f539d7a89f2102d07d7375b1e0a81f7478925b3bc2e0549ebf739dae0e",
"sha256:5d092fdfedaec4cbbffbf98cddc915ba145313a6fdaab83c6e67f4e6c218e6f3", "sha256:2a034bf7d9ca894720f2ec1d8b7b5832d7e363571828037f9e0c4f18c1b58a58",
"sha256:5f0ff6e18d13a3de56f609dd1fd11470918f770c6bd5d00d632076c727d35485", "sha256:342f3767e25876751e14f8459ad85e77e660537ca0a066e10e75df9c9e9099f0",
"sha256:7bfc55a5eae8b86a287747053140ba221afc65eb06207bedf6e019b8934b477c", "sha256:439c3cc4c0d42fa999b83ded80a9a1fb54d53c58d6e59234cfe97f241e6c781d",
"sha256:7fa01527046ca5facdf973eef2535a27fec4cb651e4daec4d043ef63f6ecd4ca", "sha256:49c3222bb8f8e800aead2e376cbef687bc9e3cb9b58b29a261210456a7783d83",
"sha256:8dde71c4169ec5ccc1087bb7521d54251c016f126f922ab2dfe6649170a3b8c5", "sha256:674b669d5daa64206c38e507808aae49904c988fa0a71c935e7006a3e1e83831",
"sha256:8f4ab7021127a9b4323537300a2acfb450124b2def3756f64dc3a3d2160ee4b5", "sha256:7a9a3bced53b7f09da251685224d6a260c3cb291768f54954e28f03ef14e3766",
"sha256:948224d76c4b6457349d47c0c98657557f429b4e93057cf5a2f71d603e2fc3a3", "sha256:7af244b012711a26196450d34f483357e42aeddb04128885d95a69bd8b14b69b",
"sha256:9a6c7a3c87d595608a39980ebaa04d5a37f94024c9f24eb7d10262b92f739ddb", "sha256:7d230bf856164de164ecb615ccc14c7fc6de6906ddd5b491f3af90d3514c925c",
"sha256:b46e37db3cc267b4dea1f56da7346c9727e1209aa98487179ee8ebed09d21e43", "sha256:84609ade00a6ec59a89729e87a503c6e36af98ddcd566d5f3be52e29ba993182",
"sha256:b4ceb5324b998ce2003bc17d519080b4ec8d5b7b70794cbd2836101406a9be31", "sha256:9a6673c1828db6270b76b22cc696f40cde9043eb90373da5c2f8f2158957f42f",
"sha256:cb33ccf15e89f7ed89b235cff9d49e2e62c6c981a6061c9c8bb47ed7951190bc", "sha256:9b6d717393dbae53d4e52684ef4f022444fc1cce3c48c38cb74fca29e1f08eaa",
"sha256:d198820aba55660b4d74f7b5fd1f17db3aa5eb3e6893b0a41b75e84e4f9e0e4b", "sha256:9c3fe6534d59d071ee82081ca3d71eed3210f76ebd0361798c74abc2bcf347d4",
"sha256:d34579085401d3f49762d2f7d6634d6b6c2ae1242202e860f4d26b046e3a1006", "sha256:a719399b99377b218dac6cf547b6ec54e6ef20207b6165126a280b0ce97e0d2a",
"sha256:eb8163f5e549a22888c18b0d53d6bb62a20510060a22fd5a995ec8a05268df8a", "sha256:b332cba64d99a70c1e0836902720887fb4529ea49ea7f5462cf6640e095e11d2",
"sha256:f73bff05db2a3e5974a6fd248af2566134d8981fd7ab012e5dd4ddb1d9a70699" "sha256:d124682c7a23c9764e54ca9ab5b308b14b18eba02722b8659fb238546de83a76",
"sha256:d73f419a56d74fef257955f51b18d046f3506270a5fd2ac5febbfa259d6c0fa5",
"sha256:f0dc40e6f7aa37af01aba07277d3d64d5a03dc66d682097541ec4da03cc140ee",
"sha256:f14ad275364c8b4e525d018f6716537ae7b6d369c094805cae45300847e0894f",
"sha256:f772610fe364372de33d76edcd313636a25684edb94cee53fd790195f5989d14"
], ],
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==41.0.1" "version": "==41.0.2"
},
"daphne": {
"hashes": [
"sha256:a288ece46012b6b719c37150be67c69ebfca0793a8521bf821533bad983179b2",
"sha256:cce9afc8f49a4f15d4270b8cfb0e0fe811b770a5cc795474e97e4da287497666"
],
"index": "pypi",
"version": "==4.0.0"
}, },
"defusedxml": { "defusedxml": {
"hashes": [ "hashes": [
@ -225,11 +266,26 @@
}, },
"django": { "django": {
"hashes": [ "hashes": [
"sha256:2a6b6fbff5b59dd07bef10bcb019bee2ea97a30b2a656d51346596724324badf", "sha256:45a747e1c5b3d6df1b141b1481e193b033fd1fdbda3ff52677dc81afdaacbaed",
"sha256:672b3fa81e1f853bb58be1b51754108ab4ffa12a77c06db86aa8df9ed0c46fe5" "sha256:f7c7852a5ac5a3da5a8d5b35cc6168f31b605971441798dac845f17ca8028039"
], ],
"index": "pypi", "index": "pypi",
"version": "==4.2.2" "version": "==4.2.3"
},
"django-extra-fields": {
"hashes": [
"sha256:2334e914b346c0a19a7765bf0ff7895c46cf35d5f40315a68418f44b7ddbb33b"
],
"index": "pypi",
"version": "==3.0.2"
},
"django-leaflet": {
"hashes": [
"sha256:2f6dc8c7187fd22e62b6f2b7b42eed86920f81bec312aa654981ebe5bc8e0866",
"sha256:ea35244539fe298156feafc7f1e2ce63067c8caa2ac6f8344069796b19d1ce9b"
],
"index": "pypi",
"version": "==0.29.0"
}, },
"django-templated-mail": { "django-templated-mail": {
"hashes": [ "hashes": [
@ -270,6 +326,20 @@
"index": "pypi", "index": "pypi",
"version": "==2.2.0" "version": "==2.2.0"
}, },
"gdal": {
"hashes": [
"sha256:f78861fb5115d5c2f8cf3c52a492ff548da9e1256dc84088947379f90e77e5b6"
],
"path": "./packages/GDAL-3.4.3-cp311-cp311-win_amd64.whl",
"version": "==3.4.3"
},
"hyperlink": {
"hashes": [
"sha256:427af957daa58bc909471c6c40f74c5450fa123dd093fc53efd2e91d2705a56b",
"sha256:e6b14c37ecb73e89c77d78cdb4c2cc8f3fb59a885c5b3f819ff4ed80f25af1b4"
],
"version": "==21.0.0"
},
"idna": { "idna": {
"hashes": [ "hashes": [
"sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4",
@ -278,6 +348,13 @@
"markers": "python_version >= '3.5'", "markers": "python_version >= '3.5'",
"version": "==3.4" "version": "==3.4"
}, },
"incremental": {
"hashes": [
"sha256:912feeb5e0f7e0188e6f42241d2f450002e11bbc0937c65865045854c24c0bd0",
"sha256:b864a1f30885ee72c5ac2835a761b8fe8aa9c28b9395cacf27286602688d3e51"
],
"version": "==22.10.0"
},
"oauthlib": { "oauthlib": {
"hashes": [ "hashes": [
"sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca", "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca",
@ -288,75 +365,100 @@
}, },
"pillow": { "pillow": {
"hashes": [ "hashes": [
"sha256:07999f5834bdc404c442146942a2ecadd1cb6292f5229f4ed3b31e0a108746b1", "sha256:00e65f5e822decd501e374b0650146063fbb30a7264b4d2744bdd7b913e0cab5",
"sha256:0852ddb76d85f127c135b6dd1f0bb88dbb9ee990d2cd9aa9e28526c93e794fba", "sha256:040586f7d37b34547153fa383f7f9aed68b738992380ac911447bb78f2abe530",
"sha256:1781a624c229cb35a2ac31cc4a77e28cafc8900733a864870c49bfeedacd106a", "sha256:0b6eb5502f45a60a3f411c63187db83a3d3107887ad0d036c13ce836f8a36f1d",
"sha256:1e7723bd90ef94eda669a3c2c19d549874dd5badaeefabefd26053304abe5799", "sha256:1ce91b6ec08d866b14413d3f0bbdea7e24dfdc8e59f562bb77bc3fe60b6144ca",
"sha256:229e2c79c00e85989a34b5981a2b67aa079fd08c903f0aaead522a1d68d79e51", "sha256:1f62406a884ae75fb2f818694469519fb685cc7eaff05d3451a9ebe55c646891",
"sha256:22baf0c3cf0c7f26e82d6e1adf118027afb325e703922c8dfc1d5d0156bb2eeb", "sha256:22c10cc517668d44b211717fd9775799ccec4124b9a7f7b3635fc5386e584992",
"sha256:252a03f1bdddce077eff2354c3861bf437c892fb1832f75ce813ee94347aa9b5", "sha256:3400aae60685b06bb96f99a21e1ada7bc7a413d5f49bce739828ecd9391bb8f7",
"sha256:2dfaaf10b6172697b9bceb9a3bd7b951819d1ca339a5ef294d1f1ac6d7f63270", "sha256:349930d6e9c685c089284b013478d6f76e3a534e36ddfa912cde493f235372f3",
"sha256:322724c0032af6692456cd6ed554bb85f8149214d97398bb80613b04e33769f6", "sha256:368ab3dfb5f49e312231b6f27b8820c823652b7cd29cfbd34090565a015e99ba",
"sha256:35f6e77122a0c0762268216315bf239cf52b88865bba522999dc38f1c52b9b47", "sha256:38250a349b6b390ee6047a62c086d3817ac69022c127f8a5dc058c31ccef17f3",
"sha256:375f6e5ee9620a271acb6820b3d1e94ffa8e741c0601db4c0c4d3cb0a9c224bf", "sha256:3a684105f7c32488f7153905a4e3015a3b6c7182e106fe3c37fbb5ef3e6994c3",
"sha256:3ded42b9ad70e5f1754fb7c2e2d6465a9c842e41d178f262e08b8c85ed8a1d8e", "sha256:3a82c40d706d9aa9734289740ce26460a11aeec2d9c79b7af87bb35f0073c12f",
"sha256:432b975c009cf649420615388561c0ce7cc31ce9b2e374db659ee4f7d57a1f8b", "sha256:3b08d4cc24f471b2c8ca24ec060abf4bebc6b144cb89cba638c720546b1cf538",
"sha256:482877592e927fd263028c105b36272398e3e1be3269efda09f6ba21fd83ec66", "sha256:3ed64f9ca2f0a95411e88a4efbd7a29e5ce2cea36072c53dd9d26d9c76f753b3",
"sha256:489f8389261e5ed43ac8ff7b453162af39c3e8abd730af8363587ba64bb2e865", "sha256:3f07ea8d2f827d7d2a49ecf1639ec02d75ffd1b88dcc5b3a61bbb37a8759ad8d",
"sha256:54f7102ad31a3de5666827526e248c3530b3a33539dbda27c6843d19d72644ec", "sha256:520f2a520dc040512699f20fa1c363eed506e94248d71f85412b625026f6142c",
"sha256:560737e70cb9c6255d6dcba3de6578a9e2ec4b573659943a5e7e4af13f298f5c", "sha256:5c6e3df6bdd396749bafd45314871b3d0af81ff935b2d188385e970052091017",
"sha256:5671583eab84af046a397d6d0ba25343c00cd50bce03787948e0fff01d4fd9b1", "sha256:608bfdee0d57cf297d32bcbb3c728dc1da0907519d1784962c5f0c68bb93e5a3",
"sha256:5ba1b81ee69573fe7124881762bb4cd2e4b6ed9dd28c9c60a632902fe8db8b38", "sha256:685ac03cc4ed5ebc15ad5c23bc555d68a87777586d970c2c3e216619a5476223",
"sha256:5d4ebf8e1db4441a55c509c4baa7a0587a0210f7cd25fcfe74dbbce7a4bd1906", "sha256:76de421f9c326da8f43d690110f0e79fe3ad1e54be811545d7d91898b4c8493e",
"sha256:60037a8db8750e474af7ffc9faa9b5859e6c6d0a50e55c45576bf28be7419705", "sha256:76edb0a1fa2b4745fb0c99fb9fb98f8b180a1bbceb8be49b087e0b21867e77d3",
"sha256:608488bdcbdb4ba7837461442b90ea6f3079397ddc968c31265c1e056964f1ef", "sha256:7be600823e4c8631b74e4a0d38384c73f680e6105a7d3c6824fcf226c178c7e6",
"sha256:6608ff3bf781eee0cd14d0901a2b9cc3d3834516532e3bd673a0a204dc8615fc", "sha256:81ff539a12457809666fef6624684c008e00ff6bf455b4b89fd00a140eecd640",
"sha256:662da1f3f89a302cc22faa9f14a262c2e3951f9dbc9617609a47521c69dd9f8f", "sha256:88af2003543cc40c80f6fca01411892ec52b11021b3dc22ec3bc9d5afd1c5334",
"sha256:7002d0797a3e4193c7cdee3198d7c14f92c0836d6b4a3f3046a64bd1ce8df2bf", "sha256:8c11160913e3dd06c8ffdb5f233a4f254cb449f4dfc0f8f4549eda9e542c93d1",
"sha256:763782b2e03e45e2c77d7779875f4432e25121ef002a41829d8868700d119392", "sha256:8f8182b523b2289f7c415f589118228d30ac8c355baa2f3194ced084dac2dbba",
"sha256:77165c4a5e7d5a284f10a6efaa39a0ae8ba839da344f20b111d62cc932fa4e5d", "sha256:9211e7ad69d7c9401cfc0e23d49b69ca65ddd898976d660a2fa5904e3d7a9baa",
"sha256:7c9af5a3b406a50e313467e3565fc99929717f780164fe6fbb7704edba0cebbe", "sha256:92be919bbc9f7d09f7ae343c38f5bb21c973d2576c1d45600fce4b74bafa7ac0",
"sha256:7ec6f6ce99dab90b52da21cf0dc519e21095e332ff3b399a357c187b1a5eee32", "sha256:9c82b5b3e043c7af0d95792d0d20ccf68f61a1fec6b3530e718b688422727396",
"sha256:833b86a98e0ede388fa29363159c9b1a294b0905b5128baf01db683672f230f5", "sha256:9f7c16705f44e0504a3a2a14197c1f0b32a95731d251777dcb060aa83022cb2d",
"sha256:84a6f19ce086c1bf894644b43cd129702f781ba5751ca8572f08aa40ef0ab7b7", "sha256:9fb218c8a12e51d7ead2a7c9e101a04982237d4855716af2e9499306728fb485",
"sha256:8507eda3cd0608a1f94f58c64817e83ec12fa93a9436938b191b80d9e4c0fc44", "sha256:a74ba0c356aaa3bb8e3eb79606a87669e7ec6444be352870623025d75a14a2bf",
"sha256:85ec677246533e27770b0de5cf0f9d6e4ec0c212a1f89dfc941b64b21226009d", "sha256:b4f69b3700201b80bb82c3a97d5e9254084f6dd5fb5b16fc1a7b974260f89f43",
"sha256:8aca1152d93dcc27dc55395604dcfc55bed5f25ef4c98716a928bacba90d33a3", "sha256:bc2ec7c7b5d66b8ec9ce9f720dbb5fa4bace0f545acd34870eff4a369b44bf37",
"sha256:8d935f924bbab8f0a9a28404422da8af4904e36d5c33fc6f677e4c4485515625", "sha256:c189af0545965fa8d3b9613cfdb0cd37f9d71349e0f7750e1fd704648d475ed2",
"sha256:8f36397bf3f7d7c6a3abdea815ecf6fd14e7fcd4418ab24bae01008d8d8ca15e", "sha256:c1fbe7621c167ecaa38ad29643d77a9ce7311583761abf7836e1510c580bf3dd",
"sha256:91ec6fe47b5eb5a9968c79ad9ed78c342b1f97a091677ba0e012701add857829", "sha256:c7cf14a27b0d6adfaebb3ae4153f1e516df54e47e42dcc073d7b3d76111a8d86",
"sha256:965e4a05ef364e7b973dd17fc765f42233415974d773e82144c9bbaaaea5d089", "sha256:c9f72a021fbb792ce98306ffb0c348b3c9cb967dce0f12a49aa4c3d3fdefa967",
"sha256:96e88745a55b88a7c64fa49bceff363a1a27d9a64e04019c2281049444a571e3", "sha256:cd25d2a9d2b36fcb318882481367956d2cf91329f6892fe5d385c346c0649629",
"sha256:99eb6cafb6ba90e436684e08dad8be1637efb71c4f2180ee6b8f940739406e78", "sha256:ce543ed15570eedbb85df19b0a1a7314a9c8141a36ce089c0a894adbfccb4568",
"sha256:9adf58f5d64e474bed00d69bcd86ec4bcaa4123bfa70a65ce72e424bfb88ed96", "sha256:ce7b031a6fc11365970e6a5686d7ba8c63e4c1cf1ea143811acbb524295eabed",
"sha256:9b1af95c3a967bf1da94f253e56b6286b50af23392a886720f563c547e48e964", "sha256:d35e3c8d9b1268cbf5d3670285feb3528f6680420eafe35cccc686b73c1e330f",
"sha256:a0aa9417994d91301056f3d0038af1199eb7adc86e646a36b9e050b06f526597", "sha256:d50b6aec14bc737742ca96e85d6d0a5f9bfbded018264b3b70ff9d8c33485551",
"sha256:a0f9bb6c80e6efcde93ffc51256d5cfb2155ff8f78292f074f60f9e70b942d99", "sha256:d5d0dae4cfd56969d23d94dc8e89fb6a217be461c69090768227beb8ed28c0a3",
"sha256:a127ae76092974abfbfa38ca2d12cbeddcdeac0fb71f9627cc1135bedaf9d51a", "sha256:d5db32e2a6ccbb3d34d87c87b432959e0db29755727afb37290e10f6e8e62614",
"sha256:aaf305d6d40bd9632198c766fb64f0c1a83ca5b667f16c1e79e1661ab5060140", "sha256:d72e2ecc68a942e8cf9739619b7f408cc7b272b279b56b2c83c6123fcfa5cdff",
"sha256:aca1c196f407ec7cf04dcbb15d19a43c507a81f7ffc45b690899d6a76ac9fda7", "sha256:d737a602fbd82afd892ca746392401b634e278cb65d55c4b7a8f48e9ef8d008d",
"sha256:ace6ca218308447b9077c14ea4ef381ba0b67ee78d64046b3f19cf4e1139ad16", "sha256:d80cf684b541685fccdd84c485b31ce73fc5c9b5d7523bf1394ce134a60c6883",
"sha256:b416f03d37d27290cb93597335a2f85ed446731200705b22bb927405320de903", "sha256:db24668940f82321e746773a4bc617bfac06ec831e5c88b643f91f122a785684",
"sha256:bf548479d336726d7a0eceb6e767e179fbde37833ae42794602631a070d630f1", "sha256:dbc02381779d412145331789b40cc7b11fdf449e5d94f6bc0b080db0a56ea3f0",
"sha256:c1170d6b195555644f0616fd6ed929dfcf6333b8675fcca044ae5ab110ded296", "sha256:dffe31a7f47b603318c609f378ebcd57f1554a3a6a8effbc59c3c69f804296de",
"sha256:c380b27d041209b849ed246b111b7c166ba36d7933ec6e41175fd15ab9eb1572", "sha256:edf4392b77bdc81f36e92d3a07a5cd072f90253197f4a52a55a8cec48a12483b",
"sha256:c446d2245ba29820d405315083d55299a796695d747efceb5717a8b450324115", "sha256:efe8c0681042536e0d06c11f48cebe759707c9e9abf880ee213541c5b46c5bf3",
"sha256:c830a02caeb789633863b466b9de10c015bded434deb3ec87c768e53752ad22a", "sha256:f31f9fdbfecb042d046f9d91270a0ba28368a723302786c0009ee9b9f1f60199",
"sha256:cb841572862f629b99725ebaec3287fc6d275be9b14443ea746c1dd325053cbd", "sha256:f88a0b92277de8e3ca715a0d79d68dc82807457dae3ab8699c758f07c20b3c51",
"sha256:cfa4561277f677ecf651e2b22dc43e8f5368b74a25a8f7d1d4a3a243e573f2d4", "sha256:faaf07ea35355b01a35cb442dd950d8f1bb5b040a7787791a535de13db15ed90"
"sha256:cfcc2c53c06f2ccb8976fb5c71d448bdd0a07d26d8e07e321c103416444c7ad1",
"sha256:d3c6b54e304c60c4181da1c9dadf83e4a54fd266a99c70ba646a9baa626819eb",
"sha256:d3d403753c9d5adc04d4694d35cf0391f0f3d57c8e0030aac09d7678fa8030aa",
"sha256:d9c206c29b46cfd343ea7cdfe1232443072bbb270d6a46f59c259460db76779a",
"sha256:e49eb4e95ff6fd7c0c402508894b1ef0e01b99a44320ba7d8ecbabefddcc5569",
"sha256:f8286396b351785801a976b1e85ea88e937712ee2c3ac653710a4a57a8da5d9c",
"sha256:f8fc330c3370a81bbf3f88557097d1ea26cd8b019d6433aa59f71195f5ddebbf",
"sha256:fbd359831c1657d69bb81f0db962905ee05e5e9451913b18b831febfe0519082",
"sha256:fe7e1c262d3392afcf5071df9afa574544f28eac825284596ac6db56e6d11062",
"sha256:fed1e1cf6a42577953abbe8e6cf2fe2f566daebde7c34724ec8803c4c0cda579"
], ],
"index": "pypi", "index": "pypi",
"version": "==9.5.0" "version": "==10.0.0"
},
"psycopg2": {
"hashes": [
"sha256:11aca705ec888e4f4cea97289a0bf0f22a067a32614f6ef64fcf7b8bfbc53744",
"sha256:1861a53a6a0fd248e42ea37c957d36950da00266378746588eab4f4b5649e95f",
"sha256:2362ee4d07ac85ff0ad93e22c693d0f37ff63e28f0615a16b6635a645f4b9214",
"sha256:36c941a767341d11549c0fbdbb2bf5be2eda4caf87f65dfcd7d146828bd27f39",
"sha256:53f4ad0a3988f983e9b49a5d9765d663bbe84f508ed655affdb810af9d0972ad",
"sha256:869776630c04f335d4124f120b7fb377fe44b0a7645ab3c34b4ba42516951889",
"sha256:a8ad4a47f42aa6aec8d061fdae21eaed8d864d4bb0f0cade5ad32ca16fcd6258",
"sha256:b81fcb9ecfc584f661b71c889edeae70bae30d3ef74fa0ca388ecda50b1222b7",
"sha256:d24ead3716a7d093b90b27b3d73459fe8cd90fd7065cf43b3c40966221d8c394",
"sha256:ded2faa2e6dfb430af7713d87ab4abbfc764d8d7fb73eafe96a24155f906ebf5",
"sha256:f15158418fd826831b28585e2ab48ed8df2d0d98f502a2b4fe619e7d5ca29011",
"sha256:f75001a1cbbe523e00b0ef896a5a1ada2da93ccd752b7636db5a99bc57c44494",
"sha256:f7a7a5ee78ba7dc74265ba69e010ae89dae635eea0e97b055fb641a01a31d2b1"
],
"index": "pypi",
"version": "==2.9.6"
},
"pyasn1": {
"hashes": [
"sha256:87a2121042a1ac9358cabcaf1d07680ff97ee6404333bacca15f76aa8ad01a57",
"sha256:97b7290ca68e62a832558ec3976f15cbf911bf5d7c7039d8b861c2a0ece69fde"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
"version": "==0.5.0"
},
"pyasn1-modules": {
"hashes": [
"sha256:5bd01446b736eb9d31512a30d46c1ac3395d676c6f3cafa4c03eb54b9925631c",
"sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
"version": "==0.3.0"
}, },
"pycparser": { "pycparser": {
"hashes": [ "hashes": [
@ -373,6 +475,13 @@
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==2.7.0" "version": "==2.7.0"
}, },
"pyopenssl": {
"hashes": [
"sha256:24f0dc5227396b3e831f4c7f602b950a5e9833d292c8e4a2e06b709292806ae2",
"sha256:276f931f55a452e7dea69c7173e984eb2a4407ce413c918aa34b55f82f9b8bac"
],
"version": "==23.2.0"
},
"python-dotenv": { "python-dotenv": {
"hashes": [ "hashes": [
"sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba", "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba",
@ -411,6 +520,29 @@
"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": "==1.3.1" "version": "==1.3.1"
}, },
"service-identity": {
"hashes": [
"sha256:87415a691d52fcad954a500cb81f424d0273f8e7e3ee7d766128f4575080f383",
"sha256:ecb33cd96307755041e978ab14f8b14e13b40f1fbd525a4dc78f46d2b986431d"
],
"version": "==23.1.0"
},
"setuptools": {
"hashes": [
"sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f",
"sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"
],
"markers": "python_version >= '3.7'",
"version": "==68.0.0"
},
"six": {
"hashes": [
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.16.0"
},
"social-auth-app-django": { "social-auth-app-django": {
"hashes": [ "hashes": [
"sha256:0347ca4cd23ea9d15a665da9d22950552fb66b95600e6c2ebae38ca883b3a4ed", "sha256:0347ca4cd23ea9d15a665da9d22950552fb66b95600e6c2ebae38ca883b3a4ed",
@ -435,6 +567,55 @@
"markers": "python_version >= '3.5'", "markers": "python_version >= '3.5'",
"version": "==0.4.4" "version": "==0.4.4"
}, },
"twisted": {
"extras": [
"tls"
],
"hashes": [
"sha256:32acbd40a94f5f46e7b42c109bfae2b302250945561783a8b7a059048f2d4d31",
"sha256:86c55f712cc5ab6f6d64e02503352464f0400f66d4f079096d744080afcccbd0"
],
"markers": "python_full_version >= '3.7.1'",
"version": "==22.10.0"
},
"twisted-iocpsupport": {
"hashes": [
"sha256:1bdccbb22199fc69fd7744d6d2dfd22d073c028c8611d994b41d2d2ad0e0f40d",
"sha256:1dbfac706972bf9ec5ce1ddbc735d2ebba406ad363345df8751ffd5252aa1618",
"sha256:1ddfc5fa22ec6f913464b736b3f46e642237f17ac41be47eed6fa9bd52f5d0e0",
"sha256:1ea2c3fbdb739c95cc8b3355305cd593d2c9ec56d709207aa1a05d4d98671e85",
"sha256:3f39c41c0213a81a9ce0961e30d0d7650f371ad80f8d261007d15a2deb6d5be3",
"sha256:4f249d0baac836bb431d6fa0178be063a310136bc489465a831e3abd2d7acafd",
"sha256:67bec1716eb8f466ef366bbf262e1467ecc9e20940111207663ac24049785bad",
"sha256:6f8c433faaad5d53d30d1da6968d5a3730df415e2efb6864847267a9b51290cd",
"sha256:7efcdfafb377f32db90f42bd5fc5bb32cd1e3637ee936cdaf3aff4f4786ab3bf",
"sha256:8faceae553cfadc42ad791b1790e7cdecb7751102608c405217f6a26e877e0c5",
"sha256:98a6f16ab215f8c1446e9fc60aaed0ab7c746d566aa2f3492a23cea334e6bebb",
"sha256:a379ef56a576c8090889f74441bc3822ca31ac82253cc61e8d50631bcb0c26d0",
"sha256:aaca8f30c3b7c80d27a33fe9fe0d0bac42b1b012ddc60f677175c30e1becc1f3",
"sha256:afb00801fdfbaccf0d0173a722626500023d4a19719ac9f129d1347a32e2fc66",
"sha256:db11c80054b52dbdea44d63d5474a44c9a6531882f0e2960268b15123088641a",
"sha256:dff43136c33665c2d117a73706aef6f7d6433e5c4560332a118fe066b16b8695"
],
"markers": "platform_system == 'Windows'",
"version": "==1.0.3"
},
"txaio": {
"hashes": [
"sha256:aaea42f8aad50e0ecfb976130ada140797e9dcb85fad2cf72b0f37f8cefcb490",
"sha256:f9a9216e976e5e3246dfd112ad7ad55ca915606b60b84a757ac769bd404ff704"
],
"markers": "python_version >= '3.7'",
"version": "==23.1.1"
},
"typing-extensions": {
"hashes": [
"sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36",
"sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"
],
"markers": "python_version >= '3.7'",
"version": "==4.7.1"
},
"tzdata": { "tzdata": {
"hashes": [ "hashes": [
"sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a", "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a",
@ -458,6 +639,42 @@
], ],
"index": "pypi", "index": "pypi",
"version": "==6.5.0" "version": "==6.5.0"
},
"zope.interface": {
"hashes": [
"sha256:042f2381118b093714081fd82c98e3b189b68db38ee7d35b63c327c470ef8373",
"sha256:0ec9653825f837fbddc4e4b603d90269b501486c11800d7c761eee7ce46d1bbb",
"sha256:12175ca6b4db7621aedd7c30aa7cfa0a2d65ea3a0105393e05482d7a2d367446",
"sha256:1592f68ae11e557b9ff2bc96ac8fc30b187e77c45a3c9cd876e3368c53dc5ba8",
"sha256:23ac41d52fd15dd8be77e3257bc51bbb82469cf7f5e9a30b75e903e21439d16c",
"sha256:424d23b97fa1542d7be882eae0c0fc3d6827784105264a8169a26ce16db260d8",
"sha256:4407b1435572e3e1610797c9203ad2753666c62883b921318c5403fb7139dec2",
"sha256:48f4d38cf4b462e75fac78b6f11ad47b06b1c568eb59896db5b6ec1094eb467f",
"sha256:4c3d7dfd897a588ec27e391edbe3dd320a03684457470415870254e714126b1f",
"sha256:5171eb073474a5038321409a630904fd61f12dd1856dd7e9d19cd6fe092cbbc5",
"sha256:5a158846d0fca0a908c1afb281ddba88744d403f2550dc34405c3691769cdd85",
"sha256:6ee934f023f875ec2cfd2b05a937bd817efcc6c4c3f55c5778cbf78e58362ddc",
"sha256:790c1d9d8f9c92819c31ea660cd43c3d5451df1df61e2e814a6f99cebb292788",
"sha256:809fe3bf1a91393abc7e92d607976bbb8586512913a79f2bf7d7ec15bd8ea518",
"sha256:87b690bbee9876163210fd3f500ee59f5803e4a6607d1b1238833b8885ebd410",
"sha256:89086c9d3490a0f265a3c4b794037a84541ff5ffa28bb9c24cc9f66566968464",
"sha256:99856d6c98a326abbcc2363827e16bd6044f70f2ef42f453c0bd5440c4ce24e5",
"sha256:aab584725afd10c710b8f1e6e208dbee2d0ad009f57d674cb9d1b3964037275d",
"sha256:af169ba897692e9cd984a81cb0f02e46dacdc07d6cf9fd5c91e81f8efaf93d52",
"sha256:b39b8711578dcfd45fc0140993403b8a81e879ec25d53189f3faa1f006087dca",
"sha256:b3f543ae9d3408549a9900720f18c0194ac0fe810cecda2a584fd4dca2eb3bb8",
"sha256:d0583b75f2e70ec93f100931660328965bb9ff65ae54695fb3fa0a1255daa6f2",
"sha256:dfbbbf0809a3606046a41f8561c3eada9db811be94138f42d9135a5c47e75f6f",
"sha256:e538f2d4a6ffb6edfb303ce70ae7e88629ac6e5581870e66c306d9ad7b564a58",
"sha256:eba51599370c87088d8882ab74f637de0c4f04a6d08a312dce49368ba9ed5c2a",
"sha256:ee4b43f35f5dc15e1fec55ccb53c130adb1d11e8ad8263d68b1284b66a04190d",
"sha256:f2363e5fd81afb650085c6686f2ee3706975c54f331b426800b53531191fdf28",
"sha256:f299c020c6679cb389814a3b81200fe55d428012c5e76da7e722491f5d205990",
"sha256:f72f23bab1848edb7472309e9898603141644faec9fd57a823ea6b4d1c4c8995",
"sha256:fa90bac61c9dc3e1a563e5babb3fd2c0c1c80567e815442ddbe561eadc803b30"
],
"markers": "python_version >= '3.7'",
"version": "==6.0"
} }
}, },
"develop": {} "develop": {}

Binary file not shown.

5
packages/readme.md Normal file
View file

@ -0,0 +1,5 @@
Some stuff we need to manually install
> pipenv install
Running the command above should automatically install these packages

View file

@ -5,6 +5,7 @@ from .models import CustomUser
from year_levels.models import Year_Level from year_levels.models import Year_Level
from semesters.models import Semester from semesters.models import Semester
from courses.models import Course from courses.models import Course
from subjects.models import Subject
class CustomUserForm(forms.ModelForm): class CustomUserForm(forms.ModelForm):
@ -14,6 +15,8 @@ class CustomUserForm(forms.ModelForm):
queryset=Semester.objects.all(), required=False) queryset=Semester.objects.all(), required=False)
course = forms.ModelChoiceField( course = forms.ModelChoiceField(
queryset=Course.objects.all(), required=False) queryset=Course.objects.all(), required=False)
subjects = forms.ModelMultipleChoiceField(
queryset=Subject.objects.all(), required=False, widget=forms.CheckboxSelectMultiple)
avatar = forms.ImageField(required=False) avatar = forms.ImageField(required=False)
class Meta: class Meta:
@ -27,7 +30,7 @@ class CustomUserAdmin(UserAdmin):
fieldsets = UserAdmin.fieldsets + ( fieldsets = UserAdmin.fieldsets + (
(None, {'fields': ('student_id_number', (None, {'fields': ('student_id_number',
'year_level', 'semester', 'course', 'avatar', 'is_student', 'is_banned')}), 'year_level', 'semester', 'course', 'subjects', 'avatar', 'is_student', 'is_banned')}),
) )

View file

View file

@ -0,0 +1,14 @@
from django.core.management.base import BaseCommand
from django.db import connection
from django.core.management import call_command
class Command(BaseCommand):
help = 'Run InitSpatialMetaData and then migrate'
def handle(self, *args, **kwargs):
with connection.cursor() as cursor:
cursor.execute('SELECT InitSpatialMetaData(1);')
# Call the Django migrate command
call_command('migrate')

View file

@ -1,4 +1,4 @@
# Generated by Django 4.2.2 on 2023-06-27 15:21 # Generated by Django 4.2.3 on 2023-07-18 07:43
import accounts.models import accounts.models
import django.contrib.auth.models import django.contrib.auth.models
@ -25,10 +25,10 @@ class Migration(migrations.Migration):
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('first_name', models.CharField(max_length=100)), ('first_name', models.CharField(max_length=100)),
('last_name', models.CharField(max_length=100)), ('last_name', models.CharField(max_length=100)),
('is_active', models.BooleanField(default=False)),
('is_student', models.BooleanField(default=True)), ('is_student', models.BooleanField(default=True)),
('is_studying', models.BooleanField(default=False)), ('is_studying', models.BooleanField(default=False)),
('is_banned', models.BooleanField(default=False)), ('is_banned', models.BooleanField(default=False)),

View file

@ -1,4 +1,4 @@
# Generated by Django 4.2.2 on 2023-06-27 15:21 # Generated by Django 4.2.3 on 2023-07-18 07:43
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
@ -12,15 +12,16 @@ class Migration(migrations.Migration):
('auth', '0012_alter_user_first_name_max_length'), ('auth', '0012_alter_user_first_name_max_length'),
('year_levels', '0001_initial'), ('year_levels', '0001_initial'),
('accounts', '0001_initial'), ('accounts', '0001_initial'),
('courses', '0002_initial'),
('semesters', '0001_initial'), ('semesters', '0001_initial'),
('courses', '0002_initial'),
('subjects', '0001_initial'),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='customuser', model_name='customuser',
name='course', name='course',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='courses.course'), field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='courses.course'),
), ),
migrations.AddField( migrations.AddField(
model_name='customuser', model_name='customuser',
@ -30,7 +31,12 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='customuser', model_name='customuser',
name='semester', name='semester',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='semesters.semester'), field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='semesters.semester'),
),
migrations.AddField(
model_name='customuser',
name='subjects',
field=models.ManyToManyField(to='subjects.subject'),
), ),
migrations.AddField( migrations.AddField(
model_name='customuser', model_name='customuser',
@ -40,6 +46,6 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='customuser', model_name='customuser',
name='year_level', name='year_level',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='year_levels.year_level'), field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='year_levels.year_level'),
), ),
] ]

View file

@ -1,19 +0,0 @@
# Generated by Django 4.2.2 on 2023-06-28 03:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('subjects', '0002_subjectstudent_subject_students'),
('accounts', '0002_initial'),
]
operations = [
migrations.AddField(
model_name='customuser',
name='subjects',
field=models.ManyToManyField(related_name='SubjectStudent_user', through='subjects.SubjectStudent', to='subjects.subject'),
),
]

View file

@ -1,32 +0,0 @@
# Generated by Django 4.2.2 on 2023-07-04 10:04
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('semesters', '0001_initial'),
('courses', '0002_initial'),
('year_levels', '0001_initial'),
('accounts', '0003_customuser_subjects'),
]
operations = [
migrations.AlterField(
model_name='customuser',
name='course',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='courses.course'),
),
migrations.AlterField(
model_name='customuser',
name='semester',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='semesters.semester'),
),
migrations.AlterField(
model_name='customuser',
name='year_level',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='year_levels.year_level'),
),
]

View file

@ -1,18 +0,0 @@
# Generated by Django 4.2.2 on 2023-07-04 11:33
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0004_alter_customuser_course_alter_customuser_semester_and_more'),
]
operations = [
migrations.AlterField(
model_name='customuser',
name='is_active',
field=models.BooleanField(default=False),
),
]

View file

@ -20,11 +20,9 @@ def validate_student_id(value):
class CustomUser(AbstractUser): class CustomUser(AbstractUser):
def _get_upload_to(instance, filename): def _get_upload_to(instance, filename):
base_filename, file_extension = os.path.splitext(filename) base_filename, file_extension = os.path.splitext(filename)
# Convert filename to a slug format
cleaned_filename = slugify(base_filename)
# Get the student ID number # Get the student ID number
student_id = str(instance.student_id_number) student_id = str(instance.student_id_number)
new_filename = f"{student_id}_{cleaned_filename}{file_extension}" new_filename = f"{student_id}_{file_extension}"
return os.path.join('avatars', new_filename) return os.path.join('avatars', new_filename)
first_name = models.CharField(max_length=100) first_name = models.CharField(max_length=100)
@ -55,8 +53,7 @@ class CustomUser(AbstractUser):
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
null=True null=True
) )
subjects = models.ManyToManyField( subjects = models.ManyToManyField('subjects.Subject')
'subjects.Subject', through='subjects.SubjectStudent', related_name='SubjectStudent_user')
@property @property
def full_name(self): def full_name(self):
@ -80,3 +77,23 @@ def create_superuser(sender, **kwargs):
# Activate the superuser # Activate the superuser
superuser.is_active = True superuser.is_active = True
superuser.save() superuser.save()
User = CustomUser
username = 'keannu125'
email = os.getenv('DJANGO_ADMIN_EMAIL')
password = os.getenv('DJANGO_ADMIN_PASSWORD')
student_id_number = '2020300490'
first_name = 'Keannu'
last_name = 'Bernasol'
# course = 'Bachelor of Science in Information Technology'
# year_level = '1st Year'
# semester = '1st Semester'
if not User.objects.filter(username=username).exists():
# Create the superuser with is_active set to False
user = User.objects.create_user(
username=username, email=email, password=password, first_name=first_name, last_name=last_name, student_id_number=student_id_number)
# Activate the superuser
user.is_active = True
user.save()

View file

@ -11,23 +11,69 @@ from django.contrib.auth.password_validation import validate_password
from courses.models import Course from courses.models import Course
from year_levels.models import Year_Level from year_levels.models import Year_Level
from semesters.models import Semester from semesters.models import Semester
from subjects.models import Subject
from django.contrib.gis.geos import Point
class CustomUserSerializer(BaseUserSerializer): class CustomUserSerializer(BaseUserSerializer):
user_status = StudentStatusSerializer( # user_status = StudentStatusSerializer(
source='studentstatus', read_only=True) # source='studentstatus', read_only=True)
course_shortname = serializers.SerializerMethodField()
yearlevel_shortname = serializers.SerializerMethodField()
semester_shortname = serializers.SerializerMethodField()
course = serializers.SlugRelatedField( course = serializers.SlugRelatedField(
many=False, slug_field='name', queryset=Course.objects.all(), required=False, allow_null=True) many=False, slug_field='name', queryset=Course.objects.all(), required=False, allow_null=True)
year_level = serializers.SlugRelatedField( year_level = serializers.SlugRelatedField(
many=False, slug_field='name', queryset=Year_Level.objects.all(), required=False, allow_null=True) many=False, slug_field='name', queryset=Year_Level.objects.all(), required=False, allow_null=True)
semester = serializers.SlugRelatedField( semester = serializers.SlugRelatedField(
many=False, slug_field='name', queryset=Semester.objects.all(), required=False, allow_null=True) many=False, slug_field='name', queryset=Semester.objects.all(), required=False, allow_null=True)
subjects = serializers.SlugRelatedField(
many=True, slug_field='name', queryset=Subject.objects.all(), required=False, allow_null=True)
class Meta(BaseUserSerializer.Meta): class Meta(BaseUserSerializer.Meta):
model = CustomUser model = CustomUser
fields = ('username', 'email', fields = ('username', 'email',
'student_id_number', 'year_level', 'semester', 'course', 'subjects', 'avatar', 'first_name', 'last_name', 'is_banned', 'user_status') 'student_id_number', 'year_level', 'yearlevel_shortname', 'semester', 'semester_shortname', 'course', 'course_shortname', 'subjects', 'avatar', 'first_name', 'last_name', 'is_banned')
read_only_fields = ('is_banned', 'user_status') read_only_fields = ('is_banned', 'user_status', 'yearlevel_shortname',
'semester_shortname', 'course_shortname')
def get_course_shortname(self, instance):
return instance.course.shortname if instance.course else None
def get_yearlevel_shortname(self, instance):
return instance.year_level.shortname if instance.year_level else None
def get_semester_shortname(self, instance):
return instance.semester.shortname if instance.semester else None
def update(self, instance, validated_data):
# First, we'll remove all the existing subjects from the user
print(validated_data)
# If course, year_level, or semester is changed
if any(field in validated_data for field in ['course', 'year_level', 'semester']):
if (instance.course != validated_data['course'] or
instance.year_level != validated_data['year_level'] or
instance.semester != validated_data['semester']):
# Clear all subjects
instance.subjects.clear()
# Update the user instance with the validated data
instance = super().update(instance, validated_data)
# Then add new subjects matching the new criteria
self.add_subjects(instance)
# Else update as usual
else:
instance = super().update(instance, validated_data)
return instance
def add_subjects(self, instance):
# Get the matching subjects based on the user's course, year level, and semester
matching_subjects = Subject.objects.filter(
courses=instance.course, year_levels=instance.year_level, semesters=instance.semester)
# Add the matching subjects to the user's subjects list
instance.subjects.add(*matching_subjects)
# The model from your custom user # The model from your custom user
@ -35,7 +81,10 @@ class CustomUserSerializer(BaseUserSerializer):
class UserRegistrationSerializer(serializers.ModelSerializer): class UserRegistrationSerializer(serializers.ModelSerializer):
email = serializers.EmailField(required=True) email = serializers.EmailField(required=True)
student_id_number = serializers.CharField(required=True) student_id_number = serializers.CharField(required=True)
password = serializers.CharField(write_only=True) password = serializers.CharField(
write_only=True, style={'input_type': 'password', 'placeholder': 'Password'})
subjects = serializers.SlugRelatedField(
many=True, slug_field='name', queryset=Subject.objects.all(), required=False, allow_null=True)
class Meta: class Meta:
model = CustomUser # Use your custom user model here model = CustomUser # Use your custom user model here
@ -64,8 +113,7 @@ class UserRegistrationSerializer(serializers.ModelSerializer):
StudentStatus.objects.create( StudentStatus.objects.create(
user=user, user=user,
active=False, active=False,
x=None, location=Point(0, 0),
y=None,
subject=None subject=None
) )
return user return user

View file

@ -9,5 +9,6 @@ urlpatterns = [
path('semesters/', include('semesters.urls')), path('semesters/', include('semesters.urls')),
path('subjects/', include('subjects.urls')), path('subjects/', include('subjects.urls')),
path('study_groups/', include('study_groups.urls')), path('study_groups/', include('study_groups.urls')),
path('messages/', include('studygroup_messages.urls')) path('messages/', include('studygroup_messages.urls')),
path('landmarks/', include('landmarks.urls')),
] ]

View file

@ -14,6 +14,7 @@ from pathlib import Path
from dotenv import load_dotenv # Python dotenv from dotenv import load_dotenv # Python dotenv
import os import os
load_dotenv() # loads the configs from .env load_dotenv() # loads the configs from .env
# Build paths inside the project like this: BASE_DIR / 'subdir'. # Build paths inside the project like this: BASE_DIR / 'subdir'.
@ -50,8 +51,21 @@ else:
EMAIL_PORT = str(os.getenv('PROD_EMAIL_PORT')) EMAIL_PORT = str(os.getenv('PROD_EMAIL_PORT'))
EMAIL_USE_TLS = str(os.getenv('PROD_EMAIL_TLS')) EMAIL_USE_TLS = str(os.getenv('PROD_EMAIL_TLS'))
# Will need to install OSGeo4W for this!
if os.name == 'nt':
OSGEO4W = r"C:\OSGeo4W"
if not os.path.isdir(OSGEO4W):
OSGEO4W += '64'
os.environ['OSGEO4W_ROOT'] = OSGEO4W
os.environ['GDAL_DATA'] = "C:\Program Files\GDAL\gdal-data"
os.environ['PROJ_LIB'] = OSGEO4W + r"\share\proj"
GDAL_LIBRARY_PATH = r'C:\OSGeo4W64\bin\gdal204'
os.environ['PATH'] = OSGEO4W + r"\bin;" + os.environ['PATH']
# Application definition GEOS_LIBRARY_PATH = str(os.environ.get('VIRTUAL_ENV') +
r"\Lib\site-packages\osgeo\geos_c.dll")
GDAL_LIBRARY_PATH = str(os.environ.get('VIRTUAL_ENV') +
r"\Lib\site-packages\osgeo\gdal304.dll")
INSTALLED_APPS = [ INSTALLED_APPS = [
'daphne', 'daphne',
@ -61,6 +75,7 @@ INSTALLED_APPS = [
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.messages', 'django.contrib.messages',
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'django.contrib.gis',
'rest_framework', 'rest_framework',
'rest_framework_simplejwt', 'rest_framework_simplejwt',
'djoser', 'djoser',
@ -72,6 +87,8 @@ INSTALLED_APPS = [
'subjects', 'subjects',
'study_groups', 'study_groups',
'studygroup_messages', 'studygroup_messages',
'leaflet',
'landmarks',
] ]
MIDDLEWARE = [ MIDDLEWARE = [
@ -123,11 +140,18 @@ WSGI_APPLICATION = 'config.wsgi.application'
# Database # Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases # https://docs.djangoproject.com/en/4.2/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',
} }
}"""
DATABASES = {
'default': {
'ENGINE': 'django.contrib.gis.db.backends.spatialite',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
} }
AUTH_USER_MODEL = 'accounts.CustomUser' AUTH_USER_MODEL = 'accounts.CustomUser'
@ -203,3 +227,11 @@ SITE_NAME = 'Stud-E'
JWT_TOKEN_LIFETIME = 10800 JWT_TOKEN_LIFETIME = 10800
ACCESS_TOKEN_LIFETIME = JWT_TOKEN_LIFETIME ACCESS_TOKEN_LIFETIME = JWT_TOKEN_LIFETIME
REFRESH_TOKEN_LIFETIME = 24 * JWT_TOKEN_LIFETIME REFRESH_TOKEN_LIFETIME = 24 * JWT_TOKEN_LIFETIME
LEAFLET_CONFIG = {
'DEFAULT_CENTER': (8.48567, 124.65642),
'DEFAULT_ZOOM': 19,
'MAX_ZOOM': 20,
'MIN_ZOOM': 3,
'SCALE': 'both'
}

View file

@ -1,6 +1,5 @@
from django.contrib import admin from django.contrib import admin
from .models import Course, SubjectCourse from .models import Course
admin.site.register(Course) admin.site.register(Course)
admin.site.register(SubjectCourse)

View file

@ -1,7 +1,6 @@
# Generated by Django 4.2.2 on 2023-06-27 15:21 # Generated by Django 4.2.3 on 2023-07-18 07:43
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
@ -20,11 +19,4 @@ class Migration(migrations.Migration):
('shortname', models.CharField(max_length=16)), ('shortname', models.CharField(max_length=16)),
], ],
), ),
migrations.CreateModel(
name='SubjectCourse',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('course', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='courses.course')),
],
),
] ]

View file

@ -1,7 +1,6 @@
# Generated by Django 4.2.2 on 2023-06-27 15:21 # Generated by Django 4.2.3 on 2023-07-18 07:43
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
@ -9,19 +8,14 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('subjects', '0001_initial'),
('courses', '0001_initial'), ('courses', '0001_initial'),
('subjects', '0001_initial'),
] ]
operations = [ operations = [
migrations.AddField(
model_name='subjectcourse',
name='subject',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='subjects.subject'),
),
migrations.AddField( migrations.AddField(
model_name='course', model_name='course',
name='subjects', name='subjects',
field=models.ManyToManyField(related_name='SubjectCourse_course', through='courses.SubjectCourse', to='subjects.subject'), field=models.ManyToManyField(related_name='SubjectCourse_course', through='subjects.SubjectCourse', to='subjects.subject'),
), ),
] ]

View file

@ -0,0 +1,23 @@
# Generated by Django 4.2.3 on 2023-07-18 10:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('courses', '0002_initial'),
]
operations = [
migrations.AlterField(
model_name='course',
name='name',
field=models.CharField(max_length=64, unique=True),
),
migrations.AlterField(
model_name='course',
name='shortname',
field=models.CharField(max_length=16, unique=True),
),
]

View file

@ -5,21 +5,15 @@ from django.db import models
class Course(models.Model): class Course(models.Model):
name = models.CharField(max_length=64) name = models.CharField(max_length=64, unique=True)
shortname = models.CharField(max_length=16) shortname = models.CharField(max_length=16, unique=True)
subjects = models.ManyToManyField( subjects = models.ManyToManyField(
'subjects.Subject', related_name='SubjectCourse_course', through='courses.SubjectCourse') 'subjects.Subject', related_name='SubjectCourse_course', through='subjects.SubjectCourse')
def __str__(self): def __str__(self):
return self.name return self.name
class SubjectCourse(models.Model):
subject = models.ForeignKey('subjects.Subject', on_delete=models.CASCADE)
course = models.ForeignKey(
'courses.Course', on_delete=models.CASCADE, null=True)
@receiver(post_migrate) @receiver(post_migrate)
def populate_courses(sender, **kwargs): def populate_courses(sender, **kwargs):
if sender.name == 'courses': if sender.name == 'courses':

View file

5
stude/landmarks/admin.py Normal file
View file

@ -0,0 +1,5 @@
from django.contrib import admin
from leaflet.admin import LeafletGeoAdmin
from .models import Landmark
admin.site.register(Landmark, LeafletGeoAdmin)

6
stude/landmarks/apps.py Normal file
View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class LandmarksConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'landmarks'

View file

@ -0,0 +1,23 @@
# Generated by Django 4.2.3 on 2023-07-18 07:43
import django.contrib.gis.db.models.fields
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Landmark',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=64)),
('location', django.contrib.gis.db.models.fields.PolygonField(srid=4326)),
],
),
]

View file

218
stude/landmarks/models.py Normal file
View file

@ -0,0 +1,218 @@
from django.db import models
from django.contrib.gis.db import models as gis_models
from django.contrib.gis.geos import GEOSGeometry
from django.db.models.signals import post_migrate
from django.dispatch import receiver
# Create your models here.
class Landmark(models.Model):
name = models.CharField(max_length=64)
location = gis_models.PolygonField(srid=4326)
def __str__(self):
return self.name
@receiver(post_migrate)
def populate_landmarks(sender, **kwargs):
if sender.name == 'landmarks':
SRID = 4326
Landmark.objects.get_or_create(
name='Gymnasium',
location=GEOSGeometry(
'POLYGON ((124.656383 8.485963, 124.656576 8.485483, 124.657009 8.485659, 124.656827 8.486126, 124.656383 8.485963))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Arts & Culture Building',
location=GEOSGeometry(
'POLYGON ((124.658427 8.486268, 124.658432 8.48617, 124.658582 8.486202, 124.658555 8.4863, 124.658427 8.486268))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Guidance and Testing Center',
location=GEOSGeometry(
'POLYGON ((124.658191 8.486326, 124.658377 8.486359, 124.658394 8.486261, 124.658209 8.486231, 124.658191 8.486326))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Old Civil Engineering Building',
location=GEOSGeometry(
'POLYGON ((124.657244 8.485617, 124.657228 8.485743, 124.658014 8.485844, 124.658032 8.485711, 124.657244 8.485617))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='ITB Building',
location=GEOSGeometry(
'POLYGON ((124.658035 8.48622, 124.658056 8.485906, 124.658592 8.485942, 124.658582 8.486077, 124.6582 8.486056, 124.658188 8.486231, 124.658035 8.48622))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='SPED Center',
location=GEOSGeometry(
'POLYGON ((124.658236 8.485918, 124.658348 8.485923, 124.658348 8.485874, 124.658236 8.485881, 124.658236 8.485918))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Administration Building',
location=GEOSGeometry(
'POLYGON ((124.657236 8.486097, 124.657213 8.486064, 124.657196 8.486074, 124.657177 8.486037, 124.657279 8.485944, 124.657401 8.485893, 124.657426 8.485935, 124.657411 8.485946, 124.65743 8.485971, 124.657236 8.486097))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Informations and Communications Technology Building',
location=GEOSGeometry(
'POLYGON ((124.657204 8.486478, 124.657142 8.486326, 124.657201 8.486307, 124.657273 8.486272, 124.657291 8.486287, 124.65741 8.486216, 124.65752 8.486097, 124.657552 8.486031, 124.657537 8.486025, 124.657523 8.486009, 124.657513 8.485994, 124.657512 8.485978, 124.657515 8.48596, 124.657521 8.485944, 124.657535 8.485927, 124.65756 8.485914, 124.657578 8.48591, 124.657592 8.485913, 124.65761 8.485921, 124.657627 8.485934, 124.657639 8.485948, 124.657639 8.485963, 124.657639 8.485978, 124.657638 8.485992, 124.657626 8.486008, 124.657605 8.486025, 124.657666 8.486053, 124.657634 8.486139, 124.65758 8.486206, 124.657511 8.486279, 124.657425 8.486352, 124.65735 8.486405, 124.657204 8.486478))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Finance and Accounting Building',
location=GEOSGeometry(
'POLYGON ((124.656457 8.486273, 124.656844 8.486425, 124.656974 8.486104, 124.656855 8.486057, 124.656772 8.486259, 124.656503 8.486157, 124.656457 8.486273))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Culinary Building',
location=GEOSGeometry(
'POLYGON ((124.65708 8.485527, 124.657104 8.485261, 124.657205 8.485268, 124.657175 8.485533, 124.65708 8.485527))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Science Centrum Building',
location=GEOSGeometry(
'POLYGON ((124.657114 8.485195, 124.657128 8.484964, 124.657224 8.48497, 124.657212 8.485202, 124.657114 8.485195))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Engineering Complex Right Wing',
location=GEOSGeometry(
'POLYGON ((124.656961 8.484943, 124.656934 8.48482, 124.656959 8.484813, 124.656939 8.484744, 124.657229 8.484684, 124.657228 8.484898, 124.656961 8.484943))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Engineering Complex Left Wing',
location=GEOSGeometry(
'POLYGON ((124.656949 8.484975, 124.656962 8.484944, 124.656935 8.484821, 124.656701 8.484767, 124.65666 8.484765, 124.656632 8.484772, 124.656605 8.484783, 124.656596 8.484798, 124.656591 8.484813, 124.656588 8.484828, 124.656587 8.484858, 124.656595 8.484878, 124.656604 8.484893, 124.65662 8.484907, 124.656647 8.484922, 124.656681 8.484935, 124.656693 8.484903, 124.656949 8.484975))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Cafeteria',
location=GEOSGeometry(
'POLYGON ((124.656651 8.48535, 124.656772 8.485021, 124.656917 8.485077, 124.656799 8.485403, 124.656651 8.48535))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='HRM Building',
location=GEOSGeometry(
'POLYGON ((124.656359 8.486151, 124.656471 8.486198, 124.656497 8.486141, 124.656627 8.486189, 124.656655 8.486118, 124.65641 8.486023, 124.656359 8.486151))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Sports Complex',
location=GEOSGeometry(
'POLYGON ((124.65625 8.486543, 124.656813 8.486763, 124.65687 8.486617, 124.656306 8.486401, 124.65625 8.486543))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Printing Press',
location=GEOSGeometry(
'POLYGON ((124.656053 8.486711, 124.656092 8.486597, 124.656195 8.486636, 124.656152 8.486748, 124.656053 8.486711))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Learning Resource Center',
location=GEOSGeometry(
'POLYGON ((124.655575 8.486698, 124.655663 8.486454, 124.655783 8.486502, 124.655799 8.486458, 124.655916 8.486499, 124.655899 8.486543, 124.656041 8.486593, 124.655951 8.486833, 124.655575 8.486698))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Food Innovation Center',
location=GEOSGeometry(
'POLYGON ((124.655633 8.486304, 124.655681 8.486175, 124.656239 8.486394, 124.65619 8.486516, 124.656101 8.486482, 124.656085 8.486523, 124.656007 8.486494, 124.656022 8.486454, 124.655633 8.486304))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Technology Building',
location=GEOSGeometry(
'POLYGON ((124.655184 8.486766, 124.655252 8.486674, 124.655632 8.486823, 124.655575 8.486919, 124.655184 8.486766))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Foods Trade Building',
location=GEOSGeometry(
'POLYGON ((124.655251 8.486585, 124.655427 8.486651, 124.655478 8.486521, 124.655416 8.4865, 124.65552 8.486246, 124.655571 8.486263, 124.65563 8.486128, 124.655451 8.486059, 124.655251 8.486585))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Old Medical Building',
location=GEOSGeometry(
'POLYGON ((124.655574 8.485952, 124.655708 8.486004, 124.655732 8.485944, 124.655594 8.485895, 124.655574 8.485952))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Old Science Building',
location=GEOSGeometry(
'POLYGON ((124.655534 8.485857, 124.655629 8.485588, 124.655795 8.485647, 124.655755 8.485757, 124.656271 8.485946, 124.656212 8.486104, 124.655534 8.485857))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Science Complex',
location=GEOSGeometry(
'POLYGON ((124.655743 8.485616, 124.655743 8.48563, 124.655829 8.485659, 124.655845 8.485623, 124.656325 8.485793, 124.656381 8.485629, 124.655806 8.485427, 124.655761 8.485558, 124.655742 8.485547, 124.655719 8.485608, 124.655743 8.485616))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='SUMP PIT',
location=GEOSGeometry(
'POLYGON ((124.65478 8.486829, 124.654976 8.486897, 124.65502 8.486779, 124.654826 8.486707, 124.65478 8.486829))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Fabrication Laboratory',
location=GEOSGeometry(
'POLYGON ((124.654816 8.486586, 124.654933 8.4863, 124.65511 8.486373, 124.654993 8.486658, 124.654816 8.486586))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Old Student Center',
location=GEOSGeometry(
'POLYGON ((124.655046 8.486251, 124.655178 8.485921, 124.655311 8.485972, 124.655173 8.486301, 124.655046 8.486251))',
srid=SRID
)
)
Landmark.objects.get_or_create(
name='Old Education Building',
location=GEOSGeometry(
'POLYGON ((124.655181 8.485909, 124.655307 8.485612, 124.655432 8.485663, 124.655305 8.485959, 124.655181 8.485909))',
srid=SRID
)
)
# Add more predefined records as needed

View file

@ -0,0 +1,8 @@
from .models import Landmark
from rest_framework import serializers
class LandmarkSerializer(serializers.ModelSerializer):
class Meta:
model = Landmark
fields = '__all__'

3
stude/landmarks/tests.py Normal file
View file

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

6
stude/landmarks/urls.py Normal file
View file

@ -0,0 +1,6 @@
from django.urls import path
from .views import LandmarkListView
urlpatterns = [
path('', LandmarkListView.as_view()),
]

10
stude/landmarks/views.py Normal file
View file

@ -0,0 +1,10 @@
from rest_framework import generics
from rest_framework.permissions import IsAuthenticated
from .serializers import LandmarkSerializer
from .models import Landmark
class LandmarkListView(generics.ListAPIView):
serializer_class = LandmarkSerializer
# permission_classes = [IsAuthenticated]
queryset = Landmark.objects.all()

View file

@ -1,4 +1,4 @@
# Generated by Django 4.2.2 on 2023-06-27 15:21 # Generated by Django 4.2.3 on 2023-07-18 07:43
from django.db import migrations, models from django.db import migrations, models

View file

@ -0,0 +1,23 @@
# Generated by Django 4.2.3 on 2023-07-18 10:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('semesters', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='semester',
name='name',
field=models.CharField(max_length=64, unique=True),
),
migrations.AlterField(
model_name='semester',
name='shortname',
field=models.CharField(max_length=16, unique=True),
),
]

View file

@ -6,8 +6,8 @@ from django.dispatch import receiver
class Semester(models.Model): class Semester(models.Model):
name = models.CharField(max_length=64) name = models.CharField(max_length=64, unique=True)
shortname = models.CharField(max_length=16) shortname = models.CharField(max_length=16, unique=True)
def __str__(self): def __str__(self):
return self.name return self.name

View file

@ -1,4 +1,15 @@
from django.contrib import admin from django.contrib import admin
from .models import StudentStatus from .models import StudentStatus
from leaflet.admin import LeafletGeoAdmin
admin.site.register(StudentStatus)
class StudentStatusAdmin(LeafletGeoAdmin):
# define which fields are required
def get_form(self, request, obj=None, **kwargs):
form = super(StudentStatusAdmin, self).get_form(request, obj, **kwargs)
form.base_fields['landmark'].required = False
return form
# Register the new StudentStatus model
admin.site.register(StudentStatus, StudentStatusAdmin)

View file

@ -1,6 +1,7 @@
# Generated by Django 4.2.2 on 2023-06-27 15:21 # Generated by Django 4.2.3 on 2023-07-18 07:43
from django.conf import settings from django.conf import settings
import django.contrib.gis.db.models.fields
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
@ -11,6 +12,7 @@ class Migration(migrations.Migration):
dependencies = [ dependencies = [
('accounts', '0002_initial'), ('accounts', '0002_initial'),
('landmarks', '0001_initial'),
] ]
operations = [ operations = [
@ -18,10 +20,10 @@ class Migration(migrations.Migration):
name='StudentStatus', name='StudentStatus',
fields=[ fields=[
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)), ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)),
('x', models.FloatField(null=True)), ('location', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=4326)),
('y', models.FloatField(null=True)),
('active', models.BooleanField(default=False)), ('active', models.BooleanField(default=False)),
('timestamp', models.DateField(auto_now_add=True)), ('timestamp', models.DateField(auto_now_add=True)),
('landmark', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='landmarks.landmark')),
], ],
), ),
] ]

View file

@ -1,4 +1,4 @@
# Generated by Django 4.2.2 on 2023-06-27 15:21 # Generated by Django 4.2.3 on 2023-07-18 07:43
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
@ -9,20 +9,20 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('study_groups', '0001_initial'),
('student_status', '0001_initial'), ('student_status', '0001_initial'),
('subjects', '0001_initial'), ('subjects', '0001_initial'),
('study_groups', '0001_initial'),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='studentstatus', model_name='studentstatus',
name='study_group', name='study_group',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='study_groups.studygroup'), field=models.ManyToManyField(blank=True, through='study_groups.StudyGroupMembership', to='study_groups.studygroup'),
), ),
migrations.AddField( migrations.AddField(
model_name='studentstatus', model_name='studentstatus',
name='subject', name='subject',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='subjects.subject'), field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='subjects.subject'),
), ),
] ]

View file

@ -1,23 +0,0 @@
# Generated by Django 4.2.2 on 2023-06-27 15:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('study_groups', '0001_initial'),
('student_status', '0002_initial'),
]
operations = [
migrations.RemoveField(
model_name='studentstatus',
name='study_group',
),
migrations.AddField(
model_name='studentstatus',
name='study_group',
field=models.ManyToManyField(blank=True, null=True, through='study_groups.StudyGroupMembership', to='study_groups.studygroup'),
),
]

View file

@ -1,19 +0,0 @@
# Generated by Django 4.2.2 on 2023-06-27 17:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('study_groups', '0001_initial'),
('student_status', '0003_remove_studentstatus_study_group_and_more'),
]
operations = [
migrations.AlterField(
model_name='studentstatus',
name='study_group',
field=models.ManyToManyField(blank=True, through='study_groups.StudyGroupMembership', to='study_groups.studygroup'),
),
]

View file

@ -1,20 +0,0 @@
# Generated by Django 4.2.2 on 2023-07-04 10:01
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('subjects', '0002_subjectstudent_subject_students'),
('student_status', '0004_alter_studentstatus_study_group'),
]
operations = [
migrations.AlterField(
model_name='studentstatus',
name='subject',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='subjects.subject'),
),
]

View file

@ -1,18 +1,23 @@
from django.db import models from django.db import models
from accounts.models import CustomUser from accounts.models import CustomUser
from study_groups.models import StudyGroup from study_groups.models import StudyGroup
from django.contrib.gis.db import models as gis_models
from django.contrib.gis.geos import Point
# Create your models here. # Create your models here.
class StudentStatus(models.Model): class StudentStatus(models.Model):
user = models.OneToOneField( user = models.OneToOneField(
CustomUser, on_delete=models.CASCADE, primary_key=True) CustomUser, on_delete=models.CASCADE, primary_key=True)
x = models.FloatField(null=True) location = gis_models.PointField(blank=True, null=True, srid=4326)
y = models.FloatField(null=True)
subject = models.ForeignKey( subject = models.ForeignKey(
'subjects.Subject', on_delete=models.SET_NULL, null=True) 'subjects.Subject', on_delete=models.SET_NULL, null=True)
active = models.BooleanField(default=False) active = models.BooleanField(default=False)
timestamp = models.DateField(auto_now_add=True) timestamp = models.DateField(auto_now_add=True)
landmark = models.ForeignKey(
'landmarks.Landmark', on_delete=models.SET_NULL, null=True)
study_group = models.ManyToManyField( study_group = models.ManyToManyField(
'study_groups.StudyGroup', through='study_groups.StudyGroupMembership', blank=True) 'study_groups.StudyGroup', through='study_groups.StudyGroupMembership', blank=True)
def __str__(self):
return self.user.full_name

View file

@ -1,18 +1,23 @@
from rest_framework import serializers from rest_framework import serializers
from .models import StudentStatus from .models import StudentStatus
from subjects.models import Subject
from django.contrib.gis.geos import Point
from drf_extra_fields.geo_fields import PointField
from landmarks.models import Landmark
class StudentStatusSerializer(serializers.ModelSerializer): class StudentStatusSerializer(serializers.ModelSerializer):
year_level = serializers.CharField( subject = serializers.SlugRelatedField(
source='user.year_level', read_only=True) queryset=Subject.objects.all(), slug_field='name', required=True)
course = serializers.CharField(source='user.course', read_only=True)
semester = serializers.CharField(source='user.semester', read_only=True)
user = serializers.CharField(source='user.full_name', read_only=True) user = serializers.CharField(source='user.full_name', read_only=True)
location = PointField()
landmark = serializers.SlugRelatedField(
queryset=Landmark.objects.all(), many=False, slug_field='name', required=False, allow_null=True)
class Meta: class Meta:
model = StudentStatus model = StudentStatus
fields = '__all__' fields = '__all__'
read_only_fields = ['user'] read_only_fields = ['user', 'landmark']
def create(self, validated_data): def create(self, validated_data):
user = self.context['request'].user user = self.context['request'].user
@ -24,8 +29,14 @@ class StudentStatusSerializer(serializers.ModelSerializer):
active = validated_data.get('active', None) active = validated_data.get('active', None)
if active is not None and active is False: if active is not None and active is False:
validated_data['x'] = None validated_data['location'] = Point(0, 0)
validated_data['y'] = None
validated_data['subject'] = None validated_data['subject'] = None
validated_data['landmark'] = None
else:
# Check each landmark to see if our location is within it
for landmark in Landmark.objects.all():
if landmark.location.contains(validated_data['location']):
validated_data['landmark'] = landmark
break
return super().update(instance, validated_data) return super().update(instance, validated_data)

View file

@ -19,4 +19,4 @@ class ActiveStudentStatusListAPIView(generics.ListAPIView):
def get_queryset(self): def get_queryset(self):
user = self.request.user user = self.request.user
return StudentStatus.objects.filter(active=True).exclude(user=user) return StudentStatus.objects.filter(active=True)

View file

@ -1,6 +1,7 @@
from django.contrib import admin from django.contrib import admin
from .models import StudyGroup, StudyGroupMembership from .models import StudyGroup, StudyGroupMembership
from leaflet.admin import LeafletGeoAdmin
admin.site.register(StudyGroup) admin.site.register(StudyGroup, LeafletGeoAdmin)
admin.site.register(StudyGroupMembership) admin.site.register(StudyGroupMembership)

View file

@ -1,5 +1,6 @@
# Generated by Django 4.2.2 on 2023-06-27 15:21 # Generated by Django 4.2.3 on 2023-07-18 07:43
import django.contrib.gis.db.models.fields
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
@ -19,8 +20,7 @@ class Migration(migrations.Migration):
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=48)), ('name', models.CharField(max_length=48)),
('x', models.FloatField(null=True)), ('location', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=4326)),
('y', models.FloatField(null=True)),
('active', models.BooleanField(default=False)), ('active', models.BooleanField(default=False)),
('timestamp', models.DateField(auto_now_add=True)), ('timestamp', models.DateField(auto_now_add=True)),
('subject', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='subjects.subject')), ('subject', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='subjects.subject')),

View file

@ -1,5 +1,7 @@
from django.db import models from django.db import models
from subjects.models import Subject from subjects.models import Subject
from django.contrib.gis.db import models as gis_models
from django.contrib.gis.geos import Point
# Create your models here. # Create your models here.
@ -7,12 +9,14 @@ class StudyGroup(models.Model):
name = models.CharField(max_length=48) name = models.CharField(max_length=48)
users = models.ManyToManyField( users = models.ManyToManyField(
'student_status.StudentStatus', through='StudyGroupMembership') 'student_status.StudentStatus', through='StudyGroupMembership')
x = models.FloatField(null=True) location = gis_models.PointField(blank=True, null=True, srid=4326)
y = models.FloatField(null=True)
subject = models.ForeignKey(Subject, on_delete=models.CASCADE) subject = models.ForeignKey(Subject, on_delete=models.CASCADE)
active = models.BooleanField(default=False) active = models.BooleanField(default=False)
timestamp = models.DateField(auto_now_add=True) timestamp = models.DateField(auto_now_add=True)
def __str__(self):
return self.name
class StudyGroupMembership(models.Model): class StudyGroupMembership(models.Model):
user = models.ForeignKey( user = models.ForeignKey(
@ -21,4 +25,4 @@ class StudyGroupMembership(models.Model):
'study_groups.StudyGroup', on_delete=models.CASCADE) 'study_groups.StudyGroup', on_delete=models.CASCADE)
def __str__(self): def __str__(self):
return f'StudyGroupMembership: User={self.user_id}, StudyGroup={self.study_group_id}' return f'StudyGroupMembership: User={self.user}, StudyGroup={self.study_group.name}'

View file

@ -2,6 +2,8 @@ from rest_framework import serializers
from .models import StudyGroup, StudyGroupMembership from .models import StudyGroup, StudyGroupMembership
from accounts.models import CustomUser from accounts.models import CustomUser
from subjects.models import Subject from subjects.models import Subject
from drf_extra_fields.geo_fields import PointField
from landmarks.models import Landmark
class StudyGroupSerializer(serializers.ModelSerializer): class StudyGroupSerializer(serializers.ModelSerializer):
@ -9,10 +11,29 @@ class StudyGroupSerializer(serializers.ModelSerializer):
queryset=CustomUser.objects.all(), many=True, slug_field='name', required=False, allow_null=True) queryset=CustomUser.objects.all(), many=True, slug_field='name', required=False, allow_null=True)
subject = serializers.SlugRelatedField( subject = serializers.SlugRelatedField(
many=False, slug_field='name', queryset=Subject.objects.all(), required=True, allow_null=False) many=False, slug_field='name', queryset=Subject.objects.all(), required=True, allow_null=False)
location = PointField()
landmark = serializers.SlugRelatedField(
queryset=Landmark.objects.all(), many=False, slug_field='name', required=False, allow_null=True)
def create(self, validated_data):
user = self.context['request'].user
study_group = StudyGroup.objects.create(
users=[user], defaults=validated_data)
validated_data['location'].read_only = True
return study_group
def update(self, instance, validated_data):
# Check each landmark to see if our location is within it
for landmark in Landmark.objects.all():
if landmark.location.contains(validated_data['location']):
validated_data['landmark'] = landmark
break
return super().update(instance, validated_data)
class Meta: class Meta:
model = StudyGroup model = StudyGroup
fields = '__all__' fields = '__all__'
read_only_fields = ['landmark']
class StudyGroupMembershipSerializer(serializers.ModelSerializer): class StudyGroupMembershipSerializer(serializers.ModelSerializer):

View file

@ -4,7 +4,7 @@ from rest_framework.exceptions import PermissionDenied
from rest_framework.permissions import IsAuthenticated from rest_framework.permissions import IsAuthenticated
from .serializers import StudyGroupSerializer from .serializers import StudyGroupSerializer
from .models import StudyGroup from .models import StudyGroup
from courses.models import SubjectCourse from subjects.models import SubjectCourse
# Create your views here. # Create your views here.

View file

@ -1,4 +1,4 @@
# Generated by Django 4.2.2 on 2023-06-27 15:24 # Generated by Django 4.2.3 on 2023-07-18 07:43
from django.conf import settings from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
@ -20,7 +20,7 @@ class Migration(migrations.Migration):
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('message_content', models.TextField(max_length=1024)), ('message_content', models.TextField(max_length=1024)),
('timestamp', models.DateField(auto_now_add=True)), ('timestamp', models.DateTimeField(auto_now_add=True)),
('study_group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='study_groups.studygroup')), ('study_group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='study_groups.studygroup')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
], ],

View file

@ -1,18 +0,0 @@
# Generated by Django 4.2.2 on 2023-06-27 17:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('studygroup_messages', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='message',
name='timestamp',
field=models.DateTimeField(auto_now_add=True),
),
]

View file

@ -9,3 +9,6 @@ class Message(models.Model):
study_group = models.ForeignKey(StudyGroup, on_delete=models.CASCADE) study_group = models.ForeignKey(StudyGroup, on_delete=models.CASCADE)
message_content = models.TextField(max_length=1024) message_content = models.TextField(max_length=1024)
timestamp = models.DateTimeField(auto_now_add=True) timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f'Message: User={self.user.full_name}, Study_group={self.study_group.name}, ID={self.id}'

View file

@ -1,6 +1,5 @@
from django.contrib import admin from django.contrib import admin
from courses.models import Course from .models import Subject, SubjectCourse, SubjectSemester, SubjectYearLevel
from .models import Subject, SubjectStudent
class SubjectAdmin(admin.ModelAdmin): class SubjectAdmin(admin.ModelAdmin):
@ -8,4 +7,6 @@ class SubjectAdmin(admin.ModelAdmin):
admin.site.register(Subject, SubjectAdmin) admin.site.register(Subject, SubjectAdmin)
admin.site.register(SubjectStudent) admin.site.register(SubjectCourse)
admin.site.register(SubjectSemester)
admin.site.register(SubjectYearLevel)

View file

@ -1,5 +1,6 @@
# Generated by Django 4.2.2 on 2023-06-27 15:21 # Generated by Django 4.2.3 on 2023-07-18 07:43
from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
@ -10,8 +11,9 @@ class Migration(migrations.Migration):
dependencies = [ dependencies = [
('semesters', '0001_initial'), ('semesters', '0001_initial'),
('year_levels', '0001_initial'), migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('courses', '0001_initial'), ('courses', '0001_initial'),
('year_levels', '0001_initial'),
] ]
operations = [ operations = [
@ -21,9 +23,50 @@ class Migration(migrations.Migration):
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=64)), ('name', models.CharField(max_length=64)),
('code', models.CharField(max_length=16)), ('code', models.CharField(max_length=16)),
('courses', models.ManyToManyField(related_name='SubjectCourse_subject', through='courses.SubjectCourse', to='courses.course')),
('semester', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='semesters.semester')),
('year_level', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='Year_Level_name', to='year_levels.year_level')),
], ],
), ),
migrations.CreateModel(
name='SubjectYearLevel',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('subject', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='subjects.subject')),
('year_level', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='year_levels.year_level')),
],
),
migrations.CreateModel(
name='SubjectSemester',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('semester', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='semesters.semester')),
('subject', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='subjects.subject')),
],
),
migrations.CreateModel(
name='SubjectCourse',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('course', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='courses.course')),
('subject', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='subjects.subject')),
],
),
migrations.AddField(
model_name='subject',
name='courses',
field=models.ManyToManyField(related_name='SubjectCourse_subject', through='subjects.SubjectCourse', to='courses.course'),
),
migrations.AddField(
model_name='subject',
name='semesters',
field=models.ManyToManyField(related_name='SubjectSemester_subject', through='subjects.SubjectSemester', to='semesters.semester'),
),
migrations.AddField(
model_name='subject',
name='students',
field=models.ManyToManyField(to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='subject',
name='year_levels',
field=models.ManyToManyField(related_name='SubjectYearLevel_subject', through='subjects.SubjectYearLevel', to='year_levels.year_level'),
),
] ]

View file

@ -0,0 +1,76 @@
# Generated by Django 4.2.3 on 2023-07-18 10:28
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('year_levels', '0002_alter_year_level_name_alter_year_level_shortname'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('courses', '0003_alter_course_name_alter_course_shortname'),
('semesters', '0002_alter_semester_name_alter_semester_shortname'),
('subjects', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='subject',
name='code',
field=models.CharField(max_length=16, unique=True),
),
migrations.AlterField(
model_name='subject',
name='name',
field=models.CharField(max_length=64, unique=True),
),
migrations.AlterField(
model_name='subject',
name='students',
field=models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL),
),
migrations.AlterField(
model_name='subjectcourse',
name='course',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='courses.course', to_field='name'),
),
migrations.AlterField(
model_name='subjectcourse',
name='subject',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='subjects.subject', to_field='name'),
),
migrations.AlterField(
model_name='subjectsemester',
name='semester',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='semesters.semester', to_field='name'),
),
migrations.AlterField(
model_name='subjectsemester',
name='subject',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='subjects.subject', to_field='name'),
),
migrations.AlterField(
model_name='subjectyearlevel',
name='subject',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='subjects.subject', to_field='name'),
),
migrations.AlterField(
model_name='subjectyearlevel',
name='year_level',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='year_levels.year_level', to_field='name'),
),
migrations.AlterUniqueTogether(
name='subjectcourse',
unique_together={('subject', 'course')},
),
migrations.AlterUniqueTogether(
name='subjectsemester',
unique_together={('subject', 'semester')},
),
migrations.AlterUniqueTogether(
name='subjectyearlevel',
unique_together={('subject', 'year_level')},
),
]

View file

@ -1,29 +0,0 @@
# Generated by Django 4.2.2 on 2023-06-28 03:09
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('subjects', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='SubjectStudent',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('subject', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='subjects.subject')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.AddField(
model_name='subject',
name='students',
field=models.ManyToManyField(related_name='SubjectStudent_subject', through='subjects.SubjectStudent', to=settings.AUTH_USER_MODEL),
),
]

View file

@ -0,0 +1,29 @@
# Generated by Django 4.2.3 on 2023-07-19 07:04
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('subjects', '0002_alter_subject_code_alter_subject_name_and_more'),
]
operations = [
migrations.CreateModel(
name='SubjectCode',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('code', models.CharField(max_length=16, unique=True)),
],
),
migrations.RemoveField(
model_name='subject',
name='code',
),
migrations.AddField(
model_name='subject',
name='code',
field=models.ManyToManyField(to='subjects.subjectcode'),
),
]

View file

@ -0,0 +1,18 @@
# Generated by Django 4.2.3 on 2023-07-19 07:09
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('subjects', '0003_subjectcode_remove_subject_code_subject_code'),
]
operations = [
migrations.RenameField(
model_name='subject',
old_name='code',
new_name='codes',
),
]

View file

@ -1,38 +1,168 @@
import os
import csv
from django.conf import settings
from django.db import models from django.db import models
from django.db.models.signals import post_migrate
from django.dispatch import receiver
from courses.models import Course
from year_levels.models import Year_Level from year_levels.models import Year_Level
from semesters.models import Semester from semesters.models import Semester
# Create your models here. # Create your models here.
class Subject(models.Model): class Subject(models.Model):
name = models.CharField(max_length=64) name = models.CharField(max_length=64, unique=True)
code = models.CharField(max_length=16) codes = models.ManyToManyField(
'subjects.SubjectCode')
courses = models.ManyToManyField( courses = models.ManyToManyField(
'courses.Course', through='courses.SubjectCourse', related_name='SubjectCourse_subject') 'courses.Course', through='subjects.SubjectCourse', related_name='SubjectCourse_subject')
students = models.ManyToManyField( students = models.ManyToManyField(
'accounts.CustomUser', through='subjects.SubjectStudent', related_name='SubjectStudent_subject') 'accounts.CustomUser', blank=True)
year_level = models.ForeignKey( year_levels = models.ManyToManyField(
Year_Level, 'year_levels.Year_Level', through='subjects.SubjectYearLevel', related_name='SubjectYearLevel_subject')
on_delete=models.SET_NULL,
null=True, semesters = models.ManyToManyField(
related_name='Year_Level_name' 'semesters.Semester', through='subjects.SubjectSemester', related_name='SubjectSemester_subject')
)
semester = models.ForeignKey(
Semester,
on_delete=models.SET_NULL,
null=True
)
def __str__(self): def __str__(self):
return self.name code_list = ', '.join(self.codes.values_list('code', flat=True))
return f'{self.name} ({code_list})'
class SubjectStudent(models.Model): class SubjectCode(models.Model):
user = models.ForeignKey( code = models.CharField(max_length=16, unique=True)
'accounts.CustomUser', on_delete=models.CASCADE)
def __str__(self):
return self.code
class SubjectCourse(models.Model):
subject = models.ForeignKey( subject = models.ForeignKey(
'subjects.Subject', on_delete=models.CASCADE) 'subjects.Subject', on_delete=models.CASCADE, to_field='name')
course = models.ForeignKey(
'courses.Course', on_delete=models.CASCADE, null=True, to_field='name')
def __str__(self): def __str__(self):
return f'User: User={self.user_id}, Subject={self.subject_name}' return f'Subject={self.subject.name}, Course={self.course.name}'
class Meta:
unique_together = [['subject', 'course']]
class SubjectYearLevel(models.Model):
subject = models.ForeignKey(
'subjects.Subject', on_delete=models.CASCADE, to_field='name')
year_level = models.ForeignKey(
'year_levels.Year_Level', on_delete=models.CASCADE, to_field='name')
def __str__(self):
return f'Subject={self.subject.name}, Year Level={self.year_level.name}'
class Meta:
unique_together = [['subject', 'year_level']]
class SubjectSemester(models.Model):
subject = models.ForeignKey(
'subjects.Subject', on_delete=models.CASCADE, to_field='name')
semester = models.ForeignKey(
'semesters.Semester', on_delete=models.CASCADE, to_field='name')
def __str__(self):
return f'Subject={self.subject.name}, Semester={self.semester.name}'
class Meta:
unique_together = [['subject', 'semester']]
# Create subjects on initial migrate
@receiver(post_migrate)
def populate_subjects(sender, **kwargs):
if sender.name == 'subjects':
root_path = os.path.join(settings.MEDIA_ROOT, 'records')
csv_files = [f for f in os.listdir(root_path) if f.endswith('.csv')]
for csv_file in csv_files:
csv_file_path = os.path.join(root_path, csv_file)
# Filename contains course of subjects
filename = os.path.splitext(csv_file)[0]
print('Reading subjects from', filename)
with open(csv_file_path, newline='') as csvfile:
reader = csv.reader(csvfile)
next(reader) # Skip the header row
subject_count = 0
updated_subjects = 0
ignored_subjects = 0
for row in reader:
if not any(row):
continue
# Get subject information
year_term = row[0].split('-')
subject_year_level = year_term[0].strip()
subject_semester = year_term[1].strip()
subject_code = row[1]
subject_name = row[2]
# Definitions of subjects to ignore
ignored_subject_codes = ['NSTP', 'ROTC', 'CWTS', 'LTS']
ignored_subject_names = [
'PRACTICUM', 'On the Job Training', 'CAPSTONE', 'Capstone']
# Skip ignored subjects
if any(ignored_code in subject_code for ignored_code in ignored_subject_codes):
ignored_subjects += 1
continue
if any(ignored_name in subject_name for ignored_name in ignored_subject_names):
ignored_subjects += 1
continue
# Get relevant info for specific subject
course = Course.objects.filter(
name=filename).first()
year_level = Year_Level.objects.filter(
name=subject_year_level).first()
semester = Semester.objects.filter(
name=subject_semester).first()
# If subject already exists with relevant info, skip over it
if (Subject.objects.filter(name=subject_name, year_levels=year_level, semesters=semester).exists()):
# print('Duplicate subject')
continue
# Else if subject exists without relevant info, add relevant info
if (Subject.objects.filter(name=subject_name).exists()):
SUBJECT = Subject.objects.filter(name=subject_name
).first()
SUBJECT.courses.add(course)
SUBJECT.year_levels.add(year_level)
SUBJECT.semesters.add(semester)
SUBJECT_CODE = SubjectCode.objects.get_or_create(
code=subject_code)
SUBJECT.codes.add(SUBJECT_CODE[0])
updated_subjects += 1
# If subject does not exist at all, then create new subject
else:
SUBJECT = Subject.objects.get_or_create(
name=subject_name,
)
SUBJECT[0].courses.set([course])
SUBJECT[0].year_levels.set([year_level])
SUBJECT[0].semesters.set([semester])
SUBJECT_CODE = SubjectCode.objects.get_or_create(
code=subject_code)
SUBJECT[0].codes.add(SUBJECT_CODE[0])
subject_count += 1
# Set the course, year level, and semester of the subject
print('Added', subject_count, 'subjects from', filename,)
print('Updated', updated_subjects, 'subjects from', filename)
print('Ignored', ignored_subjects,
'subjects from', filename, '\n')

View file

@ -1,23 +1,21 @@
from rest_framework import serializers from rest_framework import serializers
from .models import Subject from .models import Subject, SubjectCode
from courses.models import Course from courses.models import Course
from year_levels.serializers import YearLevelSerializer from year_levels.models import Year_Level
from semesters.serializers import SemesterSerializer from semesters.models import Semester
from courses.serializers import CourseSerializer from accounts.models import CustomUser
class SubjectSerializer(serializers.ModelSerializer): class SubjectSerializer(serializers.ModelSerializer):
year_level = serializers.SerializerMethodField() year_levels = serializers.SlugRelatedField(
semester = serializers.SerializerMethodField() queryset=Year_Level.objects.all(), many=True, slug_field='name', allow_null=True)
semesters = serializers.SlugRelatedField(
queryset=Semester.objects.all(), many=True, slug_field='name', allow_null=True)
courses = serializers.SlugRelatedField( courses = serializers.SlugRelatedField(
queryset=Course.objects.all(), many=True, slug_field='name', allow_null=True) queryset=Course.objects.all(), many=True, slug_field='name', allow_null=True)
codes = serializers.SlugRelatedField(
queryset=SubjectCode.objects.all(), many=True, slug_field='code', allow_null=False)
class Meta: class Meta:
model = Subject model = Subject
fields = ('name', 'code', 'courses', 'year_level', 'semester') fields = ('id', 'name', 'codes', 'courses', 'year_levels', 'semesters')
def get_year_level(self, obj):
return obj.year_level.name
def get_semester(self, obj):
return obj.semester.name

View file

@ -1,11 +1,8 @@
from django.urls import include, path from django.urls import include, path
from .views import SubjectListView from .views import SubjectByYearSemesterView, SubjectListView
from .views import SubjectByYearSemesterView, SubjectByYearView from rest_framework import routers
urlpatterns = [ urlpatterns = [
path('', SubjectListView.as_view()), path('', SubjectListView.as_view()),
path('<slug:year_slug>/', path('<slug:course_slug>/<slug:year_slug>/<slug:semester_slug>',
SubjectByYearView.as_view()),
path('<slug:year_slug>/<slug:semester_slug>',
SubjectByYearSemesterView.as_view()), SubjectByYearSemesterView.as_view()),
] ]

View file

@ -1,4 +1,4 @@
from rest_framework import generics from rest_framework import generics, viewsets
from .models import Subject from .models import Subject
from .serializers import SubjectSerializer from .serializers import SubjectSerializer
from rest_framework.views import APIView from rest_framework.views import APIView
@ -10,27 +10,13 @@ class SubjectListView(generics.ListAPIView):
queryset = Subject.objects.all() queryset = Subject.objects.all()
class SubjectByYearView(generics.ListAPIView):
queryset = Subject.objects.all()
def get(self, request, year_slug):
# Retrieve the subjects based on year level and semester slugs
subjects = Subject.objects.filter(
year_level__shortname=year_slug)
# Serialize the subjects
serializer = SubjectSerializer(subjects, many=True)
return Response(serializer.data)
class SubjectByYearSemesterView(generics.ListAPIView): class SubjectByYearSemesterView(generics.ListAPIView):
queryset = Subject.objects.all() queryset = Subject.objects.all()
def get(self, request, year_slug, semester_slug): def get(self, request, course_slug, year_slug, semester_slug):
# Retrieve the subjects based on year level and semester slugs # Retrieve the subjects based on year level and semester slugs
subjects = Subject.objects.filter( subjects = Subject.objects.filter(
year_level__shortname=year_slug, semester__shortname=semester_slug) courses__shortname=course_slug, year_levels__shortname=year_slug, semesters__shortname=semester_slug)
# Serialize the subjects # Serialize the subjects
serializer = SubjectSerializer(subjects, many=True) serializer = SubjectSerializer(subjects, many=True)

View file

@ -19,7 +19,7 @@
<p>{% blocktrans %}You're receiving this email because you need to finish activation process on {{ site_name }}.{% endblocktrans %}</p> <p>{% blocktrans %}You're receiving this email because you need to finish activation process on {{ site_name }}.{% endblocktrans %}</p>
<p>{% trans "Please go to the following page to activate your account in-app:" %}</p> <p>{% trans "Please go to the following page to activate your account in-app:" %}</p>
<p><a href="{{ domain }}://{{ url|safe }}">{{ domain }}://--/{{ url|safe }}</a></p> <p><a href="{{domain}}://{{url}}">{{ domain }}://{{url}}</a></p>
<p>{% blocktrans %}Many thanks from the {{ site_name }} team{% endblocktrans %}</p> <p>{% blocktrans %}Many thanks from the {{ site_name }} team{% endblocktrans %}</p>

View file

@ -1,4 +1,4 @@
# Generated by Django 4.2.2 on 2023-06-27 15:21 # Generated by Django 4.2.3 on 2023-07-18 07:43
from django.db import migrations, models from django.db import migrations, models

View file

@ -0,0 +1,23 @@
# Generated by Django 4.2.3 on 2023-07-18 10:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('year_levels', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='year_level',
name='name',
field=models.CharField(max_length=64, unique=True),
),
migrations.AlterField(
model_name='year_level',
name='shortname',
field=models.CharField(max_length=16, unique=True),
),
]

View file

@ -6,8 +6,8 @@ from django.dispatch import receiver
class Year_Level(models.Model): class Year_Level(models.Model):
name = models.CharField(max_length=64) name = models.CharField(max_length=64, unique=True)
shortname = models.CharField(max_length=16) shortname = models.CharField(max_length=16, unique=True)
def __str__(self): def __str__(self):
return self.name return self.name