diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy-test.yml similarity index 74% rename from .github/workflows/deploy.yml rename to .github/workflows/deploy-test.yml index 4446fa95..c8f5ac81 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy-test.yml @@ -1,16 +1,16 @@ -name: deploy +name: Deploy Test Environment -on: workflow_dispatch +on: push jobs: deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: wshihadeh/docker-deployment-action@v2 with: remote_docker_host: webstrom@server.strom.sk ssh_private_key: ${{ secrets.WEBSTROM_DEPLOY_SSH_PRIVATE_KEY }} ssh_public_key: ${{ secrets.WEBSTROM_DEPLOY_SSH_PUBLIC_KEY }} - stack_file_name: compose.yaml + stack_file_name: deployment/compose-test.yaml args: up --build --force-recreate --detach diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8192b463..13698a6b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,7 +16,7 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Upgrade pip run: pip3 install --upgrade pip @@ -37,7 +37,7 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Upgrade pip run: pip3 install --upgrade pip diff --git a/.github/workflows/migrate-test.yml b/.github/workflows/migrate-test.yml new file mode 100644 index 00000000..bdf85e4c --- /dev/null +++ b/.github/workflows/migrate-test.yml @@ -0,0 +1,16 @@ +name: Migrate Test Environment + +on: push + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: wshihadeh/docker-deployment-action@v2 + with: + remote_docker_host: webstrom@server.strom.sk + ssh_private_key: ${{ secrets.WEBSTROM_DEPLOY_SSH_PRIVATE_KEY }} + ssh_public_key: ${{ secrets.WEBSTROM_DEPLOY_SSH_PUBLIC_KEY }} + stack_file_name: deployment/compose-test.yaml + args: run webstrom-backend python manage.py migrate --noinput diff --git a/.gitignore b/.gitignore index a6d9e34b..b2a5c20a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,9 +7,6 @@ db.sqlite3-journal /media /protected_media -**/migrations/** -!**/migrations/__init__.py - fixtures/sources !fixtures/sources/*.py !fixtures/sources/requirements.txt diff --git a/.vscode/settings.json b/.vscode/settings.json index 3784257a..05430d69 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,8 +6,11 @@ "editor.defaultFormatter": "ms-python.autopep8", "editor.formatOnSave": true, }, + "files.associations": { + "compose-*.yaml": "dockercompose" + }, "git.branchProtection": [ "master" ], "git.branchProtectionPrompt": "alwaysCommitToNewBranch" -} \ No newline at end of file +} diff --git a/Pipfile b/Pipfile index ad8d4a45..1bd6ba65 100644 --- a/Pipfile +++ b/Pipfile @@ -6,13 +6,14 @@ name = "pypi" [packages] daphne = "~=4.0.0" dj-rest-auth = "~=5.0.1" -django = "~=3.2.23" +django = "~=4.2.11" django-allauth = "~=0.58.2" django-filter = "~=23.5" django-sendfile2 = "~=0.7.1" djangorestframework = "~=3.14.0" drf-writable-nested = "~=0.7.0" pillow = "~=10.3.0" +psycopg = "~=3.1.18" python-magic = "~=0.4.27" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index 580c70b5..c77b7330 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "7df0459bbb2186ea13bb8c25ce90a415fc188092d1f00f88ca5d6350af79aa21" + "sha256": "ff0a666df6d2bf1a9581a35000f93debf146851d2e82a0d5be910dea8a7b00e0" }, "pipfile-spec": 6, "requires": {}, @@ -46,11 +46,11 @@ }, "certifi": { "hashes": [ - "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", - "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" + "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516", + "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56" ], "markers": "python_version >= '3.6'", - "version": "==2024.2.2" + "version": "==2024.6.2" }, "cffi": { "hashes": [ @@ -216,41 +216,41 @@ }, "cryptography": { "hashes": [ - "sha256:02c0eee2d7133bdbbc5e24441258d5d2244beb31da5ed19fbb80315f4bbbff55", - "sha256:0d563795db98b4cd57742a78a288cdbdc9daedac29f2239793071fe114f13785", - "sha256:16268d46086bb8ad5bf0a2b5544d8a9ed87a0e33f5e77dd3c3301e63d941a83b", - "sha256:1a58839984d9cb34c855197043eaae2c187d930ca6d644612843b4fe8513c886", - "sha256:2954fccea107026512b15afb4aa664a5640cd0af630e2ee3962f2602693f0c82", - "sha256:2e47577f9b18723fa294b0ea9a17d5e53a227867a0a4904a1a076d1646d45ca1", - "sha256:31adb7d06fe4383226c3e963471f6837742889b3c4caa55aac20ad951bc8ffda", - "sha256:3577d029bc3f4827dd5bf8bf7710cac13527b470bbf1820a3f394adb38ed7d5f", - "sha256:36017400817987670037fbb0324d71489b6ead6231c9604f8fc1f7d008087c68", - "sha256:362e7197754c231797ec45ee081f3088a27a47c6c01eff2ac83f60f85a50fe60", - "sha256:3de9a45d3b2b7d8088c3fbf1ed4395dfeff79d07842217b38df14ef09ce1d8d7", - "sha256:4f698edacf9c9e0371112792558d2f705b5645076cc0aaae02f816a0171770fd", - "sha256:5482e789294854c28237bba77c4c83be698be740e31a3ae5e879ee5444166582", - "sha256:5e44507bf8d14b36b8389b226665d597bc0f18ea035d75b4e53c7b1ea84583cc", - "sha256:779245e13b9a6638df14641d029add5dc17edbef6ec915688f3acb9e720a5858", - "sha256:789caea816c6704f63f6241a519bfa347f72fbd67ba28d04636b7c6b7da94b0b", - "sha256:7f8b25fa616d8b846aef64b15c606bb0828dbc35faf90566eb139aa9cff67af2", - "sha256:8cb8ce7c3347fcf9446f201dc30e2d5a3c898d009126010cbd1f443f28b52678", - "sha256:93a3209f6bb2b33e725ed08ee0991b92976dfdcf4e8b38646540674fc7508e13", - "sha256:a3a5ac8b56fe37f3125e5b72b61dcde43283e5370827f5233893d461b7360cd4", - "sha256:a47787a5e3649008a1102d3df55424e86606c9bae6fb77ac59afe06d234605f8", - "sha256:a79165431551042cc9d1d90e6145d5d0d3ab0f2d66326c201d9b0e7f5bf43604", - "sha256:a987f840718078212fdf4504d0fd4c6effe34a7e4740378e59d47696e8dfb477", - "sha256:a9bc127cdc4ecf87a5ea22a2556cab6c7eda2923f84e4f3cc588e8470ce4e42e", - "sha256:bd13b5e9b543532453de08bcdc3cc7cebec6f9883e886fd20a92f26940fd3e7a", - "sha256:c65f96dad14f8528a447414125e1fc8feb2ad5a272b8f68477abbcc1ea7d94b9", - "sha256:d8e3098721b84392ee45af2dd554c947c32cc52f862b6a3ae982dbb90f577f14", - "sha256:e6b79d0adb01aae87e8a44c2b64bc3f3fe59515280e00fb6d57a7267a2583cda", - "sha256:e6b8f1881dac458c34778d0a424ae5769de30544fc678eac51c1c8bb2183e9da", - "sha256:e9b2a6309f14c0497f348d08a065d52f3020656f675819fc405fb63bbcd26562", - "sha256:ecbfbc00bf55888edda9868a4cf927205de8499e7fabe6c050322298382953f2", - "sha256:efd0bf5205240182e0f13bcaea41be4fdf5c22c5129fc7ced4a0282ac86998c9" + "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad", + "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583", + "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b", + "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c", + "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1", + "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648", + "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949", + "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba", + "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c", + "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9", + "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d", + "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c", + "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e", + "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2", + "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d", + "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7", + "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70", + "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2", + "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7", + "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14", + "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe", + "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e", + "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71", + "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961", + "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7", + "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c", + "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28", + "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842", + "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902", + "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801", + "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a", + "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e" ], "markers": "python_version >= '3.7'", - "version": "==42.0.7" + "version": "==42.0.8" }, "daphne": { "hashes": [ @@ -277,11 +277,11 @@ }, "django": { "hashes": [ - "sha256:7ca38a78654aee72378594d63e51636c04b8e28574f5505dff630895b5472777", - "sha256:a52ea7fcf280b16f7b739cec38fa6d3f8953a5456986944c3ca97e79882b4e38" + "sha256:837e3cf1f6c31347a1396a3f6b65688f2b4bb4a11c580dcb628b5afe527b68a5", + "sha256:a17fcba2aad3fc7d46fdb23215095dbbd64e6174bf4589171e732b18b07e426a" ], "index": "pypi", - "version": "==3.2.25" + "version": "==4.2.13" }, "django-allauth": { "hashes": [ @@ -298,6 +298,14 @@ "index": "pypi", "version": "==23.5" }, + "django-sendfile2": { + "hashes": [ + "sha256:81971df1db77f688c4834b8540930902d0d929c64cf374bd604b81f5ac52c04a", + "sha256:b5bec07f1c9b1875a60ea74beb306e9aba964bd8b54f00b4432cb77cc35bc58c" + ], + "index": "pypi", + "version": "==0.7.1" + }, "djangorestframework": { "hashes": [ "sha256:579a333e6256b09489cbe0a067e66abe55c6595d8926be6b99423786334350c8", @@ -418,6 +426,14 @@ "index": "pypi", "version": "==10.3.0" }, + "psycopg": { + "hashes": [ + "sha256:92d7b78ad82426cdcf1a0440678209faa890c6e1721361c2f8901f0dccd62961", + "sha256:dca5e5521c859f6606686432ae1c94e8766d29cc91f2ee595378c510cc5b0731" + ], + "index": "pypi", + "version": "==3.1.19" + }, "pyasn1": { "hashes": [ "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c", @@ -484,11 +500,11 @@ }, "requests": { "hashes": [ - "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", - "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" ], - "markers": "python_version >= '3.7'", - "version": "==2.31.0" + "markers": "python_version >= '3.8'", + "version": "==2.32.3" }, "requests-oauthlib": { "hashes": [ @@ -507,11 +523,11 @@ }, "setuptools": { "hashes": [ - "sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987", - "sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32" + "sha256:54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4", + "sha256:f211a66637b8fa059bb28183da127d4e86396c991a942b028c6650d4319c3fd0" ], "markers": "python_version >= '3.8'", - "version": "==69.5.1" + "version": "==70.0.0" }, "six": { "hashes": [ @@ -550,11 +566,11 @@ }, "typing-extensions": { "hashes": [ - "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0", - "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a" + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], "markers": "python_version >= '3.8'", - "version": "==4.11.0" + "version": "==4.12.2" }, "urllib3": { "hashes": [ @@ -566,37 +582,45 @@ }, "zope-interface": { "hashes": [ - "sha256:21732994aa3ca43bbb6b36335c288023428a3c5b7322b637c7b0a03053937578", - "sha256:36ee6e507a9fd4f1f0aab8e8dfc801d162e7211c27503cbfb47e1d558941a7fa", - "sha256:3945f4fda92c1b6fb0cb6eaaaf72599e5c2c2059654bdc42bc09c6e711c214c8", - "sha256:414e6dccdf4a5c96c0c98da68ba040dbf9ba7511b61b34e228f11b0ed90c439d", - "sha256:4782e173c2fde4f649c2a9a68082445bc1f2c27f41907de06bf1ba82585847f2", - "sha256:4cd56eb9a23767958c9a0654306b9a4a74def485f645b3a7378cc6ab661ef31c", - "sha256:502d2c9c4231d022b20225dba5c6c736236ed65e1d7e2f6f402b5aa6a7040ec9", - "sha256:57f34b7997f8de7d2db08363eaccd05dad20f106e39efe95bed4fac84af2d022", - "sha256:5fbbb290751f5c4ed81e54ae73fe8557c4a85973f5ab019edbb0f746244ecea6", - "sha256:604fa920478dfc0c76cdb7c203572400a8317ffcdac288245c408b42b3d9aee9", - "sha256:62e6b756663deade5270f67899753437b39d970f9eecd49e19fae3b880310cf0", - "sha256:646cd83d24065d074f22f61fe101d20dbf4b729ca7831cc782ec986eb9156f93", - "sha256:6494dc0314e782ce4fb0e624b4ce2458f54d074382f50a920c7700c05cbcef28", - "sha256:6e4cc017206c1429a6d8fdd8a25c6efc15512065eec0a8d45c350df96a0911ed", - "sha256:72faa868fcfde49a29d287dce3c83180322467eecd725dd351098efe96e8d4bb", - "sha256:7cda82ab32f984985f09e4ec20a4f9665b26779a1b8e443b34a148de256f2052", - "sha256:855b7233fa5d0d1f3be8c14fadf4718dee1c928e1d75f1584bea6ecec6dcc4af", - "sha256:86e85eada0eb551950df05d72dc0e892320f14daa78bc434059e834d4b1f9300", - "sha256:8e246357f52952ae5fa950d19eda8572594c49e6cb1e5462508e6cec561a37de", - "sha256:93f28d84517dcd6c240979bd9b2f262a373832baef856fe663a24b9171d7f04d", - "sha256:b0f61ccbc26e08031d0e72b6a0cbf9b4030f035913cb2b39f940aa42eb8e0063", - "sha256:b11f2b67ccc990a1522fa8cd3f5d185a068459f944ab2d0e7a1b15d31bcb4af4", - "sha256:c04bd4ee4766d285e83c6d8c042663a98efb934389e05ccd643fefb066c88a9d", - "sha256:ee1e3ca6c98efe213a96dece89100a8aa52e210ac354861d8039d69bd1d6e5ff", - "sha256:f33af86ed460eb28dc9da1de1f3305795271a19c665161c1d973a737596b2081", - "sha256:f5092f2712e1fd07579fc3101b18e9c95857c853e836847598bf992c8e672434", - "sha256:f78e1eac48c4f4e0168a91cabcd8d1aedb972836df5c8769071fc6173294a0a3", - "sha256:fe636b49c333bfc5b0913590e36a2f151167c462fb36d9f4acc66029e45c974b" + "sha256:00b5c3e9744dcdc9e84c24ed6646d5cf0cf66551347b310b3ffd70f056535854", + "sha256:0e4fa5d34d7973e6b0efa46fe4405090f3b406f64b6290facbb19dcbf642ad6b", + "sha256:136cacdde1a2c5e5bc3d0b2a1beed733f97e2dad8c2ad3c2e17116f6590a3827", + "sha256:1730c93a38b5a18d24549bc81613223962a19d457cfda9bdc66e542f475a36f4", + "sha256:1a62fd6cd518693568e23e02f41816adedfca637f26716837681c90b36af3671", + "sha256:1c207e6f6dfd5749a26f5a5fd966602d6b824ec00d2df84a7e9a924e8933654e", + "sha256:2eccd5bef45883802848f821d940367c1d0ad588de71e5cabe3813175444202c", + "sha256:33ee982237cffaf946db365c3a6ebaa37855d8e3ca5800f6f48890209c1cfefc", + "sha256:3d136e5b8821073e1a09dde3eb076ea9988e7010c54ffe4d39701adf0c303438", + "sha256:47654177e675bafdf4e4738ce58cdc5c6d6ee2157ac0a78a3fa460942b9d64a8", + "sha256:47937cf2e7ed4e0e37f7851c76edeb8543ec9b0eae149b36ecd26176ff1ca874", + "sha256:4ac46298e0143d91e4644a27a769d1388d5d89e82ee0cf37bf2b0b001b9712a4", + "sha256:4c0b208a5d6c81434bdfa0f06d9b667e5de15af84d8cae5723c3a33ba6611b82", + "sha256:551db2fe892fcbefb38f6f81ffa62de11090c8119fd4e66a60f3adff70751ec7", + "sha256:599f3b07bde2627e163ce484d5497a54a0a8437779362395c6b25e68c6590ede", + "sha256:5ef8356f16b1a83609f7a992a6e33d792bb5eff2370712c9eaae0d02e1924341", + "sha256:5fe919027f29b12f7a2562ba0daf3e045cb388f844e022552a5674fcdf5d21f1", + "sha256:6f0a6be264afb094975b5ef55c911379d6989caa87c4e558814ec4f5125cfa2e", + "sha256:706efc19f9679a1b425d6fa2b4bc770d976d0984335eaea0869bd32f627591d2", + "sha256:73f9752cf3596771c7726f7eea5b9e634ad47c6d863043589a1c3bb31325c7eb", + "sha256:762e616199f6319bb98e7f4f27d254c84c5fb1c25c908c2a9d0f92b92fb27530", + "sha256:866a0f583be79f0def667a5d2c60b7b4cc68f0c0a470f227e1122691b443c934", + "sha256:86a94af4a88110ed4bb8961f5ac72edf782958e665d5bfceaab6bf388420a78b", + "sha256:8e0343a6e06d94f6b6ac52fbc75269b41dd3c57066541a6c76517f69fe67cb43", + "sha256:97e615eab34bd8477c3f34197a17ce08c648d38467489359cb9eb7394f1083f7", + "sha256:a96e6d4074db29b152222c34d7eec2e2db2f92638d2b2b2c704f9e8db3ae0edc", + "sha256:b912750b13d76af8aac45ddf4679535def304b2a48a07989ec736508d0bbfbde", + "sha256:bc2676312cc3468a25aac001ec727168994ea3b69b48914944a44c6a0b251e79", + "sha256:cebff2fe5dc82cb22122e4e1225e00a4a506b1a16fafa911142ee124febf2c9e", + "sha256:d22fce0b0f5715cdac082e35a9e735a1752dc8585f005d045abb1a7c20e197f9", + "sha256:d3f7e001328bd6466b3414215f66dde3c7c13d8025a9c160a75d7b2687090d15", + "sha256:d3fe667935e9562407c2511570dca14604a654988a13d8725667e95161d92e9b", + "sha256:dabb70a6e3d9c22df50e08dc55b14ca2a99da95a2d941954255ac76fd6982bc5", + "sha256:e2fb8e8158306567a3a9a41670c1ff99d0567d7fc96fa93b7abf8b519a46b250", + "sha256:e96ac6b3169940a8cd57b4f2b8edcad8f5213b60efcd197d59fbe52f0accd66e", + "sha256:fbf649bc77510ef2521cf797700b96167bb77838c40780da7ea3edd8b78044d1" ], "markers": "python_version >= '3.7'", - "version": "==6.4" + "version": "==6.4.post2" } }, "develop": { @@ -610,27 +634,27 @@ }, "astroid": { "hashes": [ - "sha256:902564b36796ba1eab3ad2c7a694861fbd926f574d5dbb5fa1d86778a2ba2d91", - "sha256:b452064132234819f023b94f4bd045b250ea0009f372b4377cfcd87f10806ca5" + "sha256:8ead48e31b92b2e217b6c9733a21afafe479d52d6e164dd25fb1a770c7c3cf94", + "sha256:e8a0083b4bb28fcffb6207a3bfc9e5d0a68be951dd7e336d5dcf639c682388c0" ], "markers": "python_full_version >= '3.8.0'", - "version": "==3.2.1" + "version": "==3.2.2" }, "autopep8": { "hashes": [ - "sha256:1fa8964e4618929488f4ec36795c7ff12924a68b8bf01366c094fc52f770b6e7", - "sha256:2bb76888c5edbcafe6aabab3c47ba534f5a2c2d245c2eddced4a30c4b4946357" + "sha256:05418a981f038969d8bdcd5636bf15948db7555ae944b9f79b5a34b35f1370d4", + "sha256:d306a0581163ac29908280ad557773a95a9bede072c0fafed6f141f5311f43c1" ], "index": "pypi", - "version": "==2.1.0" + "version": "==2.2.0" }, "certifi": { "hashes": [ - "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", - "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" + "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516", + "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56" ], "markers": "python_version >= '3.6'", - "version": "==2024.2.2" + "version": "==2024.6.2" }, "charset-normalizer": { "hashes": [ @@ -752,11 +776,11 @@ }, "django": { "hashes": [ - "sha256:7ca38a78654aee72378594d63e51636c04b8e28574f5505dff630895b5472777", - "sha256:a52ea7fcf280b16f7b739cec38fa6d3f8953a5456986944c3ca97e79882b4e38" + "sha256:837e3cf1f6c31347a1396a3f6b65688f2b4bb4a11c580dcb628b5afe527b68a5", + "sha256:a17fcba2aad3fc7d46fdb23215095dbbd64e6174bf4589171e732b18b07e426a" ], "index": "pypi", - "version": "==3.2.25" + "version": "==4.2.13" }, "django-rest-swagger": { "hashes": [ @@ -768,11 +792,11 @@ }, "django-typomatic": { "hashes": [ - "sha256:1903d983f73fb7ac2f47f4f44e10d1500f8f42df400cae31f1e250397d91d22e", - "sha256:2e79dbd37b562c31c541a7dd50d2c09dbf44b778ea99555d7c229d3c66f86573" + "sha256:4a4d588ade9c2dd5278a94ca5603bd2b3779784273458cd7652e784412b15e16", + "sha256:c2c8ae8ad8d2c195185d02e91078c6973174c471abc7ddbc7a231d553cf6c976" ], "index": "pypi", - "version": "==2.5.0" + "version": "==2.5.1" }, "djangorestframework": { "hashes": [ @@ -911,11 +935,11 @@ }, "pylint": { "hashes": [ - "sha256:9f20c05398520474dac03d7abb21ab93181f91d4c110e1e0b32bc0d016c34fa4", - "sha256:ad8baf17c8ea5502f23ae38d7c1b7ec78bd865ce34af9a0b986282e2611a8ff2" + "sha256:02f6c562b215582386068d52a30f520d84fdbcf2a95fc7e855b816060d048b60", + "sha256:b3d7d2708a3e04b4679e02d99e72329a8b7ee8afb8d04110682278781f889fa8" ], "index": "pypi", - "version": "==3.2.0" + "version": "==3.2.3" }, "pylint-django": { "hashes": [ @@ -942,11 +966,11 @@ }, "requests": { "hashes": [ - "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", - "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" ], - "markers": "python_version >= '3.7'", - "version": "==2.31.0" + "markers": "python_version >= '3.8'", + "version": "==2.32.3" }, "simplejson": { "hashes": [ diff --git a/cms/migrations/0001_initial.py b/cms/migrations/0001_initial.py new file mode 100644 index 00000000..4f62e71f --- /dev/null +++ b/cms/migrations/0001_initial.py @@ -0,0 +1,105 @@ +# Generated by Django 4.2.11 on 2024-04-14 09:24 + +import base.models +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('sites', '0002_alter_domain_unique'), + ] + + operations = [ + migrations.CreateModel( + name='InfoBanner', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('visible_after', models.DateTimeField(verbose_name='Zobrazuj od')), + ('visible_until', models.DateTimeField(verbose_name='Zobrazuj do')), + ('message', models.CharField(help_text='Správa sa zobrazí v baneri. Správa musí byť stručná - jedna krátka veta.', max_length=200, verbose_name='správa')), + ], + options={ + 'verbose_name': 'Informácia v pohyblivom baneri', + 'verbose_name_plural': 'Informácie v pohyblivom baneri', + }, + ), + migrations.CreateModel( + name='Logo', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=150, verbose_name='názov loga')), + ('disabled', models.BooleanField()), + ('image', base.models.RestrictedFileField(upload_to='logo_images/', verbose_name='Logo')), + ], + options={ + 'verbose_name': 'logo', + 'verbose_name_plural': 'logá', + 'ordering': ['name'], + }, + ), + migrations.CreateModel( + name='MessageTemplate', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(help_text='Pomenovanie generickej správy. Slúži pre orientáciu', max_length=50, verbose_name='Názov')), + ('message', models.CharField(help_text='Generické správy pre banner a posty', max_length=200, verbose_name='Generická správa')), + ('is_active', models.BooleanField(default=True, verbose_name='Aktívna')), + ], + options={ + 'verbose_name': 'Generické správy pre banner a posty', + 'verbose_name_plural': 'Generické správy pre banner a posty', + }, + ), + migrations.CreateModel( + name='Post', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('visible_after', models.DateTimeField(verbose_name='Zobrazuj od')), + ('visible_until', models.DateTimeField(verbose_name='Zobrazuj do')), + ('caption', models.CharField(max_length=50, verbose_name='nadpis')), + ('short_text', models.CharField(help_text='Krátky 1-2 vetový popis.', max_length=200, verbose_name='krátky text')), + ('details', models.TextField(blank=True, help_text='Dlhší text, ktorý sa zobrazí po rozkliknutí.', verbose_name='podrobnosti k príspevku')), + ('added_at', models.DateTimeField(auto_now_add=True, verbose_name='pridané')), + ('sites', models.ManyToManyField(to='sites.site')), + ], + options={ + 'verbose_name': 'príspevok', + 'verbose_name_plural': 'príspevky', + 'ordering': ['-added_at'], + }, + ), + migrations.CreateModel( + name='PostLink', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('caption', models.CharField(help_text='Nápis, ktorý po kliknutí presmeruje na link. Maximálne 2 slová.', max_length=25, verbose_name='názov')), + ('url', models.CharField(help_text='URL stránky kam má preklik viesť', max_length=100, verbose_name='URL')), + ('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='links', to='cms.post', verbose_name='Relevantný príspevok')), + ], + options={ + 'verbose_name': 'link k príspevku', + 'verbose_name_plural': 'linky k príspevkom', + }, + ), + migrations.CreateModel( + name='MenuItem', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('caption', models.CharField(help_text='Nápis, ktorý sa zobrazí v menu. Maximálne 2 slová.', max_length=25, verbose_name='názov')), + ('url', models.CharField(help_text='URL stránky kam má preklik viesť', max_length=100, verbose_name='URL')), + ('priority', models.SmallIntegerField(help_text='Priorita, čím väčšie, tým vyššie v menu.', verbose_name='priorita')), + ('in_footer', models.BooleanField(default=False, verbose_name='Je v pätičke')), + ('in_menu', models.BooleanField(default=True, verbose_name='Je v menu')), + ('sites', models.ManyToManyField(to='sites.site')), + ], + options={ + 'verbose_name': 'položka v menu', + 'verbose_name_plural': 'položky v menu', + 'ordering': ['-priority'], + }, + ), + ] diff --git a/cms/migrations/0002_initial.py b/cms/migrations/0002_initial.py new file mode 100644 index 00000000..0c854b68 --- /dev/null +++ b/cms/migrations/0002_initial.py @@ -0,0 +1,38 @@ +# Generated by Django 4.2.11 on 2024-04-14 09:24 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('flatpages', '0001_initial'), + ('cms', '0001_initial'), + ('competition', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='infobanner', + name='event', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='competition.event'), + ), + migrations.AddField( + model_name='infobanner', + name='message_template', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='cms.messagetemplate'), + ), + migrations.AddField( + model_name='infobanner', + name='page', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='flatpages.flatpage'), + ), + migrations.AddField( + model_name='infobanner', + name='series', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='competition.series'), + ), + ] diff --git a/competition/migrations/0001_initial.py b/competition/migrations/0001_initial.py new file mode 100644 index 00000000..f9263d2d --- /dev/null +++ b/competition/migrations/0001_initial.py @@ -0,0 +1,235 @@ +# Generated by Django 4.2.11 on 2024-04-14 09:24 + +import base.models +import base.validators +import django.core.files.storage +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import re + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Comment', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('text', models.TextField()), + ('posted_at', models.DateTimeField(auto_now_add=True, verbose_name='dátum pridania')), + ('state', models.IntegerField(choices=[(1, 'čaká'), (2, 'zverejnený'), (3, 'skrytý')], default=1, verbose_name='komentár publikovaný')), + ('hidden_response', models.TextField(blank=True, null=True, verbose_name='Skrytá odpoveď na komentár')), + ], + options={ + 'verbose_name': 'komentár', + 'verbose_name_plural': 'komentáre', + 'ordering': ['posted_at'], + }, + ), + migrations.CreateModel( + name='Competition', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=50, verbose_name='názov')), + ('slug', models.SlugField()), + ('start_year', models.PositiveSmallIntegerField(blank=True, verbose_name='rok prvého ročníka súťaže')), + ('description', models.TextField(blank=True, verbose_name='Popis súťaže')), + ('rules', models.TextField(blank=True, null=True, verbose_name='Pravidlá súťaže')), + ('who_can_participate', models.CharField(blank=True, max_length=50, verbose_name='Pre koho je súťaž určená')), + ('min_years_until_graduation', models.PositiveSmallIntegerField(help_text='Horná hranica na účasť v súťaži. Zadáva sa v počte rokov do maturity. Ak najstraší, kto môže riešiť súťaž je deviatak, zadá sa 4.', null=True, verbose_name='Minimálny počet rokov do maturity')), + ], + options={ + 'verbose_name': 'súťaž', + 'verbose_name_plural': 'súťaže', + }, + ), + migrations.CreateModel( + name='CompetitionType', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200, verbose_name='typ súťaže')), + ], + options={ + 'verbose_name': 'Typ súťaže', + 'verbose_name_plural': 'Typy súťaží', + }, + ), + migrations.CreateModel( + name='Event', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('year', models.PositiveSmallIntegerField(blank=True, verbose_name='ročník')), + ('school_year', models.CharField(blank=True, max_length=10, validators=[base.validators.school_year_validator], verbose_name='školský rok')), + ('season_code', models.PositiveSmallIntegerField(choices=[(0, 'Zimný'), (1, 'Letný'), (2, '')], default=2)), + ('start', models.DateTimeField(verbose_name='dátum začiatku súťaže')), + ('end', models.DateTimeField(verbose_name='dátum konca súťaže')), + ('additional_name', models.CharField(blank=True, max_length=50, null=True, verbose_name='Prívlastok súťaže')), + ], + options={ + 'verbose_name': 'ročník súťaže', + 'verbose_name_plural': 'ročníky súťaží', + 'ordering': ['-school_year'], + }, + ), + migrations.CreateModel( + name='EventRegistration', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ], + options={ + 'verbose_name': 'registrácia užívateľa na akciu', + 'verbose_name_plural': 'registrácie užívateľov na akcie', + }, + ), + migrations.CreateModel( + name='Grade', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=32, verbose_name='názov ročníku')), + ('tag', models.CharField(max_length=2, unique=True, verbose_name='skratka')), + ('years_until_graduation', models.SmallIntegerField(verbose_name='počet rokov do maturity')), + ('is_active', models.BooleanField(verbose_name='aktuálne používaný ročník')), + ], + options={ + 'verbose_name': 'ročník účastníka', + 'verbose_name_plural': 'ročníky účastníka', + 'ordering': ['years_until_graduation'], + }, + ), + migrations.CreateModel( + name='LateTag', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=50, verbose_name='označenie štítku pre riešiteľa')), + ('slug', models.CharField(max_length=50, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), 'Enter a valid “slug” consisting of letters, numbers, underscores or hyphens.', 'invalid')], verbose_name='označenie priečinku pri stiahnutí')), + ('upper_bound', models.DurationField(verbose_name='maximálna dĺžka omeškania')), + ('comment', models.TextField(verbose_name='komentár pre opravovateľa')), + ('can_resubmit', models.BooleanField(verbose_name='Možnosť prepísať odovzdané riešenie')), + ], + options={ + 'verbose_name': 'omeškanie', + 'verbose_name_plural': 'omeškanie', + }, + ), + migrations.CreateModel( + name='Problem', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('text', models.TextField(verbose_name='znenie úlohy')), + ('order', models.PositiveSmallIntegerField(verbose_name='poradie v sérii')), + ('image', models.ImageField(blank=True, null=True, upload_to='problem_images/', verbose_name='Obrázok k úlohe')), + ('solution_pdf', base.models.RestrictedFileField(blank=True, null=True, upload_to='model_solutions/', verbose_name='Vzorové riešenie')), + ], + options={ + 'verbose_name': 'úloha', + 'verbose_name_plural': 'úlohy', + 'ordering': ['series', 'order'], + }, + ), + migrations.CreateModel( + name='PublicationType', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=100, verbose_name='názov typu')), + ], + options={ + 'verbose_name': 'Typ publikácie', + 'verbose_name_plural': 'Typy publikácií', + }, + ), + migrations.CreateModel( + name='RegistrationLink', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('url', models.URLField(verbose_name='url registrácie')), + ('start', models.DateTimeField(verbose_name='Začiatok registrácie')), + ('end', models.DateTimeField(verbose_name='Koniec registrácie')), + ('additional_info', models.TextField(blank=True, null=True, verbose_name='Doplňujúce informácie')), + ], + options={ + 'verbose_name': 'link na registráciu', + 'verbose_name_plural': 'linky na registráciu', + }, + ), + migrations.CreateModel( + name='Series', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('order', models.PositiveSmallIntegerField(verbose_name='poradie série')), + ('deadline', models.DateTimeField(verbose_name='termín série')), + ('sum_method', models.CharField(blank=True, choices=[('series_simple_sum', 'Jednoduchý súčet bodov'), ('series_Malynar_sum', 'Bonifikácia Malynár'), ('series_Matik_sum', 'Bonifikácia Matik'), ('series_STROM_sum', 'Bonifikácia STROM'), ('series_Malynar_sum_until_2021', 'Bonifikácia Malynár (Do 2020/2021)'), ('series_Matik_sum_until_2021', 'Bonifikácia Matik (Do 2020/2021)'), ('series_STROM_sum_until_2021', 'Bonifikácia STROM (Do 2020/2021)'), ('series_STROM_4problems_sum', 'Bonifikácia STROM (4. úlohy)')], max_length=50, verbose_name='Súčtová metóda')), + ('frozen_results', models.TextField(blank=True, default=None, null=True)), + ], + options={ + 'verbose_name': 'séria', + 'verbose_name_plural': 'série', + 'ordering': ['semester', '-order'], + }, + ), + migrations.CreateModel( + name='Semester', + fields=[ + ('event_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='competition.event')), + ('frozen_results', models.TextField(blank=True, default=None, null=True)), + ], + options={ + 'verbose_name': 'semester', + 'verbose_name_plural': 'semestre', + 'ordering': ['-year', '-season_code'], + }, + bases=('competition.event',), + ), + migrations.CreateModel( + name='Solution', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('solution', base.models.RestrictedFileField(blank=True, storage=django.core.files.storage.FileSystemStorage(location='/home/mihal/Documents/STROM/webstrom/webstrom-backend/protected_media'), upload_to='solutions/user_solutions', verbose_name='účastnícke riešenie')), + ('corrected_solution', base.models.RestrictedFileField(blank=True, storage=django.core.files.storage.FileSystemStorage(location='/home/mihal/Documents/STROM/webstrom/webstrom-backend/protected_media'), upload_to='solutions/corrected/', verbose_name='opravené riešenie')), + ('score', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='body')), + ('vote', models.IntegerField(choices=[(-1, 'negatívny'), (0, 'žiaden'), (1, 'pozitívny')], default=0)), + ('uploaded_at', models.DateTimeField(auto_now_add=True, verbose_name='dátum pridania')), + ('is_online', models.BooleanField(default=False, verbose_name='internetové riešenie')), + ('late_tag', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='competition.latetag', verbose_name='Stavy omeškania')), + ('problem', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='competition.problem')), + ('semester_registration', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='competition.eventregistration')), + ], + options={ + 'verbose_name': 'riešenie', + 'verbose_name_plural': 'riešenia', + }, + ), + migrations.CreateModel( + name='Publication', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(blank=True, max_length=30)), + ('file', base.models.RestrictedFileField(upload_to='publications/%Y', verbose_name='súbor')), + ('order', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='poradie')), + ('event', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='competition.event')), + ('publication_type', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='competition.publicationtype')), + ], + options={ + 'verbose_name': 'Publikácia', + 'verbose_name_plural': 'Publikácie', + 'ordering': ['order'], + }, + ), + migrations.CreateModel( + name='ProblemCorrection', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('correct_solution_text', models.TextField(verbose_name='vzorák')), + ('best_solution', models.ManyToManyField(to='competition.solution', verbose_name='najkrajšie riešenia')), + ], + options={ + 'verbose_name': 'opravenie úlohy', + 'verbose_name_plural': 'opravene ulohy', + }, + ), + ] diff --git a/competition/migrations/0002_initial.py b/competition/migrations/0002_initial.py new file mode 100644 index 00000000..8355aed2 --- /dev/null +++ b/competition/migrations/0002_initial.py @@ -0,0 +1,105 @@ +# Generated by Django 4.2.11 on 2024-04-14 09:24 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ('personal', '0002_initial'), + ('competition', '0001_initial'), + ('sites', '0002_alter_domain_unique'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AddField( + model_name='problemcorrection', + name='corrected_by', + field=models.ManyToManyField(to=settings.AUTH_USER_MODEL, verbose_name='opravovatelia'), + ), + migrations.AddField( + model_name='problemcorrection', + name='problem', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='correction', to='competition.problem'), + ), + migrations.AddField( + model_name='problem', + name='series', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='problems', to='competition.series', verbose_name='úloha zaradená do série'), + ), + migrations.AddField( + model_name='eventregistration', + name='event', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='competition.event', verbose_name='semester'), + ), + migrations.AddField( + model_name='eventregistration', + name='grade', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='competition.grade', verbose_name='ročník'), + ), + migrations.AddField( + model_name='eventregistration', + name='profile', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='personal.profile', verbose_name='profil'), + ), + migrations.AddField( + model_name='eventregistration', + name='school', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='personal.school', verbose_name='škola'), + ), + migrations.AddField( + model_name='event', + name='competition', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='competition.competition'), + ), + migrations.AddField( + model_name='event', + name='registration_link', + field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.SET_NULL, to='competition.registrationlink'), + ), + migrations.AddField( + model_name='competition', + name='competition_type', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='competition.competitiontype', verbose_name='typ súťaže'), + ), + migrations.AddField( + model_name='competition', + name='permission_group', + field=models.ManyToManyField(blank=True, related_name='competition_permissions', to='auth.group', verbose_name='Skupiny práv'), + ), + migrations.AddField( + model_name='competition', + name='sites', + field=models.ManyToManyField(to='sites.site'), + ), + migrations.AddField( + model_name='comment', + name='posted_by', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='autor komentára'), + ), + migrations.AddField( + model_name='comment', + name='problem', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='competition.problem', verbose_name='komentár k úlohe'), + ), + migrations.AddField( + model_name='series', + name='semester', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='competition.semester', verbose_name='semester'), + ), + migrations.AddField( + model_name='semester', + name='late_tags', + field=models.ManyToManyField(blank=True, to='competition.latetag', verbose_name='Stavy omeškania'), + ), + migrations.AddConstraint( + model_name='eventregistration', + constraint=models.UniqueConstraint(fields=('profile', 'event'), name='single_registration_in_event'), + ), + ] diff --git a/competition/migrations/0003_alter_grade_name.py b/competition/migrations/0003_alter_grade_name.py new file mode 100644 index 00000000..74ae0f94 --- /dev/null +++ b/competition/migrations/0003_alter_grade_name.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.11 on 2024-04-14 10:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('competition', '0002_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='grade', + name='name', + field=models.CharField(max_length=256, verbose_name='názov ročníku'), + ), + ] diff --git a/competition/models.py b/competition/models.py index 72c24f5e..b103f2e1 100644 --- a/competition/models.py +++ b/competition/models.py @@ -542,7 +542,7 @@ class Meta: verbose_name_plural = 'ročníky účastníka' ordering = ['years_until_graduation', ] - name = models.CharField(verbose_name='názov ročníku', max_length=32) + name = models.CharField(verbose_name='názov ročníku', max_length=256) tag = models.CharField(verbose_name='skratka', max_length=2, unique=True) years_until_graduation = models.SmallIntegerField( verbose_name='počet rokov do maturity') diff --git a/compose.yaml b/compose.yaml deleted file mode 100644 index 6aed2794..00000000 --- a/compose.yaml +++ /dev/null @@ -1,9 +0,0 @@ -version: "3.3" - -services: - website: - build: . - image: webstrom-backend - ports: - - "8000:8000" - restart: always diff --git a/deployment/compose-test.yaml b/deployment/compose-test.yaml new file mode 100644 index 00000000..be492213 --- /dev/null +++ b/deployment/compose-test.yaml @@ -0,0 +1,32 @@ +version: "3" + +services: + webstrom-backend: + build: + dockerfile: deployment/webstrom-backend.dockerfile + context: .. + + image: webstrom-test-backend + + environment: + - DJANGO_SETTINGS_MODULE=webstrom.settings_test + + volumes: + - /var/run/postgresql:/var/run/postgresql:rw + + ports: + - "127.0.0.1:8920:8000" + + restart: always + + static-files: + build: + dockerfile: deployment/static-files.dockerfile + context: .. + + image: webstrom-test-static + + ports: + - "127.0.0.1:8921:80" + + restart: always diff --git a/deployment/static-files.dockerfile b/deployment/static-files.dockerfile new file mode 100644 index 00000000..89c9875d --- /dev/null +++ b/deployment/static-files.dockerfile @@ -0,0 +1,17 @@ +FROM python:3.11 AS static-files-builder + +WORKDIR /app + +COPY Pipfile /app +COPY Pipfile.lock /app + +RUN pip install pipenv +RUN pipenv sync --dev --system + +COPY . /app + +RUN python manage.py collectstatic --no-input + +FROM nginx:1.25 + +COPY --from=static-files-builder /app/static /usr/share/nginx/html diff --git a/Dockerfile b/deployment/webstrom-backend.dockerfile similarity index 52% rename from Dockerfile rename to deployment/webstrom-backend.dockerfile index bbe44070..191986a0 100644 --- a/Dockerfile +++ b/deployment/webstrom-backend.dockerfile @@ -10,8 +10,4 @@ RUN pipenv sync --dev --system COPY . /app -RUN python manage.py restoredb - -EXPOSE 8000 - -ENTRYPOINT [ "daphne", "-b", "0.0.0.0", "-p", "8000", "webstrom.asgi:application" ] +CMD [ "daphne", "-b", "0.0.0.0", "-p", "8000", "webstrom.asgi:application" ] diff --git a/downloads/urls.py b/downloads/urls.py index d871f9c7..4495d7f0 100644 --- a/downloads/urls.py +++ b/downloads/urls.py @@ -1,5 +1,4 @@ -from django.conf.urls import url -from django.utils.translation import ugettext_lazy as _ +from django.urls import re_path from competition.models import Solution @@ -7,12 +6,11 @@ urlpatterns = [ # Include non-translated versions only since Admin ignores lang prefix - url(r'solutions/(?P.*)$', download_protected_file, - {'path_prefix': 'solutions/', 'model_class': Solution}, - name='download_solution'), - url(r'corrected_solutions/(?P.*)$', download_protected_file, - {'path_prefix': 'corrected_solutions/', - 'model_class': Solution}, - name='download_corrected_solution'), - + re_path(r'solutions/(?P.*)$', download_protected_file, + {'path_prefix': 'solutions/', 'model_class': Solution}, + name='download_solution'), + re_path(r'corrected_solutions/(?P.*)$', download_protected_file, + {'path_prefix': 'corrected_solutions/', + 'model_class': Solution}, + name='download_corrected_solution'), ] diff --git a/personal/migrations/0001_initial.py b/personal/migrations/0001_initial.py new file mode 100644 index 00000000..9d549156 --- /dev/null +++ b/personal/migrations/0001_initial.py @@ -0,0 +1,72 @@ +# Generated by Django 4.2.11 on 2024-04-14 09:24 + +import base.managers +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='County', + fields=[ + ('code', models.AutoField(primary_key=True, serialize=False, verbose_name='kód')), + ('name', models.CharField(max_length=30, verbose_name='názov')), + ], + options={ + 'verbose_name': 'kraj', + 'verbose_name_plural': 'kraje', + }, + ), + migrations.CreateModel( + name='District', + fields=[ + ('code', models.AutoField(primary_key=True, serialize=False, verbose_name='kód')), + ('name', models.CharField(max_length=30, verbose_name='názov')), + ('abbreviation', models.CharField(max_length=2, verbose_name='skratka')), + ], + options={ + 'verbose_name': 'okres', + 'verbose_name_plural': 'okresy', + }, + ), + migrations.CreateModel( + name='School', + fields=[ + ('code', models.AutoField(primary_key=True, serialize=False, verbose_name='kód')), + ('name', models.CharField(max_length=100, verbose_name='názov')), + ('abbreviation', models.CharField(max_length=10, verbose_name='skratka')), + ('street', models.CharField(max_length=100, verbose_name='ulica')), + ('city', models.CharField(max_length=100, verbose_name='obec')), + ('zip_code', models.CharField(max_length=6, verbose_name='PSČ')), + ('email', models.CharField(blank=True, max_length=50, verbose_name='email')), + ('district', models.ForeignKey(on_delete=models.SET(base.managers.UnspecifiedValueManager.get_unspecified_value), to='personal.district', verbose_name='okres')), + ], + options={ + 'verbose_name': 'škola', + 'verbose_name_plural': 'školy', + }, + ), + migrations.CreateModel( + name='Profile', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('first_name', models.CharField(max_length=150, verbose_name='krstné meno')), + ('last_name', models.CharField(max_length=150, verbose_name='priezvisko')), + ('year_of_graduation', models.PositiveSmallIntegerField(verbose_name='rok maturity')), + ('phone', models.CharField(blank=True, help_text='Telefonné číslo v medzinárodnom formáte (napr. +421 123 456 789).', max_length=32, validators=[django.core.validators.RegexValidator(message='Zadaj telefónne číslo vo formáte +421 123 456 789 alebo 0912 345 678.', regex='^(\\+\\d{1,3}\\d{9})$')], verbose_name='telefónne číslo')), + ('parent_phone', models.CharField(blank=True, help_text='Telefonné číslo v medzinárodnom formáte (napr. +421 123 456 789).', max_length=32, validators=[django.core.validators.RegexValidator(message='Zadaj telefónne číslo vo formáte +421 123 456 789 alebo 0912 345 678.', regex='^(\\+\\d{1,3}\\d{9})$')], verbose_name='telefónne číslo na rodiča')), + ('school', models.ForeignKey(on_delete=models.SET(base.managers.UnspecifiedValueManager.get_unspecified_value), to='personal.school', verbose_name='škola')), + ], + options={ + 'verbose_name': 'profil', + 'verbose_name_plural': 'profily', + }, + ), + ] diff --git a/personal/migrations/0002_initial.py b/personal/migrations/0002_initial.py new file mode 100644 index 00000000..c5b595ec --- /dev/null +++ b/personal/migrations/0002_initial.py @@ -0,0 +1,29 @@ +# Generated by Django 4.2.11 on 2024-04-14 09:24 + +import base.managers +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('personal', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AddField( + model_name='profile', + name='user', + field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='district', + name='county', + field=models.ForeignKey(on_delete=models.SET(base.managers.UnspecifiedValueManager.get_unspecified_value), to='personal.county', verbose_name='kraj'), + ), + ] diff --git a/personal/migrations/0003_alter_district_county_alter_profile_school_and_more.py b/personal/migrations/0003_alter_district_county_alter_profile_school_and_more.py new file mode 100644 index 00000000..3425ec86 --- /dev/null +++ b/personal/migrations/0003_alter_district_county_alter_profile_school_and_more.py @@ -0,0 +1,29 @@ +# Generated by Django 4.2.11 on 2024-04-14 10:51 + +import base.managers +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('personal', '0002_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='district', + name='county', + field=models.ForeignKey(on_delete=models.SET(base.managers.UnspecifiedValueManager.get_unspecified_value), to='personal.county', verbose_name='kraj'), + ), + migrations.AlterField( + model_name='profile', + name='school', + field=models.ForeignKey(on_delete=models.SET(base.managers.UnspecifiedValueManager.get_unspecified_value), to='personal.school', verbose_name='škola'), + ), + migrations.AlterField( + model_name='school', + name='district', + field=models.ForeignKey(on_delete=models.SET(base.managers.UnspecifiedValueManager.get_unspecified_value), to='personal.district', verbose_name='okres'), + ), + ] diff --git a/problem_database/migrations/0001_initial.py b/problem_database/migrations/0001_initial.py new file mode 100644 index 00000000..186e8e6e --- /dev/null +++ b/problem_database/migrations/0001_initial.py @@ -0,0 +1,153 @@ +# Generated by Django 4.2.11 on 2024-04-14 09:24 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Activity', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.DateField(verbose_name='dátum')), + ('description', models.TextField(verbose_name='popis')), + ('soft_deleted', models.BooleanField(default=False)), + ], + options={ + 'verbose_name': 'aktivita', + 'verbose_name_plural': 'aktivity', + }, + ), + migrations.CreateModel( + name='ActivityType', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=64, verbose_name='názov')), + ], + options={ + 'verbose_name': 'typ aktivity', + 'verbose_name_plural': 'typy aktivít', + }, + ), + migrations.CreateModel( + name='Difficulty', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=128, verbose_name='názov')), + ('activity_type', models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='problem_database.activitytype', verbose_name='typ aktivity')), + ], + options={ + 'verbose_name': 'náročnosť', + 'verbose_name_plural': 'náročnosti', + }, + ), + migrations.CreateModel( + name='Problem', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('problem', models.TextField(verbose_name='príklad')), + ('result', models.CharField(max_length=128, verbose_name='výsledok')), + ('solution', models.TextField(verbose_name='riešenie')), + ('soft_deleted', models.BooleanField(default=False)), + ], + options={ + 'verbose_name': 'príklad', + 'verbose_name_plural': 'príklady', + }, + ), + migrations.CreateModel( + name='Seminar', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=32, verbose_name='názov seminára')), + ], + options={ + 'verbose_name': 'seminár', + 'verbose_name_plural': 'semináre', + }, + ), + migrations.CreateModel( + name='Tag', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=64, verbose_name='názov tagu')), + ], + options={ + 'verbose_name': 'tag', + 'verbose_name_plural': 'tagy', + }, + ), + migrations.CreateModel( + name='ProblemType', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=64, verbose_name='názov')), + ('description', models.TextField(verbose_name='popis')), + ('seminar', models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='problem_database.seminar', verbose_name='seminár')), + ], + options={ + 'verbose_name': 'typ príkladu', + 'verbose_name_plural': 'typy príkladov', + }, + ), + migrations.CreateModel( + name='ProblemTag', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('problem', models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='problem_database.problem', verbose_name='príklad')), + ('tag', models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='problem_database.tag', verbose_name='aktivita')), + ], + options={ + 'verbose_name': 'priradenie príkladu k tagu', + 'verbose_name_plural': 'priradenia príkladov k tagom', + }, + ), + migrations.CreateModel( + name='ProblemActivity', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('activity', models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='problem_database.activity', verbose_name='aktivita')), + ('difficulty', models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='problem_database.difficulty', verbose_name='náročnosť')), + ('problem', models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='problem_database.problem', verbose_name='príklad')), + ], + options={ + 'verbose_name': 'priradenie problému k aktivite/obtiežnosti', + 'verbose_name_plural': 'priradenie problémov k aktivitám/obtiažnostiam', + }, + ), + migrations.AddField( + model_name='problem', + name='problem_type', + field=models.ManyToManyField(to='problem_database.problemtype'), + ), + migrations.CreateModel( + name='Media', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('data', models.ImageField(upload_to='', verbose_name='priložené súbory')), + ('soft_deleted', models.BooleanField(default=False)), + ('problem', models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='problem_database.problem', verbose_name='príklad')), + ], + options={ + 'verbose_name': 'súbor', + 'verbose_name_plural': 'súbory', + }, + ), + migrations.AddField( + model_name='activitytype', + name='seminar', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='problem_database.seminar', verbose_name='seminár'), + ), + migrations.AddField( + model_name='activity', + name='activity_type', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='problem_database.activitytype', verbose_name='typ aktivity'), + ), + ] diff --git a/requirements.txt b/requirements.txt index c4036f94..6ef4ddea 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,26 +1,26 @@ asgiref==3.8.1 -astroid==3.2.1 +astroid==3.2.2 attrs==23.2.0 autobahn==23.6.2 Automat==22.10.0 -autopep8==2.1.0 -certifi==2024.2.2 +autopep8==2.2.0 +certifi==2024.6.2 cffi==1.16.0 charset-normalizer==3.3.2 constantly==23.10.4 coreapi==2.3.3 coreschema==0.0.4 -cryptography==42.0.7 +cryptography==42.0.8 daphne==4.0.0 defusedxml==0.7.1 dill==0.3.8 dj-rest-auth==5.0.2 -Django==3.2.25 +Django==4.2.13 django-allauth==0.58.2 django-filter==23.5 django-rest-swagger==2.2.0 django-sendfile2==0.7.1 -django-typomatic==2.5.0 +django-typomatic==2.5.1 djangorestframework==3.14.0 drf-writable-nested==0.7.0 hyperlink==21.0.0 @@ -35,20 +35,20 @@ oauthlib==3.2.2 openapi-codec==1.3.2 pillow==10.3.0 platformdirs==4.2.2 -psycopg==3.1.18 +psycopg==3.1.19 pyasn1==0.6.0 pyasn1_modules==0.4.0 pycodestyle==2.11.1 pycparser==2.22 PyJWT==2.8.0 -pylint==3.2.0 +pylint==3.2.3 pylint-django==2.5.5 pylint-plugin-utils==0.8.2 pyOpenSSL==24.1.0 python-magic==0.4.27 python3-openid==3.2.0 pytz==2024.1 -requests==2.31.0 +requests==2.32.3 requests-oauthlib==2.0.0 service-identity==24.1.0 simplejson==3.19.2 @@ -57,8 +57,8 @@ sqlparse==0.5.0 tomlkit==0.12.5 Twisted==24.3.0 txaio==23.1.1 -typing_extensions==4.11.0 +typing_extensions==4.12.2 Unidecode==1.3.8 uritemplate==4.1.1 urllib3==2.2.1 -zope.interface==6.4 +zope.interface==6.4.post2 diff --git a/user/migrations/0001_initial.py b/user/migrations/0001_initial.py new file mode 100644 index 00000000..f5ccea1d --- /dev/null +++ b/user/migrations/0001_initial.py @@ -0,0 +1,41 @@ +# Generated by Django 4.2.11 on 2024-04-14 09:24 + +import django.contrib.auth.models +from django.db import migrations, models +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='User', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), + ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), + ('email', models.EmailField(max_length=254, unique=True, verbose_name='email')), + ('verified_email', models.BooleanField(default=False, verbose_name='overený email')), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), + ], + options={ + 'verbose_name': 'user', + 'verbose_name_plural': 'users', + 'abstract': False, + }, + managers=[ + ('objects', django.contrib.auth.models.UserManager()), + ], + ), + ] diff --git a/webstrom/settings_test.py b/webstrom/settings_test.py new file mode 100644 index 00000000..65d76d71 --- /dev/null +++ b/webstrom/settings_test.py @@ -0,0 +1,23 @@ +# pylint: disable=wildcard-import,unused-wildcard-import + +from .settings import * + +DEBUG = True + +ALLOWED_HOSTS = [ + "test.strom.sk", +] + +USE_X_FORWARDED_HOST = True + +SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': 'webstrom-test', + 'USER': 'webstrom', + } +} + +EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"