From 0ad426398a29bf6ab52557865d33c5822763cb3e Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Sat, 6 Jan 2024 12:13:39 +0800 Subject: [PATCH] Initial commit --- .gitignore | 172 +++ Dockerfile | 28 + Pipfile | 24 + Pipfile.lock | 1080 +++++++++++++++++++ backend/.env.sample | 21 + backend/accounts/__init__.py | 0 backend/accounts/admin.py | 16 + backend/accounts/apps.py | 6 + backend/accounts/migrations/0001_initial.py | 45 + backend/accounts/migrations/__init__.py | 0 backend/accounts/models.py | 87 ++ backend/accounts/serializers.py | 53 + backend/accounts/urls.py | 7 + backend/accounts/views.py | 5 + backend/api/__init__.py | 0 backend/api/urls.py | 14 + backend/config/__init__.py | 0 backend/config/asgi.py | 16 + backend/config/settings.py | 227 ++++ backend/config/urls.py | 29 + backend/config/wsgi.py | 16 + backend/manage.py | 22 + backend/schema.yml | 713 ++++++++++++ docker-compose.yml | 24 + requirements.txt | 43 + 25 files changed, 2648 insertions(+) create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 Pipfile create mode 100644 Pipfile.lock create mode 100644 backend/.env.sample create mode 100644 backend/accounts/__init__.py create mode 100644 backend/accounts/admin.py create mode 100644 backend/accounts/apps.py create mode 100644 backend/accounts/migrations/0001_initial.py create mode 100644 backend/accounts/migrations/__init__.py create mode 100644 backend/accounts/models.py create mode 100644 backend/accounts/serializers.py create mode 100644 backend/accounts/urls.py create mode 100644 backend/accounts/views.py create mode 100644 backend/api/__init__.py create mode 100644 backend/api/urls.py create mode 100644 backend/config/__init__.py create mode 100644 backend/config/asgi.py create mode 100644 backend/config/settings.py create mode 100644 backend/config/urls.py create mode 100644 backend/config/wsgi.py create mode 100644 backend/manage.py create mode 100644 backend/schema.yml create mode 100644 docker-compose.yml create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..59a050c --- /dev/null +++ b/.gitignore @@ -0,0 +1,172 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Static Media Stuff +equipment_tracker/media/* +equipment_tracker/static/* + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +backend/db.sqlite3 +backend/.env +backend/static/* +backend/static/ +backend/media/ + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +**/__pycache__/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..3e2822f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,28 @@ +ARG DOCKER_PLATFORM=$TARGETPLATFORM +FROM --platform=$DOCKER_PLATFORM python:3.11.4-bookworm + +ENV PYTHONBUFFERED 1 + +# Create directory +RUN mkdir /code + +# Set the working directory to /code +WORKDIR /code + +# Mirror the current directory to the working directory for hotreloading +ADD . /code/ + +# Install pipenv +RUN pip install --no-cache-dir -r requirements.txt + +# Make migrations +RUN python backend/manage.py makemigrations + +# Run custom migrate +RUN python backend/manage.py migrate + +# Generate DRF Spectacular Documentation +RUN python backend/manage.py spectacular --color --file backend/schema.yml + +# Expose port 8000 for the web server +EXPOSE 8000 diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..de09d75 --- /dev/null +++ b/Pipfile @@ -0,0 +1,24 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +django = "*" +djangorestframework = "*" +python-dotenv = "*" +whitenoise = "*" +djoser = "*" +django-cors-headers = "*" +drf-spectacular = {version = "*", extras = ["sidecar"]} +django-extra-fields = "*" +pillow = "*" +psycopg2 = "*" +django-simple-history = "*" +django-unfold = "*" +django-resized = "*" + +[dev-packages] + +[requires] +python_version = "3.11" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..4d6fe99 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,1080 @@ +{ + "_meta": { + "hash": { + "sha256": "76312f845fabe0018aeaa99f91c1f80e3825b1e241d419c2d0b8467519b47b2c" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.11" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "annotated-types": { + "hashes": [ + "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43", + "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d" + ], + "markers": "python_version >= '3.8'", + "version": "==0.6.0" + }, + "asgiref": { + "hashes": [ + "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e", + "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed" + ], + "markers": "python_version >= '3.7'", + "version": "==3.7.2" + }, + "attrs": { + "hashes": [ + "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30", + "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1" + ], + "markers": "python_version >= '3.7'", + "version": "==23.2.0" + }, + "certifi": { + "hashes": [ + "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1", + "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474" + ], + "markers": "python_version >= '3.6'", + "version": "==2023.11.17" + }, + "cffi": { + "hashes": [ + "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc", + "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a", + "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417", + "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab", + "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520", + "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36", + "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743", + "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8", + "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed", + "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684", + "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56", + "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324", + "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d", + "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", + "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e", + "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088", + "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000", + "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7", + "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e", + "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673", + "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c", + "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe", + "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2", + "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098", + "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8", + "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a", + "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0", + "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b", + "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896", + "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e", + "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9", + "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2", + "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b", + "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6", + "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404", + "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f", + "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0", + "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4", + "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc", + "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936", + "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba", + "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872", + "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb", + "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614", + "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1", + "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d", + "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969", + "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b", + "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4", + "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627", + "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", + "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357" + ], + "markers": "python_version >= '3.8'", + "version": "==1.16.0" + }, + "charset-normalizer": { + "hashes": [ + "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027", + "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087", + "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786", + "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", + "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09", + "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185", + "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", + "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e", + "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519", + "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898", + "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269", + "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3", + "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f", + "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6", + "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8", + "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a", + "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73", + "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", + "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714", + "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2", + "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", + "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", + "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d", + "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", + "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", + "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269", + "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", + "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d", + "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a", + "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", + "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", + "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d", + "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0", + "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", + "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", + "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac", + "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25", + "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", + "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", + "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", + "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2", + "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", + "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", + "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5", + "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99", + "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c", + "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", + "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811", + "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", + "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", + "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03", + "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", + "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04", + "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c", + "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", + "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458", + "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", + "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99", + "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985", + "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537", + "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238", + "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f", + "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d", + "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796", + "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a", + "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", + "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8", + "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c", + "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5", + "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5", + "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711", + "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4", + "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6", + "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c", + "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", + "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4", + "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b", + "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae", + "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12", + "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c", + "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae", + "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8", + "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887", + "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b", + "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", + "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f", + "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", + "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33", + "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519", + "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561" + ], + "markers": "python_full_version >= '3.7.0'", + "version": "==3.3.2" + }, + "click": { + "hashes": [ + "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", + "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de" + ], + "markers": "python_version >= '3.7'", + "version": "==8.1.7" + }, + "colorama": { + "hashes": [ + "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", + "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" + ], + "markers": "platform_system == 'Windows'", + "version": "==0.4.6" + }, + "cryptography": { + "hashes": [ + "sha256:079b85658ea2f59c4f43b70f8119a52414cdb7be34da5d019a77bf96d473b960", + "sha256:09616eeaef406f99046553b8a40fbf8b1e70795a91885ba4c96a70793de5504a", + "sha256:13f93ce9bea8016c253b34afc6bd6a75993e5c40672ed5405a9c832f0d4a00bc", + "sha256:37a138589b12069efb424220bf78eac59ca68b95696fc622b6ccc1c0a197204a", + "sha256:3c78451b78313fa81607fa1b3f1ae0a5ddd8014c38a02d9db0616133987b9cdf", + "sha256:43f2552a2378b44869fe8827aa19e69512e3245a219104438692385b0ee119d1", + "sha256:48a0476626da912a44cc078f9893f292f0b3e4c739caf289268168d8f4702a39", + "sha256:49f0805fc0b2ac8d4882dd52f4a3b935b210935d500b6b805f321addc8177406", + "sha256:5429ec739a29df2e29e15d082f1d9ad683701f0ec7709ca479b3ff2708dae65a", + "sha256:5a1b41bc97f1ad230a41657d9155113c7521953869ae57ac39ac7f1bb471469a", + "sha256:68a2dec79deebc5d26d617bfdf6e8aab065a4f34934b22d3b5010df3ba36612c", + "sha256:7a698cb1dac82c35fcf8fe3417a3aaba97de16a01ac914b89a0889d364d2f6be", + "sha256:841df4caa01008bad253bce2a6f7b47f86dc9f08df4b433c404def869f590a15", + "sha256:90452ba79b8788fa380dfb587cca692976ef4e757b194b093d845e8d99f612f2", + "sha256:928258ba5d6f8ae644e764d0f996d61a8777559f72dfeb2eea7e2fe0ad6e782d", + "sha256:af03b32695b24d85a75d40e1ba39ffe7db7ffcb099fe507b39fd41a565f1b157", + "sha256:b640981bf64a3e978a56167594a0e97db71c89a479da8e175d8bb5be5178c003", + "sha256:c5ca78485a255e03c32b513f8c2bc39fedb7f5c5f8535545bdc223a03b24f248", + "sha256:c7f3201ec47d5207841402594f1d7950879ef890c0c495052fa62f58283fde1a", + "sha256:d5ec85080cce7b0513cfd233914eb8b7bbd0633f1d1703aa28d1dd5a72f678ec", + "sha256:d6c391c021ab1f7a82da5d8d0b3cee2f4b2c455ec86c8aebbc84837a631ff309", + "sha256:e3114da6d7f95d2dee7d3f4eec16dacff819740bbab931aff8648cb13c5ff5e7", + "sha256:f983596065a18a2183e7f79ab3fd4c475205b839e02cbc0efbbf9666c4b3083d" + ], + "markers": "python_version >= '3.7'", + "version": "==41.0.7" + }, + "defusedxml": { + "hashes": [ + "sha256:138c7d540a78775182206c7c97fe65b246a2f40b29471e1a2f1b0da76e7a3942", + "sha256:1c812964311154c3bf4aaf3bc1443b31ee13530b7f255eaaa062c0553c76103d" + ], + "markers": "python_version >= '3.6'", + "version": "==0.8.0rc2" + }, + "django": { + "hashes": [ + "sha256:8c8659665bc6e3a44fefe1ab0a291e5a3fb3979f9a8230be29de975e57e8f854", + "sha256:f47a37a90b9bbe2c8ec360235192c7fddfdc832206fcf618bb849b39256affc1" + ], + "index": "pypi", + "version": "==5.0.1" + }, + "django-cors-headers": { + "hashes": [ + "sha256:0b1fd19297e37417fc9f835d39e45c8c642938ddba1acce0c1753d3edef04f36", + "sha256:0bf65ef45e606aff1994d35503e6b677c0b26cafff6506f8fd7187f3be840207" + ], + "index": "pypi", + "version": "==4.3.1" + }, + "django-extra-fields": { + "hashes": [ + "sha256:2334e914b346c0a19a7765bf0ff7895c46cf35d5f40315a68418f44b7ddbb33b" + ], + "index": "pypi", + "version": "==3.0.2" + }, + "django-resized": { + "hashes": [ + "sha256:52d727860f64ef4fdadbe2e74b66231c71c59df4d95949e338fcd320450f77fa", + "sha256:d55a8d4125838486a1e76ffb689f8364f7d579bc7562b04400065602ec2ba7cc" + ], + "index": "pypi", + "version": "==1.0.2" + }, + "django-simple-history": { + "hashes": [ + "sha256:19bd1a87e1e2eba34dfd43eab1fcf2da5752221f343232f2372b2121c7e3b97d", + "sha256:992dcca3cddc0b67b470fc91f77292e2d2a6010d37c9eac3536e9d80e8754032" + ], + "index": "pypi", + "version": "==3.4.0" + }, + "django-templated-mail": { + "hashes": [ + "sha256:8db807effebb42a532622e2d142dfd453dafcd0d7794c4c3332acb90656315f9", + "sha256:f7127e1e31d7cad4e6c4b4801d25814d4b8782627ead76f4a75b3b7650687556" + ], + "version": "==1.1.1" + }, + "django-unfold": { + "hashes": [ + "sha256:38a3a784ffec90ac8e1177ffe88ae1b15080bf9d89493b5ee648623cbe02ce54", + "sha256:eb5edca8d83258e5491458c83ec46f3c5ae1a652740ccb6a6bf55bd6bc86fead" + ], + "index": "pypi", + "version": "==0.18.1" + }, + "djangorestframework": { + "hashes": [ + "sha256:579a333e6256b09489cbe0a067e66abe55c6595d8926be6b99423786334350c8", + "sha256:eb63f58c9f218e1a7d064d17a70751f528ed4e1d35547fdade9aaf4cd103fd08" + ], + "index": "pypi", + "version": "==3.14.0" + }, + "djangorestframework-simplejwt": { + "hashes": [ + "sha256:381bc966aa46913905629d472cd72ad45faa265509764e20ffd440164c88d220", + "sha256:6c4bd37537440bc439564ebf7d6085e74c5411485197073f508ebdfa34bc9fae" + ], + "markers": "python_version >= '3.8'", + "version": "==5.3.1" + }, + "djoser": { + "hashes": [ + "sha256:9deb831a1c8781ceff325699e1407b4e1be8b4588e87071621d88ba31c09349f", + "sha256:efb91ad61e4d5b8d664db029b5947df9d34078289ef2680a1ab665e047144b74" + ], + "index": "pypi", + "version": "==2.2.2" + }, + "dotty-dict": { + "hashes": [ + "sha256:4b016e03b8ae265539757a53eba24b9bfda506fb94fbce0bee843c6f05541a15", + "sha256:5022d234d9922f13aa711b4950372a06a6d64cb6d6db9ba43d0ba133ebfce31f" + ], + "markers": "python_version >= '3.5' and python_version < '4.0'", + "version": "==1.3.1" + }, + "drf-spectacular": { + "extras": [ + "sidecar" + ], + "hashes": [ + "sha256:18d7ae74b2b5d533fd31f1c591ebaa5cce1447e0976ced927401e3163040dea9", + "sha256:6ab2d20674244e8c940c2883f744b43c34fc68c70ea3aefa802f574108c9699b" + ], + "index": "pypi", + "version": "==0.27.0" + }, + "drf-spectacular-sidecar": { + "hashes": [ + "sha256:099ec58b6af6a90e851a9329b12a57aa1ee7daa6cef62fb504f2ed302f10da76", + "sha256:4b9e33b4dcfa43f84e3db2659d31766a018a2b98b02d8856d9cd69580a4911c9" + ], + "version": "==2024.1.1" + }, + "gitdb": { + "hashes": [ + "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4", + "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b" + ], + "markers": "python_version >= '3.7'", + "version": "==4.0.11" + }, + "gitpython": { + "hashes": [ + "sha256:22b126e9ffb671fdd0c129796343a02bf67bf2994b35449ffc9321aa755e18a4", + "sha256:cf14627d5a8049ffbf49915732e5eddbe8134c3bdb9d476e6182b676fc573f8a" + ], + "markers": "python_version >= '3.7'", + "version": "==3.1.40" + }, + "idna": { + "hashes": [ + "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", + "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" + ], + "markers": "python_version >= '3.5'", + "version": "==3.6" + }, + "importlib-resources": { + "hashes": [ + "sha256:3893a00122eafde6894c59914446a512f728a0c1a45f9bb9b63721b6bacf0b4a", + "sha256:e8bf90d8213b486f428c9c39714b920041cb02c184686a3dee24905aaa8105d6" + ], + "markers": "python_version >= '3.8'", + "version": "==6.1.1" + }, + "inflection": { + "hashes": [ + "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417", + "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2" + ], + "markers": "python_version >= '3.5'", + "version": "==0.5.1" + }, + "jinja2": { + "hashes": [ + "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", + "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" + ], + "markers": "python_version >= '3.7'", + "version": "==3.1.2" + }, + "jsonschema": { + "hashes": [ + "sha256:4f614fd46d8d61258610998997743ec5492a648b33cf478c1ddc23ed4598a5fa", + "sha256:ed6231f0429ecf966f5bc8dfef245998220549cbbcf140f913b7464c52c3b6b3" + ], + "markers": "python_version >= '3.8'", + "version": "==4.20.0" + }, + "jsonschema-specifications": { + "hashes": [ + "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc", + "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c" + ], + "markers": "python_version >= '3.8'", + "version": "==2023.12.1" + }, + "markdown-it-py": { + "hashes": [ + "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", + "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb" + ], + "markers": "python_version >= '3.8'", + "version": "==3.0.0" + }, + "markupsafe": { + "hashes": [ + "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e", + "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e", + "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431", + "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686", + "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c", + "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559", + "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc", + "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb", + "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939", + "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c", + "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0", + "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4", + "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9", + "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575", + "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba", + "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d", + "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd", + "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3", + "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00", + "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155", + "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac", + "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52", + "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f", + "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8", + "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b", + "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007", + "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24", + "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea", + "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198", + "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0", + "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee", + "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be", + "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2", + "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1", + "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707", + "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6", + "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c", + "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58", + "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823", + "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779", + "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636", + "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c", + "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad", + "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee", + "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc", + "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2", + "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48", + "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7", + "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e", + "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b", + "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa", + "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5", + "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e", + "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb", + "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9", + "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57", + "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc", + "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc", + "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2", + "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11" + ], + "markers": "python_version >= '3.7'", + "version": "==2.1.3" + }, + "mdurl": { + "hashes": [ + "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", + "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" + ], + "markers": "python_version >= '3.7'", + "version": "==0.1.2" + }, + "oauthlib": { + "hashes": [ + "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca", + "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918" + ], + "markers": "python_version >= '3.6'", + "version": "==3.2.2" + }, + "pillow": { + "hashes": [ + "sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8", + "sha256:0689b5a8c5288bc0504d9fcee48f61a6a586b9b98514d7d29b840143d6734f39", + "sha256:0eae2073305f451d8ecacb5474997c08569fb4eb4ac231ffa4ad7d342fdc25ac", + "sha256:0fb3e7fc88a14eacd303e90481ad983fd5b69c761e9e6ef94c983f91025da869", + "sha256:11fa2e5984b949b0dd6d7a94d967743d87c577ff0b83392f17cb3990d0d2fd6e", + "sha256:127cee571038f252a552760076407f9cff79761c3d436a12af6000cd182a9d04", + "sha256:154e939c5f0053a383de4fd3d3da48d9427a7e985f58af8e94d0b3c9fcfcf4f9", + "sha256:15587643b9e5eb26c48e49a7b33659790d28f190fc514a322d55da2fb5c2950e", + "sha256:170aeb00224ab3dc54230c797f8404507240dd868cf52066f66a41b33169bdbe", + "sha256:1b5e1b74d1bd1b78bc3477528919414874748dd363e6272efd5abf7654e68bef", + "sha256:1da3b2703afd040cf65ec97efea81cfba59cdbed9c11d8efc5ab09df9509fc56", + "sha256:1e23412b5c41e58cec602f1135c57dfcf15482013ce6e5f093a86db69646a5aa", + "sha256:2247178effb34a77c11c0e8ac355c7a741ceca0a732b27bf11e747bbc950722f", + "sha256:257d8788df5ca62c980314053197f4d46eefedf4e6175bc9412f14412ec4ea2f", + "sha256:3031709084b6e7852d00479fd1d310b07d0ba82765f973b543c8af5061cf990e", + "sha256:322209c642aabdd6207517e9739c704dc9f9db943015535783239022002f054a", + "sha256:322bdf3c9b556e9ffb18f93462e5f749d3444ce081290352c6070d014c93feb2", + "sha256:33870dc4653c5017bf4c8873e5488d8f8d5f8935e2f1fb9a2208c47cdd66efd2", + "sha256:35bb52c37f256f662abdfa49d2dfa6ce5d93281d323a9af377a120e89a9eafb5", + "sha256:3c31822339516fb3c82d03f30e22b1d038da87ef27b6a78c9549888f8ceda39a", + "sha256:3eedd52442c0a5ff4f887fab0c1c0bb164d8635b32c894bc1faf4c618dd89df2", + "sha256:3ff074fc97dd4e80543a3e91f69d58889baf2002b6be64347ea8cf5533188213", + "sha256:47c0995fc4e7f79b5cfcab1fc437ff2890b770440f7696a3ba065ee0fd496563", + "sha256:49d9ba1ed0ef3e061088cd1e7538a0759aab559e2e0a80a36f9fd9d8c0c21591", + "sha256:51f1a1bffc50e2e9492e87d8e09a17c5eea8409cda8d3f277eb6edc82813c17c", + "sha256:52a50aa3fb3acb9cf7213573ef55d31d6eca37f5709c69e6858fe3bc04a5c2a2", + "sha256:54f1852cd531aa981bc0965b7d609f5f6cc8ce8c41b1139f6ed6b3c54ab82bfb", + "sha256:609448742444d9290fd687940ac0b57fb35e6fd92bdb65386e08e99af60bf757", + "sha256:69ffdd6120a4737710a9eee73e1d2e37db89b620f702754b8f6e62594471dee0", + "sha256:6fad5ff2f13d69b7e74ce5b4ecd12cc0ec530fcee76356cac6742785ff71c452", + "sha256:7049e301399273a0136ff39b84c3678e314f2158f50f517bc50285fb5ec847ad", + "sha256:70c61d4c475835a19b3a5aa42492409878bbca7438554a1f89d20d58a7c75c01", + "sha256:716d30ed977be8b37d3ef185fecb9e5a1d62d110dfbdcd1e2a122ab46fddb03f", + "sha256:753cd8f2086b2b80180d9b3010dd4ed147efc167c90d3bf593fe2af21265e5a5", + "sha256:773efe0603db30c281521a7c0214cad7836c03b8ccff897beae9b47c0b657d61", + "sha256:7823bdd049099efa16e4246bdf15e5a13dbb18a51b68fa06d6c1d4d8b99a796e", + "sha256:7c8f97e8e7a9009bcacbe3766a36175056c12f9a44e6e6f2d5caad06dcfbf03b", + "sha256:823ef7a27cf86df6597fa0671066c1b596f69eba53efa3d1e1cb8b30f3533068", + "sha256:8373c6c251f7ef8bda6675dd6d2b3a0fcc31edf1201266b5cf608b62a37407f9", + "sha256:83b2021f2ade7d1ed556bc50a399127d7fb245e725aa0113ebd05cfe88aaf588", + "sha256:870ea1ada0899fd0b79643990809323b389d4d1d46c192f97342eeb6ee0b8483", + "sha256:8d12251f02d69d8310b046e82572ed486685c38f02176bd08baf216746eb947f", + "sha256:9c23f307202661071d94b5e384e1e1dc7dfb972a28a2310e4ee16103e66ddb67", + "sha256:9d189550615b4948f45252d7f005e53c2040cea1af5b60d6f79491a6e147eef7", + "sha256:a086c2af425c5f62a65e12fbf385f7c9fcb8f107d0849dba5839461a129cf311", + "sha256:a2b56ba36e05f973d450582fb015594aaa78834fefe8dfb8fcd79b93e64ba4c6", + "sha256:aebb6044806f2e16ecc07b2a2637ee1ef67a11840a66752751714a0d924adf72", + "sha256:b1b3020d90c2d8e1dae29cf3ce54f8094f7938460fb5ce8bc5c01450b01fbaf6", + "sha256:b4b6b1e20608493548b1f32bce8cca185bf0480983890403d3b8753e44077129", + "sha256:b6f491cdf80ae540738859d9766783e3b3c8e5bd37f5dfa0b76abdecc5081f13", + "sha256:b792a349405fbc0163190fde0dc7b3fef3c9268292586cf5645598b48e63dc67", + "sha256:b7c2286c23cd350b80d2fc9d424fc797575fb16f854b831d16fd47ceec078f2c", + "sha256:babf5acfede515f176833ed6028754cbcd0d206f7f614ea3447d67c33be12516", + "sha256:c365fd1703040de1ec284b176d6af5abe21b427cb3a5ff68e0759e1e313a5e7e", + "sha256:c4225f5220f46b2fde568c74fca27ae9771536c2e29d7c04f4fb62c83275ac4e", + "sha256:c570f24be1e468e3f0ce7ef56a89a60f0e05b30a3669a459e419c6eac2c35364", + "sha256:c6dafac9e0f2b3c78df97e79af707cdc5ef8e88208d686a4847bab8266870023", + "sha256:c8de2789052ed501dd829e9cae8d3dcce7acb4777ea4a479c14521c942d395b1", + "sha256:cb28c753fd5eb3dd859b4ee95de66cc62af91bcff5db5f2571d32a520baf1f04", + "sha256:cb4c38abeef13c61d6916f264d4845fab99d7b711be96c326b84df9e3e0ff62d", + "sha256:d1b35bcd6c5543b9cb547dee3150c93008f8dd0f1fef78fc0cd2b141c5baf58a", + "sha256:d8e6aeb9201e655354b3ad049cb77d19813ad4ece0df1249d3c793de3774f8c7", + "sha256:d8ecd059fdaf60c1963c58ceb8997b32e9dc1b911f5da5307aab614f1ce5c2fb", + "sha256:da2b52b37dad6d9ec64e653637a096905b258d2fc2b984c41ae7d08b938a67e4", + "sha256:e87f0b2c78157e12d7686b27d63c070fd65d994e8ddae6f328e0dcf4a0cd007e", + "sha256:edca80cbfb2b68d7b56930b84a0e45ae1694aeba0541f798e908a49d66b837f1", + "sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48", + "sha256:fe4c15f6c9285dc54ce6553a3ce908ed37c8f3825b5a51a15c91442bb955b868" + ], + "index": "pypi", + "version": "==10.2.0" + }, + "psycopg2": { + "hashes": [ + "sha256:121081ea2e76729acfb0673ff33755e8703d45e926e416cb59bae3a86c6a4981", + "sha256:38a8dcc6856f569068b47de286b472b7c473ac7977243593a288ebce0dc89516", + "sha256:426f9f29bde126913a20a96ff8ce7d73fd8a216cfb323b1f04da402d452853c3", + "sha256:5e0d98cade4f0e0304d7d6f25bbfbc5bd186e07b38eac65379309c4ca3193efa", + "sha256:7e2dacf8b009a1c1e843b5213a87f7c544b2b042476ed7755be813eaf4e8347a", + "sha256:a7653d00b732afb6fc597e29c50ad28087dcb4fbfb28e86092277a559ae4e693", + "sha256:ade01303ccf7ae12c356a5e10911c9e1c51136003a9a1d92f7aa9d010fb98372", + "sha256:bac58c024c9922c23550af2a581998624d6e02350f4ae9c5f0bc642c633a2d5e", + "sha256:c92811b2d4c9b6ea0285942b2e7cac98a59e166d59c588fe5cfe1eda58e72d59", + "sha256:d1454bde93fb1e224166811694d600e746430c006fbb031ea06ecc2ea41bf156", + "sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024", + "sha256:de80739447af31525feddeb8effd640782cf5998e1a4e9192ebdf829717e3913", + "sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c" + ], + "index": "pypi", + "version": "==2.9.9" + }, + "pycparser": { + "hashes": [ + "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", + "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206" + ], + "version": "==2.21" + }, + "pydantic": { + "hashes": [ + "sha256:b3ef57c62535b0941697cce638c08900d87fcb67e29cfa99e8a68f747f393f7a", + "sha256:d0caf5954bee831b6bfe7e338c32b9e30c85dfe080c843680783ac2b631673b4" + ], + "markers": "python_version >= '3.7'", + "version": "==2.5.3" + }, + "pydantic-core": { + "hashes": [ + "sha256:00646784f6cd993b1e1c0e7b0fdcbccc375d539db95555477771c27555e3c556", + "sha256:00b1087dabcee0b0ffd104f9f53d7d3eaddfaa314cdd6726143af6bc713aa27e", + "sha256:0348b1dc6b76041516e8a854ff95b21c55f5a411c3297d2ca52f5528e49d8411", + "sha256:036137b5ad0cb0004c75b579445a1efccd072387a36c7f217bb8efd1afbe5245", + "sha256:095b707bb287bfd534044166ab767bec70a9bba3175dcdc3371782175c14e43c", + "sha256:0c08de15d50fa190d577e8591f0329a643eeaed696d7771760295998aca6bc66", + "sha256:1302a54f87b5cd8528e4d6d1bf2133b6aa7c6122ff8e9dc5220fbc1e07bffebd", + "sha256:172de779e2a153d36ee690dbc49c6db568d7b33b18dc56b69a7514aecbcf380d", + "sha256:1b027c86c66b8627eb90e57aee1f526df77dc6d8b354ec498be9a757d513b92b", + "sha256:1ce830e480f6774608dedfd4a90c42aac4a7af0a711f1b52f807130c2e434c06", + "sha256:1fd0c1d395372843fba13a51c28e3bb9d59bd7aebfeb17358ffaaa1e4dbbe948", + "sha256:23598acb8ccaa3d1d875ef3b35cb6376535095e9405d91a3d57a8c7db5d29341", + "sha256:24368e31be2c88bd69340fbfe741b405302993242ccb476c5c3ff48aeee1afe0", + "sha256:26a92ae76f75d1915806b77cf459811e772d8f71fd1e4339c99750f0e7f6324f", + "sha256:27e524624eace5c59af499cd97dc18bb201dc6a7a2da24bfc66ef151c69a5f2a", + "sha256:2b8719037e570639e6b665a4050add43134d80b687288ba3ade18b22bbb29dd2", + "sha256:2c5bcf3414367e29f83fd66f7de64509a8fd2368b1edf4351e862910727d3e51", + "sha256:2dbe357bc4ddda078f79d2a36fc1dd0494a7f2fad83a0a684465b6f24b46fe80", + "sha256:2f5fa187bde8524b1e37ba894db13aadd64faa884657473b03a019f625cee9a8", + "sha256:2f6ffc6701a0eb28648c845f4945a194dc7ab3c651f535b81793251e1185ac3d", + "sha256:314ccc4264ce7d854941231cf71b592e30d8d368a71e50197c905874feacc8a8", + "sha256:36026d8f99c58d7044413e1b819a67ca0e0b8ebe0f25e775e6c3d1fabb3c38fb", + "sha256:36099c69f6b14fc2c49d7996cbf4f87ec4f0e66d1c74aa05228583225a07b590", + "sha256:36fa402dcdc8ea7f1b0ddcf0df4254cc6b2e08f8cd80e7010d4c4ae6e86b2a87", + "sha256:370ffecb5316ed23b667d99ce4debe53ea664b99cc37bfa2af47bc769056d534", + "sha256:3860c62057acd95cc84044e758e47b18dcd8871a328ebc8ccdefd18b0d26a21b", + "sha256:399ac0891c284fa8eb998bcfa323f2234858f5d2efca3950ae58c8f88830f145", + "sha256:3a0b5db001b98e1c649dd55afa928e75aa4087e587b9524a4992316fa23c9fba", + "sha256:3dcf1978be02153c6a31692d4fbcc2a3f1db9da36039ead23173bc256ee3b91b", + "sha256:4241204e4b36ab5ae466ecec5c4c16527a054c69f99bba20f6f75232a6a534e2", + "sha256:438027a975cc213a47c5d70672e0d29776082155cfae540c4e225716586be75e", + "sha256:43e166ad47ba900f2542a80d83f9fc65fe99eb63ceec4debec160ae729824052", + "sha256:478e9e7b360dfec451daafe286998d4a1eeaecf6d69c427b834ae771cad4b622", + "sha256:4ce8299b481bcb68e5c82002b96e411796b844d72b3e92a3fbedfe8e19813eab", + "sha256:4f86f1f318e56f5cbb282fe61eb84767aee743ebe32c7c0834690ebea50c0a6b", + "sha256:55a23dcd98c858c0db44fc5c04fc7ed81c4b4d33c653a7c45ddaebf6563a2f66", + "sha256:599c87d79cab2a6a2a9df4aefe0455e61e7d2aeede2f8577c1b7c0aec643ee8e", + "sha256:5aa90562bc079c6c290f0512b21768967f9968e4cfea84ea4ff5af5d917016e4", + "sha256:64634ccf9d671c6be242a664a33c4acf12882670b09b3f163cd00a24cffbd74e", + "sha256:667aa2eac9cd0700af1ddb38b7b1ef246d8cf94c85637cbb03d7757ca4c3fdec", + "sha256:6a31d98c0d69776c2576dda4b77b8e0c69ad08e8b539c25c7d0ca0dc19a50d6c", + "sha256:6af4b3f52cc65f8a0bc8b1cd9676f8c21ef3e9132f21fed250f6958bd7223bed", + "sha256:6c8edaea3089bf908dd27da8f5d9e395c5b4dc092dbcce9b65e7156099b4b937", + "sha256:71d72ca5eaaa8d38c8df16b7deb1a2da4f650c41b58bb142f3fb75d5ad4a611f", + "sha256:72f9a942d739f09cd42fffe5dc759928217649f070056f03c70df14f5770acf9", + "sha256:747265448cb57a9f37572a488a57d873fd96bf51e5bb7edb52cfb37124516da4", + "sha256:75ec284328b60a4e91010c1acade0c30584f28a1f345bc8f72fe8b9e46ec6a96", + "sha256:78d0768ee59baa3de0f4adac9e3748b4b1fffc52143caebddfd5ea2961595277", + "sha256:78ee52ecc088c61cce32b2d30a826f929e1708f7b9247dc3b921aec367dc1b23", + "sha256:7be719e4d2ae6c314f72844ba9d69e38dff342bc360379f7c8537c48e23034b7", + "sha256:7e1f4744eea1501404b20b0ac059ff7e3f96a97d3e3f48ce27a139e053bb370b", + "sha256:7e90d6cc4aad2cc1f5e16ed56e46cebf4877c62403a311af20459c15da76fd91", + "sha256:7ebe3416785f65c28f4f9441e916bfc8a54179c8dea73c23023f7086fa601c5d", + "sha256:7f41533d7e3cf9520065f610b41ac1c76bc2161415955fbcead4981b22c7611e", + "sha256:7f5025db12fc6de7bc1104d826d5aee1d172f9ba6ca936bf6474c2148ac336c1", + "sha256:86c963186ca5e50d5c8287b1d1c9d3f8f024cbe343d048c5bd282aec2d8641f2", + "sha256:86ce5fcfc3accf3a07a729779d0b86c5d0309a4764c897d86c11089be61da160", + "sha256:8a14c192c1d724c3acbfb3f10a958c55a2638391319ce8078cb36c02283959b9", + "sha256:8b93785eadaef932e4fe9c6e12ba67beb1b3f1e5495631419c784ab87e975670", + "sha256:8ed1af8692bd8d2a29d702f1a2e6065416d76897d726e45a1775b1444f5928a7", + "sha256:92879bce89f91f4b2416eba4429c7b5ca22c45ef4a499c39f0c5c69257522c7c", + "sha256:94fc0e6621e07d1e91c44e016cc0b189b48db053061cc22d6298a611de8071bb", + "sha256:982487f8931067a32e72d40ab6b47b1628a9c5d344be7f1a4e668fb462d2da42", + "sha256:9862bf828112e19685b76ca499b379338fd4c5c269d897e218b2ae8fcb80139d", + "sha256:99b14dbea2fdb563d8b5a57c9badfcd72083f6006caf8e126b491519c7d64ca8", + "sha256:9c6a5c79b28003543db3ba67d1df336f253a87d3112dac3a51b94f7d48e4c0e1", + "sha256:a19b794f8fe6569472ff77602437ec4430f9b2b9ec7a1105cfd2232f9ba355e6", + "sha256:a306cdd2ad3a7d795d8e617a58c3a2ed0f76c8496fb7621b6cd514eb1532cae8", + "sha256:a3dde6cac75e0b0902778978d3b1646ca9f438654395a362cb21d9ad34b24acf", + "sha256:a874f21f87c485310944b2b2734cd6d318765bcbb7515eead33af9641816506e", + "sha256:a983cca5ed1dd9a35e9e42ebf9f278d344603bfcb174ff99a5815f953925140a", + "sha256:aca48506a9c20f68ee61c87f2008f81f8ee99f8d7f0104bff3c47e2d148f89d9", + "sha256:b2602177668f89b38b9f84b7b3435d0a72511ddef45dc14446811759b82235a1", + "sha256:b3e5fe4538001bb82e2295b8d2a39356a84694c97cb73a566dc36328b9f83b40", + "sha256:b6ca36c12a5120bad343eef193cc0122928c5c7466121da7c20f41160ba00ba2", + "sha256:b89f4477d915ea43b4ceea6756f63f0288941b6443a2b28c69004fe07fde0d0d", + "sha256:b9a9d92f10772d2a181b5ca339dee066ab7d1c9a34ae2421b2a52556e719756f", + "sha256:c99462ffc538717b3e60151dfaf91125f637e801f5ab008f81c402f1dff0cd0f", + "sha256:cb92f9061657287eded380d7dc455bbf115430b3aa4741bdc662d02977e7d0af", + "sha256:cdee837710ef6b56ebd20245b83799fce40b265b3b406e51e8ccc5b85b9099b7", + "sha256:cf10b7d58ae4a1f07fccbf4a0a956d705356fea05fb4c70608bb6fa81d103cda", + "sha256:d15687d7d7f40333bd8266f3814c591c2e2cd263fa2116e314f60d82086e353a", + "sha256:d5c28525c19f5bb1e09511669bb57353d22b94cf8b65f3a8d141c389a55dec95", + "sha256:d5f916acf8afbcab6bacbb376ba7dc61f845367901ecd5e328fc4d4aef2fcab0", + "sha256:dab03ed811ed1c71d700ed08bde8431cf429bbe59e423394f0f4055f1ca0ea60", + "sha256:db453f2da3f59a348f514cfbfeb042393b68720787bbef2b4c6068ea362c8149", + "sha256:de2a0645a923ba57c5527497daf8ec5df69c6eadf869e9cd46e86349146e5975", + "sha256:dea7fcd62915fb150cdc373212141a30037e11b761fbced340e9db3379b892d4", + "sha256:dfcbebdb3c4b6f739a91769aea5ed615023f3c88cb70df812849aef634c25fbe", + "sha256:dfcebb950aa7e667ec226a442722134539e77c575f6cfaa423f24371bb8d2e94", + "sha256:e0641b506486f0b4cd1500a2a65740243e8670a2549bb02bc4556a83af84ae03", + "sha256:e33b0834f1cf779aa839975f9d8755a7c2420510c0fa1e9fa0497de77cd35d2c", + "sha256:e4ace1e220b078c8e48e82c081e35002038657e4b37d403ce940fa679e57113b", + "sha256:e4cf2d5829f6963a5483ec01578ee76d329eb5caf330ecd05b3edd697e7d768a", + "sha256:e574de99d735b3fc8364cba9912c2bec2da78775eba95cbb225ef7dda6acea24", + "sha256:e646c0e282e960345314f42f2cea5e0b5f56938c093541ea6dbf11aec2862391", + "sha256:e8a5ac97ea521d7bde7621d86c30e86b798cdecd985723c4ed737a2aa9e77d0c", + "sha256:eedf97be7bc3dbc8addcef4142f4b4164066df0c6f36397ae4aaed3eb187d8ab", + "sha256:ef633add81832f4b56d3b4c9408b43d530dfca29e68fb1b797dcb861a2c734cd", + "sha256:f27207e8ca3e5e021e2402ba942e5b4c629718e665c81b8b306f3c8b1ddbb786", + "sha256:f85f3843bdb1fe80e8c206fe6eed7a1caeae897e496542cee499c374a85c6e08", + "sha256:f8e81e4b55930e5ffab4a68db1af431629cf2e4066dbdbfef65348b8ab804ea8", + "sha256:f96ae96a060a8072ceff4cfde89d261837b4294a4f28b84a28765470d502ccc6", + "sha256:fd9e98b408384989ea4ab60206b8e100d8687da18b5c813c11e92fd8212a98e0", + "sha256:ffff855100bc066ff2cd3aa4a60bc9534661816b110f0243e59503ec2df38421" + ], + "markers": "python_version >= '3.7'", + "version": "==2.14.6" + }, + "pygments": { + "hashes": [ + "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c", + "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367" + ], + "markers": "python_version >= '3.7'", + "version": "==2.17.2" + }, + "pyjwt": { + "hashes": [ + "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de", + "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320" + ], + "markers": "python_version >= '3.7'", + "version": "==2.8.0" + }, + "python-dotenv": { + "hashes": [ + "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba", + "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a" + ], + "index": "pypi", + "version": "==1.0.0" + }, + "python-gitlab": { + "hashes": [ + "sha256:cc1dc49c562c02ffbad3656e668234c45ea6210688ade59865b284313f45000d", + "sha256:eb31d1f2bfd8653f74996f9d0bf84ce7afb0843f9122a257c9a93b0e027d1df0" + ], + "markers": "python_full_version >= '3.8.0'", + "version": "==4.3.0" + }, + "python-semantic-release": { + "hashes": [ + "sha256:6bbd11b1e8ac70e0946ed6d257094c851b2507edfbc393eef6093d0ed1dbe0b4", + "sha256:a016b1cf43a5f3667ce2cfddd8e30b6210a2d52b0e2f6b487aae1164f2540eaa" + ], + "markers": "python_version >= '3.7'", + "version": "==8.7.0" + }, + "python3-openid": { + "hashes": [ + "sha256:33fbf6928f401e0b790151ed2b5290b02545e8775f982485205a066f874aaeaf", + "sha256:6626f771e0417486701e0b4daff762e7212e820ca5b29fcc0d05f6f8736dfa6b" + ], + "version": "==3.2.0" + }, + "pytz": { + "hashes": [ + "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b", + "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7" + ], + "version": "==2023.3.post1" + }, + "pyyaml": { + "hashes": [ + "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", + "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", + "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", + "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", + "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", + "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", + "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595", + "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", + "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", + "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", + "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", + "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", + "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", + "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", + "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", + "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", + "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", + "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6", + "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", + "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", + "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", + "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", + "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", + "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", + "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", + "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", + "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", + "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", + "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", + "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", + "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", + "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", + "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0", + "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515", + "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c", + "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c", + "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924", + "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", + "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", + "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", + "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", + "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", + "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", + "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", + "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", + "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", + "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", + "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585", + "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", + "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f" + ], + "markers": "python_version >= '3.6'", + "version": "==6.0.1" + }, + "referencing": { + "hashes": [ + "sha256:3c57da0513e9563eb7e203ebe9bb3a1b509b042016433bd1e45a2853466c3dd3", + "sha256:7e4dc12271d8e15612bfe35792f5ea1c40970dadf8624602e33db2758f7ee554" + ], + "markers": "python_version >= '3.8'", + "version": "==0.32.1" + }, + "requests": { + "hashes": [ + "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", + "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" + ], + "markers": "python_version >= '3.7'", + "version": "==2.31.0" + }, + "requests-oauthlib": { + "hashes": [ + "sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5", + "sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.3.1" + }, + "requests-toolbelt": { + "hashes": [ + "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", + "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.0.0" + }, + "rich": { + "hashes": [ + "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa", + "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235" + ], + "markers": "python_full_version >= '3.7.0'", + "version": "==13.7.0" + }, + "rpds-py": { + "hashes": [ + "sha256:0474df4ade9a3b4af96c3d36eb81856cb9462e4c6657d4caecfd840d2a13f3c9", + "sha256:071980663c273bf3d388fe5c794c547e6f35ba3335477072c713a3176bf14a60", + "sha256:07aab64e2808c3ebac2a44f67e9dc0543812b715126dfd6fe4264df527556cb6", + "sha256:088396c7c70e59872f67462fcac3ecbded5233385797021976a09ebd55961dfe", + "sha256:162d7cd9cd311c1b0ff1c55a024b8f38bd8aad1876b648821da08adc40e95734", + "sha256:19f00f57fdd38db4bb5ad09f9ead1b535332dbf624200e9029a45f1f35527ebb", + "sha256:1bdbc5fcb04a7309074de6b67fa9bc4b418ab3fc435fec1f2779a0eced688d04", + "sha256:1be2f033df1b8be8c3167ba3c29d5dca425592ee31e35eac52050623afba5772", + "sha256:24f7a2eb3866a9e91f4599851e0c8d39878a470044875c49bd528d2b9b88361c", + "sha256:290a81cfbe4673285cdf140ec5cd1658ffbf63ab359f2b352ebe172e7cfa5bf0", + "sha256:2946b120718eba9af2b4dd103affc1164a87b9e9ebff8c3e4c05d7b7a7e274e2", + "sha256:2bd82db36cd70b3628c0c57d81d2438e8dd4b7b32a6a9f25f24ab0e657cb6c4e", + "sha256:2ddef620e70eaffebed5932ce754d539c0930f676aae6212f8e16cd9743dd365", + "sha256:2e53b9b25cac9065328901713a7e9e3b12e4f57ef4280b370fbbf6fef2052eef", + "sha256:302bd4983bbd47063e452c38be66153760112f6d3635c7eeefc094299fa400a9", + "sha256:349cb40897fd529ca15317c22c0eab67f5ac5178b5bd2c6adc86172045210acc", + "sha256:358dafc89ce3894c7f486c615ba914609f38277ef67f566abc4c854d23b997fa", + "sha256:35953f4f2b3216421af86fd236b7c0c65935936a94ea83ddbd4904ba60757773", + "sha256:35ae5ece284cf36464eb160880018cf6088a9ac5ddc72292a6092b6ef3f4da53", + "sha256:3b811d182ad17ea294f2ec63c0621e7be92a1141e1012383461872cead87468f", + "sha256:3da5a4c56953bdbf6d04447c3410309616c54433146ccdb4a277b9cb499bc10e", + "sha256:3dc6a7620ba7639a3db6213da61312cb4aa9ac0ca6e00dc1cbbdc21c2aa6eb57", + "sha256:3f91df8e6dbb7360e176d1affd5fb0246d2b88d16aa5ebc7db94fd66b68b61da", + "sha256:4022b9dc620e14f30201a8a73898a873c8e910cb642bcd2f3411123bc527f6ac", + "sha256:413b9c17388bbd0d87a329d8e30c1a4c6e44e2bb25457f43725a8e6fe4161e9e", + "sha256:43d4dd5fb16eb3825742bad8339d454054261ab59fed2fbac84e1d84d5aae7ba", + "sha256:44627b6ca7308680a70766454db5249105fa6344853af6762eaad4158a2feebe", + "sha256:44a54e99a2b9693a37ebf245937fd6e9228b4cbd64b9cc961e1f3391ec6c7391", + "sha256:47713dc4fce213f5c74ca8a1f6a59b622fc1b90868deb8e8e4d993e421b4b39d", + "sha256:495a14b72bbe217f2695dcd9b5ab14d4f8066a00f5d209ed94f0aca307f85f6e", + "sha256:4c46ad6356e1561f2a54f08367d1d2e70a0a1bb2db2282d2c1972c1d38eafc3b", + "sha256:4d6a9f052e72d493efd92a77f861e45bab2f6be63e37fa8ecf0c6fd1a58fedb0", + "sha256:509b617ac787cd1149600e731db9274ebbef094503ca25158e6f23edaba1ca8f", + "sha256:5552f328eaef1a75ff129d4d0c437bf44e43f9436d3996e8eab623ea0f5fcf73", + "sha256:5a80e2f83391ad0808b4646732af2a7b67550b98f0cae056cb3b40622a83dbb3", + "sha256:5cf6af100ffb5c195beec11ffaa8cf8523057f123afa2944e6571d54da84cdc9", + "sha256:5e6caa3809e50690bd92fa490f5c38caa86082c8c3315aa438bce43786d5e90d", + "sha256:5ef00873303d678aaf8b0627e111fd434925ca01c657dbb2641410f1cdaef261", + "sha256:69ac7ea9897ec201ce68b48582f3eb34a3f9924488a5432a93f177bf76a82a7e", + "sha256:6a61226465bda9283686db8f17d02569a98e4b13c637be5a26d44aa1f1e361c2", + "sha256:6d904c5693e08bad240f16d79305edba78276be87061c872a4a15e2c301fa2c0", + "sha256:6dace7b26a13353e24613417ce2239491b40a6ad44e5776a18eaff7733488b44", + "sha256:6df15846ee3fb2e6397fe25d7ca6624af9f89587f3f259d177b556fed6bebe2c", + "sha256:703d95c75a72e902544fda08e965885525e297578317989fd15a6ce58414b41d", + "sha256:726ac36e8a3bb8daef2fd482534cabc5e17334052447008405daca7ca04a3108", + "sha256:781ef8bfc091b19960fc0142a23aedadafa826bc32b433fdfe6fd7f964d7ef44", + "sha256:80443fe2f7b3ea3934c5d75fb0e04a5dbb4a8e943e5ff2de0dec059202b70a8b", + "sha256:83640a5d7cd3bff694747d50436b8b541b5b9b9782b0c8c1688931d6ee1a1f2d", + "sha256:84c5a4d1f9dd7e2d2c44097fb09fffe728629bad31eb56caf97719e55575aa82", + "sha256:882ce6e25e585949c3d9f9abd29202367175e0aab3aba0c58c9abbb37d4982ff", + "sha256:888a97002e986eca10d8546e3c8b97da1d47ad8b69726dcfeb3e56348ebb28a3", + "sha256:8aad80645a011abae487d356e0ceb359f4938dfb6f7bcc410027ed7ae4f7bb8b", + "sha256:8cb6fe8ecdfffa0e711a75c931fb39f4ba382b4b3ccedeca43f18693864fe850", + "sha256:8d6b6937ae9eac6d6c0ca3c42774d89fa311f55adff3970fb364b34abde6ed3d", + "sha256:90123853fc8b1747f80b0d354be3d122b4365a93e50fc3aacc9fb4c2488845d6", + "sha256:96f957d6ab25a78b9e7fc9749d754b98eac825a112b4e666525ce89afcbd9ed5", + "sha256:981d135c7cdaf6cd8eadae1c950de43b976de8f09d8e800feed307140d3d6d00", + "sha256:9b32f742ce5b57201305f19c2ef7a184b52f6f9ba6871cc042c2a61f0d6b49b8", + "sha256:9f0350ef2fba5f34eb0c9000ea328e51b9572b403d2f7f3b19f24085f6f598e8", + "sha256:a297a4d08cc67c7466c873c78039d87840fb50d05473db0ec1b7b03d179bf322", + "sha256:a3d7e2ea25d3517c6d7e5a1cc3702cffa6bd18d9ef8d08d9af6717fc1c700eed", + "sha256:a4b682c5775d6a3d21e314c10124599976809455ee67020e8e72df1769b87bc3", + "sha256:a4ebb8b20bd09c5ce7884c8f0388801100f5e75e7f733b1b6613c713371feefc", + "sha256:a61f659665a39a4d17d699ab3593d7116d66e1e2e3f03ef3fb8f484e91908808", + "sha256:a9880b4656efe36ccad41edc66789e191e5ee19a1ea8811e0aed6f69851a82f4", + "sha256:ac08472f41ea77cd6a5dae36ae7d4ed3951d6602833af87532b556c1b4601d63", + "sha256:adc0c3d6fc6ae35fee3e4917628983f6ce630d513cbaad575b4517d47e81b4bb", + "sha256:af27423662f32d7501a00c5e7342f7dbd1e4a718aea7a239781357d15d437133", + "sha256:b2e75e17bd0bb66ee34a707da677e47c14ee51ccef78ed6a263a4cc965a072a1", + "sha256:b634c5ec0103c5cbebc24ebac4872b045cccb9456fc59efdcf6fe39775365bd2", + "sha256:b6f5549d6ed1da9bfe3631ca9483ae906f21410be2445b73443fa9f017601c6f", + "sha256:bd4b677d929cf1f6bac07ad76e0f2d5de367e6373351c01a9c0a39f6b21b4a8b", + "sha256:bf721ede3eb7b829e4a9b8142bd55db0bdc82902720548a703f7e601ee13bdc3", + "sha256:c647ca87fc0ebe808a41de912e9a1bfef9acb85257e5d63691364ac16b81c1f0", + "sha256:ca57468da2d9a660bcf8961637c85f2fbb2aa64d9bc3f9484e30c3f9f67b1dd7", + "sha256:cad0f59ee3dc35526039f4bc23642d52d5f6616b5f687d846bfc6d0d6d486db0", + "sha256:cc97f0640e91d7776530f06e6836c546c1c752a52de158720c4224c9e8053cad", + "sha256:ccd4e400309e1f34a5095bf9249d371f0fd60f8a3a5c4a791cad7b99ce1fd38d", + "sha256:cffa76b385dfe1e38527662a302b19ffb0e7f5cf7dd5e89186d2c94a22dd9d0c", + "sha256:d0dd7ed2f16df2e129496e7fbe59a34bc2d7fc8db443a606644d069eb69cbd45", + "sha256:d452817e0d9c749c431a1121d56a777bd7099b720b3d1c820f1725cb40928f58", + "sha256:d8dda2a806dfa4a9b795950c4f5cc56d6d6159f7d68080aedaff3bdc9b5032f5", + "sha256:dcbe1f8dd179e4d69b70b1f1d9bb6fd1e7e1bdc9c9aad345cdeb332e29d40748", + "sha256:e0441fb4fdd39a230477b2ca9be90868af64425bfe7b122b57e61e45737a653b", + "sha256:e04e56b4ca7a770593633556e8e9e46579d66ec2ada846b401252a2bdcf70a6d", + "sha256:e061de3b745fe611e23cd7318aec2c8b0e4153939c25c9202a5811ca911fd733", + "sha256:e93ec1b300acf89730cf27975ef574396bc04edecc358e9bd116fb387a123239", + "sha256:e9e557db6a177470316c82f023e5d571811c9a4422b5ea084c85da9aa3c035fc", + "sha256:eab36eae3f3e8e24b05748ec9acc66286662f5d25c52ad70cadab544e034536b", + "sha256:ec23fcad480e77ede06cf4127a25fc440f7489922e17fc058f426b5256ee0edb", + "sha256:ec2e1cf025b2c0f48ec17ff3e642661da7ee332d326f2e6619366ce8e221f018", + "sha256:ed99b4f7179d2111702020fd7d156e88acd533f5a7d3971353e568b6051d5c97", + "sha256:ee94cb58c0ba2c62ee108c2b7c9131b2c66a29e82746e8fa3aa1a1effbd3dcf1", + "sha256:f19afcfc0dd0dca35694df441e9b0f95bc231b512f51bded3c3d8ca32153ec19", + "sha256:f1b9d9260e06ea017feb7172976ab261e011c1dc2f8883c7c274f6b2aabfe01a", + "sha256:f28ac0e8e7242d140f99402a903a2c596ab71550272ae9247ad78f9a932b5698", + "sha256:f42e25c016927e2a6b1ce748112c3ab134261fc2ddc867e92d02006103e1b1b7", + "sha256:f4bd4578e44f26997e9e56c96dedc5f1af43cc9d16c4daa29c771a00b2a26851", + "sha256:f811771019f063bbd0aa7bb72c8a934bc13ebacb4672d712fc1639cfd314cccc" + ], + "markers": "python_version >= '3.8'", + "version": "==0.16.2" + }, + "shellingham": { + "hashes": [ + "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", + "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de" + ], + "markers": "python_version >= '3.7'", + "version": "==1.5.4" + }, + "smmap": { + "hashes": [ + "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62", + "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da" + ], + "markers": "python_version >= '3.7'", + "version": "==5.0.1" + }, + "social-auth-app-django": { + "hashes": [ + "sha256:09ac02a063cb313eed5e9ef2f9ac4477c8bf5bbd685925ff3aba43f9072f1bbb", + "sha256:28c65b2e2092f30cdb3cf912eeaa6988b49fdf4001b29bd89e683673d700a38e" + ], + "markers": "python_version >= '3.8'", + "version": "==5.4.0" + }, + "social-auth-core": { + "hashes": [ + "sha256:307a4ba64d4f3ec86e4389163eac1d8b8656ffe5ab2e964aeff043ab00b3a662", + "sha256:54d0c598bf6ea0ec12bbcf78bee035c7cd604b5d781d80b7997e9e033c3ac05d" + ], + "markers": "python_version >= '3.8'", + "version": "==4.5.1" + }, + "sqlparse": { + "hashes": [ + "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3", + "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c" + ], + "markers": "python_version >= '3.5'", + "version": "==0.4.4" + }, + "tomlkit": { + "hashes": [ + "sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4", + "sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba" + ], + "markers": "python_version >= '3.7'", + "version": "==0.12.3" + }, + "typing-extensions": { + "hashes": [ + "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", + "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + ], + "markers": "python_version >= '3.8'", + "version": "==4.9.0" + }, + "tzdata": { + "hashes": [ + "sha256:aa3ace4329eeacda5b7beb7ea08ece826c28d761cda36e747cfbf97996d39bf3", + "sha256:dd54c94f294765522c77399649b4fefd95522479a664a0cec87f41bebc6148c9" + ], + "markers": "sys_platform == 'win32'", + "version": "==2023.4" + }, + "uritemplate": { + "hashes": [ + "sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0", + "sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e" + ], + "markers": "python_version >= '3.6'", + "version": "==4.1.1" + }, + "urllib3": { + "hashes": [ + "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3", + "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54" + ], + "markers": "python_version >= '3.8'", + "version": "==2.1.0" + }, + "whitenoise": { + "hashes": [ + "sha256:8998f7370973447fac1e8ef6e8ded2c5209a7b1f67c1012866dbcd09681c3251", + "sha256:b1f9db9bf67dc183484d760b99f4080185633136a273a03f6436034a41064146" + ], + "index": "pypi", + "version": "==6.6.0" + } + }, + "develop": {} +} diff --git a/backend/.env.sample b/backend/.env.sample new file mode 100644 index 0000000..9a5e266 --- /dev/null +++ b/backend/.env.sample @@ -0,0 +1,21 @@ +# Django +SECRET_KEY = "" + +# Superuser Credentials +DJANGO_ADMIN_USERNAME = "" +DJANGO_ADMIN_EMAIL = "" +DJANGO_ADMIN_PASSWORD = "" + +# Production Email Credentials +PROD_EMAIL_HOST = "" +PROD_EMAIL_HOST_USER = "" +PROD_EMAIL_HOST_PASSWORD = "" +PROD_EMAIL_PORT = "" +PROD_EMAIL_TLS = "" + + +# Dev Email Credentials +DEV_EMAIL_HOST = "" +DEV_EMAIL_HOST_USER = "" +DEV_EMAIL_HOST_PASSWORD = "" +DEV_EMAIL_PORT = "" diff --git a/backend/accounts/__init__.py b/backend/accounts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/accounts/admin.py b/backend/accounts/admin.py new file mode 100644 index 0000000..fcc6fd2 --- /dev/null +++ b/backend/accounts/admin.py @@ -0,0 +1,16 @@ +from django import forms +from django.contrib import admin +from django.contrib.auth.admin import UserAdmin +from .models import CustomUser + + +class CustomUserAdmin(UserAdmin): + model = CustomUser + list_display = ('id',) + UserAdmin.list_display + # Editable fields per instance + fieldsets = UserAdmin.fieldsets + ( + (None, {'fields': ('avatar',)}), + ) + + +admin.site.register(CustomUser, CustomUserAdmin) diff --git a/backend/accounts/apps.py b/backend/accounts/apps.py new file mode 100644 index 0000000..3e3c765 --- /dev/null +++ b/backend/accounts/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class AccountsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'accounts' diff --git a/backend/accounts/migrations/0001_initial.py b/backend/accounts/migrations/0001_initial.py new file mode 100644 index 0000000..cc7cdcb --- /dev/null +++ b/backend/accounts/migrations/0001_initial.py @@ -0,0 +1,45 @@ +# Generated by Django 5.0.1 on 2024-01-06 04:09 + +import django.contrib.auth.models +import django.contrib.auth.validators +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='CustomUser', + 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')), + ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), + ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), + ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), + ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), + ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), + ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), + ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), + ('avatar', models.ImageField(null=True, upload_to='avatars/')), + ('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/backend/accounts/migrations/__init__.py b/backend/accounts/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/accounts/models.py b/backend/accounts/models.py new file mode 100644 index 0000000..2e2d03b --- /dev/null +++ b/backend/accounts/models.py @@ -0,0 +1,87 @@ +from django.db import models +from django.contrib.auth.models import AbstractUser +from django.urls import reverse +from django.db.models.signals import post_migrate +from django.dispatch import receiver +from django_resized import ResizedImageField +import os + + +class CustomUser(AbstractUser): + # first_name inherited from base user class + # last_name inherited from base user class + # email inherited from base user class + # username inherited from base user class + # password inherited from base user class + # is_admin inherited from base user class + + avatar = models.ImageField( + null=True, upload_to='avatars/') + + def avatar_url(self): + # Assuming your media root is set to 'media/' + return f'/api/v1/media/avatars/{self.avatar.name}' + + @property + def full_name(self): + return f"{self.first_name} {self.last_name}" + + @property + def admin_url(self): + return reverse('admin:users_customuser_change', args=(self.pk,)) + + def get_prep_value(self, value): + # Get the original filename without the random string + original_filename = self.avatar.field.storage.name(self.avatar.path) + return original_filename + pass + + +@receiver(post_migrate) +def create_superuser(sender, **kwargs): + if sender.name == 'accounts': + # Add test users here if needed + # They will automatically be created after migrating the db + users = [ + # Superadmin Account + { + 'username': os.getenv('DJANGO_ADMIN_USERNAME'), + 'email': os.getenv('DJANGO_ADMIN_EMAIL'), + 'password': os.getenv('DJANGO_ADMIN_PASSWORD'), + 'is_staff': True, + 'is_superuser': True, + 'first_name': 'Super', + 'last_name': 'Admin' + }, + # Debug User + { + 'username': 'debug-user', + 'email': os.getenv('DJANGO_ADMIN_EMAIL'), + 'password': os.getenv('DJANGO_ADMIN_PASSWORD'), + 'is_staff': False, + 'is_superuser': False, + 'first_name': "Test", + 'last_name': "User" + }, + ] + + for user in users: + if not CustomUser.objects.filter(username=user['username']).exists(): + if (user['is_superuser']): + USER = CustomUser.objects.create_superuser( + username=user['username'], + password=user['password'], + email=user['email'], + ) + print('Created Superuser:', user['username']) + else: + USER = CustomUser.objects.create_user( + username=user['username'], + password=user['password'], + email=user['email'], + ) + print('Created User:', user['username']) + USER.first_name = user['first_name'] + USER.last_name = user['last_name'] + USER.is_active = True + USER.save() diff --git a/backend/accounts/serializers.py b/backend/accounts/serializers.py new file mode 100644 index 0000000..d6f828f --- /dev/null +++ b/backend/accounts/serializers.py @@ -0,0 +1,53 @@ +from djoser.serializers import UserCreateSerializer as BaseUserRegistrationSerializer +from djoser.serializers import UserSerializer as BaseUserSerializer +from django.core import exceptions as django_exceptions +from rest_framework import serializers +from accounts.models import CustomUser +from rest_framework.settings import api_settings +from django.contrib.auth.password_validation import validate_password +from django.utils.encoding import smart_str +from drf_spectacular.utils import extend_schema_field +from drf_spectacular.types import OpenApiTypes +from drf_extra_fields.fields import Base64ImageField + +# There can be multiple subject instances with the same name, only differing in course, year level, and semester. We filter them here + + +class CustomUserSerializer(BaseUserSerializer): + avatar = Base64ImageField() + + class Meta(BaseUserSerializer.Meta): + model = CustomUser + fields = ('id', 'username', 'email', 'avatar', 'first_name', + 'last_name') + + +class UserRegistrationSerializer(serializers.ModelSerializer): + email = serializers.EmailField(required=True) + password = serializers.CharField( + write_only=True, style={'input_type': 'password', 'placeholder': 'Password'}) + + class Meta: + model = CustomUser # Use your custom user model here + fields = ('username', 'email', 'password', 'avatar', + 'first_name', 'last_name') + + def validate(self, attrs): + user = self.Meta.model(**attrs) + password = attrs.get("password") + try: + validate_password(password, user) + except django_exceptions.ValidationError as e: + serializer_error = serializers.as_serializer_error(e) + raise serializers.ValidationError( + {"password": serializer_error[api_settings.NON_FIELD_ERRORS_KEY]} + ) + + return super().validate(attrs) + + def create(self, validated_data): + user = self.Meta.model(**validated_data) + user.set_password(validated_data['password']) + user.save() + + return user diff --git a/backend/accounts/urls.py b/backend/accounts/urls.py new file mode 100644 index 0000000..22c121e --- /dev/null +++ b/backend/accounts/urls.py @@ -0,0 +1,7 @@ +from django.contrib import admin +from django.urls import path, include + +urlpatterns = [ + path('', include('djoser.urls')), + path('', include('djoser.urls.jwt')), +] diff --git a/backend/accounts/views.py b/backend/accounts/views.py new file mode 100644 index 0000000..3a2ebcf --- /dev/null +++ b/backend/accounts/views.py @@ -0,0 +1,5 @@ +from rest_framework.permissions import IsAuthenticated +from rest_framework import generics +from accounts.serializers import CustomUserSerializer +from rest_framework.response import Response +from accounts.models import CustomUser diff --git a/backend/api/__init__.py b/backend/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/api/urls.py b/backend/api/urls.py new file mode 100644 index 0000000..b92de4d --- /dev/null +++ b/backend/api/urls.py @@ -0,0 +1,14 @@ +from django.urls import path, include +from config import settings +urlpatterns = [ + path('accounts/', include('accounts.urls')), + +] +if settings.DEBUG: + from django.contrib.staticfiles.urls import staticfiles_urlpatterns + from django.conf.urls.static import static + + # Media files + urlpatterns += staticfiles_urlpatterns() + urlpatterns += static( + settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/backend/config/__init__.py b/backend/config/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/config/asgi.py b/backend/config/asgi.py new file mode 100644 index 0000000..80d4e77 --- /dev/null +++ b/backend/config/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for equipment_tracker project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') + +application = get_asgi_application() diff --git a/backend/config/settings.py b/backend/config/settings.py new file mode 100644 index 0000000..61487df --- /dev/null +++ b/backend/config/settings.py @@ -0,0 +1,227 @@ +""" +Django settings for test backend project. + +Generated by 'django-admin startproject' using Django 4.2.6. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/4.2/ref/settings/ +""" + +from datetime import timedelta +from pathlib import Path +from dotenv import load_dotenv # Python dotenv +import os + +load_dotenv() # loads the configs from .env + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = str(os.getenv('SECRET_KEY')) + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = ['*'] +CSRF_TRUSTED_ORIGINS = ["https://testing.keannu1.duckdns.org"] + +# Email credentials +EMAIL_HOST = '' +EMAIL_HOST_USER = '' +EMAIL_HOST_PASSWORD = '' +EMAIL_PORT = '' +EMAIL_USE_TLS = False + +if (DEBUG == True): + EMAIL_HOST = str(os.getenv('DEV_EMAIL_HOST')) + EMAIL_HOST_USER = str(os.getenv('DEV_EMAIL_HOST_USER')) + EMAIL_HOST_PASSWORD = str(os.getenv('DEV_EMAIL_HOST_PASSWORD')) + EMAIL_PORT = str(os.getenv('DEV_EMAIL_PORT')) +else: + EMAIL_HOST = str(os.getenv('PROD_EMAIL_HOST')) + EMAIL_HOST_USER = str(os.getenv('PROD_EMAIL_HOST_USER')) + EMAIL_HOST_PASSWORD = str(os.getenv('PROD_EMAIL_HOST_PASSWORD')) + EMAIL_PORT = str(os.getenv('PROD_EMAIL_PORT')) + EMAIL_USE_TLS = str(os.getenv('PROD_EMAIL_TLS')) + +# Application definition + +INSTALLED_APPS = [ + 'unfold', + 'unfold.contrib.simple_history', + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'rest_framework', + 'rest_framework_simplejwt', + 'simple_history', + 'djoser', + 'corsheaders', + 'drf_spectacular', + 'drf_spectacular_sidecar', + 'accounts', +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + "whitenoise.middleware.WhiteNoiseMiddleware", + 'django.contrib.sessions.middleware.SessionMiddleware', + "corsheaders.middleware.CorsMiddleware", + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.2/howto/static-files/ + +STATIC_URL = 'static/' +STATIC_ROOT = os.path.join(BASE_DIR, 'static') +STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage" +MEDIA_URL = 'api/v1/media/' +MEDIA_ROOT = os.path.join(BASE_DIR, 'media') + +ROOT_URLCONF = 'config.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +REST_FRAMEWORK = { + 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'rest_framework_simplejwt.authentication.JWTAuthentication', + ), + 'DEFAULT_THROTTLE_CLASSES': [ + + 'rest_framework.throttling.AnonRateThrottle', + + 'rest_framework.throttling.UserRateThrottle' + + ], + + 'DEFAULT_THROTTLE_RATES': { + + 'anon': '360/min', + + 'user': '1440/min' + + }, + 'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema', +} + +# DRF-Spectacular +SPECTACULAR_SETTINGS = { + 'TITLE': 'Test Backend', + 'DESCRIPTION': 'A Project by Keannu Bernasol', + 'VERSION': '1.0.0', + 'SERVE_INCLUDE_SCHEMA': False, + 'SWAGGER_UI_DIST': 'SIDECAR', + 'SWAGGER_UI_FAVICON_HREF': 'SIDECAR', + 'REDOC_DIST': 'SIDECAR', + # OTHER SETTINGS +} + +WSGI_APPLICATION = 'config.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/4.2/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', + } +} + +AUTH_USER_MODEL = 'accounts.CustomUser' + +DJOSER = { + 'SEND_ACTIVATION_EMAIL': True, + 'SEND_CONFIRMATION_EMAIL': True, + 'PASSWORD_RESET_CONFIRM_URL': 'reset_password_confirm/{uid}/{token}', + 'ACTIVATION_URL': 'activation/{uid}/{token}', + 'USER_AUTHENTICATION_RULES': ['djoser.authentication.TokenAuthenticationRule'], + 'SERIALIZERS': { + 'user': 'accounts.serializers.CustomUserSerializer', + 'current_user': 'accounts.serializers.CustomUserSerializer', + 'user_create': 'accounts.serializers.UserRegistrationSerializer', + }, +} + +# Password validation +# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/4.2/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'Asia/Manila' + +USE_I18N = True + +USE_TZ = True + + +# Default primary key field type +# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +DOMAIN = 'testing.keannu1.duckdns.org/#' + +SITE_NAME = 'Test Backend' + +# 1 week access token lifetime +SIMPLE_JWT = { + "ACCESS_TOKEN_LIFETIME": timedelta(minutes=10080), + "REFRESH_TOKEN_LIFETIME": timedelta(minutes=10080) +} + +SESSION_ENGINE = "django.contrib.sessions.backends.cache" +SESSION_CACHE_ALIAS = "default" + +CORS_ALLOW_ALL_ORIGINS = True +CORS_ALLOW_CREDENTIALS = True diff --git a/backend/config/urls.py b/backend/config/urls.py new file mode 100644 index 0000000..8c0ff9e --- /dev/null +++ b/backend/config/urls.py @@ -0,0 +1,29 @@ +""" +URL configuration for equipment_tracker project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/4.2/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path, include +from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView + +urlpatterns = [ + path('admin/', admin.site.urls), + path('api/v1/', include('api.urls')), + path('schema/', SpectacularAPIView.as_view(), name='schema'), + path('swagger/', + SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'), + path('redoc/', + SpectacularRedocView.as_view(url_name='schema'), name='redoc'), +] diff --git a/backend/config/wsgi.py b/backend/config/wsgi.py new file mode 100644 index 0000000..9c0f843 --- /dev/null +++ b/backend/config/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for equipment_tracker project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') + +application = get_wsgi_application() diff --git a/backend/manage.py b/backend/manage.py new file mode 100644 index 0000000..8e7ac79 --- /dev/null +++ b/backend/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/backend/schema.yml b/backend/schema.yml new file mode 100644 index 0000000..e1c6d3d --- /dev/null +++ b/backend/schema.yml @@ -0,0 +1,713 @@ +openapi: 3.0.3 +info: + title: Test Backend + version: 1.0.0 + description: A Project by Keannu Bernasol +paths: + /api/v1/accounts/jwt/create/: + post: + operationId: api_v1_accounts_jwt_create_create + description: |- + Takes a set of user credentials and returns an access and refresh JSON web + token pair to prove the authentication of those credentials. + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/TokenObtainPair' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/TokenObtainPair' + multipart/form-data: + schema: + $ref: '#/components/schemas/TokenObtainPair' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/TokenObtainPair' + description: '' + /api/v1/accounts/jwt/refresh/: + post: + operationId: api_v1_accounts_jwt_refresh_create + description: |- + Takes a refresh type JSON web token and returns an access type JSON web + token if the refresh token is valid. + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/TokenRefresh' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/TokenRefresh' + multipart/form-data: + schema: + $ref: '#/components/schemas/TokenRefresh' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/TokenRefresh' + description: '' + /api/v1/accounts/jwt/verify/: + post: + operationId: api_v1_accounts_jwt_verify_create + description: |- + Takes a token and indicates if it is valid. This view provides no + information about a token's fitness for a particular use. + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/TokenVerify' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/TokenVerify' + multipart/form-data: + schema: + $ref: '#/components/schemas/TokenVerify' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/TokenVerify' + description: '' + /api/v1/accounts/users/: + get: + operationId: api_v1_accounts_users_list + tags: + - api + security: + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/CustomUser' + description: '' + post: + operationId: api_v1_accounts_users_create + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UserRegistration' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/UserRegistration' + multipart/form-data: + schema: + $ref: '#/components/schemas/UserRegistration' + required: true + security: + - jwtAuth: [] + - {} + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/UserRegistration' + description: '' + /api/v1/accounts/users/{id}/: + get: + operationId: api_v1_accounts_users_retrieve + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this user. + required: true + tags: + - api + security: + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/CustomUser' + description: '' + put: + operationId: api_v1_accounts_users_update + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this user. + required: true + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CustomUser' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/CustomUser' + multipart/form-data: + schema: + $ref: '#/components/schemas/CustomUser' + required: true + security: + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/CustomUser' + description: '' + patch: + operationId: api_v1_accounts_users_partial_update + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this user. + required: true + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PatchedCustomUser' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PatchedCustomUser' + multipart/form-data: + schema: + $ref: '#/components/schemas/PatchedCustomUser' + security: + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/CustomUser' + description: '' + delete: + operationId: api_v1_accounts_users_destroy + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this user. + required: true + tags: + - api + security: + - jwtAuth: [] + responses: + '204': + description: No response body + /api/v1/accounts/users/activation/: + post: + operationId: api_v1_accounts_users_activation_create + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Activation' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/Activation' + multipart/form-data: + schema: + $ref: '#/components/schemas/Activation' + required: true + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Activation' + description: '' + /api/v1/accounts/users/me/: + get: + operationId: api_v1_accounts_users_me_retrieve + tags: + - api + security: + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/CustomUser' + description: '' + put: + operationId: api_v1_accounts_users_me_update + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CustomUser' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/CustomUser' + multipart/form-data: + schema: + $ref: '#/components/schemas/CustomUser' + required: true + security: + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/CustomUser' + description: '' + patch: + operationId: api_v1_accounts_users_me_partial_update + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PatchedCustomUser' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PatchedCustomUser' + multipart/form-data: + schema: + $ref: '#/components/schemas/PatchedCustomUser' + security: + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/CustomUser' + description: '' + delete: + operationId: api_v1_accounts_users_me_destroy + tags: + - api + security: + - jwtAuth: [] + responses: + '204': + description: No response body + /api/v1/accounts/users/resend_activation/: + post: + operationId: api_v1_accounts_users_resend_activation_create + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SendEmailReset' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/SendEmailReset' + multipart/form-data: + schema: + $ref: '#/components/schemas/SendEmailReset' + required: true + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/SendEmailReset' + description: '' + /api/v1/accounts/users/reset_password/: + post: + operationId: api_v1_accounts_users_reset_password_create + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SendEmailReset' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/SendEmailReset' + multipart/form-data: + schema: + $ref: '#/components/schemas/SendEmailReset' + required: true + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/SendEmailReset' + description: '' + /api/v1/accounts/users/reset_password_confirm/: + post: + operationId: api_v1_accounts_users_reset_password_confirm_create + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PasswordResetConfirm' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PasswordResetConfirm' + multipart/form-data: + schema: + $ref: '#/components/schemas/PasswordResetConfirm' + required: true + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PasswordResetConfirm' + description: '' + /api/v1/accounts/users/reset_username/: + post: + operationId: api_v1_accounts_users_reset_username_create + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SendEmailReset' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/SendEmailReset' + multipart/form-data: + schema: + $ref: '#/components/schemas/SendEmailReset' + required: true + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/SendEmailReset' + description: '' + /api/v1/accounts/users/reset_username_confirm/: + post: + operationId: api_v1_accounts_users_reset_username_confirm_create + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UsernameResetConfirm' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/UsernameResetConfirm' + multipart/form-data: + schema: + $ref: '#/components/schemas/UsernameResetConfirm' + required: true + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/UsernameResetConfirm' + description: '' + /api/v1/accounts/users/set_password/: + post: + operationId: api_v1_accounts_users_set_password_create + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SetPassword' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/SetPassword' + multipart/form-data: + schema: + $ref: '#/components/schemas/SetPassword' + required: true + security: + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/SetPassword' + description: '' + /api/v1/accounts/users/set_username/: + post: + operationId: api_v1_accounts_users_set_username_create + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SetUsername' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/SetUsername' + multipart/form-data: + schema: + $ref: '#/components/schemas/SetUsername' + required: true + security: + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/SetUsername' + description: '' +components: + schemas: + Activation: + type: object + properties: + uid: + type: string + token: + type: string + required: + - token + - uid + CustomUser: + type: object + properties: + id: + type: integer + readOnly: true + username: + type: string + readOnly: true + description: Required. 150 characters or fewer. Letters, digits and @/./+/-/_ + only. + email: + type: string + format: email + title: Email address + maxLength: 254 + avatar: + type: string + format: uri + first_name: + type: string + maxLength: 150 + last_name: + type: string + maxLength: 150 + required: + - avatar + - id + - username + PasswordResetConfirm: + type: object + properties: + uid: + type: string + token: + type: string + new_password: + type: string + required: + - new_password + - token + - uid + PatchedCustomUser: + type: object + properties: + id: + type: integer + readOnly: true + username: + type: string + readOnly: true + description: Required. 150 characters or fewer. Letters, digits and @/./+/-/_ + only. + email: + type: string + format: email + title: Email address + maxLength: 254 + avatar: + type: string + format: uri + first_name: + type: string + maxLength: 150 + last_name: + type: string + maxLength: 150 + SendEmailReset: + type: object + properties: + email: + type: string + format: email + required: + - email + SetPassword: + type: object + properties: + new_password: + type: string + current_password: + type: string + required: + - current_password + - new_password + SetUsername: + type: object + properties: + current_password: + type: string + new_username: + type: string + title: Username + description: Required. 150 characters or fewer. Letters, digits and @/./+/-/_ + only. + pattern: ^[\w.@+-]+$ + maxLength: 150 + required: + - current_password + - new_username + TokenObtainPair: + type: object + properties: + username: + type: string + writeOnly: true + password: + type: string + writeOnly: true + access: + type: string + readOnly: true + refresh: + type: string + readOnly: true + required: + - access + - password + - refresh + - username + TokenRefresh: + type: object + properties: + access: + type: string + readOnly: true + refresh: + type: string + writeOnly: true + required: + - access + - refresh + TokenVerify: + type: object + properties: + token: + type: string + writeOnly: true + required: + - token + UserRegistration: + type: object + properties: + username: + type: string + description: Required. 150 characters or fewer. Letters, digits and @/./+/-/_ + only. + pattern: ^[\w.@+-]+$ + maxLength: 150 + email: + type: string + format: email + password: + type: string + writeOnly: true + avatar: + type: string + format: uri + nullable: true + first_name: + type: string + maxLength: 150 + last_name: + type: string + maxLength: 150 + required: + - email + - password + - username + UsernameResetConfirm: + type: object + properties: + new_username: + type: string + title: Username + description: Required. 150 characters or fewer. Letters, digits and @/./+/-/_ + only. + pattern: ^[\w.@+-]+$ + maxLength: 150 + required: + - new_username + securitySchemes: + jwtAuth: + type: http + scheme: bearer + bearerFormat: JWT diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..7210e7b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,24 @@ +version: "3.9" + +services: + # Django App + django_backend: + build: + context: . + dockerfile: Dockerfile + image: dmca_backend:latest + ports: + - "8092:8000" + environment: + - PYTHONBUFFERED=1 + command: + [ + "sh", + "-c", + "python backend/manage.py spectacular --color --file backend/schema.yml && python backend/manage.py collectstatic --noinput && python backend/manage.py makemigrations && python backend/manage.py migrate && python backend/manage.py runserver 127.0.0.1:8000", + ] + volumes: + - .:/code # For hotreloading + +volumes: + dmca_backend: diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..7e55fe0 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,43 @@ +-i https://pypi.org/simple +asgiref==3.7.2; python_version >= '3.7' +attrs==23.1.0; python_version >= '3.7' +certifi==2023.11.17; python_version >= '3.6' +cffi==1.16.0; python_version >= '3.8' +charset-normalizer==3.3.2; python_full_version >= '3.7.0' +cryptography==41.0.7; python_version >= '3.7' +defusedxml==0.8.0rc2; python_version >= '3.6' +django==4.2.7 +django-cors-headers==4.3.1 +django-extra-fields==3.0.2 +django-simple-history==3.4.0 +django-templated-mail==1.1.1 +django-unfold==0.17.1 +djangorestframework==3.14.0 +djangorestframework-simplejwt==5.3.0; python_version >= '3.7' +djoser==2.2.2 +drf-spectacular[sidecar]==0.26.5 +drf-spectacular-sidecar==2023.10.1 +idna==3.6; python_version >= '3.5' +inflection==0.5.1; python_version >= '3.5' +jsonschema==4.20.0; python_version >= '3.8' +jsonschema-specifications==2023.11.2; python_version >= '3.8' +oauthlib==3.2.2; python_version >= '3.6' +pillow==10.1.0 +psycopg2==2.9.9 +pycparser==2.21 +pyjwt==2.8.0; python_version >= '3.7' +python-dotenv==1.0.0 +python3-openid==3.2.0 +pytz==2023.3.post1 +pyyaml==6.0.1; python_version >= '3.6' +referencing==0.31.1; python_version >= '3.8' +requests==2.31.0; python_version >= '3.7' +requests-oauthlib==1.3.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +rpds-py==0.13.2; python_version >= '3.8' +social-auth-app-django==5.4.0; python_version >= '3.8' +social-auth-core==4.5.1; python_version >= '3.8' +sqlparse==0.4.4; python_version >= '3.5' +tzdata==2023.3; sys_platform == 'win32' +uritemplate==4.1.1; python_version >= '3.6' +urllib3==2.1.0; python_version >= '3.8' +whitenoise==6.6.0