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..2f58e7f1 100644 --- a/Pipfile +++ b/Pipfile @@ -4,15 +4,16 @@ verify_ssl = true 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" +gunicorn = "~=22.0.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..7e575cc1 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "7df0459bbb2186ea13bb8c25ce90a415fc188092d1f00f88ca5d6350af79aa21" + "sha256": "fd2f8d27e2405d6db987ee9460aba608c0354df14453b74bec50df6804f7ef48" }, "pipfile-spec": 6, "requires": {}, @@ -22,35 +22,13 @@ "markers": "python_version >= '3.8'", "version": "==3.8.1" }, - "attrs": { - "hashes": [ - "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", - "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" - ], - "markers": "python_version >= '3.7'", - "version": "==23.2.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:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", - "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" + "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516", + "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56" ], "markers": "python_version >= '3.6'", - "version": "==2024.2.2" + "version": "==2024.6.2" }, "cffi": { "hashes": [ @@ -206,59 +184,43 @@ "markers": "python_full_version >= '3.7.0'", "version": "==3.3.2" }, - "constantly": { - "hashes": [ - "sha256:3fd9b4d1c3dc1ec9757f3c52aef7e53ad9323dbe39f51dfd4c43853b68dfa3f9", - "sha256:aa92b70a33e2ac0bb33cd745eb61776594dc48764b06c35e0efd050b7f1c7cbd" - ], - "markers": "python_version >= '3.8'", - "version": "==23.10.4" - }, "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" - }, - "daphne": { - "hashes": [ - "sha256:a288ece46012b6b719c37150be67c69ebfca0793a8521bf821533bad983179b2", - "sha256:cce9afc8f49a4f15d4270b8cfb0e0fe811b770a5cc795474e97e4da287497666" - ], - "index": "pypi", - "version": "==4.0.0" + "version": "==42.0.8" }, "defusedxml": { "hashes": [ @@ -277,11 +239,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 +260,14 @@ "index": "pypi", "version": "==23.5" }, + "django-sendfile2": { + "hashes": [ + "sha256:81971df1db77f688c4834b8540930902d0d929c64cf374bd604b81f5ac52c04a", + "sha256:b5bec07f1c9b1875a60ea74beb306e9aba964bd8b54f00b4432cb77cc35bc58c" + ], + "index": "pypi", + "version": "==0.7.1" + }, "djangorestframework": { "hashes": [ "sha256:579a333e6256b09489cbe0a067e66abe55c6595d8926be6b99423786334350c8", @@ -313,12 +283,13 @@ "index": "pypi", "version": "==0.7.0" }, - "hyperlink": { + "gunicorn": { "hashes": [ - "sha256:427af957daa58bc909471c6c40f74c5450fa123dd093fc53efd2e91d2705a56b", - "sha256:e6b14c37ecb73e89c77d78cdb4c2cc8f3fb59a885c5b3f819ff4ed80f25af1b4" + "sha256:350679f91b24062c86e386e198a15438d53a7a8207235a78ba1b53df4c4378d9", + "sha256:4a0b436239ff76fb33f11c07a16482c521a7e09c1ce3cc293c2330afe01bec63" ], - "version": "==21.0.0" + "index": "pypi", + "version": "==22.0.0" }, "idna": { "hashes": [ @@ -328,13 +299,6 @@ "markers": "python_version >= '3.5'", "version": "==3.7" }, - "incremental": { - "hashes": [ - "sha256:912feeb5e0f7e0188e6f42241d2f450002e11bbc0937c65865045854c24c0bd0", - "sha256:b864a1f30885ee72c5ac2835a761b8fe8aa9c28b9395cacf27286602688d3e51" - ], - "version": "==22.10.0" - }, "oauthlib": { "hashes": [ "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca", @@ -343,6 +307,14 @@ "markers": "python_version >= '3.6'", "version": "==3.2.2" }, + "packaging": { + "hashes": [ + "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", + "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" + ], + "markers": "python_version >= '3.7'", + "version": "==24.0" + }, "pillow": { "hashes": [ "sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c", @@ -418,21 +390,13 @@ "index": "pypi", "version": "==10.3.0" }, - "pyasn1": { + "psycopg": { "hashes": [ - "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c", - "sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473" + "sha256:92d7b78ad82426cdcf1a0440678209faa890c6e1721361c2f8901f0dccd62961", + "sha256:dca5e5521c859f6606686432ae1c94e8766d29cc91f2ee595378c510cc5b0731" ], - "markers": "python_version >= '3.8'", - "version": "==0.6.0" - }, - "pyasn1-modules": { - "hashes": [ - "sha256:831dbcea1b177b28c9baddf4c6d1013c24c3accd14a1873fffaa6a2e905f17b6", - "sha256:be04f15b66c206eed667e0bb5ab27e2b1855ea54a842e5037738099e8ca4ae0b" - ], - "markers": "python_version >= '3.8'", - "version": "==0.4.0" + "index": "pypi", + "version": "==3.1.19" }, "pycparser": { "hashes": [ @@ -453,13 +417,6 @@ "markers": "python_version >= '3.7'", "version": "==2.8.0" }, - "pyopenssl": { - "hashes": [ - "sha256:17ed5be5936449c5418d1cd269a1a9e9081bc54c17aed272b45856a3d3dc86ad", - "sha256:cabed4bfaa5df9f1a16c0ef64a0cb65318b5cd077a7eda7d6970131ca2f41a6f" - ], - "version": "==24.1.0" - }, "python-magic": { "hashes": [ "sha256:c1ba14b08e4a5f5c31a302b7721239695b2f0f058d125bd5ce1ee36b9d9d3c3b", @@ -484,11 +441,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": [ @@ -498,29 +455,6 @@ "markers": "python_version >= '3.4'", "version": "==2.0.0" }, - "service-identity": { - "hashes": [ - "sha256:6829c9d62fb832c2e1c435629b0a8c476e1929881f28bee4d20bc24161009221", - "sha256:a28caf8130c8a5c1c7a6f5293faaf239bbfb7751e4862436920ee6f2616f568a" - ], - "version": "==24.1.0" - }, - "setuptools": { - "hashes": [ - "sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987", - "sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32" - ], - "markers": "python_version >= '3.8'", - "version": "==69.5.1" - }, - "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" - }, "sqlparse": { "hashes": [ "sha256:714d0a4932c059d16189f58ef5411ec2287a4360f17cdd0edd2d09d4c5087c93", @@ -529,32 +463,13 @@ "markers": "python_version >= '3.8'", "version": "==0.5.0" }, - "twisted": { - "extras": [ - "tls" - ], - "hashes": [ - "sha256:039f2e6a49ab5108abd94de187fa92377abe5985c7a72d68d0ad266ba19eae63", - "sha256:6b38b6ece7296b5e122c9eb17da2eeab3d98a198f50ca9efd00fb03e5b4fd4ae" - ], - "markers": "python_full_version >= '3.8.0'", - "version": "==24.3.0" - }, - "txaio": { - "hashes": [ - "sha256:aaea42f8aad50e0ecfb976130ada140797e9dcb85fad2cf72b0f37f8cefcb490", - "sha256:f9a9216e976e5e3246dfd112ad7ad55ca915606b60b84a757ac769bd404ff704" - ], - "markers": "python_version >= '3.7'", - "version": "==23.1.1" - }, "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": [ @@ -563,40 +478,6 @@ ], "markers": "python_version >= '3.8'", "version": "==2.2.1" - }, - "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" - ], - "markers": "python_version >= '3.7'", - "version": "==6.4" } }, "develop": { @@ -610,27 +491,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 +633,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 +649,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 +792,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 +823,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..98a0ea83 --- /dev/null +++ b/cms/migrations/0001_initial.py @@ -0,0 +1,105 @@ +# Generated by Django 4.2.13 on 2024-06-10 20:10 + +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..22145826 --- /dev/null +++ b/cms/migrations/0002_initial.py @@ -0,0 +1,38 @@ +# Generated by Django 4.2.13 on 2024-06-10 20:10 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('flatpages', '0001_initial'), + ('competition', '0001_initial'), + ('cms', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='infobanner', + name='event', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='competition.event'), + ), + migrations.AddField( + model_name='infobanner', + name='message_template', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='cms.messagetemplate'), + ), + migrations.AddField( + model_name='infobanner', + name='page', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='flatpages.flatpage'), + ), + migrations.AddField( + model_name='infobanner', + name='series', + field=models.ForeignKey(blank=True, 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..2c58a262 --- /dev/null +++ b/competition/migrations/0001_initial.py @@ -0,0 +1,238 @@ +# Generated by Django 4.2.13 on 2024-06-10 20:10 + +import base.models +import base.validators +import competition.models +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')), + ('short_name', models.CharField(max_length=32, verbose_name='Krátky jednoslovný názov')), + ], + 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')), + ('location', models.TextField(blank=True, help_text='Napríklad "v Košiciach"', null=True, verbose_name='Miesto konania')), + ('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=256, 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(base_url='/protected/', location='/home/mihal/Documents/STROM/webstrom/webstrom-backend/protected_media/'), upload_to=competition.models.get_solution_path, verbose_name='účastnícke riešenie')), + ('corrected_solution', base.models.RestrictedFileField(blank=True, storage=django.core.files.storage.FileSystemStorage(base_url='/protected/', location='/home/mihal/Documents/STROM/webstrom/webstrom-backend/protected_media/'), upload_to=competition.models.get_corrected_solution_path, 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..ba03d52b --- /dev/null +++ b/competition/migrations/0002_initial.py @@ -0,0 +1,105 @@ +# Generated by Django 4.2.13 on 2024-06-10 20:10 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('personal', '0002_initial'), + ('competition', '0001_initial'), + ('sites', '0002_alter_domain_unique'), + ('auth', '0012_alter_user_first_name_max_length'), + 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(blank=True, 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/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..02d9c4e6 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 [ "gunicorn", "-b", "0.0.0.0", "-p", "8000", "webstrom.wsgi: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..66ae2f7b --- /dev/null +++ b/personal/migrations/0001_initial.py @@ -0,0 +1,72 @@ +# Generated by Django 4.2.13 on 2024-06-10 20:10 + +import django.core.validators +from django.db import migrations, models +import personal.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(personal.models.unspecified_district), 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(personal.models.unspecified_school), 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..8778794b --- /dev/null +++ b/personal/migrations/0002_initial.py @@ -0,0 +1,29 @@ +# Generated by Django 4.2.13 on 2024-06-10 20:10 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import personal.models + + +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(personal.models.unspecified_county), to='personal.county', verbose_name='kraj'), + ), + ] diff --git a/personal/models.py b/personal/models.py index c48a45ff..6b71574d 100644 --- a/personal/models.py +++ b/personal/models.py @@ -20,6 +20,10 @@ def __str__(self): return self.name +def unspecified_county(): + return County.objects.get_unspecified_value() + + class District(models.Model): class Meta: verbose_name = 'okres' @@ -31,7 +35,8 @@ class Meta: county = models.ForeignKey( County, verbose_name='kraj', - on_delete=models.SET(County.objects.get_unspecified_value)) + on_delete=models.SET(unspecified_county) + ) objects = UnspecifiedValueManager(unspecified_value_pk=0) @@ -39,6 +44,10 @@ def __str__(self): return self.name +def unspecified_district(): + return District.objects.get_unspecified_value() + + class School(models.Model): class Meta: verbose_name = 'škola' @@ -55,7 +64,8 @@ class Meta: district = models.ForeignKey( District, verbose_name='okres', - on_delete=models.SET(District.objects.get_unspecified_value)) + on_delete=models.SET(unspecified_district) + ) objects = UnspecifiedValueManager(unspecified_value_pk=0) @@ -74,6 +84,10 @@ def stitok(self): f'{{{ self.printable_zip_code }}}{{{ self.street }}}' +def unspecified_school(): + return School.objects.get_unspecified_value() + + class Profile(models.Model): class Meta: verbose_name = 'profil' @@ -92,8 +106,9 @@ class Meta: ) school = models.ForeignKey( - School, on_delete=models.SET(School.objects.get_unspecified_value), - verbose_name='škola') + School, on_delete=models.SET(unspecified_school), + verbose_name='škola' + ) year_of_graduation = models.PositiveSmallIntegerField( verbose_name='rok maturity') 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..abc55862 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,31 +1,25 @@ asgiref==3.8.1 -astroid==3.2.1 -attrs==23.2.0 -autobahn==23.6.2 -Automat==22.10.0 -autopep8==2.1.0 -certifi==2024.2.2 +astroid==3.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 -daphne==4.0.0 +cryptography==42.0.8 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 +gunicorn==22.0.0 idna==3.7 -incremental==22.10.0 isort==5.13.2 itypes==1.2.0 Jinja2==3.1.4 @@ -33,32 +27,25 @@ MarkupSafe==2.1.5 mccabe==0.7.0 oauthlib==3.2.2 openapi-codec==1.3.2 +packaging==24.0 pillow==10.3.0 platformdirs==4.2.2 -psycopg==3.1.18 -pyasn1==0.6.0 -pyasn1_modules==0.4.0 +psycopg==3.1.19 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 -six==1.16.0 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 diff --git a/user/migrations/0001_initial.py b/user/migrations/0001_initial.py new file mode 100644 index 00000000..34e75912 --- /dev/null +++ b/user/migrations/0001_initial.py @@ -0,0 +1,41 @@ +# Generated by Django 4.2.13 on 2024-06-10 20:10 + +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..3f895d49 --- /dev/null +++ b/webstrom/settings_test.py @@ -0,0 +1,24 @@ +# pylint: disable=wildcard-import,unused-wildcard-import + +from .settings import * + +DEBUG = True + +ALLOWED_HOSTS = [ + "localhost", + "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"