diff --git a/Pipfile b/Pipfile index c235739..3e23d2f 100644 --- a/Pipfile +++ b/Pipfile @@ -11,6 +11,11 @@ djoser = "*" pillow = "*" whitenoise = "*" djangochannelsrestframework = "*" +daphne = "*" +psycopg2 = "*" +gdal = {path = "./packages/GDAL-3.4.3-cp311-cp311-win_amd64.whl"} +django-leaflet = "*" +django-extra-fields = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index b67ebf8..3d11d05 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "231f11224ec1ef1ad1406ac5644ebcdfac020af9478f407d577553bb05c637df" + "sha256": "975af7eaaedebb1c31a1828fdf307574edc293e0de15ecfd9cf7107f98d642f5" }, "pipfile-spec": 6, "requires": { @@ -24,6 +24,28 @@ "markers": "python_version >= '3.7'", "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": { "hashes": [ "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7", @@ -111,109 +133,128 @@ }, "charset-normalizer": { "hashes": [ - "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6", - "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1", - "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e", - "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373", - "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62", - "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230", - "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be", - "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c", - "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0", - "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448", - "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f", - "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649", - "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d", - "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0", - "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706", - "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a", - "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59", - "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23", - "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5", - "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb", - "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e", - "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e", - "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c", - "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28", - "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d", - "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41", - "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974", - "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce", - "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f", - "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1", - "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d", - "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8", - "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017", - "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31", - "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7", - "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8", - "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e", - "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14", - "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd", - "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d", - "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795", - "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b", - "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b", - "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b", - "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203", - "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f", - "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19", - "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1", - "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a", - "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac", - "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9", - "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0", - "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137", - "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f", - "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6", - "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5", - "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909", - "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f", - "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0", - "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324", - "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755", - "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb", - "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854", - "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c", - "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60", - "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84", - "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0", - "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b", - "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1", - "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531", - "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1", - "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11", - "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326", - "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df", - "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab" + "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96", + "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c", + "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710", + "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706", + "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020", + "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252", + "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad", + "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329", + "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a", + "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f", + "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6", + "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4", + "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a", + "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46", + "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2", + "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23", + "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace", + "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd", + "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982", + "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10", + "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2", + "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea", + "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09", + "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5", + "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149", + "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489", + "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9", + "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80", + "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592", + "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3", + "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6", + "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed", + "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c", + "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200", + "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a", + "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e", + "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d", + "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6", + "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623", + "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669", + "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3", + "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa", + "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9", + "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2", + "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f", + "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1", + "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4", + "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a", + "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8", + "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3", + "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029", + "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f", + "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959", + "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22", + "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7", + "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952", + "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346", + "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e", + "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d", + "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299", + "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd", + "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a", + "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3", + "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037", + "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94", + "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c", + "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858", + "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a", + "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449", + "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c", + "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918", + "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1", + "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c", + "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac", + "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa" ], "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": { "hashes": [ - "sha256:059e348f9a3c1950937e1b5d7ba1f8e968508ab181e75fc32b879452f08356db", - "sha256:1a5472d40c8f8e91ff7a3d8ac6dfa363d8e3138b961529c996f3e2df0c7a411a", - "sha256:1a8e6c2de6fbbcc5e14fd27fb24414507cb3333198ea9ab1258d916f00bc3039", - "sha256:1fee5aacc7367487b4e22484d3c7e547992ed726d14864ee33c0176ae43b0d7c", - "sha256:5d092fdfedaec4cbbffbf98cddc915ba145313a6fdaab83c6e67f4e6c218e6f3", - "sha256:5f0ff6e18d13a3de56f609dd1fd11470918f770c6bd5d00d632076c727d35485", - "sha256:7bfc55a5eae8b86a287747053140ba221afc65eb06207bedf6e019b8934b477c", - "sha256:7fa01527046ca5facdf973eef2535a27fec4cb651e4daec4d043ef63f6ecd4ca", - "sha256:8dde71c4169ec5ccc1087bb7521d54251c016f126f922ab2dfe6649170a3b8c5", - "sha256:8f4ab7021127a9b4323537300a2acfb450124b2def3756f64dc3a3d2160ee4b5", - "sha256:948224d76c4b6457349d47c0c98657557f429b4e93057cf5a2f71d603e2fc3a3", - "sha256:9a6c7a3c87d595608a39980ebaa04d5a37f94024c9f24eb7d10262b92f739ddb", - "sha256:b46e37db3cc267b4dea1f56da7346c9727e1209aa98487179ee8ebed09d21e43", - "sha256:b4ceb5324b998ce2003bc17d519080b4ec8d5b7b70794cbd2836101406a9be31", - "sha256:cb33ccf15e89f7ed89b235cff9d49e2e62c6c981a6061c9c8bb47ed7951190bc", - "sha256:d198820aba55660b4d74f7b5fd1f17db3aa5eb3e6893b0a41b75e84e4f9e0e4b", - "sha256:d34579085401d3f49762d2f7d6634d6b6c2ae1242202e860f4d26b046e3a1006", - "sha256:eb8163f5e549a22888c18b0d53d6bb62a20510060a22fd5a995ec8a05268df8a", - "sha256:f73bff05db2a3e5974a6fd248af2566134d8981fd7ab012e5dd4ddb1d9a70699" + "sha256:01f1d9e537f9a15b037d5d9ee442b8c22e3ae11ce65ea1f3316a41c78756b711", + "sha256:079347de771f9282fbfe0e0236c716686950c19dee1b76240ab09ce1624d76d7", + "sha256:182be4171f9332b6741ee818ec27daff9fb00349f706629f5cbf417bd50e66fd", + "sha256:192255f539d7a89f2102d07d7375b1e0a81f7478925b3bc2e0549ebf739dae0e", + "sha256:2a034bf7d9ca894720f2ec1d8b7b5832d7e363571828037f9e0c4f18c1b58a58", + "sha256:342f3767e25876751e14f8459ad85e77e660537ca0a066e10e75df9c9e9099f0", + "sha256:439c3cc4c0d42fa999b83ded80a9a1fb54d53c58d6e59234cfe97f241e6c781d", + "sha256:49c3222bb8f8e800aead2e376cbef687bc9e3cb9b58b29a261210456a7783d83", + "sha256:674b669d5daa64206c38e507808aae49904c988fa0a71c935e7006a3e1e83831", + "sha256:7a9a3bced53b7f09da251685224d6a260c3cb291768f54954e28f03ef14e3766", + "sha256:7af244b012711a26196450d34f483357e42aeddb04128885d95a69bd8b14b69b", + "sha256:7d230bf856164de164ecb615ccc14c7fc6de6906ddd5b491f3af90d3514c925c", + "sha256:84609ade00a6ec59a89729e87a503c6e36af98ddcd566d5f3be52e29ba993182", + "sha256:9a6673c1828db6270b76b22cc696f40cde9043eb90373da5c2f8f2158957f42f", + "sha256:9b6d717393dbae53d4e52684ef4f022444fc1cce3c48c38cb74fca29e1f08eaa", + "sha256:9c3fe6534d59d071ee82081ca3d71eed3210f76ebd0361798c74abc2bcf347d4", + "sha256:a719399b99377b218dac6cf547b6ec54e6ef20207b6165126a280b0ce97e0d2a", + "sha256:b332cba64d99a70c1e0836902720887fb4529ea49ea7f5462cf6640e095e11d2", + "sha256:d124682c7a23c9764e54ca9ab5b308b14b18eba02722b8659fb238546de83a76", + "sha256:d73f419a56d74fef257955f51b18d046f3506270a5fd2ac5febbfa259d6c0fa5", + "sha256:f0dc40e6f7aa37af01aba07277d3d64d5a03dc66d682097541ec4da03cc140ee", + "sha256:f14ad275364c8b4e525d018f6716537ae7b6d369c094805cae45300847e0894f", + "sha256:f772610fe364372de33d76edcd313636a25684edb94cee53fd790195f5989d14" ], "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": { "hashes": [ @@ -225,11 +266,26 @@ }, "django": { "hashes": [ - "sha256:2a6b6fbff5b59dd07bef10bcb019bee2ea97a30b2a656d51346596724324badf", - "sha256:672b3fa81e1f853bb58be1b51754108ab4ffa12a77c06db86aa8df9ed0c46fe5" + "sha256:45a747e1c5b3d6df1b141b1481e193b033fd1fdbda3ff52677dc81afdaacbaed", + "sha256:f7c7852a5ac5a3da5a8d5b35cc6168f31b605971441798dac845f17ca8028039" ], "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": { "hashes": [ @@ -270,6 +326,20 @@ "index": "pypi", "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": { "hashes": [ "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", @@ -278,6 +348,13 @@ "markers": "python_version >= '3.5'", "version": "==3.4" }, + "incremental": { + "hashes": [ + "sha256:912feeb5e0f7e0188e6f42241d2f450002e11bbc0937c65865045854c24c0bd0", + "sha256:b864a1f30885ee72c5ac2835a761b8fe8aa9c28b9395cacf27286602688d3e51" + ], + "version": "==22.10.0" + }, "oauthlib": { "hashes": [ "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca", @@ -288,75 +365,100 @@ }, "pillow": { "hashes": [ - "sha256:07999f5834bdc404c442146942a2ecadd1cb6292f5229f4ed3b31e0a108746b1", - "sha256:0852ddb76d85f127c135b6dd1f0bb88dbb9ee990d2cd9aa9e28526c93e794fba", - "sha256:1781a624c229cb35a2ac31cc4a77e28cafc8900733a864870c49bfeedacd106a", - "sha256:1e7723bd90ef94eda669a3c2c19d549874dd5badaeefabefd26053304abe5799", - "sha256:229e2c79c00e85989a34b5981a2b67aa079fd08c903f0aaead522a1d68d79e51", - "sha256:22baf0c3cf0c7f26e82d6e1adf118027afb325e703922c8dfc1d5d0156bb2eeb", - "sha256:252a03f1bdddce077eff2354c3861bf437c892fb1832f75ce813ee94347aa9b5", - "sha256:2dfaaf10b6172697b9bceb9a3bd7b951819d1ca339a5ef294d1f1ac6d7f63270", - "sha256:322724c0032af6692456cd6ed554bb85f8149214d97398bb80613b04e33769f6", - "sha256:35f6e77122a0c0762268216315bf239cf52b88865bba522999dc38f1c52b9b47", - "sha256:375f6e5ee9620a271acb6820b3d1e94ffa8e741c0601db4c0c4d3cb0a9c224bf", - "sha256:3ded42b9ad70e5f1754fb7c2e2d6465a9c842e41d178f262e08b8c85ed8a1d8e", - "sha256:432b975c009cf649420615388561c0ce7cc31ce9b2e374db659ee4f7d57a1f8b", - "sha256:482877592e927fd263028c105b36272398e3e1be3269efda09f6ba21fd83ec66", - "sha256:489f8389261e5ed43ac8ff7b453162af39c3e8abd730af8363587ba64bb2e865", - "sha256:54f7102ad31a3de5666827526e248c3530b3a33539dbda27c6843d19d72644ec", - "sha256:560737e70cb9c6255d6dcba3de6578a9e2ec4b573659943a5e7e4af13f298f5c", - "sha256:5671583eab84af046a397d6d0ba25343c00cd50bce03787948e0fff01d4fd9b1", - "sha256:5ba1b81ee69573fe7124881762bb4cd2e4b6ed9dd28c9c60a632902fe8db8b38", - "sha256:5d4ebf8e1db4441a55c509c4baa7a0587a0210f7cd25fcfe74dbbce7a4bd1906", - "sha256:60037a8db8750e474af7ffc9faa9b5859e6c6d0a50e55c45576bf28be7419705", - "sha256:608488bdcbdb4ba7837461442b90ea6f3079397ddc968c31265c1e056964f1ef", - "sha256:6608ff3bf781eee0cd14d0901a2b9cc3d3834516532e3bd673a0a204dc8615fc", - "sha256:662da1f3f89a302cc22faa9f14a262c2e3951f9dbc9617609a47521c69dd9f8f", - "sha256:7002d0797a3e4193c7cdee3198d7c14f92c0836d6b4a3f3046a64bd1ce8df2bf", - "sha256:763782b2e03e45e2c77d7779875f4432e25121ef002a41829d8868700d119392", - "sha256:77165c4a5e7d5a284f10a6efaa39a0ae8ba839da344f20b111d62cc932fa4e5d", - "sha256:7c9af5a3b406a50e313467e3565fc99929717f780164fe6fbb7704edba0cebbe", - "sha256:7ec6f6ce99dab90b52da21cf0dc519e21095e332ff3b399a357c187b1a5eee32", - "sha256:833b86a98e0ede388fa29363159c9b1a294b0905b5128baf01db683672f230f5", - "sha256:84a6f19ce086c1bf894644b43cd129702f781ba5751ca8572f08aa40ef0ab7b7", - "sha256:8507eda3cd0608a1f94f58c64817e83ec12fa93a9436938b191b80d9e4c0fc44", - "sha256:85ec677246533e27770b0de5cf0f9d6e4ec0c212a1f89dfc941b64b21226009d", - "sha256:8aca1152d93dcc27dc55395604dcfc55bed5f25ef4c98716a928bacba90d33a3", - "sha256:8d935f924bbab8f0a9a28404422da8af4904e36d5c33fc6f677e4c4485515625", - "sha256:8f36397bf3f7d7c6a3abdea815ecf6fd14e7fcd4418ab24bae01008d8d8ca15e", - "sha256:91ec6fe47b5eb5a9968c79ad9ed78c342b1f97a091677ba0e012701add857829", - "sha256:965e4a05ef364e7b973dd17fc765f42233415974d773e82144c9bbaaaea5d089", - "sha256:96e88745a55b88a7c64fa49bceff363a1a27d9a64e04019c2281049444a571e3", - "sha256:99eb6cafb6ba90e436684e08dad8be1637efb71c4f2180ee6b8f940739406e78", - "sha256:9adf58f5d64e474bed00d69bcd86ec4bcaa4123bfa70a65ce72e424bfb88ed96", - "sha256:9b1af95c3a967bf1da94f253e56b6286b50af23392a886720f563c547e48e964", - "sha256:a0aa9417994d91301056f3d0038af1199eb7adc86e646a36b9e050b06f526597", - "sha256:a0f9bb6c80e6efcde93ffc51256d5cfb2155ff8f78292f074f60f9e70b942d99", - "sha256:a127ae76092974abfbfa38ca2d12cbeddcdeac0fb71f9627cc1135bedaf9d51a", - "sha256:aaf305d6d40bd9632198c766fb64f0c1a83ca5b667f16c1e79e1661ab5060140", - "sha256:aca1c196f407ec7cf04dcbb15d19a43c507a81f7ffc45b690899d6a76ac9fda7", - "sha256:ace6ca218308447b9077c14ea4ef381ba0b67ee78d64046b3f19cf4e1139ad16", - "sha256:b416f03d37d27290cb93597335a2f85ed446731200705b22bb927405320de903", - "sha256:bf548479d336726d7a0eceb6e767e179fbde37833ae42794602631a070d630f1", - "sha256:c1170d6b195555644f0616fd6ed929dfcf6333b8675fcca044ae5ab110ded296", - "sha256:c380b27d041209b849ed246b111b7c166ba36d7933ec6e41175fd15ab9eb1572", - "sha256:c446d2245ba29820d405315083d55299a796695d747efceb5717a8b450324115", - "sha256:c830a02caeb789633863b466b9de10c015bded434deb3ec87c768e53752ad22a", - "sha256:cb841572862f629b99725ebaec3287fc6d275be9b14443ea746c1dd325053cbd", - "sha256:cfa4561277f677ecf651e2b22dc43e8f5368b74a25a8f7d1d4a3a243e573f2d4", - "sha256:cfcc2c53c06f2ccb8976fb5c71d448bdd0a07d26d8e07e321c103416444c7ad1", - "sha256:d3c6b54e304c60c4181da1c9dadf83e4a54fd266a99c70ba646a9baa626819eb", - "sha256:d3d403753c9d5adc04d4694d35cf0391f0f3d57c8e0030aac09d7678fa8030aa", - "sha256:d9c206c29b46cfd343ea7cdfe1232443072bbb270d6a46f59c259460db76779a", - "sha256:e49eb4e95ff6fd7c0c402508894b1ef0e01b99a44320ba7d8ecbabefddcc5569", - "sha256:f8286396b351785801a976b1e85ea88e937712ee2c3ac653710a4a57a8da5d9c", - "sha256:f8fc330c3370a81bbf3f88557097d1ea26cd8b019d6433aa59f71195f5ddebbf", - "sha256:fbd359831c1657d69bb81f0db962905ee05e5e9451913b18b831febfe0519082", - "sha256:fe7e1c262d3392afcf5071df9afa574544f28eac825284596ac6db56e6d11062", - "sha256:fed1e1cf6a42577953abbe8e6cf2fe2f566daebde7c34724ec8803c4c0cda579" + "sha256:00e65f5e822decd501e374b0650146063fbb30a7264b4d2744bdd7b913e0cab5", + "sha256:040586f7d37b34547153fa383f7f9aed68b738992380ac911447bb78f2abe530", + "sha256:0b6eb5502f45a60a3f411c63187db83a3d3107887ad0d036c13ce836f8a36f1d", + "sha256:1ce91b6ec08d866b14413d3f0bbdea7e24dfdc8e59f562bb77bc3fe60b6144ca", + "sha256:1f62406a884ae75fb2f818694469519fb685cc7eaff05d3451a9ebe55c646891", + "sha256:22c10cc517668d44b211717fd9775799ccec4124b9a7f7b3635fc5386e584992", + "sha256:3400aae60685b06bb96f99a21e1ada7bc7a413d5f49bce739828ecd9391bb8f7", + "sha256:349930d6e9c685c089284b013478d6f76e3a534e36ddfa912cde493f235372f3", + "sha256:368ab3dfb5f49e312231b6f27b8820c823652b7cd29cfbd34090565a015e99ba", + "sha256:38250a349b6b390ee6047a62c086d3817ac69022c127f8a5dc058c31ccef17f3", + "sha256:3a684105f7c32488f7153905a4e3015a3b6c7182e106fe3c37fbb5ef3e6994c3", + "sha256:3a82c40d706d9aa9734289740ce26460a11aeec2d9c79b7af87bb35f0073c12f", + "sha256:3b08d4cc24f471b2c8ca24ec060abf4bebc6b144cb89cba638c720546b1cf538", + "sha256:3ed64f9ca2f0a95411e88a4efbd7a29e5ce2cea36072c53dd9d26d9c76f753b3", + "sha256:3f07ea8d2f827d7d2a49ecf1639ec02d75ffd1b88dcc5b3a61bbb37a8759ad8d", + "sha256:520f2a520dc040512699f20fa1c363eed506e94248d71f85412b625026f6142c", + "sha256:5c6e3df6bdd396749bafd45314871b3d0af81ff935b2d188385e970052091017", + "sha256:608bfdee0d57cf297d32bcbb3c728dc1da0907519d1784962c5f0c68bb93e5a3", + "sha256:685ac03cc4ed5ebc15ad5c23bc555d68a87777586d970c2c3e216619a5476223", + "sha256:76de421f9c326da8f43d690110f0e79fe3ad1e54be811545d7d91898b4c8493e", + "sha256:76edb0a1fa2b4745fb0c99fb9fb98f8b180a1bbceb8be49b087e0b21867e77d3", + "sha256:7be600823e4c8631b74e4a0d38384c73f680e6105a7d3c6824fcf226c178c7e6", + "sha256:81ff539a12457809666fef6624684c008e00ff6bf455b4b89fd00a140eecd640", + "sha256:88af2003543cc40c80f6fca01411892ec52b11021b3dc22ec3bc9d5afd1c5334", + "sha256:8c11160913e3dd06c8ffdb5f233a4f254cb449f4dfc0f8f4549eda9e542c93d1", + "sha256:8f8182b523b2289f7c415f589118228d30ac8c355baa2f3194ced084dac2dbba", + "sha256:9211e7ad69d7c9401cfc0e23d49b69ca65ddd898976d660a2fa5904e3d7a9baa", + "sha256:92be919bbc9f7d09f7ae343c38f5bb21c973d2576c1d45600fce4b74bafa7ac0", + "sha256:9c82b5b3e043c7af0d95792d0d20ccf68f61a1fec6b3530e718b688422727396", + "sha256:9f7c16705f44e0504a3a2a14197c1f0b32a95731d251777dcb060aa83022cb2d", + "sha256:9fb218c8a12e51d7ead2a7c9e101a04982237d4855716af2e9499306728fb485", + "sha256:a74ba0c356aaa3bb8e3eb79606a87669e7ec6444be352870623025d75a14a2bf", + "sha256:b4f69b3700201b80bb82c3a97d5e9254084f6dd5fb5b16fc1a7b974260f89f43", + "sha256:bc2ec7c7b5d66b8ec9ce9f720dbb5fa4bace0f545acd34870eff4a369b44bf37", + "sha256:c189af0545965fa8d3b9613cfdb0cd37f9d71349e0f7750e1fd704648d475ed2", + "sha256:c1fbe7621c167ecaa38ad29643d77a9ce7311583761abf7836e1510c580bf3dd", + "sha256:c7cf14a27b0d6adfaebb3ae4153f1e516df54e47e42dcc073d7b3d76111a8d86", + "sha256:c9f72a021fbb792ce98306ffb0c348b3c9cb967dce0f12a49aa4c3d3fdefa967", + "sha256:cd25d2a9d2b36fcb318882481367956d2cf91329f6892fe5d385c346c0649629", + "sha256:ce543ed15570eedbb85df19b0a1a7314a9c8141a36ce089c0a894adbfccb4568", + "sha256:ce7b031a6fc11365970e6a5686d7ba8c63e4c1cf1ea143811acbb524295eabed", + "sha256:d35e3c8d9b1268cbf5d3670285feb3528f6680420eafe35cccc686b73c1e330f", + "sha256:d50b6aec14bc737742ca96e85d6d0a5f9bfbded018264b3b70ff9d8c33485551", + "sha256:d5d0dae4cfd56969d23d94dc8e89fb6a217be461c69090768227beb8ed28c0a3", + "sha256:d5db32e2a6ccbb3d34d87c87b432959e0db29755727afb37290e10f6e8e62614", + "sha256:d72e2ecc68a942e8cf9739619b7f408cc7b272b279b56b2c83c6123fcfa5cdff", + "sha256:d737a602fbd82afd892ca746392401b634e278cb65d55c4b7a8f48e9ef8d008d", + "sha256:d80cf684b541685fccdd84c485b31ce73fc5c9b5d7523bf1394ce134a60c6883", + "sha256:db24668940f82321e746773a4bc617bfac06ec831e5c88b643f91f122a785684", + "sha256:dbc02381779d412145331789b40cc7b11fdf449e5d94f6bc0b080db0a56ea3f0", + "sha256:dffe31a7f47b603318c609f378ebcd57f1554a3a6a8effbc59c3c69f804296de", + "sha256:edf4392b77bdc81f36e92d3a07a5cd072f90253197f4a52a55a8cec48a12483b", + "sha256:efe8c0681042536e0d06c11f48cebe759707c9e9abf880ee213541c5b46c5bf3", + "sha256:f31f9fdbfecb042d046f9d91270a0ba28368a723302786c0009ee9b9f1f60199", + "sha256:f88a0b92277de8e3ca715a0d79d68dc82807457dae3ab8699c758f07c20b3c51", + "sha256:faaf07ea35355b01a35cb442dd950d8f1bb5b040a7787791a535de13db15ed90" ], "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": { "hashes": [ @@ -373,6 +475,13 @@ "markers": "python_version >= '3.7'", "version": "==2.7.0" }, + "pyopenssl": { + "hashes": [ + "sha256:24f0dc5227396b3e831f4c7f602b950a5e9833d292c8e4a2e06b709292806ae2", + "sha256:276f931f55a452e7dea69c7173e984eb2a4407ce413c918aa34b55f82f9b8bac" + ], + "version": "==23.2.0" + }, "python-dotenv": { "hashes": [ "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba", @@ -411,6 +520,29 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "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": { "hashes": [ "sha256:0347ca4cd23ea9d15a665da9d22950552fb66b95600e6c2ebae38ca883b3a4ed", @@ -435,6 +567,55 @@ "markers": "python_version >= '3.5'", "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": { "hashes": [ "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a", @@ -458,6 +639,42 @@ ], "index": "pypi", "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": {} diff --git a/packages/GDAL-3.4.3-cp311-cp311-win_amd64.whl b/packages/GDAL-3.4.3-cp311-cp311-win_amd64.whl new file mode 100644 index 0000000..573d1c0 Binary files /dev/null and b/packages/GDAL-3.4.3-cp311-cp311-win_amd64.whl differ diff --git a/packages/readme.md b/packages/readme.md new file mode 100644 index 0000000..fd14b80 --- /dev/null +++ b/packages/readme.md @@ -0,0 +1,5 @@ +Some stuff we need to manually install + +> pipenv install + +Running the command above should automatically install these packages diff --git a/stude/accounts/admin.py b/stude/accounts/admin.py index 2ce5065..37df597 100644 --- a/stude/accounts/admin.py +++ b/stude/accounts/admin.py @@ -5,6 +5,7 @@ from .models import CustomUser from year_levels.models import Year_Level from semesters.models import Semester from courses.models import Course +from subjects.models import Subject class CustomUserForm(forms.ModelForm): @@ -14,6 +15,8 @@ class CustomUserForm(forms.ModelForm): queryset=Semester.objects.all(), required=False) course = forms.ModelChoiceField( queryset=Course.objects.all(), required=False) + subjects = forms.ModelMultipleChoiceField( + queryset=Subject.objects.all(), required=False, widget=forms.CheckboxSelectMultiple) avatar = forms.ImageField(required=False) class Meta: @@ -27,7 +30,7 @@ class CustomUserAdmin(UserAdmin): fieldsets = UserAdmin.fieldsets + ( (None, {'fields': ('student_id_number', - 'year_level', 'semester', 'course', 'avatar', 'is_student', 'is_banned')}), + 'year_level', 'semester', 'course', 'subjects', 'avatar', 'is_student', 'is_banned')}), ) diff --git a/stude/accounts/management/__init__.py b/stude/accounts/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/stude/accounts/management/commands/__init__.py b/stude/accounts/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/stude/accounts/management/commands/custom_migrate.py b/stude/accounts/management/commands/custom_migrate.py new file mode 100644 index 0000000..ad953c5 --- /dev/null +++ b/stude/accounts/management/commands/custom_migrate.py @@ -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') diff --git a/stude/accounts/migrations/0001_initial.py b/stude/accounts/migrations/0001_initial.py index 1c5b101..fedcb98 100644 --- a/stude/accounts/migrations/0001_initial.py +++ b/stude/accounts/migrations/0001_initial.py @@ -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 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')), ('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_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')), ('first_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_studying', models.BooleanField(default=False)), ('is_banned', models.BooleanField(default=False)), diff --git a/stude/accounts/migrations/0002_initial.py b/stude/accounts/migrations/0002_initial.py index 8e150eb..c0e486a 100644 --- a/stude/accounts/migrations/0002_initial.py +++ b/stude/accounts/migrations/0002_initial.py @@ -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 import django.db.models.deletion @@ -12,15 +12,16 @@ class Migration(migrations.Migration): ('auth', '0012_alter_user_first_name_max_length'), ('year_levels', '0001_initial'), ('accounts', '0001_initial'), - ('courses', '0002_initial'), ('semesters', '0001_initial'), + ('courses', '0002_initial'), + ('subjects', '0001_initial'), ] operations = [ migrations.AddField( model_name='customuser', 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( model_name='customuser', @@ -30,7 +31,12 @@ class Migration(migrations.Migration): migrations.AddField( model_name='customuser', 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( model_name='customuser', @@ -40,6 +46,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name='customuser', 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'), ), ] diff --git a/stude/accounts/migrations/0003_customuser_subjects.py b/stude/accounts/migrations/0003_customuser_subjects.py deleted file mode 100644 index 37f2fd5..0000000 --- a/stude/accounts/migrations/0003_customuser_subjects.py +++ /dev/null @@ -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'), - ), - ] diff --git a/stude/accounts/migrations/0004_alter_customuser_course_alter_customuser_semester_and_more.py b/stude/accounts/migrations/0004_alter_customuser_course_alter_customuser_semester_and_more.py deleted file mode 100644 index 0527dd0..0000000 --- a/stude/accounts/migrations/0004_alter_customuser_course_alter_customuser_semester_and_more.py +++ /dev/null @@ -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'), - ), - ] diff --git a/stude/accounts/migrations/0005_alter_customuser_is_active.py b/stude/accounts/migrations/0005_alter_customuser_is_active.py deleted file mode 100644 index f6ebd78..0000000 --- a/stude/accounts/migrations/0005_alter_customuser_is_active.py +++ /dev/null @@ -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), - ), - ] diff --git a/stude/accounts/models.py b/stude/accounts/models.py index 4f33659..296ac68 100644 --- a/stude/accounts/models.py +++ b/stude/accounts/models.py @@ -20,11 +20,9 @@ def validate_student_id(value): class CustomUser(AbstractUser): def _get_upload_to(instance, 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 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) first_name = models.CharField(max_length=100) @@ -55,8 +53,7 @@ class CustomUser(AbstractUser): on_delete=models.SET_NULL, null=True ) - subjects = models.ManyToManyField( - 'subjects.Subject', through='subjects.SubjectStudent', related_name='SubjectStudent_user') + subjects = models.ManyToManyField('subjects.Subject') @property def full_name(self): @@ -80,3 +77,23 @@ def create_superuser(sender, **kwargs): # Activate the superuser superuser.is_active = True 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() diff --git a/stude/accounts/serializers.py b/stude/accounts/serializers.py index 90f3b54..a8b9dad 100644 --- a/stude/accounts/serializers.py +++ b/stude/accounts/serializers.py @@ -11,23 +11,69 @@ from django.contrib.auth.password_validation import validate_password from courses.models import Course from year_levels.models import Year_Level from semesters.models import Semester +from subjects.models import Subject +from django.contrib.gis.geos import Point class CustomUserSerializer(BaseUserSerializer): - user_status = StudentStatusSerializer( - source='studentstatus', read_only=True) + # user_status = StudentStatusSerializer( + # source='studentstatus', read_only=True) + course_shortname = serializers.SerializerMethodField() + yearlevel_shortname = serializers.SerializerMethodField() + semester_shortname = serializers.SerializerMethodField() course = serializers.SlugRelatedField( many=False, slug_field='name', queryset=Course.objects.all(), required=False, allow_null=True) year_level = serializers.SlugRelatedField( many=False, slug_field='name', queryset=Year_Level.objects.all(), required=False, allow_null=True) semester = serializers.SlugRelatedField( 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): model = CustomUser fields = ('username', 'email', - 'student_id_number', 'year_level', 'semester', 'course', 'subjects', 'avatar', 'first_name', 'last_name', 'is_banned', 'user_status') - read_only_fields = ('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', '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 @@ -35,7 +81,10 @@ class CustomUserSerializer(BaseUserSerializer): class UserRegistrationSerializer(serializers.ModelSerializer): email = serializers.EmailField(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: model = CustomUser # Use your custom user model here @@ -64,8 +113,7 @@ class UserRegistrationSerializer(serializers.ModelSerializer): StudentStatus.objects.create( user=user, active=False, - x=None, - y=None, + location=Point(0, 0), subject=None ) return user diff --git a/stude/api/urls.py b/stude/api/urls.py index 6942309..9cce2fa 100644 --- a/stude/api/urls.py +++ b/stude/api/urls.py @@ -9,5 +9,6 @@ urlpatterns = [ path('semesters/', include('semesters.urls')), path('subjects/', include('subjects.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')), ] diff --git a/stude/config/settings.py b/stude/config/settings.py index bca689c..b6dfe66 100644 --- a/stude/config/settings.py +++ b/stude/config/settings.py @@ -14,6 +14,7 @@ from pathlib import Path from dotenv import load_dotenv # Python dotenv import os + load_dotenv() # loads the configs from .env # Build paths inside the project like this: BASE_DIR / 'subdir'. @@ -50,8 +51,21 @@ else: EMAIL_PORT = str(os.getenv('PROD_EMAIL_PORT')) 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 = [ 'daphne', @@ -61,6 +75,7 @@ INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'django.contrib.gis', 'rest_framework', 'rest_framework_simplejwt', 'djoser', @@ -72,6 +87,8 @@ INSTALLED_APPS = [ 'subjects', 'study_groups', 'studygroup_messages', + 'leaflet', + 'landmarks', ] MIDDLEWARE = [ @@ -123,11 +140,18 @@ WSGI_APPLICATION = 'config.wsgi.application' # Database # https://docs.djangoproject.com/en/4.2/ref/settings/#databases -DATABASES = { +"""DATABASES = { 'default': { 'ENGINE': 'django.db.backends.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' @@ -203,3 +227,11 @@ SITE_NAME = 'Stud-E' JWT_TOKEN_LIFETIME = 10800 ACCESS_TOKEN_LIFETIME = 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' +} diff --git a/stude/courses/admin.py b/stude/courses/admin.py index 83c9d9a..41f0dbf 100644 --- a/stude/courses/admin.py +++ b/stude/courses/admin.py @@ -1,6 +1,5 @@ from django.contrib import admin -from .models import Course, SubjectCourse +from .models import Course admin.site.register(Course) -admin.site.register(SubjectCourse) diff --git a/stude/courses/migrations/0001_initial.py b/stude/courses/migrations/0001_initial.py index 2530e9b..e6da990 100644 --- a/stude/courses/migrations/0001_initial.py +++ b/stude/courses/migrations/0001_initial.py @@ -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 -import django.db.models.deletion class Migration(migrations.Migration): @@ -20,11 +19,4 @@ class Migration(migrations.Migration): ('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')), - ], - ), ] diff --git a/stude/courses/migrations/0002_initial.py b/stude/courses/migrations/0002_initial.py index 5f3e96f..a4f4500 100644 --- a/stude/courses/migrations/0002_initial.py +++ b/stude/courses/migrations/0002_initial.py @@ -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 -import django.db.models.deletion class Migration(migrations.Migration): @@ -9,19 +8,14 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('subjects', '0001_initial'), ('courses', '0001_initial'), + ('subjects', '0001_initial'), ] operations = [ - migrations.AddField( - model_name='subjectcourse', - name='subject', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='subjects.subject'), - ), migrations.AddField( model_name='course', 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'), ), ] diff --git a/stude/courses/migrations/0003_alter_course_name_alter_course_shortname.py b/stude/courses/migrations/0003_alter_course_name_alter_course_shortname.py new file mode 100644 index 0000000..72f807a --- /dev/null +++ b/stude/courses/migrations/0003_alter_course_name_alter_course_shortname.py @@ -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), + ), + ] diff --git a/stude/courses/models.py b/stude/courses/models.py index f31467c..e9e6fca 100644 --- a/stude/courses/models.py +++ b/stude/courses/models.py @@ -5,21 +5,15 @@ from django.db import models class Course(models.Model): - name = models.CharField(max_length=64) - shortname = models.CharField(max_length=16) + name = models.CharField(max_length=64, unique=True) + shortname = models.CharField(max_length=16, unique=True) subjects = models.ManyToManyField( - 'subjects.Subject', related_name='SubjectCourse_course', through='courses.SubjectCourse') + 'subjects.Subject', related_name='SubjectCourse_course', through='subjects.SubjectCourse') def __str__(self): 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) def populate_courses(sender, **kwargs): if sender.name == 'courses': diff --git a/stude/landmarks/__init__.py b/stude/landmarks/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/stude/landmarks/admin.py b/stude/landmarks/admin.py new file mode 100644 index 0000000..950b566 --- /dev/null +++ b/stude/landmarks/admin.py @@ -0,0 +1,5 @@ +from django.contrib import admin +from leaflet.admin import LeafletGeoAdmin +from .models import Landmark + +admin.site.register(Landmark, LeafletGeoAdmin) diff --git a/stude/landmarks/apps.py b/stude/landmarks/apps.py new file mode 100644 index 0000000..a076cf5 --- /dev/null +++ b/stude/landmarks/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class LandmarksConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'landmarks' diff --git a/stude/landmarks/migrations/0001_initial.py b/stude/landmarks/migrations/0001_initial.py new file mode 100644 index 0000000..0018b9c --- /dev/null +++ b/stude/landmarks/migrations/0001_initial.py @@ -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)), + ], + ), + ] diff --git a/stude/landmarks/migrations/__init__.py b/stude/landmarks/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/stude/landmarks/models.py b/stude/landmarks/models.py new file mode 100644 index 0000000..b7be508 --- /dev/null +++ b/stude/landmarks/models.py @@ -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 diff --git a/stude/landmarks/serializers.py b/stude/landmarks/serializers.py new file mode 100644 index 0000000..20796ac --- /dev/null +++ b/stude/landmarks/serializers.py @@ -0,0 +1,8 @@ +from .models import Landmark +from rest_framework import serializers + + +class LandmarkSerializer(serializers.ModelSerializer): + class Meta: + model = Landmark + fields = '__all__' diff --git a/stude/landmarks/tests.py b/stude/landmarks/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/stude/landmarks/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/stude/landmarks/urls.py b/stude/landmarks/urls.py new file mode 100644 index 0000000..7917063 --- /dev/null +++ b/stude/landmarks/urls.py @@ -0,0 +1,6 @@ +from django.urls import path +from .views import LandmarkListView + +urlpatterns = [ + path('', LandmarkListView.as_view()), +] diff --git a/stude/landmarks/views.py b/stude/landmarks/views.py new file mode 100644 index 0000000..9a064f5 --- /dev/null +++ b/stude/landmarks/views.py @@ -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() diff --git a/stude/semesters/migrations/0001_initial.py b/stude/semesters/migrations/0001_initial.py index e890336..bc479f6 100644 --- a/stude/semesters/migrations/0001_initial.py +++ b/stude/semesters/migrations/0001_initial.py @@ -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 diff --git a/stude/semesters/migrations/0002_alter_semester_name_alter_semester_shortname.py b/stude/semesters/migrations/0002_alter_semester_name_alter_semester_shortname.py new file mode 100644 index 0000000..2923f92 --- /dev/null +++ b/stude/semesters/migrations/0002_alter_semester_name_alter_semester_shortname.py @@ -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), + ), + ] diff --git a/stude/semesters/models.py b/stude/semesters/models.py index 162c5b8..93ca4b3 100644 --- a/stude/semesters/models.py +++ b/stude/semesters/models.py @@ -6,8 +6,8 @@ from django.dispatch import receiver class Semester(models.Model): - name = models.CharField(max_length=64) - shortname = models.CharField(max_length=16) + name = models.CharField(max_length=64, unique=True) + shortname = models.CharField(max_length=16, unique=True) def __str__(self): return self.name diff --git a/stude/student_status/admin.py b/stude/student_status/admin.py index ba4cb5f..fbfe8be 100644 --- a/stude/student_status/admin.py +++ b/stude/student_status/admin.py @@ -1,4 +1,15 @@ from django.contrib import admin 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) diff --git a/stude/student_status/migrations/0001_initial.py b/stude/student_status/migrations/0001_initial.py index cf457c7..dc438b5 100644 --- a/stude/student_status/migrations/0001_initial.py +++ b/stude/student_status/migrations/0001_initial.py @@ -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 +import django.contrib.gis.db.models.fields from django.db import migrations, models import django.db.models.deletion @@ -11,6 +12,7 @@ class Migration(migrations.Migration): dependencies = [ ('accounts', '0002_initial'), + ('landmarks', '0001_initial'), ] operations = [ @@ -18,10 +20,10 @@ class Migration(migrations.Migration): name='StudentStatus', fields=[ ('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)), - ('y', models.FloatField(null=True)), + ('location', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=4326)), ('active', models.BooleanField(default=False)), ('timestamp', models.DateField(auto_now_add=True)), + ('landmark', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='landmarks.landmark')), ], ), ] diff --git a/stude/student_status/migrations/0002_initial.py b/stude/student_status/migrations/0002_initial.py index 801da19..54f0607 100644 --- a/stude/student_status/migrations/0002_initial.py +++ b/stude/student_status/migrations/0002_initial.py @@ -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 import django.db.models.deletion @@ -9,20 +9,20 @@ class Migration(migrations.Migration): initial = True dependencies = [ + ('study_groups', '0001_initial'), ('student_status', '0001_initial'), ('subjects', '0001_initial'), - ('study_groups', '0001_initial'), ] operations = [ migrations.AddField( model_name='studentstatus', 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( model_name='studentstatus', 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'), ), ] diff --git a/stude/student_status/migrations/0003_remove_studentstatus_study_group_and_more.py b/stude/student_status/migrations/0003_remove_studentstatus_study_group_and_more.py deleted file mode 100644 index 43495cc..0000000 --- a/stude/student_status/migrations/0003_remove_studentstatus_study_group_and_more.py +++ /dev/null @@ -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'), - ), - ] diff --git a/stude/student_status/migrations/0004_alter_studentstatus_study_group.py b/stude/student_status/migrations/0004_alter_studentstatus_study_group.py deleted file mode 100644 index bca9509..0000000 --- a/stude/student_status/migrations/0004_alter_studentstatus_study_group.py +++ /dev/null @@ -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'), - ), - ] diff --git a/stude/student_status/migrations/0005_alter_studentstatus_subject.py b/stude/student_status/migrations/0005_alter_studentstatus_subject.py deleted file mode 100644 index 845a322..0000000 --- a/stude/student_status/migrations/0005_alter_studentstatus_subject.py +++ /dev/null @@ -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'), - ), - ] diff --git a/stude/student_status/models.py b/stude/student_status/models.py index 2787206..b7bed57 100644 --- a/stude/student_status/models.py +++ b/stude/student_status/models.py @@ -1,18 +1,23 @@ from django.db import models from accounts.models import CustomUser 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. class StudentStatus(models.Model): user = models.OneToOneField( CustomUser, on_delete=models.CASCADE, primary_key=True) - x = models.FloatField(null=True) - y = models.FloatField(null=True) + location = gis_models.PointField(blank=True, null=True, srid=4326) subject = models.ForeignKey( 'subjects.Subject', on_delete=models.SET_NULL, null=True) active = models.BooleanField(default=False) timestamp = models.DateField(auto_now_add=True) + landmark = models.ForeignKey( + 'landmarks.Landmark', on_delete=models.SET_NULL, null=True) study_group = models.ManyToManyField( 'study_groups.StudyGroup', through='study_groups.StudyGroupMembership', blank=True) + + def __str__(self): + return self.user.full_name diff --git a/stude/student_status/serializers.py b/stude/student_status/serializers.py index 4531a88..5a2baca 100644 --- a/stude/student_status/serializers.py +++ b/stude/student_status/serializers.py @@ -1,18 +1,23 @@ from rest_framework import serializers 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): - year_level = serializers.CharField( - source='user.year_level', read_only=True) - course = serializers.CharField(source='user.course', read_only=True) - semester = serializers.CharField(source='user.semester', read_only=True) + subject = serializers.SlugRelatedField( + queryset=Subject.objects.all(), slug_field='name', required=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: model = StudentStatus fields = '__all__' - read_only_fields = ['user'] + read_only_fields = ['user', 'landmark'] def create(self, validated_data): user = self.context['request'].user @@ -24,8 +29,14 @@ class StudentStatusSerializer(serializers.ModelSerializer): active = validated_data.get('active', None) if active is not None and active is False: - validated_data['x'] = None - validated_data['y'] = None + validated_data['location'] = Point(0, 0) 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) diff --git a/stude/student_status/views.py b/stude/student_status/views.py index 0eae6c0..01727f0 100644 --- a/stude/student_status/views.py +++ b/stude/student_status/views.py @@ -19,4 +19,4 @@ class ActiveStudentStatusListAPIView(generics.ListAPIView): def get_queryset(self): user = self.request.user - return StudentStatus.objects.filter(active=True).exclude(user=user) + return StudentStatus.objects.filter(active=True) diff --git a/stude/study_groups/admin.py b/stude/study_groups/admin.py index fcfbcbe..601cdc1 100644 --- a/stude/study_groups/admin.py +++ b/stude/study_groups/admin.py @@ -1,6 +1,7 @@ from django.contrib import admin from .models import StudyGroup, StudyGroupMembership +from leaflet.admin import LeafletGeoAdmin -admin.site.register(StudyGroup) +admin.site.register(StudyGroup, LeafletGeoAdmin) admin.site.register(StudyGroupMembership) diff --git a/stude/study_groups/migrations/0001_initial.py b/stude/study_groups/migrations/0001_initial.py index 6c2f8df..5f1af60 100644 --- a/stude/study_groups/migrations/0001_initial.py +++ b/stude/study_groups/migrations/0001_initial.py @@ -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 import django.db.models.deletion @@ -19,8 +20,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=48)), - ('x', models.FloatField(null=True)), - ('y', models.FloatField(null=True)), + ('location', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=4326)), ('active', models.BooleanField(default=False)), ('timestamp', models.DateField(auto_now_add=True)), ('subject', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='subjects.subject')), diff --git a/stude/study_groups/models.py b/stude/study_groups/models.py index e6647c9..9aa761e 100644 --- a/stude/study_groups/models.py +++ b/stude/study_groups/models.py @@ -1,5 +1,7 @@ from django.db import models 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. @@ -7,12 +9,14 @@ class StudyGroup(models.Model): name = models.CharField(max_length=48) users = models.ManyToManyField( 'student_status.StudentStatus', through='StudyGroupMembership') - x = models.FloatField(null=True) - y = models.FloatField(null=True) + location = gis_models.PointField(blank=True, null=True, srid=4326) subject = models.ForeignKey(Subject, on_delete=models.CASCADE) active = models.BooleanField(default=False) timestamp = models.DateField(auto_now_add=True) + def __str__(self): + return self.name + class StudyGroupMembership(models.Model): user = models.ForeignKey( @@ -21,4 +25,4 @@ class StudyGroupMembership(models.Model): 'study_groups.StudyGroup', on_delete=models.CASCADE) 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}' diff --git a/stude/study_groups/serializers.py b/stude/study_groups/serializers.py index 5c1ec6e..d67fcb1 100644 --- a/stude/study_groups/serializers.py +++ b/stude/study_groups/serializers.py @@ -2,6 +2,8 @@ from rest_framework import serializers from .models import StudyGroup, StudyGroupMembership from accounts.models import CustomUser from subjects.models import Subject +from drf_extra_fields.geo_fields import PointField +from landmarks.models import Landmark 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) subject = serializers.SlugRelatedField( 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: model = StudyGroup fields = '__all__' + read_only_fields = ['landmark'] class StudyGroupMembershipSerializer(serializers.ModelSerializer): diff --git a/stude/study_groups/views.py b/stude/study_groups/views.py index 6c37c9f..6916fd1 100644 --- a/stude/study_groups/views.py +++ b/stude/study_groups/views.py @@ -4,7 +4,7 @@ from rest_framework.exceptions import PermissionDenied from rest_framework.permissions import IsAuthenticated from .serializers import StudyGroupSerializer from .models import StudyGroup -from courses.models import SubjectCourse +from subjects.models import SubjectCourse # Create your views here. diff --git a/stude/studygroup_messages/migrations/0001_initial.py b/stude/studygroup_messages/migrations/0001_initial.py index f6cdecc..8dc01db 100644 --- a/stude/studygroup_messages/migrations/0001_initial.py +++ b/stude/studygroup_messages/migrations/0001_initial.py @@ -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.db import migrations, models @@ -20,7 +20,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('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')), ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], diff --git a/stude/studygroup_messages/migrations/0002_alter_message_timestamp.py b/stude/studygroup_messages/migrations/0002_alter_message_timestamp.py deleted file mode 100644 index 55d8981..0000000 --- a/stude/studygroup_messages/migrations/0002_alter_message_timestamp.py +++ /dev/null @@ -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), - ), - ] diff --git a/stude/studygroup_messages/models.py b/stude/studygroup_messages/models.py index d864ea0..ef2609c 100644 --- a/stude/studygroup_messages/models.py +++ b/stude/studygroup_messages/models.py @@ -9,3 +9,6 @@ class Message(models.Model): study_group = models.ForeignKey(StudyGroup, on_delete=models.CASCADE) message_content = models.TextField(max_length=1024) 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}' diff --git a/stude/subjects/admin.py b/stude/subjects/admin.py index c57f7c0..77d9077 100644 --- a/stude/subjects/admin.py +++ b/stude/subjects/admin.py @@ -1,6 +1,5 @@ from django.contrib import admin -from courses.models import Course -from .models import Subject, SubjectStudent +from .models import Subject, SubjectCourse, SubjectSemester, SubjectYearLevel class SubjectAdmin(admin.ModelAdmin): @@ -8,4 +7,6 @@ class SubjectAdmin(admin.ModelAdmin): admin.site.register(Subject, SubjectAdmin) -admin.site.register(SubjectStudent) +admin.site.register(SubjectCourse) +admin.site.register(SubjectSemester) +admin.site.register(SubjectYearLevel) diff --git a/stude/subjects/migrations/0001_initial.py b/stude/subjects/migrations/0001_initial.py index ec2350e..c83d0ea 100644 --- a/stude/subjects/migrations/0001_initial.py +++ b/stude/subjects/migrations/0001_initial.py @@ -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 import django.db.models.deletion @@ -10,8 +11,9 @@ class Migration(migrations.Migration): dependencies = [ ('semesters', '0001_initial'), - ('year_levels', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), ('courses', '0001_initial'), + ('year_levels', '0001_initial'), ] operations = [ @@ -21,9 +23,50 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=64)), ('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'), + ), ] diff --git a/stude/subjects/migrations/0002_alter_subject_code_alter_subject_name_and_more.py b/stude/subjects/migrations/0002_alter_subject_code_alter_subject_name_and_more.py new file mode 100644 index 0000000..a55567d --- /dev/null +++ b/stude/subjects/migrations/0002_alter_subject_code_alter_subject_name_and_more.py @@ -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')}, + ), + ] diff --git a/stude/subjects/migrations/0002_subjectstudent_subject_students.py b/stude/subjects/migrations/0002_subjectstudent_subject_students.py deleted file mode 100644 index e83702f..0000000 --- a/stude/subjects/migrations/0002_subjectstudent_subject_students.py +++ /dev/null @@ -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), - ), - ] diff --git a/stude/subjects/migrations/0003_subjectcode_remove_subject_code_subject_code.py b/stude/subjects/migrations/0003_subjectcode_remove_subject_code_subject_code.py new file mode 100644 index 0000000..f63db3e --- /dev/null +++ b/stude/subjects/migrations/0003_subjectcode_remove_subject_code_subject_code.py @@ -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'), + ), + ] diff --git a/stude/subjects/migrations/0004_rename_code_subject_codes.py b/stude/subjects/migrations/0004_rename_code_subject_codes.py new file mode 100644 index 0000000..6aa4990 --- /dev/null +++ b/stude/subjects/migrations/0004_rename_code_subject_codes.py @@ -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', + ), + ] diff --git a/stude/subjects/models.py b/stude/subjects/models.py index 5743157..b98fead 100644 --- a/stude/subjects/models.py +++ b/stude/subjects/models.py @@ -1,38 +1,168 @@ + +import os +import csv +from django.conf import settings 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 semesters.models import Semester # Create your models here. class Subject(models.Model): - name = models.CharField(max_length=64) - code = models.CharField(max_length=16) + name = models.CharField(max_length=64, unique=True) + codes = models.ManyToManyField( + 'subjects.SubjectCode') courses = models.ManyToManyField( - 'courses.Course', through='courses.SubjectCourse', related_name='SubjectCourse_subject') + 'courses.Course', through='subjects.SubjectCourse', related_name='SubjectCourse_subject') students = models.ManyToManyField( - 'accounts.CustomUser', through='subjects.SubjectStudent', related_name='SubjectStudent_subject') + 'accounts.CustomUser', blank=True) - year_level = models.ForeignKey( - Year_Level, - on_delete=models.SET_NULL, - null=True, - related_name='Year_Level_name' - ) - semester = models.ForeignKey( - Semester, - on_delete=models.SET_NULL, - null=True - ) + year_levels = models.ManyToManyField( + 'year_levels.Year_Level', through='subjects.SubjectYearLevel', related_name='SubjectYearLevel_subject') + + semesters = models.ManyToManyField( + 'semesters.Semester', through='subjects.SubjectSemester', related_name='SubjectSemester_subject') 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): - user = models.ForeignKey( - 'accounts.CustomUser', on_delete=models.CASCADE) +class SubjectCode(models.Model): + code = models.CharField(max_length=16, unique=True) + + def __str__(self): + return self.code + + +class SubjectCourse(models.Model): 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): - 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') diff --git a/stude/subjects/serializers.py b/stude/subjects/serializers.py index 7669ffc..f34b174 100644 --- a/stude/subjects/serializers.py +++ b/stude/subjects/serializers.py @@ -1,23 +1,21 @@ from rest_framework import serializers -from .models import Subject +from .models import Subject, SubjectCode from courses.models import Course -from year_levels.serializers import YearLevelSerializer -from semesters.serializers import SemesterSerializer -from courses.serializers import CourseSerializer +from year_levels.models import Year_Level +from semesters.models import Semester +from accounts.models import CustomUser class SubjectSerializer(serializers.ModelSerializer): - year_level = serializers.SerializerMethodField() - semester = serializers.SerializerMethodField() + year_levels = serializers.SlugRelatedField( + 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( 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: model = Subject - fields = ('name', 'code', 'courses', 'year_level', 'semester') - - def get_year_level(self, obj): - return obj.year_level.name - - def get_semester(self, obj): - return obj.semester.name + fields = ('id', 'name', 'codes', 'courses', 'year_levels', 'semesters') diff --git a/stude/subjects/urls.py b/stude/subjects/urls.py index 5d3c133..3cecd12 100644 --- a/stude/subjects/urls.py +++ b/stude/subjects/urls.py @@ -1,11 +1,8 @@ from django.urls import include, path -from .views import SubjectListView -from .views import SubjectByYearSemesterView, SubjectByYearView - +from .views import SubjectByYearSemesterView, SubjectListView +from rest_framework import routers urlpatterns = [ path('', SubjectListView.as_view()), - path('/', - SubjectByYearView.as_view()), - path('/', + path('//', SubjectByYearSemesterView.as_view()), ] diff --git a/stude/subjects/views.py b/stude/subjects/views.py index 9842658..60818f5 100644 --- a/stude/subjects/views.py +++ b/stude/subjects/views.py @@ -1,4 +1,4 @@ -from rest_framework import generics +from rest_framework import generics, viewsets from .models import Subject from .serializers import SubjectSerializer from rest_framework.views import APIView @@ -10,27 +10,13 @@ class SubjectListView(generics.ListAPIView): 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): 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 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 serializer = SubjectSerializer(subjects, many=True) diff --git a/stude/templates/email_activation/email_activation.html b/stude/templates/email_activation/email_activation.html index 03321f8..d628f3a 100644 --- a/stude/templates/email_activation/email_activation.html +++ b/stude/templates/email_activation/email_activation.html @@ -19,7 +19,7 @@

{% blocktrans %}You're receiving this email because you need to finish activation process on {{ site_name }}.{% endblocktrans %}

{% trans "Please go to the following page to activate your account in-app:" %}

-

{{ domain }}://--/{{ url|safe }}

+

{{ domain }}://{{url}}

{% blocktrans %}Many thanks from the {{ site_name }} team{% endblocktrans %}

diff --git a/stude/year_levels/migrations/0001_initial.py b/stude/year_levels/migrations/0001_initial.py index 8859f76..2541862 100644 --- a/stude/year_levels/migrations/0001_initial.py +++ b/stude/year_levels/migrations/0001_initial.py @@ -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 diff --git a/stude/year_levels/migrations/0002_alter_year_level_name_alter_year_level_shortname.py b/stude/year_levels/migrations/0002_alter_year_level_name_alter_year_level_shortname.py new file mode 100644 index 0000000..2173bee --- /dev/null +++ b/stude/year_levels/migrations/0002_alter_year_level_name_alter_year_level_shortname.py @@ -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), + ), + ] diff --git a/stude/year_levels/models.py b/stude/year_levels/models.py index c67c7d1..9f89894 100644 --- a/stude/year_levels/models.py +++ b/stude/year_levels/models.py @@ -6,8 +6,8 @@ from django.dispatch import receiver class Year_Level(models.Model): - name = models.CharField(max_length=64) - shortname = models.CharField(max_length=16) + name = models.CharField(max_length=64, unique=True) + shortname = models.CharField(max_length=16, unique=True) def __str__(self): return self.name