sample api work
This commit is contained in:
parent
dffa0a86f8
commit
c18430c083
11 changed files with 325 additions and 38 deletions
37
apps/crud/migrations/0001_initial.py
Normal file
37
apps/crud/migrations/0001_initial.py
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
# Generated by Django 5.0.6 on 2024-07-20 11:50
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
migrations.swappable_dependency(settings.OAUTH2_PROVIDER_APPLICATION_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Plan',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('record_count', models.IntegerField(default=0)),
|
||||||
|
('record_limit', models.IntegerField(default=0)),
|
||||||
|
('application', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.OAUTH2_PROVIDER_APPLICATION_MODEL)),
|
||||||
|
('owner', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Data',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('data', models.JSONField(default=dict)),
|
||||||
|
('user', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)),
|
||||||
|
('plan', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='crud.plan')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Generated by Django 5.0.6 on 2024-07-20 14:04
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('crud', '0001_initial'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='plan',
|
||||||
|
name='client_id',
|
||||||
|
field=models.CharField(blank=True, max_length=255, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterUniqueTogether(
|
||||||
|
name='data',
|
||||||
|
unique_together={('user', 'plan')},
|
||||||
|
),
|
||||||
|
]
|
||||||
0
apps/crud/migrations/__init__.py
Normal file
0
apps/crud/migrations/__init__.py
Normal file
12
apps/crud/serializers.py
Normal file
12
apps/crud/serializers.py
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
from rest_framework import serializers
|
||||||
|
from .models import Data, Plan
|
||||||
|
|
||||||
|
|
||||||
|
class DataSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Data
|
||||||
|
fields = ('user',
|
||||||
|
'data',
|
||||||
|
)
|
||||||
|
|
||||||
|
read_only_fields = ['user']
|
||||||
57
apps/crud/urls.py
Normal file
57
apps/crud/urls.py
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
from rest_framework import routers
|
||||||
|
from rest_framework.routers import DefaultRouter, DynamicRoute, Route
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
|
||||||
|
class CRUDRouter(DefaultRouter):
|
||||||
|
routes = [
|
||||||
|
# List route.
|
||||||
|
Route(
|
||||||
|
url=r'^{prefix}{trailing_slash}$',
|
||||||
|
mapping={
|
||||||
|
'get': 'list',
|
||||||
|
'post': 'create'
|
||||||
|
},
|
||||||
|
name='{basename}-list',
|
||||||
|
detail=False,
|
||||||
|
initkwargs={'suffix': 'List'}
|
||||||
|
),
|
||||||
|
# Dynamically generated list routes. Generated using
|
||||||
|
# @action(detail=False) decorator on methods of the viewset.
|
||||||
|
DynamicRoute(
|
||||||
|
url=r'^{prefix}/{url_path}{trailing_slash}$',
|
||||||
|
name='{basename}-{url_name}',
|
||||||
|
detail=False,
|
||||||
|
initkwargs={}
|
||||||
|
),
|
||||||
|
# Detail route.
|
||||||
|
Route(
|
||||||
|
url=r'^{prefix}/item{trailing_slash}$',
|
||||||
|
mapping={
|
||||||
|
'get': 'retrieve',
|
||||||
|
'put': 'update',
|
||||||
|
'patch': 'partial_update',
|
||||||
|
'delete': 'destroy'
|
||||||
|
},
|
||||||
|
name='{basename}-detail',
|
||||||
|
detail=True,
|
||||||
|
initkwargs={'suffix': 'Instance'}
|
||||||
|
),
|
||||||
|
# Dynamically generated detail routes. Generated using
|
||||||
|
# @action(detail=True) decorator on methods of the viewset.
|
||||||
|
DynamicRoute(
|
||||||
|
url=r'^{prefix}/item/{url_path}{trailing_slash}$',
|
||||||
|
name='{basename}-{url_name}',
|
||||||
|
detail=True,
|
||||||
|
initkwargs={}
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
router = CRUDRouter()
|
||||||
|
|
||||||
|
app_name = 'crud'
|
||||||
|
|
||||||
|
router.register('', views.DataViewSet, basename='crud')
|
||||||
|
|
||||||
|
urlpatterns = router.urls
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
# Generated by Django 5.0.6 on 2024-07-04 11:38
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('gooyal_oauth2', '0001_initial'),
|
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='accesstoken',
|
|
||||||
name='client_owner',
|
|
||||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
# models
|
# models
|
||||||
|
import uuid
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from oauth2_provider.models import AbstractApplication, AbstractAccessToken, AbstractGrant, AbstractRefreshToken, \
|
from oauth2_provider.models import AbstractApplication, AbstractAccessToken, AbstractGrant, AbstractRefreshToken, \
|
||||||
AbstractIDToken
|
AbstractIDToken
|
||||||
|
|
||||||
|
|
||||||
class AccessToken(AbstractAccessToken):
|
class AccessToken(AbstractAccessToken):
|
||||||
|
id=None
|
||||||
|
uuid = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4, unique=True, db_index=True)
|
||||||
detail = models.JSONField(null=True, blank=True)
|
detail = models.JSONField(null=True, blank=True)
|
||||||
client_id = models.CharField(max_length=255, null=True, blank=True)
|
client_id = models.CharField(max_length=255, null=True, blank=True)
|
||||||
client_owner = models.ForeignKey('users.User', on_delete=models.PROTECT, null=True, blank=True)
|
client_owner = models.ForeignKey('users.User', on_delete=models.PROTECT, null=True, blank=True)
|
||||||
|
|
@ -14,21 +17,29 @@ class AccessToken(AbstractAccessToken):
|
||||||
|
|
||||||
|
|
||||||
class Application(AbstractApplication):
|
class Application(AbstractApplication):
|
||||||
|
id=None
|
||||||
|
uuid = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4, unique=True, db_index=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = False
|
abstract = False
|
||||||
|
|
||||||
|
|
||||||
class Grant(AbstractGrant):
|
class Grant(AbstractGrant):
|
||||||
|
id = None
|
||||||
|
uuid = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4, unique=True, db_index=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = False
|
abstract = False
|
||||||
|
|
||||||
|
|
||||||
class RefreshToken(AbstractRefreshToken):
|
class RefreshToken(AbstractRefreshToken):
|
||||||
|
id = None
|
||||||
|
uuid = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4, unique=True, db_index=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = False
|
abstract = False
|
||||||
|
|
||||||
|
|
||||||
class IDToken(AbstractIDToken):
|
class IDToken(AbstractIDToken):
|
||||||
|
id = None
|
||||||
|
uuid = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4, unique=True, db_index=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = False
|
abstract = False
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,15 +115,17 @@ class OAuth2Validator(BaseOAuth2Validator): # pylint: disable=w0223
|
||||||
log.exception("Introspection: Failed to parse response as json")
|
log.exception("Introspection: Failed to parse response as json")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
client_owner_value = None
|
owner_value = None
|
||||||
|
application_uuid = None
|
||||||
if "active" in application_introspection_content and application_introspection_content["active"] is True:
|
if "active" in application_introspection_content and application_introspection_content["active"] is True:
|
||||||
if "client_owner" in application_introspection_content:
|
if "owner" in application_introspection_content:
|
||||||
client_owner_value = application_introspection_content["client_owner"]
|
owner_value = application_introspection_content["owner"]
|
||||||
|
application_uuid = application_introspection_content.get("uuid")
|
||||||
|
|
||||||
if client_owner_value:
|
if owner_value:
|
||||||
client_owner, _ = UserModel.objects.get_or_create(pk=client_owner_value)
|
owner, _ = UserModel.objects.get_or_create(pk=owner_value)
|
||||||
else:
|
else:
|
||||||
client_owner = None
|
owner = None
|
||||||
|
|
||||||
if "username" in content:
|
if "username" in content:
|
||||||
user = self.get_or_create_user_from_content(content)
|
user = self.get_or_create_user_from_content(content)
|
||||||
|
|
@ -149,13 +151,17 @@ class OAuth2Validator(BaseOAuth2Validator): # pylint: disable=w0223
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO: get application owner and put it here
|
# TODO: get application owner and put it here
|
||||||
|
application, _created = Application.objects.get_or_create(
|
||||||
|
client_id=content["client_id"],
|
||||||
|
uuid=application_introspection_content["uuid"]
|
||||||
|
)
|
||||||
access_token, _created = AccessToken.objects.update_or_create(
|
access_token, _created = AccessToken.objects.update_or_create(
|
||||||
token=token,
|
token=token,
|
||||||
defaults={
|
defaults={
|
||||||
"user": user,
|
"user": user,
|
||||||
"client_id": content.get("client_id", ""),
|
"client_id": content["client_id"],
|
||||||
"client_owner": client_owner,
|
"client_owner": owner,
|
||||||
"application": None,
|
"application_id": application_uuid,
|
||||||
"scope": scope,
|
"scope": scope,
|
||||||
"expires": expires,
|
"expires": expires,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Generated by Django 5.0.6 on 2024-07-20 07:38
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('users', '0004_alter_oauthcode_code_verifier'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='user',
|
||||||
|
name='balance',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='user',
|
||||||
|
name='iban',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='user',
|
||||||
|
name='iban_verified',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='user',
|
||||||
|
name='last_checkout_request',
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/5.0/ref/settings/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from decouple import config
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
@ -23,39 +24,94 @@ BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
SECRET_KEY = 'django-insecure-e_%y)zafwj5!_euf29(fv5ku#yw*#6nl%)ukiku2i8o#c@donr'
|
SECRET_KEY = 'django-insecure-e_%y)zafwj5!_euf29(fv5ku#yw*#6nl%)ukiku2i8o#c@donr'
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = True
|
DEBUG = config('DEBUG', default=True, cast=bool)
|
||||||
|
|
||||||
ALLOWED_HOSTS = []
|
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = ['*']
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
|
# django apps
|
||||||
'django.contrib.admin',
|
'django.contrib.admin',
|
||||||
'django.contrib.auth',
|
'django.contrib.auth',
|
||||||
'django.contrib.contenttypes',
|
'django.contrib.contenttypes',
|
||||||
'django.contrib.sessions',
|
'django.contrib.sessions',
|
||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
|
|
||||||
|
# pip installed apps
|
||||||
|
'drf_spectacular',
|
||||||
|
'oauth2_provider',
|
||||||
|
'rest_framework',
|
||||||
|
'corsheaders',
|
||||||
|
'crispy_forms',
|
||||||
|
'crispy_bootstrap5',
|
||||||
|
'django_filters',
|
||||||
|
'jalali_date',
|
||||||
|
|
||||||
|
# local apps
|
||||||
|
'apps.core',
|
||||||
|
'apps.users',
|
||||||
|
'apps.gooyal_oauth2',
|
||||||
|
'apps.crud',
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
'django.middleware.security.SecurityMiddleware',
|
'django.middleware.security.SecurityMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
|
# 'django.middleware.locale.LocaleMiddleware',
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
|
'oauth2_provider.middleware.OAuth2TokenMiddleware',
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
|
'corsheaders.middleware.CorsMiddleware',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
OAUTH2_PROVIDER_APPLICATION_MODEL = "gooyal_oauth2.Application"
|
||||||
|
OAUTH2_PROVIDER_ACCESS_TOKEN_MODEL = "gooyal_oauth2.AccessToken"
|
||||||
|
OAUTH2_PROVIDER_ID_TOKEN_MODEL = "gooyal_oauth2.IDToken"
|
||||||
|
OAUTH2_PROVIDER_GRANT_MODEL = "gooyal_oauth2.Grant"
|
||||||
|
OAUTH2_PROVIDER_REFRESH_TOKEN_MODEL = "gooyal_oauth2.RefreshToken"
|
||||||
|
|
||||||
|
BASE_OAUTH2_PROVIDER_URL = "https://accounts.gooyal.com"
|
||||||
|
CLIENT_ID = config('CLIENT_ID')
|
||||||
|
CLIENT_SECRET = config('CLIENT_SECRET')
|
||||||
|
SCOPES = config('SCOPES', default='')
|
||||||
|
OAUTH2_PROVIDER = {
|
||||||
|
# this is the list of available scopes
|
||||||
|
# 'SCOPES_BACKEND_CLASS': 'apps.gooyal_oauth2.scopes.Scopes',
|
||||||
|
# 'SCOPES': {'read': 'Read scope',
|
||||||
|
# 'write': 'Write scope',
|
||||||
|
# 'groups': 'Access to your groups',
|
||||||
|
# 'introspection': 'Introspect token scope'},
|
||||||
|
'OAUTH2_VALIDATOR_CLASS': 'apps.gooyal_oauth2.validators.OAuth2Validator',
|
||||||
|
'RESOURCE_SERVER_INTROSPECTION_URL': BASE_OAUTH2_PROVIDER_URL + '/oauth2/introspect/',
|
||||||
|
# 'RESOURCE_SERVER_AUTH_TOKEN': '3yUqsWtwKYKHnfivFcJu', # OR this but not both:
|
||||||
|
'RESOURCE_SERVER_INTROSPECTION_CREDENTIALS': (CLIENT_ID, CLIENT_SECRET),
|
||||||
|
}
|
||||||
|
|
||||||
|
REST_FRAMEWORK = {
|
||||||
|
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||||
|
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
|
||||||
|
'rest_framework.authentication.SessionAuthentication',
|
||||||
|
),
|
||||||
|
'DEFAULT_PERMISSION_CLASSES': (
|
||||||
|
'rest_framework.permissions.IsAuthenticated',
|
||||||
|
),
|
||||||
|
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
|
||||||
|
'PAGE_SIZE': 20,
|
||||||
|
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
|
||||||
|
}
|
||||||
|
|
||||||
ROOT_URLCONF = 'data_crud.urls'
|
ROOT_URLCONF = 'data_crud.urls'
|
||||||
|
|
||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
{
|
{
|
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||||
'DIRS': [BASE_DIR / 'templates']
|
'DIRS': [BASE_DIR / 'templates'],
|
||||||
,
|
|
||||||
'APP_DIRS': True,
|
'APP_DIRS': True,
|
||||||
'OPTIONS': {
|
'OPTIONS': {
|
||||||
'context_processors': [
|
'context_processors': [
|
||||||
|
|
@ -68,6 +124,10 @@ TEMPLATES = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
AUTHENTICATION_BACKENDS = (
|
||||||
|
'oauth2_provider.backends.OAuth2Backend',
|
||||||
|
'django.contrib.auth.backends.ModelBackend',
|
||||||
|
)
|
||||||
WSGI_APPLICATION = 'data_crud.wsgi.application'
|
WSGI_APPLICATION = 'data_crud.wsgi.application'
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -76,8 +136,12 @@ WSGI_APPLICATION = 'data_crud.wsgi.application'
|
||||||
|
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {
|
'default': {
|
||||||
'ENGINE': 'django.db.backends.sqlite3',
|
'ENGINE': 'django.db.backends.postgresql',
|
||||||
'NAME': BASE_DIR / 'db.sqlite3',
|
'NAME': config('DB_NAME'),
|
||||||
|
'USER': config('DB_USER'),
|
||||||
|
'PASSWORD': config('DB_PASSWORD'),
|
||||||
|
'HOST': config('DB_HOST', '127.0.0.1'),
|
||||||
|
'PORT': config('DB_PORT', ''),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,15 +174,61 @@ TIME_ZONE = 'UTC'
|
||||||
|
|
||||||
USE_I18N = True
|
USE_I18N = True
|
||||||
|
|
||||||
|
USE_L10N = True
|
||||||
|
|
||||||
USE_TZ = True
|
USE_TZ = True
|
||||||
|
|
||||||
|
LOCALE_PATHS = [
|
||||||
|
BASE_DIR / 'locale',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
# Static files (CSS, JavaScript, Images)
|
# Static files (CSS, JavaScript, Images)
|
||||||
# https://docs.djangoproject.com/en/5.0/howto/static-files/
|
# https://docs.djangoproject.com/en/5.0/howto/static-files/
|
||||||
|
|
||||||
|
|
||||||
|
MEDIA_URL = 'media/'
|
||||||
|
MEDIA_ROOT = BASE_DIR / 'media'
|
||||||
|
|
||||||
STATIC_URL = 'static/'
|
STATIC_URL = 'static/'
|
||||||
|
|
||||||
|
if DEBUG == True:
|
||||||
|
STATICFILES_DIRS = (
|
||||||
|
BASE_DIR / 'static',
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
STATIC_ROOT = BASE_DIR / 'static'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Default primary key field type
|
# Default primary key field type
|
||||||
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
|
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
|
||||||
|
|
||||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
LOGIN_URL = '/users/login/request/'
|
||||||
|
LOGIN_REDIRECT_URL = '/'
|
||||||
|
|
||||||
|
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
|
||||||
|
CRISPY_TEMPLATE_PACK = "bootstrap5"
|
||||||
|
|
||||||
|
SPECTACULAR_SETTINGS = {
|
||||||
|
'TITLE': 'srv',
|
||||||
|
'DESCRIPTION': 'service api reference',
|
||||||
|
'VERSION': '1.0.0',
|
||||||
|
'SERVE_INCLUDE_SCHEMA': False,
|
||||||
|
# OTHER SETTINGS
|
||||||
|
}
|
||||||
|
|
||||||
|
AUTH_USER_MODEL = 'users.User'
|
||||||
|
CORS_ORIGIN_ALLOW_ALL = True
|
||||||
|
CSRF_TRUSTED_ORIGINS = ['http://*.gooyal.com', 'https://*.gooyal.com']
|
||||||
|
|
||||||
|
JALALI_DATE_DEFAULTS = {
|
||||||
|
'Strftime': {
|
||||||
|
'date': '%Y/%m/%d',
|
||||||
|
'datetime': '%H:%M:%S _ %Y/%m/%d',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,31 @@ Including another URLconf
|
||||||
1. Import the include() function: from django.urls import include, path
|
1. Import the include() function: from django.urls import include, path
|
||||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
"""
|
"""
|
||||||
|
from django.conf import settings
|
||||||
|
# from django.conf.urls import url
|
||||||
|
from django.conf.urls.static import static
|
||||||
|
from django.urls import path, include
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.urls import path
|
from rest_framework import permissions
|
||||||
|
from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView
|
||||||
|
|
||||||
|
|
||||||
|
# from apps.gooyal_oauth2.views.introspect import introspect_token
|
||||||
|
|
||||||
|
from django.contrib.auth import urls as auth_urls
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
path('swagger/', SpectacularAPIView.as_view(), name='schema'),
|
||||||
|
path('swagger/swagger-ui/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
|
||||||
|
path('swagger/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
|
||||||
|
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
|
path('', include('apps.core.urls')),
|
||||||
|
path('users/', include('apps.users.urls')),
|
||||||
|
path('oauth2/', include('oauth2_provider.urls', namespace='oauth2_provider')),
|
||||||
|
path('crud/', include('apps.crud.urls', namespace='crud')),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue