diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..5ef76aa --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,37 @@ +name: Python application + +on: [push] + +jobs: + build: + strategy: + fail-fast: false + matrix: + python-version: [3.8, 3.9] + poetry-version: [1.1.4] + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Install poetry ${{ matrix.poetry-version }} + run: | + curl -sSL https://install.python-poetry.org | python3 - + echo "$HOME/.local/bin" >> $GITHUB_PATH + + + - name: View poetry --help + run: poetry --help + + - name: Install dependencies + run: poetry install + + - name: Test + run: | + poetry run python manage.py test \ No newline at end of file diff --git a/.github/workflows/github-actions-demo.yml b/.github/workflows/github-actions-demo.yml new file mode 100644 index 0000000..2af4ce3 --- /dev/null +++ b/.github/workflows/github-actions-demo.yml @@ -0,0 +1,17 @@ +name: GitHub Actions Demo +on: [push] +jobs: + Explore-GitHub-Actions: + runs-on: ubuntu-latest + steps: + - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event." + - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!" + - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." + - name: Check out repository code + uses: actions/checkout@v2 + - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner." + - run: echo "🖥️ The workflow is now ready to test your code on the runner." + - name: List files in the repository + run: | + ls ${{ github.workspace }} + - run: echo "🍏 This job's status is ${{ job.status }}." \ No newline at end of file diff --git a/.github/workflows/workflow-pr.yml b/.github/workflows/workflow-pr.yml new file mode 100644 index 0000000..779af10 --- /dev/null +++ b/.github/workflows/workflow-pr.yml @@ -0,0 +1,38 @@ +# Exercício EBAC - Github Actions and Code Review Automation +name: Python Pull Request Workflow +on: [pull_request] +jobs: + qa: + name: Quality check + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v1 + - name: Set up Python + uses: actions/setup-python@master + with: + python-version: 3.8 + - name: Install poetry + run: | + pip install -U pip + pip install poetry + poetry install + env: + POETRY_VIRTUALENVS_CREATE: false + + - name: View poetry --help + run: poetry --help + + - name: Install dependencies + shell: bash + run: python -m poetry install + + - name: Test + run: | + poetry run python manage.py test + - name: Wemake Python Stylguide + uses: wemake-services/wemake-python-styleguide@0.16.0 + continue-on-error: true + with: + reporter: 'github-pr-review' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..1e89d8b --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +# Bookstore + +Bookstore APP from Backend Python course from EBAC + +## Prerequisites + +``` +Python 3.5> +Poetry +Docker && docker-compose +``` + +## Quickstart + +1. Clone this project + + ```shell + git clone git@github.com:drsantos20/bookstore.git + ``` + +2. Install dependencies: + + ```shell + cd bookstore + poetry install + ``` + +3. Run local dev server: + + ```shell + poetry run manage.py migrate + poetry run python manage.py runserver + ``` + +4. Run docker dev server environment: + + ```shell + docker-compose up -d --build + docker-compose exec web python manage.py migrate + ``` + +5. Run tests inside of docker: + + ```shell + docker-compose exec web python manage.py test \ No newline at end of file diff --git a/README.me b/README.me deleted file mode 100644 index e733b6b..0000000 --- a/README.me +++ /dev/null @@ -1,18 +0,0 @@ -# Scripts do Projeto: - -Git clone ... - -## Criando Ambiente Virtual: -python -m venv env -env/scripts/activate - - - -## Instalação das dependências do Projeto: -pip install -r requirements.txt - -## Build Docker: -* Abrir o Docker e digitar no terminal -docker run -docker-compose up --build - diff --git a/bookstore/__pycache__/__init__.cpython-312.pyc b/bookstore/__pycache__/__init__.cpython-312.pyc index 3bf3045..b6a423e 100644 Binary files a/bookstore/__pycache__/__init__.cpython-312.pyc and b/bookstore/__pycache__/__init__.cpython-312.pyc differ diff --git a/bookstore/__pycache__/settings.cpython-312.pyc b/bookstore/__pycache__/settings.cpython-312.pyc index a05475a..6a37da8 100644 Binary files a/bookstore/__pycache__/settings.cpython-312.pyc and b/bookstore/__pycache__/settings.cpython-312.pyc differ diff --git a/bookstore/__pycache__/urls.cpython-312.pyc b/bookstore/__pycache__/urls.cpython-312.pyc index a2f5f1a..5338c85 100644 Binary files a/bookstore/__pycache__/urls.cpython-312.pyc and b/bookstore/__pycache__/urls.cpython-312.pyc differ diff --git a/bookstore/__pycache__/wsgi.cpython-312.pyc b/bookstore/__pycache__/wsgi.cpython-312.pyc index 315e3c2..4f1cec5 100644 Binary files a/bookstore/__pycache__/wsgi.cpython-312.pyc and b/bookstore/__pycache__/wsgi.cpython-312.pyc differ diff --git a/bookstore/settings.py b/bookstore/settings.py index 1cec9c8..eb446c5 100644 --- a/bookstore/settings.py +++ b/bookstore/settings.py @@ -1,13 +1,13 @@ """ Django settings for bookstore project. -Generated by 'django-admin startproject' using Django 5.0.3. +Generated by 'django-admin startproject' using Django 3.2.8. For more information on this file, see -https://docs.djangoproject.com/en/5.0/topics/settings/ +https://docs.djangoproject.com/en/3.2/topics/settings/ For the full list of settings and their values, see -https://docs.djangoproject.com/en/5.0/ref/settings/ +https://docs.djangoproject.com/en/3.2/ref/settings/ """ import os @@ -18,10 +18,10 @@ # Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/ +# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = "django-insecure-ytvw$u%b^9xle0&yw3*%=$s2zz@spz94k*%*88xr50s$dggo#e" +SECRET_KEY = "django-insecure-f*k@=53bc5!shef1-6w+m$-g)kspbaljz%8k4(j7iuc-u2_dyd" # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -39,9 +39,9 @@ "django.contrib.messages", "django.contrib.staticfiles", "django_extensions", - "rest_framework", "order", "product", + "rest_framework", "debug_toolbar", "rest_framework.authtoken", ] @@ -79,7 +79,7 @@ # Database -# https://docs.djangoproject.com/en/5.0/ref/settings/#databases +# https://docs.djangoproject.com/en/3.2/ref/settings/#databases DATABASES = { "default": { @@ -92,9 +92,8 @@ } } - # Password validation -# https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators +# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { @@ -113,7 +112,7 @@ # Internationalization -# https://docs.djangoproject.com/en/5.0/topics/i18n/ +# https://docs.djangoproject.com/en/3.2/topics/i18n/ LANGUAGE_CODE = "en-us" @@ -121,19 +120,22 @@ USE_I18N = True +USE_L10N = True + USE_TZ = True # Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/5.0/howto/static-files/ +# https://docs.djangoproject.com/en/3.2/howto/static-files/ -STATIC_URL = "static/" +STATIC_URL = "/static/" # Default primary key field type -# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field +# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" + REST_FRAMEWORK = { "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination", "PAGE_SIZE": 5, @@ -148,11 +150,12 @@ "127.0.0.1", ] -SECRET_KEY = os.environ.get("SECRET_KEY") +# SECRET_KEY = os.environ.get("SECRET_KEY") -DEBUG = int(os.environ.get("DEBUG", default=0)) +# DEBUG = int(os.environ.get("DEBUG", default=0)) -# 'DJANGO_ALLOWED_HOSTS' should be a single string os hosts with a space between each. +# 'DJANGO_ALLOWED_HOSTS' should be a single string of hosts with a space between each. # For example: 'DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1]' +# ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ") -ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ") +ALLOWED_HOSTS = ['localhost', '127.0.0.1', 'ebac-bookstore-api.herokuapp.com'] \ No newline at end of file diff --git a/db.sqlite3 b/db.sqlite3 index c4e3cf4..92faf21 100644 Binary files a/db.sqlite3 and b/db.sqlite3 differ diff --git a/docker-compose.yml b/docker-compose.yml index 66640b1..b1dbbcc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,33 +1,28 @@ version: '3.9' services: + db: + image: postgres:13.0-alpine + ports: + - 5432:5432 + volumes: + - postgres_data:/var/lib/postgresql/data/ + environment: + - POSTGRES_USER=bookstore_dev + - POSTGRES_PASSWORD=bookstore_dev + - POSTGRES_DB=bookstore_dev_db web: build: . command: python manage.py runserver 0.0.0.0:8000 volumes: - - .:/usr/src/app + - app_data:/usr/src/app/ ports: - 8000:8000 env_file: - ./env.dev - networks: - - backend depends_on: - db - db: - image: postgres:13.0-alpine - volumes: - - postgres_data:/var/lib/postgresql/data - environment: - - POSTGRES_USER=dev - - POSTGRES_PASSWORD=dev - - POSTGRES_DB=bookstore_db - networks: - - backend - -networks: - backend: - driver: bridge volumes: - postgres_data: \ No newline at end of file + postgres_data: + app_data: \ No newline at end of file diff --git a/env.dev b/env.dev index fca16a0..491c2f0 100644 --- a/env.dev +++ b/env.dev @@ -2,8 +2,8 @@ DEBUG=1 SECRET_KEY=foo DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1] SQL_ENGINE=django.db.backends.postgresql -SQL_DATABASE=bookstore_db -SQL_USER=dev -SQL_PASSWORD=dev +SQL_DATABASE=bookstore_dev_db +SQL_USER=bookstore_dev +SQL_PASSWORD=bookstore_dev SQL_HOST=db SQL_PORT=5432 \ No newline at end of file diff --git a/order/__pycache__/__init__.cpython-312.pyc b/order/__pycache__/__init__.cpython-312.pyc index dbcc973..e3ae2ca 100644 Binary files a/order/__pycache__/__init__.cpython-312.pyc and b/order/__pycache__/__init__.cpython-312.pyc differ diff --git a/order/__pycache__/admin.cpython-312.pyc b/order/__pycache__/admin.cpython-312.pyc index d22289d..71bb81c 100644 Binary files a/order/__pycache__/admin.cpython-312.pyc and b/order/__pycache__/admin.cpython-312.pyc differ diff --git a/order/__pycache__/apps.cpython-312.pyc b/order/__pycache__/apps.cpython-312.pyc index 7b42320..930cf69 100644 Binary files a/order/__pycache__/apps.cpython-312.pyc and b/order/__pycache__/apps.cpython-312.pyc differ diff --git a/order/__pycache__/factories.cpython-312.pyc b/order/__pycache__/factories.cpython-312.pyc index 7462700..aea111b 100644 Binary files a/order/__pycache__/factories.cpython-312.pyc and b/order/__pycache__/factories.cpython-312.pyc differ diff --git a/order/__pycache__/urls.cpython-312.pyc b/order/__pycache__/urls.cpython-312.pyc index a3aeef2..62b0d80 100644 Binary files a/order/__pycache__/urls.cpython-312.pyc and b/order/__pycache__/urls.cpython-312.pyc differ diff --git a/order/factories.py b/order/factories.py index d8e4d92..b0b0164 100644 --- a/order/factories.py +++ b/order/factories.py @@ -1,14 +1,14 @@ import factory - from django.contrib.auth.models import User -from product.factories import ProductFactory from order.models import Order +from product.factories import ProductFactory + class UserFactory(factory.django.DjangoModelFactory): - email = factory.Faker("email") - username = factory.Faker("user_name") + email = factory.Faker("pystr") + username = factory.Faker("pystr") class Meta: model = User @@ -21,6 +21,7 @@ class OrderFactory(factory.django.DjangoModelFactory): def product(self, create, extracted, **kwargs): if not create: return + if extracted: for product in extracted: self.product.add(product) diff --git a/order/migrations/__pycache__/0001_initial.cpython-312.pyc b/order/migrations/__pycache__/0001_initial.cpython-312.pyc index 6f1b0bf..e09f603 100644 Binary files a/order/migrations/__pycache__/0001_initial.cpython-312.pyc and b/order/migrations/__pycache__/0001_initial.cpython-312.pyc differ diff --git a/order/migrations/__pycache__/0002_alter_order_user.cpython-312.pyc b/order/migrations/__pycache__/0002_alter_order_user.cpython-312.pyc index 7ad7335..a949783 100644 Binary files a/order/migrations/__pycache__/0002_alter_order_user.cpython-312.pyc and b/order/migrations/__pycache__/0002_alter_order_user.cpython-312.pyc differ diff --git a/order/migrations/__pycache__/0003_alter_order_user.cpython-312.pyc b/order/migrations/__pycache__/0003_alter_order_user.cpython-312.pyc index 20f5fc7..a0d0307 100644 Binary files a/order/migrations/__pycache__/0003_alter_order_user.cpython-312.pyc and b/order/migrations/__pycache__/0003_alter_order_user.cpython-312.pyc differ diff --git a/order/migrations/__pycache__/__init__.cpython-312.pyc b/order/migrations/__pycache__/__init__.cpython-312.pyc index 9e6156f..0138771 100644 Binary files a/order/migrations/__pycache__/__init__.cpython-312.pyc and b/order/migrations/__pycache__/__init__.cpython-312.pyc differ diff --git a/order/models/__pycache__/__init__.cpython-312.pyc b/order/models/__pycache__/__init__.cpython-312.pyc index 7e5d410..e427957 100644 Binary files a/order/models/__pycache__/__init__.cpython-312.pyc and b/order/models/__pycache__/__init__.cpython-312.pyc differ diff --git a/order/models/__pycache__/order.cpython-312.pyc b/order/models/__pycache__/order.cpython-312.pyc index a00174f..ad343ad 100644 Binary files a/order/models/__pycache__/order.cpython-312.pyc and b/order/models/__pycache__/order.cpython-312.pyc differ diff --git a/order/serializers/__pycache__/__init__.cpython-312.pyc b/order/serializers/__pycache__/__init__.cpython-312.pyc index ac7c6b1..ad967c9 100644 Binary files a/order/serializers/__pycache__/__init__.cpython-312.pyc and b/order/serializers/__pycache__/__init__.cpython-312.pyc differ diff --git a/order/serializers/__pycache__/order_serializer.cpython-312.pyc b/order/serializers/__pycache__/order_serializer.cpython-312.pyc index fd67f36..4849f59 100644 Binary files a/order/serializers/__pycache__/order_serializer.cpython-312.pyc and b/order/serializers/__pycache__/order_serializer.cpython-312.pyc differ diff --git a/order/serializers/order_serializer.py b/order/serializers/order_serializer.py index 9620b4f..2a3e7d5 100644 --- a/order/serializers/order_serializer.py +++ b/order/serializers/order_serializer.py @@ -25,7 +25,7 @@ def create(self, validated_data): product_data = validated_data.pop("products_id") user_data = validated_data.pop("user") - order = Order.objects.create(**validated_data) + order = Order.objects.create(user=user_data) for product in product_data: order.product.add(product) diff --git a/order/tests/__pycache__/__init__.cpython-312.pyc b/order/tests/__pycache__/__init__.cpython-312.pyc index a854db1..d81048f 100644 Binary files a/order/tests/__pycache__/__init__.cpython-312.pyc and b/order/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/order/tests/test_serializers/__init__.py b/order/tests/test_serializers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/order/tests/test_serializers/__pycache__/__init__.cpython-312.pyc b/order/tests/test_serializers/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..511bf22 Binary files /dev/null and b/order/tests/test_serializers/__pycache__/__init__.cpython-312.pyc differ diff --git a/order/tests/test_serializers/__pycache__/test_order_serializer.cpython-312.pyc b/order/tests/test_serializers/__pycache__/test_order_serializer.cpython-312.pyc new file mode 100644 index 0000000..fce5725 Binary files /dev/null and b/order/tests/test_serializers/__pycache__/test_order_serializer.cpython-312.pyc differ diff --git a/order/tests/test_serializers/test_order_serializer.py b/order/tests/test_serializers/test_order_serializer.py new file mode 100644 index 0000000..6ed1588 --- /dev/null +++ b/order/tests/test_serializers/test_order_serializer.py @@ -0,0 +1,20 @@ +from django.test import TestCase + +from order.factories import OrderFactory, ProductFactory +from order.serializers import OrderSerializer + + +class TestOrderSerializer(TestCase): + def setUp(self) -> None: + self.product_1 = ProductFactory() + self.product_2 = ProductFactory() + + self.order = OrderFactory(product=(self.product_1, self.product_2)) + self.order_serializer = OrderSerializer(self.order) + + def test_order_serializer(self): + serializer_data = self.order_serializer.data + self.assertEqual( + serializer_data["product"][0]["title"], self.product_1.title) + self.assertEqual( + serializer_data["product"][1]["title"], self.product_2.title) diff --git a/order/tests/test_viewsets/__pycache__/__init__.cpython-312.pyc b/order/tests/test_viewsets/__pycache__/__init__.cpython-312.pyc index 333e8b3..c4de5a6 100644 Binary files a/order/tests/test_viewsets/__pycache__/__init__.cpython-312.pyc and b/order/tests/test_viewsets/__pycache__/__init__.cpython-312.pyc differ diff --git a/order/tests/test_viewsets/__pycache__/test_order_viewset.cpython-312-pytest-8.0.2.pyc b/order/tests/test_viewsets/__pycache__/test_order_viewset.cpython-312-pytest-8.0.2.pyc new file mode 100644 index 0000000..47a02df Binary files /dev/null and b/order/tests/test_viewsets/__pycache__/test_order_viewset.cpython-312-pytest-8.0.2.pyc differ diff --git a/order/tests/test_viewsets/__pycache__/test_order_viewset.cpython-312.pyc b/order/tests/test_viewsets/__pycache__/test_order_viewset.cpython-312.pyc index a1fe002..c47a36a 100644 Binary files a/order/tests/test_viewsets/__pycache__/test_order_viewset.cpython-312.pyc and b/order/tests/test_viewsets/__pycache__/test_order_viewset.cpython-312.pyc differ diff --git a/order/tests/test_viewsets/test_order_viewset.py b/order/tests/test_viewsets/test_order_viewset.py index d8d3e2c..4695348 100644 --- a/order/tests/test_viewsets/test_order_viewset.py +++ b/order/tests/test_viewsets/test_order_viewset.py @@ -1,14 +1,14 @@ import json +from django.urls import reverse from rest_framework import status from rest_framework.test import APITestCase, APIClient -from django.urls import reverse -from product.factories import CategoryFactory, ProductFactory from order.factories import UserFactory, OrderFactory -from product.models import Product from order.models import Order +from product.factories import CategoryFactory, ProductFactory +from product.models import Product class TestOrderViewSet(APITestCase): @@ -23,7 +23,8 @@ def setUp(self): self.order = OrderFactory(product=[self.product]) def test_order(self): - response = self.client.get(reverse("order-list", kwargs={"version": "v1"})) + response = self.client.get( + reverse("order-list", kwargs={"version": "v1"})) self.assertEqual(response.status_code, status.HTTP_200_OK) @@ -48,10 +49,12 @@ def test_create_order(self): data = json.dumps( { "products_id": [product.id], - "user_id": user.id, + "user": user.id, } ) + print(data) + response = self.client.post( reverse("order-list", kwargs={"version": "v1"}), data=data, @@ -59,4 +62,5 @@ def test_create_order(self): ) self.assertEqual(response.status_code, status.HTTP_201_CREATED) + created_order = Order.objects.get(user=user) diff --git a/order/viewsets/__pycache__/__init__.cpython-312.pyc b/order/viewsets/__pycache__/__init__.cpython-312.pyc index 1ce246d..3eb660c 100644 Binary files a/order/viewsets/__pycache__/__init__.cpython-312.pyc and b/order/viewsets/__pycache__/__init__.cpython-312.pyc differ diff --git a/order/viewsets/__pycache__/order_viewset.cpython-312.pyc b/order/viewsets/__pycache__/order_viewset.cpython-312.pyc index ca1c306..8f92765 100644 Binary files a/order/viewsets/__pycache__/order_viewset.cpython-312.pyc and b/order/viewsets/__pycache__/order_viewset.cpython-312.pyc differ diff --git a/order/viewsets/order_viewset.py b/order/viewsets/order_viewset.py index 5a92cd6..ad52962 100644 --- a/order/viewsets/order_viewset.py +++ b/order/viewsets/order_viewset.py @@ -7,4 +7,4 @@ class OrderViewSet(ModelViewSet): serializer_class = OrderSerializer - queryset = Order.objects.all() + queryset = Order.objects.all().order_by("id") diff --git a/poetry.lock b/poetry.lock index df0ccec..9a59f72 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,18 +2,96 @@ [[package]] name = "asgiref" -version = "3.8.1" +version = "3.7.2" description = "ASGI specs, helper code, and adapters" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"}, - {file = "asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"}, + {file = "asgiref-3.7.2-py3-none-any.whl", hash = "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e"}, + {file = "asgiref-3.7.2.tar.gz", hash = "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed"}, ] +[package.dependencies] +typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} + [package.extras] tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] +[[package]] +name = "atomicwrites" +version = "1.4.1" +description = "Atomic file writes." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"}, +] + +[[package]] +name = "attrs" +version = "23.2.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, +] + +[package.dependencies] +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} + +[package.extras] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] + +[[package]] +name = "autopep8" +version = "1.7.0" +description = "A tool that automatically formats Python code to conform to the PEP 8 style guide" +optional = false +python-versions = "*" +files = [ + {file = "autopep8-1.7.0-py2.py3-none-any.whl", hash = "sha256:6f09e90a2be784317e84dc1add17ebfc7abe3924239957a37e5040e27d812087"}, + {file = "autopep8-1.7.0.tar.gz", hash = "sha256:ca9b1a83e53a7fad65d731dc7a2a2d50aa48f43850407c59f6a1a306c4201142"}, +] + +[package.dependencies] +pycodestyle = ">=2.9.1" +toml = "*" + +[[package]] +name = "backports-zoneinfo" +version = "0.2.1" +description = "Backport of the standard library zoneinfo module" +optional = false +python-versions = ">=3.6" +files = [ + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win32.whl", hash = "sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win32.whl", hash = "sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-win32.whl", hash = "sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6"}, + {file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"}, +] + +[package.extras] +tzdata = ["tzdata"] + [[package]] name = "colorama" version = "0.4.6" @@ -27,19 +105,19 @@ files = [ [[package]] name = "django" -version = "5.0.6" -description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." +version = "3.2.25" +description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." optional = false -python-versions = ">=3.10" +python-versions = ">=3.6" files = [ - {file = "Django-5.0.6-py3-none-any.whl", hash = "sha256:8363ac062bb4ef7c3f12d078f6fa5d154031d129a15170a1066412af49d30905"}, - {file = "Django-5.0.6.tar.gz", hash = "sha256:ff1b61005004e476e0aeea47c7f79b85864c70124030e95146315396f1e7951f"}, + {file = "Django-3.2.25-py3-none-any.whl", hash = "sha256:a52ea7fcf280b16f7b739cec38fa6d3f8953a5456986944c3ca97e79882b4e38"}, + {file = "Django-3.2.25.tar.gz", hash = "sha256:7ca38a78654aee72378594d63e51636c04b8e28574f5505dff630895b5472777"}, ] [package.dependencies] -asgiref = ">=3.7.0,<4" -sqlparse = ">=0.3.1" -tzdata = {version = "*", markers = "sys_platform == \"win32\""} +asgiref = ">=3.3.2,<4" +pytz = "*" +sqlparse = ">=0.2.2" [package.extras] argon2 = ["argon2-cffi (>=19.1.0)"] @@ -47,13 +125,13 @@ bcrypt = ["bcrypt"] [[package]] name = "django-debug-toolbar" -version = "4.3.0" +version = "3.8.1" description = "A configurable set of panels that display various debug information about the current request/response." optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "django_debug_toolbar-4.3.0-py3-none-any.whl", hash = "sha256:e09b7dcb8417b743234dfc57c95a7c1d1d87a88844abd13b4c5387f807b31bf6"}, - {file = "django_debug_toolbar-4.3.0.tar.gz", hash = "sha256:0b0dddee5ea29b9cb678593bc0d7a6d76b21d7799cb68e091a2148341a80f3c4"}, + {file = "django_debug_toolbar-3.8.1-py3-none-any.whl", hash = "sha256:879f8a4672d41621c06a4d322dcffa630fc4df056cada6e417ed01db0e5e0478"}, + {file = "django_debug_toolbar-3.8.1.tar.gz", hash = "sha256:24ef1a7d44d25e60d7951e378454c6509bf536dce7e7d9d36e7c387db499bc27"}, ] [package.dependencies] @@ -99,6 +177,7 @@ files = [ ] [package.dependencies] +"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} django = ">=3.0" [[package]] @@ -114,6 +193,7 @@ files = [ [package.dependencies] Faker = ">=0.7.0" +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} [package.extras] dev = ["Django", "Pillow", "SQLAlchemy", "coverage", "flake8", "isort", "mongoengine", "sqlalchemy-utils", "tox", "wheel (>=0.32.0)", "zest.releaser[recommended]"] @@ -121,33 +201,58 @@ doc = ["Sphinx", "sphinx-rtd-theme", "sphinxcontrib-spelling"] [[package]] name = "faker" -version = "25.1.0" +version = "18.13.0" description = "Faker is a Python package that generates fake data for you." optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "Faker-25.1.0-py3-none-any.whl", hash = "sha256:24e28dce0b89683bb9e017e042b971c8c4909cff551b6d46f1e207674c7c2526"}, - {file = "Faker-25.1.0.tar.gz", hash = "sha256:2107618cf306bb188dcfea3e5cfd94aa92d65c7293a2437c1e96a99c83274755"}, + {file = "Faker-18.13.0-py3-none-any.whl", hash = "sha256:801d1a2d71f1fc54d332de2ab19de7452454309937233ea2f7485402882d67b3"}, + {file = "Faker-18.13.0.tar.gz", hash = "sha256:84bcf92bb725dd7341336eea4685df9a364f16f2470c4d29c1d7e6c5fd5a457d"}, ] [package.dependencies] python-dateutil = ">=2.4" +typing-extensions = {version = ">=3.10.0.1", markers = "python_version < \"3.8\""} + +[[package]] +name = "gunicorn" +version = "20.1.0" +description = "WSGI HTTP Server for UNIX" +optional = false +python-versions = ">=3.5" +files = [ + {file = "gunicorn-20.1.0-py3-none-any.whl", hash = "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e"}, + {file = "gunicorn-20.1.0.tar.gz", hash = "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8"}, +] + +[package.dependencies] +setuptools = ">=3.0" + +[package.extras] +eventlet = ["eventlet (>=0.24.1)"] +gevent = ["gevent (>=1.4.0)"] +setproctitle = ["setproctitle"] +tornado = ["tornado (>=0.2)"] [[package]] -name = "flake8" -version = "7.0.0" -description = "the modular source code checker: pep8 pyflakes and co" +name = "importlib-metadata" +version = "6.7.0" +description = "Read metadata from Python packages" optional = false -python-versions = ">=3.8.1" +python-versions = ">=3.7" files = [ - {file = "flake8-7.0.0-py2.py3-none-any.whl", hash = "sha256:a6dfbb75e03252917f2473ea9653f7cd799c3064e54d4c8140044c5c065f53c3"}, - {file = "flake8-7.0.0.tar.gz", hash = "sha256:33f96621059e65eec474169085dc92bf26e7b2d47366b70be2f67ab80dc25132"}, + {file = "importlib_metadata-6.7.0-py3-none-any.whl", hash = "sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5"}, + {file = "importlib_metadata-6.7.0.tar.gz", hash = "sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4"}, ] [package.dependencies] -mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.11.0,<2.12.0" -pyflakes = ">=3.2.0,<3.3.0" +typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} +zipp = ">=0.5" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +perf = ["ipython"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] [[package]] name = "iniconfig" @@ -161,16 +266,22 @@ files = [ ] [[package]] -name = "mccabe" -version = "0.7.0" -description = "McCabe checker, plugin for flake8" +name = "isort" +version = "5.11.5" +description = "A Python utility / library to sort Python imports." optional = false -python-versions = ">=3.6" +python-versions = ">=3.7.0" files = [ - {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, - {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, + {file = "isort-5.11.5-py3-none-any.whl", hash = "sha256:ba1d72fb2595a01c7895a5128f9585a5cc4b6d395f1c8d514989b9a7eb2a8746"}, + {file = "isort-5.11.5.tar.gz", hash = "sha256:6be1f76a507cb2ecf16c7cf14a37e41609ca082330be4e3436a18ef74add55db"}, ] +[package.extras] +colors = ["colorama (>=0.4.3,<0.5.0)"] +pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] +plugins = ["setuptools"] +requirements-deprecated-finder = ["pip-api", "pipreqs"] + [[package]] name = "packaging" version = "24.0" @@ -184,15 +295,18 @@ files = [ [[package]] name = "pluggy" -version = "1.5.0" +version = "1.2.0" description = "plugin and hook calling mechanisms for python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, - {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, + {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, + {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, ] +[package.dependencies] +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} + [package.extras] dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] @@ -279,46 +393,51 @@ files = [ ] [[package]] -name = "pycodestyle" -version = "2.11.1" -description = "Python style guide checker" +name = "py" +version = "1.11.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" optional = false -python-versions = ">=3.8" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ - {file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"}, - {file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"}, + {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, + {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, ] [[package]] -name = "pyflakes" -version = "3.2.0" -description = "passive checker of Python programs" +name = "pycodestyle" +version = "2.10.0" +description = "Python style guide checker" optional = false -python-versions = ">=3.8" +python-versions = ">=3.6" files = [ - {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, - {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, + {file = "pycodestyle-2.10.0-py2.py3-none-any.whl", hash = "sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"}, + {file = "pycodestyle-2.10.0.tar.gz", hash = "sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053"}, ] [[package]] name = "pytest" -version = "8.2.0" +version = "6.2.5" description = "pytest: simple powerful testing with Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.6" files = [ - {file = "pytest-8.2.0-py3-none-any.whl", hash = "sha256:1733f0620f6cda4095bbf0d9ff8022486e91892245bb9e7d5542c018f612f233"}, - {file = "pytest-8.2.0.tar.gz", hash = "sha256:d507d4482197eac0ba2bae2e9babf0672eb333017bcedaa5fb1a3d42c1174b3f"}, + {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, + {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, ] [package.dependencies] +atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} +attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} iniconfig = "*" packaging = "*" -pluggy = ">=1.5,<2.0" +pluggy = ">=0.12,<2.0" +py = ">=1.8.2" +toml = "*" [package.extras] -dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] [[package]] name = "python-dateutil" @@ -334,6 +453,33 @@ files = [ [package.dependencies] six = ">=1.5" +[[package]] +name = "pytz" +version = "2024.1" +description = "World timezone definitions, modern and historical" +optional = false +python-versions = "*" +files = [ + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, +] + +[[package]] +name = "setuptools" +version = "68.0.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"}, + {file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + [[package]] name = "six" version = "1.16.0" @@ -347,31 +493,72 @@ files = [ [[package]] name = "sqlparse" -version = "0.5.0" +version = "0.4.4" description = "A non-validating SQL parser." optional = false -python-versions = ">=3.8" +python-versions = ">=3.5" files = [ - {file = "sqlparse-0.5.0-py3-none-any.whl", hash = "sha256:c204494cd97479d0e39f28c93d46c0b2d5959c7b9ab904762ea6c7af211c8663"}, - {file = "sqlparse-0.5.0.tar.gz", hash = "sha256:714d0a4932c059d16189f58ef5411ec2287a4360f17cdd0edd2d09d4c5087c93"}, + {file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"}, + {file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"}, ] [package.extras] -dev = ["build", "hatch"] +dev = ["build", "flake8"] doc = ["sphinx"] +test = ["pytest", "pytest-cov"] [[package]] -name = "tzdata" -version = "2024.1" -description = "Provider of IANA time zone data" +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" optional = false -python-versions = ">=2" +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" files = [ - {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, - {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] +[[package]] +name = "typing-extensions" +version = "4.7.1" +description = "Backported and Experimental Type Hints for Python 3.7+" +optional = false +python-versions = ">=3.7" +files = [ + {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, + {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, +] + +[[package]] +name = "whitenoise" +version = "5.3.0" +description = "Radically simplified static file serving for WSGI applications" +optional = false +python-versions = ">=3.5, <4" +files = [ + {file = "whitenoise-5.3.0-py2.py3-none-any.whl", hash = "sha256:d963ef25639d1417e8a247be36e6aedd8c7c6f0a08adcb5a89146980a96b577c"}, + {file = "whitenoise-5.3.0.tar.gz", hash = "sha256:d234b871b52271ae7ed6d9da47ffe857c76568f11dd30e28e18c5869dbd11e12"}, +] + +[package.extras] +brotli = ["Brotli"] + +[[package]] +name = "zipp" +version = "3.15.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.7" +files = [ + {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, + {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] + [metadata] lock-version = "2.0" -python-versions = "^3.12" -content-hash = "4e6e0fdefbb923f51712ef536efdc91fb2d5aa948e2d3aa4f41d79bdb27a4104" +python-versions = "^3.7" +content-hash = "3d24a74ddb066994975c85b456e5889359e72bfa95d271ccd733f12dee92b275" diff --git a/product/__pycache__/__init__.cpython-312.pyc b/product/__pycache__/__init__.cpython-312.pyc index b6765e9..c10d763 100644 Binary files a/product/__pycache__/__init__.cpython-312.pyc and b/product/__pycache__/__init__.cpython-312.pyc differ diff --git a/product/__pycache__/admin.cpython-312.pyc b/product/__pycache__/admin.cpython-312.pyc index f0a496d..bfb9952 100644 Binary files a/product/__pycache__/admin.cpython-312.pyc and b/product/__pycache__/admin.cpython-312.pyc differ diff --git a/product/__pycache__/apps.cpython-312.pyc b/product/__pycache__/apps.cpython-312.pyc index e28f29b..20f93da 100644 Binary files a/product/__pycache__/apps.cpython-312.pyc and b/product/__pycache__/apps.cpython-312.pyc differ diff --git a/product/__pycache__/factories.cpython-312.pyc b/product/__pycache__/factories.cpython-312.pyc index 8b774ba..817d3e2 100644 Binary files a/product/__pycache__/factories.cpython-312.pyc and b/product/__pycache__/factories.cpython-312.pyc differ diff --git a/product/__pycache__/urls.cpython-312.pyc b/product/__pycache__/urls.cpython-312.pyc index 3e9755f..d9c0e2b 100644 Binary files a/product/__pycache__/urls.cpython-312.pyc and b/product/__pycache__/urls.cpython-312.pyc differ diff --git a/product/factories.py b/product/factories.py index 031b956..8a6ebef 100644 --- a/product/factories.py +++ b/product/factories.py @@ -15,6 +15,7 @@ class Meta: class ProductFactory(factory.django.DjangoModelFactory): price = factory.Faker("pyint") + category = factory.LazyAttribute(CategoryFactory) title = factory.Faker("pystr") @factory.post_generation diff --git a/product/migrations/__pycache__/0001_initial.cpython-312.pyc b/product/migrations/__pycache__/0001_initial.cpython-312.pyc index 1deb86e..efd00a2 100644 Binary files a/product/migrations/__pycache__/0001_initial.cpython-312.pyc and b/product/migrations/__pycache__/0001_initial.cpython-312.pyc differ diff --git a/product/migrations/__pycache__/__init__.cpython-312.pyc b/product/migrations/__pycache__/__init__.cpython-312.pyc index 68f1ef7..d8cd976 100644 Binary files a/product/migrations/__pycache__/__init__.cpython-312.pyc and b/product/migrations/__pycache__/__init__.cpython-312.pyc differ diff --git a/product/models/__pycache__/__init__.cpython-312.pyc b/product/models/__pycache__/__init__.cpython-312.pyc index 97951aa..8fd1688 100644 Binary files a/product/models/__pycache__/__init__.cpython-312.pyc and b/product/models/__pycache__/__init__.cpython-312.pyc differ diff --git a/product/models/__pycache__/category.cpython-312.pyc b/product/models/__pycache__/category.cpython-312.pyc index 2a75446..1f683fe 100644 Binary files a/product/models/__pycache__/category.cpython-312.pyc and b/product/models/__pycache__/category.cpython-312.pyc differ diff --git a/product/models/__pycache__/product.cpython-312.pyc b/product/models/__pycache__/product.cpython-312.pyc index 55da1ea..ecdd6a1 100644 Binary files a/product/models/__pycache__/product.cpython-312.pyc and b/product/models/__pycache__/product.cpython-312.pyc differ diff --git a/product/models/product.py b/product/models/product.py index e624508..21513b2 100644 --- a/product/models/product.py +++ b/product/models/product.py @@ -1,6 +1,6 @@ from django.db import models -from product.models.category import Category +from product.models import Category class Product(models.Model): diff --git a/product/serializers/__pycache__/__init__.cpython-312.pyc b/product/serializers/__pycache__/__init__.cpython-312.pyc index c7c87f4..0c80e24 100644 Binary files a/product/serializers/__pycache__/__init__.cpython-312.pyc and b/product/serializers/__pycache__/__init__.cpython-312.pyc differ diff --git a/product/serializers/__pycache__/category_serializer.cpython-312.pyc b/product/serializers/__pycache__/category_serializer.cpython-312.pyc index 7f6f0fa..ff3de3b 100644 Binary files a/product/serializers/__pycache__/category_serializer.cpython-312.pyc and b/product/serializers/__pycache__/category_serializer.cpython-312.pyc differ diff --git a/product/serializers/__pycache__/product_serializer.cpython-312.pyc b/product/serializers/__pycache__/product_serializer.cpython-312.pyc index fe7c7eb..9739049 100644 Binary files a/product/serializers/__pycache__/product_serializer.cpython-312.pyc and b/product/serializers/__pycache__/product_serializer.cpython-312.pyc differ diff --git a/product/serializers/category_serializer.py b/product/serializers/category_serializer.py index cfe2ff8..7da9ace 100644 --- a/product/serializers/category_serializer.py +++ b/product/serializers/category_serializer.py @@ -12,3 +12,4 @@ class Meta: "description", "active", ] + extra_kwargs = {"slug": {"required": False}} diff --git a/product/tests/__pycache__/__init__.cpython-312.pyc b/product/tests/__pycache__/__init__.cpython-312.pyc index cec44f8..822a00d 100644 Binary files a/product/tests/__pycache__/__init__.cpython-312.pyc and b/product/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/product/tests/test_serializers/__init__.py b/product/tests/test_serializers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/product/tests/test_serializers/__pycache__/__init__.cpython-312.pyc b/product/tests/test_serializers/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..3904fb3 Binary files /dev/null and b/product/tests/test_serializers/__pycache__/__init__.cpython-312.pyc differ diff --git a/product/tests/test_serializers/__pycache__/test_category_serializer.cpython-312.pyc b/product/tests/test_serializers/__pycache__/test_category_serializer.cpython-312.pyc new file mode 100644 index 0000000..d2adbf9 Binary files /dev/null and b/product/tests/test_serializers/__pycache__/test_category_serializer.cpython-312.pyc differ diff --git a/product/tests/test_serializers/__pycache__/test_product_serializer.cpython-312.pyc b/product/tests/test_serializers/__pycache__/test_product_serializer.cpython-312.pyc new file mode 100644 index 0000000..1f7803c Binary files /dev/null and b/product/tests/test_serializers/__pycache__/test_product_serializer.cpython-312.pyc differ diff --git a/product/tests/test_serializers/test_category_serializer.py b/product/tests/test_serializers/test_category_serializer.py new file mode 100644 index 0000000..f79b26f --- /dev/null +++ b/product/tests/test_serializers/test_category_serializer.py @@ -0,0 +1,15 @@ +from django.test import TestCase + +from product.factories import CategoryFactory, ProductFactory +from product.serializers import CategorySerializer + + +class TestCategorySerializer(TestCase): + def setUp(self) -> None: + self.category = CategoryFactory(title="food") + self.category_serializer = CategorySerializer(self.category) + + def test_order_serializer(self): + serializer_data = self.category_serializer.data + + self.assertEqual(serializer_data["title"], "food") diff --git a/product/tests/test_serializers/test_product_serializer.py b/product/tests/test_serializers/test_product_serializer.py new file mode 100644 index 0000000..2be469a --- /dev/null +++ b/product/tests/test_serializers/test_product_serializer.py @@ -0,0 +1,20 @@ +from django.test import TestCase + +from product.factories import CategoryFactory, ProductFactory +from product.serializers import ProductSerializer + + +class TestProductSerializer(TestCase): + def setUp(self) -> None: + self.category = CategoryFactory(title="technology") + self.product_1 = ProductFactory( + title="mouse", price=100, category=[self.category] + ) + self.product_serializer = ProductSerializer(self.product_1) + + def test_product_serializer(self): + serializer_data = self.product_serializer.data + self.assertEqual(serializer_data["price"], 100) + self.assertEqual(serializer_data["title"], "mouse") + self.assertEqual( + serializer_data["category"][0]["title"], "technology") diff --git a/product/tests/tests_viewsets/__pycache__/__init__.cpython-312.pyc b/product/tests/tests_viewsets/__pycache__/__init__.cpython-312.pyc index 0260811..c085ab4 100644 Binary files a/product/tests/tests_viewsets/__pycache__/__init__.cpython-312.pyc and b/product/tests/tests_viewsets/__pycache__/__init__.cpython-312.pyc differ diff --git a/product/tests/tests_viewsets/__pycache__/test_category_viewset.cpython-312.pyc b/product/tests/tests_viewsets/__pycache__/test_category_viewset.cpython-312.pyc new file mode 100644 index 0000000..f9343dd Binary files /dev/null and b/product/tests/tests_viewsets/__pycache__/test_category_viewset.cpython-312.pyc differ diff --git a/product/tests/tests_viewsets/__pycache__/test_product_viewset.cpython-312-pytest-8.0.2.pyc b/product/tests/tests_viewsets/__pycache__/test_product_viewset.cpython-312-pytest-8.0.2.pyc new file mode 100644 index 0000000..5961e90 Binary files /dev/null and b/product/tests/tests_viewsets/__pycache__/test_product_viewset.cpython-312-pytest-8.0.2.pyc differ diff --git a/product/tests/tests_viewsets/__pycache__/test_product_viewset.cpython-312.pyc b/product/tests/tests_viewsets/__pycache__/test_product_viewset.cpython-312.pyc index ccedb76..fb0eeee 100644 Binary files a/product/tests/tests_viewsets/__pycache__/test_product_viewset.cpython-312.pyc and b/product/tests/tests_viewsets/__pycache__/test_product_viewset.cpython-312.pyc differ diff --git a/product/tests/tests_viewsets/test_category_viewset.py b/product/tests/tests_viewsets/test_category_viewset.py new file mode 100644 index 0000000..5a7d755 --- /dev/null +++ b/product/tests/tests_viewsets/test_category_viewset.py @@ -0,0 +1,40 @@ +import json + +from django.urls import reverse +from rest_framework.test import APIClient, APITestCase +from rest_framework.views import status + +from product.factories import CategoryFactory +from product.models import Category + + +class CategoryViewSet(APITestCase): + client = APIClient() + + def setUp(self): + self.category = CategoryFactory(title="books") + + def test_get_all_category(self): + response = self.client.get( + reverse("category-list", kwargs={"version": "v1"})) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + category_data = json.loads(response.content) + + self.assertEqual(category_data["results"] + [0]["title"], self.category.title) + + def test_create_category(self): + data = json.dumps({"title": "technology"}) + + response = self.client.post( + reverse("category-list", kwargs={"version": "v1"}), + data=data, + content_type="application/json", + ) + + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + created_category = Category.objects.get(title="technology") + + self.assertEqual(created_category.title, "technology") diff --git a/product/tests/tests_viewsets/test_product_viewset.py b/product/tests/tests_viewsets/test_product_viewset.py index e486ebc..ac6eddc 100644 --- a/product/tests/tests_viewsets/test_product_viewset.py +++ b/product/tests/tests_viewsets/test_product_viewset.py @@ -1,17 +1,20 @@ -from product.factories import CategoryFactory, ProductFactory -from order.factories import UserFactory -from product.models import Product, category -from rest_framework.test import APITestCase, APIClient from django.urls import reverse +from rest_framework.authtoken.models import Token +from rest_framework.test import APITestCase, APIClient from rest_framework import status +from product.factories import CategoryFactory, ProductFactory +from order.factories import UserFactory +from product.models import Product import json class TestProductViewSet(APITestCase): client = APIClient() - + def setUp(self): self.user = UserFactory() + token = Token.objects.create(user=self.user) + token.save() self.product = ProductFactory( title="pro controller", @@ -19,27 +22,32 @@ def setUp(self): ) def test_get_all_product(self): - response = self.client.get(reverse("product-list", kwargs={"version": "v1"})) + token = Token.objects.get(user__username=self.user.username) + self.client.credentials( + HTTP_AUTHORIZATION="Token " + token.key) + response = self.client.get( + reverse("product-list", kwargs={"version": "v1"})) self.assertEqual(response.status_code, status.HTTP_200_OK) product_data = json.loads(response.content) - self.assertEqual(product_data[0]["title"], self.product.title) - self.assertEqual(product_data[0]["price"], self.product.price) - self.assertEqual(product_data[0]["active"], self.product.active) + self.assertEqual(product_data["results"][0]["title"], self.product.title) + self.assertEqual(product_data["results"][0]["price"], self.product.price) + self.assertEqual(product_data["results"][0]["active"], self.product.active) def test_create_product(self): + token = Token.objects.get(user__username=self.user.username) + self.client.credentials(HTTP_AUTHORIZATION="Token " + token.key) category = CategoryFactory() data = json.dumps( - {"title": "notebook", "price": 800.00, "categories_id": [category.id]} + {"title": "notebook", "price": 800.00, + "categories_id": [category.id]} ) - print("Data sent1:", data) response = self.client.post( reverse("product-list", kwargs={"version": "v1"}), data=data, content_type="application/json", - # content_type='json' ) self.assertEqual(response.status_code, status.HTTP_201_CREATED) diff --git a/product/urls.py b/product/urls.py index d4484f7..381f1c0 100644 --- a/product/urls.py +++ b/product/urls.py @@ -5,6 +5,7 @@ router = routers.SimpleRouter() router.register(r"product", viewsets.ProductViewSet, basename="product") +router.register(r"category", viewsets.CategoryViewSet, basename="category") urlpatterns = [ path("", include(router.urls)), diff --git a/product/viewsets/__init__.py b/product/viewsets/__init__.py index ab3446c..a68317b 100644 --- a/product/viewsets/__init__.py +++ b/product/viewsets/__init__.py @@ -1 +1,2 @@ from .product_viewset import ProductViewSet +from .category_viewset import CategoryViewSet diff --git a/product/viewsets/__pycache__/__init__.cpython-312.pyc b/product/viewsets/__pycache__/__init__.cpython-312.pyc index 9f51a45..681cce6 100644 Binary files a/product/viewsets/__pycache__/__init__.cpython-312.pyc and b/product/viewsets/__pycache__/__init__.cpython-312.pyc differ diff --git a/product/viewsets/__pycache__/category_viewset.cpython-312.pyc b/product/viewsets/__pycache__/category_viewset.cpython-312.pyc new file mode 100644 index 0000000..262b603 Binary files /dev/null and b/product/viewsets/__pycache__/category_viewset.cpython-312.pyc differ diff --git a/product/viewsets/__pycache__/product_viewset.cpython-312.pyc b/product/viewsets/__pycache__/product_viewset.cpython-312.pyc index 0abb20b..acaec40 100644 Binary files a/product/viewsets/__pycache__/product_viewset.cpython-312.pyc and b/product/viewsets/__pycache__/product_viewset.cpython-312.pyc differ diff --git a/product/viewsets/category_viewset.py b/product/viewsets/category_viewset.py index dcac73a..511d41a 100644 --- a/product/viewsets/category_viewset.py +++ b/product/viewsets/category_viewset.py @@ -8,4 +8,4 @@ class CategoryViewSet(ModelViewSet): serializer_class = CategorySerializer def get_queryset(self): - return Category.objects.all() + return Category.objects.all().order_by("id") diff --git a/product/viewsets/product_viewset.py b/product/viewsets/product_viewset.py index 218cc96..42e3ec2 100644 --- a/product/viewsets/product_viewset.py +++ b/product/viewsets/product_viewset.py @@ -1,9 +1,4 @@ from rest_framework.viewsets import ModelViewSet -from rest_framework.authentication import ( - SessionAuthentication, - BasicAuthentication, - TokenAuthentication, -) from rest_framework.permissions import IsAuthenticated @@ -12,13 +7,7 @@ class ProductViewSet(ModelViewSet): - authentication_classes = [ - SessionAuthentication, - BasicAuthentication, - TokenAuthentication, - ] - permission_classes = [IsAuthenticated] serializer_class = ProductSerializer def get_queryset(self): - return Product.objects.all() + return Product.objects.all().order_by("id") diff --git a/pyproject.toml b/pyproject.toml index c2207b9..a0486e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,21 +2,24 @@ name = "bookstore" version = "0.1.0" description = "Bookstore API" -authors = ["matheus-dev-fullstack "] -readme = "README.md" +authors = ["Daniel Santos "] [tool.poetry.dependencies] -python = "^3.12" -pytest = "^8.0.2" -psycopg2-binary = "*" -factory-boy = "^3.3.0" -django = "^5.0.3" +python = "^3.7" +Django = "^3.2.8" django-rest-framework = "^0.1.0" -django-extensions = "^3.2.3" -django-debug-toolbar = "^4.3.0" -flake8 = "^7.0.0" +django-extensions = "^3.1.3" +django-debug-toolbar = "^3.2.2" +psycopg2-binary = "^2.9.2" +autopep8 = "^1.6.0" +isort = "^5.10.1" +whitenoise = "^5.3.0" +gunicorn = "^20.1.0" +[tool.poetry.dev-dependencies] +pytest = "^6.2.5" +factory-boy = "^3.2.0" [build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 8f52593..9783973 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,16 +8,22 @@ colorama==0.4.6 crashtest==0.4.1 distlib==0.3.8 Django==5.0.3 +django-debug-toolbar==4.3.0 +django-extensions==3.2.3 +django-rest-framework==0.1.0 +djangorestframework==3.15.1 dulwich==0.21.7 factory-boy==3.3.0 Faker==24.0.0 fastjsonschema==2.19.1 filelock==3.14.0 +flake8==7.0.0 idna==3.7 iniconfig==2.0.0 installer==0.7.0 jaraco.classes==3.4.0 keyring==24.3.1 +mccabe==0.7.0 more-itertools==10.2.0 msgpack==1.0.8 packaging==23.2 @@ -30,6 +36,8 @@ poetry-core==1.9.0 poetry-plugin-export==1.7.1 psycopg2==2.9.9 ptyprocess==0.7.0 +pycodestyle==2.11.1 +pyflakes==3.2.0 pyproject_hooks==1.1.0 pytest==8.0.2 python-dateutil==2.9.0.post0 @@ -45,3 +53,5 @@ trove-classifiers==2024.4.10 tzdata==2024.1 urllib3==2.2.1 virtualenv==20.26.1 + +# Exercício EBAC Build