diff --git a/django_test_app/bookings/__init__.py b/django_test_app/bookings/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/django_test_app/bookings/apps.py b/django_test_app/bookings/apps.py new file mode 100644 index 0000000..ac47a31 --- /dev/null +++ b/django_test_app/bookings/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class BookingsConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "django_test_app.bookings" diff --git a/django_test_app/bookings/migrations/0001_initial.py b/django_test_app/bookings/migrations/0001_initial.py new file mode 100644 index 0000000..498d3f6 --- /dev/null +++ b/django_test_app/bookings/migrations/0001_initial.py @@ -0,0 +1,33 @@ +# Generated by Django 4.2.15 on 2024-09-13 04:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="Booking", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("booking_agent_name", models.CharField(max_length=64)), + ("booking_description", models.TextField()), + ("booking_type", models.CharField(max_length=100)), + ("booking_date", models.DateField()), + ("created", models.DateTimeField(auto_now_add=True)), + ("updated", models.DateTimeField(auto_now=True)), + ], + ), + ] diff --git a/django_test_app/bookings/migrations/__init__.py b/django_test_app/bookings/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/django_test_app/bookings/models.py b/django_test_app/bookings/models.py new file mode 100644 index 0000000..3c07d3f --- /dev/null +++ b/django_test_app/bookings/models.py @@ -0,0 +1,16 @@ +from django.db import models + + +# Create your models here. +class Booking(models.Model): + """Test Tenant object.""" + + booking_agent_name = models.CharField(max_length=64) + booking_description = models.TextField() + booking_type = models.CharField(max_length=100) + booking_date = models.DateField() + created = models.DateTimeField(auto_now_add=True) + updated = models.DateTimeField(auto_now=True) + + def __str__(self): + return self.booking_agent_name diff --git a/django_test_app/bookings/serializers.py b/django_test_app/bookings/serializers.py new file mode 100644 index 0000000..12ebc40 --- /dev/null +++ b/django_test_app/bookings/serializers.py @@ -0,0 +1,9 @@ +from rest_framework import serializers + +from django_test_app.bookings.models import Booking + + +class BookingSerializer(serializers.ModelSerializer): + class Meta: + model = Booking + fields = "__all__" diff --git a/django_test_app/bookings/views.py b/django_test_app/bookings/views.py new file mode 100644 index 0000000..52feff1 --- /dev/null +++ b/django_test_app/bookings/views.py @@ -0,0 +1,12 @@ +from rest_framework import viewsets +from rest_framework.permissions import IsAuthenticated + +from django_test_app.bookings.models import Booking +from django_test_app.bookings.serializers import BookingSerializer + + +# Create your views here. +class BookingViewSet(viewsets.ModelViewSet): + queryset = Booking.objects.all() + serializer_class = BookingSerializer + permission_classes = (IsAuthenticated,) diff --git a/django_test_app/companies/migrations/0001_initial.py b/django_test_app/companies/migrations/0001_initial.py index b120d66..dea95b7 100644 --- a/django_test_app/companies/migrations/0001_initial.py +++ b/django_test_app/companies/migrations/0001_initial.py @@ -1,6 +1,7 @@ from django.db import migrations, models -from django_tenants.postgresql_backend.base import \ - _check_schema_name as check_schema_name +from django_tenants.postgresql_backend.base import ( + _check_schema_name as check_schema_name, +) class Migration(migrations.Migration): diff --git a/django_test_app/companies/models.py b/django_test_app/companies/models.py index 9e6037e..c75b438 100644 --- a/django_test_app/companies/models.py +++ b/django_test_app/companies/models.py @@ -1,6 +1,5 @@ from django.db import models from django_tenants.models import DomainMixin - from tenant_users.tenants.models import TenantBase _NameFieldLength = 64 diff --git a/django_test_app/settings.py b/django_test_app/settings.py index 7d79402..06961fd 100644 --- a/django_test_app/settings.py +++ b/django_test_app/settings.py @@ -8,7 +8,9 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/3.2/ref/settings/ """ + import os +from datetime import timedelta from pathlib import Path # Build paths inside the project like this: BASE_DIR / 'subdir'. @@ -39,6 +41,10 @@ "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", + # DRF apps + "rest_framework", + "rest_framework.authtoken", + "rest_framework_simplejwt", # django-tenant-users apps "tenant_users.permissions", "tenant_users.tenants", @@ -51,6 +57,8 @@ "django.contrib.auth", "django.contrib.contenttypes", "tenant_users.permissions", + # Test project apps - tenant specific apps + "django_test_app.bookings", ] INSTALLED_APPS = list(SHARED_APPS) + [ @@ -67,6 +75,28 @@ TENANT_MODEL = "companies.Company" TENANT_DOMAIN_MODEL = "companies.Domain" +# DRF Configuration +REST_FRAMEWORK = { + "NON_FIELD_ERRORS_KEY": "errors", + "DEFAULT_AUTHENTICATION_CLASSES": [ + "rest_framework_simplejwt.authentication.JWTAuthentication", + ], + "DEFAULT_PERMISSION_CLASSES": [ + "rest_framework.permissions.IsAuthenticated", + ], + "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination", + "PAGE_SIZE": 10, +} + +# Simple JWT Configuration +SIMPLE_JWT = { + "AUTH_HEADER_TYPES": ("JWT",), + "ACCESS_TOKEN_LIFETIME": timedelta(days=20), +} + +# Djoser Configuration +# In the event you are using Djoser with DRF for authentication, you easily set it up by following the Djoser documentation - https://djoser.readthedocs.io/en/latest/ + MIDDLEWARE = [ "django_tenants.middleware.main.TenantMainMiddleware", diff --git a/django_test_app/users/migrations/0001_initial.py b/django_test_app/users/migrations/0001_initial.py index e4094b0..2b3566a 100644 --- a/django_test_app/users/migrations/0001_initial.py +++ b/django_test_app/users/migrations/0001_initial.py @@ -1,5 +1,4 @@ from django.db import migrations, models - from tenant_users.permissions.models import PermissionsMixinFacade diff --git a/django_test_app/users/models.py b/django_test_app/users/models.py index 63ee365..3799ebe 100644 --- a/django_test_app/users/models.py +++ b/django_test_app/users/models.py @@ -1,5 +1,4 @@ from django.db import models - from tenant_users.tenants.models import UserProfile _NameFieldLength = 64 diff --git a/poetry.lock b/poetry.lock index b6f856f..49be159 100644 --- a/poetry.lock +++ b/poetry.lock @@ -610,6 +610,45 @@ files = [ [package.dependencies] Django = ">=2.1,<5.2" +[[package]] +name = "djangorestframework" +version = "3.15.2" +description = "Web APIs for Django, made easy." +optional = false +python-versions = ">=3.8" +files = [ + {file = "djangorestframework-3.15.2-py3-none-any.whl", hash = "sha256:2b8871b062ba1aefc2de01f773875441a961fefbf79f5eed1e32b2f096944b20"}, + {file = "djangorestframework-3.15.2.tar.gz", hash = "sha256:36fe88cd2d6c6bec23dca9804bab2ba5517a8bb9d8f47ebc68981b56840107ad"}, +] + +[package.dependencies] +"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} +django = ">=4.2" + +[[package]] +name = "djangorestframework-simplejwt" +version = "5.3.1" +description = "A minimal JSON Web Token authentication plugin for Django REST Framework" +optional = false +python-versions = ">=3.8" +files = [ + {file = "djangorestframework_simplejwt-5.3.1-py3-none-any.whl", hash = "sha256:381bc966aa46913905629d472cd72ad45faa265509764e20ffd440164c88d220"}, + {file = "djangorestframework_simplejwt-5.3.1.tar.gz", hash = "sha256:6c4bd37537440bc439564ebf7d6085e74c5411485197073f508ebdfa34bc9fae"}, +] + +[package.dependencies] +django = ">=3.2" +djangorestframework = ">=3.12" +pyjwt = ">=1.7.1,<3" + +[package.extras] +crypto = ["cryptography (>=3.3.1)"] +dev = ["Sphinx (>=1.6.5,<2)", "cryptography", "flake8", "freezegun", "ipython", "isort", "pep8", "pytest", "pytest-cov", "pytest-django", "pytest-watch", "pytest-xdist", "python-jose (==3.3.0)", "sphinx_rtd_theme (>=0.1.9)", "tox", "twine", "wheel"] +doc = ["Sphinx (>=1.6.5,<2)", "sphinx_rtd_theme (>=0.1.9)"] +lint = ["flake8", "isort", "pep8"] +python-jose = ["python-jose (==3.3.0)"] +test = ["cryptography", "freezegun", "pytest", "pytest-cov", "pytest-django", "pytest-xdist", "tox"] + [[package]] name = "doc8" version = "1.1.2" @@ -1496,6 +1535,23 @@ files = [ [package.extras] plugins = ["importlib-metadata"] +[[package]] +name = "pyjwt" +version = "2.9.0" +description = "JSON Web Token implementation in Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "PyJWT-2.9.0-py3-none-any.whl", hash = "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850"}, + {file = "pyjwt-2.9.0.tar.gz", hash = "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c"}, +] + +[package.extras] +crypto = ["cryptography (>=3.4.0)"] +dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"] +docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] +tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] + [[package]] name = "pytest" version = "8.3.2" @@ -2327,4 +2383,4 @@ test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-it [metadata] lock-version = "2.0" python-versions = "^3.8.1" -content-hash = "dffeebfc1953c44bf9dfa14faa9818bd839b6326a32a9bf67c5d7d3c64edabba" +content-hash = "1b4e636cebb9296c0ceb3538dda88e2f4608fe49970944d41a8354b744e02947" diff --git a/pyproject.toml b/pyproject.toml index 793fef5..8632306 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,6 +54,7 @@ classifiers = [ python = "^3.8.1" Django = ">=4.2" django-tenants = "^3.6" +djangorestframework-simplejwt = "^5.3.1" [tool.poetry.group.test.dependencies]