Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
f2818b8
FIX[ADDED POSTGRES CONNECTION AND SWAGGER UI]
JhimmieC137 Jul 18, 2024
e77d3fd
FIX[ADDED USER VIEWSET]
JhimmieC137 Jul 18, 2024
e6d7de7
FIX[ADDED AUTH VIEWSET]
JhimmieC137 Jul 18, 2024
77b3a4b
FIX[ADDED JWT TOKENS]
JhimmieC137 Jul 18, 2024
5549e45
FIX[RESOLVED AUTH BUGS AND ERROR HANDLING]
JhimmieC137 Jul 19, 2024
36742e4
FIX[ADDED CUSTOM PAGINATION]
JhimmieC137 Jul 19, 2024
7299fb9
FIX[ADDED CATEGORY, PRODUCT AND ORDER MODELS]
JhimmieC137 Jul 19, 2024
2149792
FIX[ADDED CATEGORY, PRODUCT AND ORDER VIEWSETS]
JhimmieC137 Jul 19, 2024
a253960
FIX[ADDED EXTRA FIELDS TO PRODUCT AND ORDER MODEL]
JhimmieC137 Jul 20, 2024
9a6788a
FIX[ADDED SEARCH QUERY INPUT ON SWAGGER UI]
JhimmieC137 Jul 21, 2024
7901b60
FIX[ADDED CUSTOM PERMISSION]
JhimmieC137 Jul 21, 2024
835c2ef
FIX[ADDED CUSTOM EXCEPTION FOR AUTH]
JhimmieC137 Jul 21, 2024
7f02854
FIX[ISOLATED VIWSETS TO SEPERATED FILES]
JhimmieC137 Jul 21, 2024
385f806
FIX[ADDED SUCCESS TESTS FOR ALL ENDPOINTS]
JhimmieC137 Jul 24, 2024
b68fcb9
FIX[ADDED SUCCESS TESTS FOR ALL ENDPOINTS]
JhimmieC137 Jul 24, 2024
e22f3e3
FIX[ADDED SUCCESS TESTS FOR ALL ENDPOINTS]
JhimmieC137 Jul 24, 2024
5dea435
FIX[ADDED ALL INSTALLED LIBRARY TO RQUIREMENTS]
JhimmieC137 Jul 24, 2024
2ff0f8f
FIX[ADDED POSTGRES CREDENTIALS]
JhimmieC137 Jul 24, 2024
dc6f610
FIX[ADDED POSTGRES CREDENTIALS]
JhimmieC137 Jul 24, 2024
bc83f3e
FIX[ADDED POSTGRES CREDENTIALS]
JhimmieC137 Jul 24, 2024
3a27edf
FIX[ADDED GUNICORN NGINX FOR PROJECT SERVER]
JhimmieC137 Jul 24, 2024
a1a77fe
FIX[ADDED CMD RENDER DEPLOYMENT]
JhimmieC137 Aug 20, 2024
f11a55c
FIX[ADDED WILDCARD FOR ALLOWED HOSTS]
JhimmieC137 Aug 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .env.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# DB CREDENTIALS
DB_NAME=seca
DB_USER=postgres
DB_PASSWORD=password
DB_HOST=db
DB_PORT=5432

# PAGE LIMIT
DJANGO_PAGINATION_LIMIT=10

# DEBUG MODE
DEBUG=True
99 changes: 93 additions & 6 deletions app/app/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@
https://docs.djangoproject.com/en/4.0/ref/settings/
"""

import os
from datetime import timedelta
from pathlib import Path
from dotenv import load_dotenv

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

load_dotenv()

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/
Expand All @@ -23,9 +27,9 @@
SECRET_KEY = 'django-insecure-h-h69cr05lmc*w4vtkf+5qltg8#&#xf8fe(v9j9oxs-*-^#vjd'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
DEBUG = os.getenv('DEBUG')

ALLOWED_HOSTS = []
ALLOWED_HOSTS = ['*']


# Application definition
Expand All @@ -37,7 +41,11 @@
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'core'
'rest_framework_simplejwt',
'rest_framework_simplejwt.token_blacklist',
'rest_framework',
'core',
'drf_yasg',
]

MIDDLEWARE = [
Expand Down Expand Up @@ -76,11 +84,17 @@

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.getenv('DB_NAME'),
'USER': os.getenv('DB_USER'),
'PASSWORD': os.getenv('DB_PASSWORD'),
'HOST': os.getenv('DB_HOST'),
'PORT': os.getenv('DB_PORT'),
}
}

# General
APPEND_SLASH = False

# Password validation
# https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators
Expand All @@ -101,6 +115,36 @@
]



# Django Rest Framework
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'core.pagination.CustomPagination',
'PAGE_SIZE': int(os.getenv('DJANGO_PAGINATION_LIMIT', 10)),
'DATETIME_FORMAT': '%Y-%m-%dT%H:%M:%S.%fZ',
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
),
'DEFAULT_PERMISSION_CLASSES': [
# 'rest_framework.permissions.IsAuthenticated',
],
"EXCEPTION_HANDLER": ("core.exceptions.custom_exception_handler"),
'DEFAULT_AUTHENTICATION_CLASSES': (
# 'rest_framework.authentication.BasicAuthentication',
# 'rest_framework.authentication.SessionAuthentication',
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle',
'rest_framework.throttling.ScopedRateThrottle',
],
'DEFAULT_THROTTLE_RATES': {'anon': '100/second', 'user': '1000/second', 'subscribe': '60/minute'},
'TEST_REQUEST_DEFAULT_FORMAT': 'json',
}



# Internationalization
# https://docs.djangoproject.com/en/4.0/topics/i18n/

Expand All @@ -117,10 +161,53 @@
# https://docs.djangoproject.com/en/4.0/howto/static-files/

STATIC_URL = 'static/'
STATIC_ROOT = 'static/'

STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
)

# Default primary key field type
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

AUTH_USER_MODEL = 'core.User'
AUTH_USER_MODEL = 'core.User'

# JWT configuration
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
'ROTATE_REFRESH_TOKENS': False,
'BLACKLIST_AFTER_ROTATION': True,
'UPDATE_LAST_LOGIN': False,
'ALGORITHM': 'HS256',
'SIGNING_KEY': SECRET_KEY,
'VERIFYING_KEY': None,
'AUDIENCE': None,
'ISSUER': None,
'AUTH_HEADER_TYPES': ('Bearer',),
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
'USER_ID_FIELD': 'id',
'USER_ID_CLAIM': 'user_id',
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
'TOKEN_TYPE_CLAIM': 'token_type',
'JTI_CLAIM': 'jti',
'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
}

LOGIN_URL = 'rest_framework:login'
LOGOUT_URL = 'rest_framework:logout'

SWAGGER_SETTINGS = {
'SECURITY_DEFINITIONS': {
'Bearer': {
'type': 'apiKey',
'name': 'Authorization',
'in': 'header',
}
}
}
34 changes: 33 additions & 1 deletion app/app/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,40 @@
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.urls import path, include, re_path

from rest_framework.routers import DefaultRouter
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)

from drf_yasg.views import get_schema_view
from drf_yasg import openapi

from core.urls import auth_router, users_router, category_router, product_router, order_router

router = DefaultRouter()

schema_view = get_schema_view(
openapi.Info(title="Simple E-commerce API", default_version='v1'),
public=True,
)

router.registry.extend(auth_router.registry)
router.registry.extend(users_router.registry)
router.registry.extend(category_router.registry)
router.registry.extend(product_router.registry)
router.registry.extend(order_router.registry)


urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include(router.urls)),
path('api/v1/auth/', include('rest_framework.urls', namespace='rest_framework')),
path('api/v1/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
# swagger docs
re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),
re_path(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
re_path(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
]
31 changes: 30 additions & 1 deletion app/core/admin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,34 @@
"""Manage admin page for main app."""
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin

# from django.contrib import admin
from core.models import *

# Register your models here.
# @admin.register(User)
# class UserAdmin(UserAdmin):
# ordering = ('email',)
# list_display = ('name',)
# fieldsets = (
# (None, {'fields': ('id',)}),
# (
# ('Personal info'),
# {
# 'fields': (
# 'first_name',
# 'last_name',
# 'name',
# 'email',
# 'username',
# 'password',
# )
# },
# ),
# (('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions',)}),
# (('Important dates'), {'fields': ('last_login', 'date_joined')}),
# )

admin.site.register(User)
admin.site.register(Category)
admin.site.register(Product)
admin.site.register(Order)
11 changes: 11 additions & 0 deletions app/core/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from rest_framework.views import exception_handler

def custom_exception_handler(exc, context):
response = exception_handler(exc, context)

if response is not None:
response.data['status_code'] = response.status_code
response.data['message'] = response.data['detail']
del response.data['detail']

return response
43 changes: 43 additions & 0 deletions app/core/migrations/0002_category_product_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Generated by Django 4.0.1 on 2024-07-19 10:18

import datetime
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('core', '0001_initial'),
]

operations = [
migrations.CreateModel(
name='Category',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=50, unique=True)),
('description', models.TextField(max_length=700, null=True)),
],
),
migrations.CreateModel(
name='Product',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=50, unique=True)),
('description', models.TextField(max_length=700, null=True)),
('price', models.BigIntegerField()),
('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.category')),
],
),
migrations.CreateModel(
name='Order',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('date_created', models.CharField(default=datetime.datetime(2024, 7, 19, 10, 18, 35, 250348), max_length=20)),
('product', models.ManyToManyField(to='core.Product')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 4.0.1 on 2024-07-19 15:03

import datetime
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('core', '0002_category_product_order'),
]

operations = [
migrations.AlterField(
model_name='order',
name='date_created',
field=models.CharField(default=datetime.datetime(2024, 7, 19, 15, 3, 14, 231429), max_length=20),
),
migrations.AlterField(
model_name='product',
name='price',
field=models.FloatField(),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Generated by Django 4.0.1 on 2024-07-19 18:42

import datetime
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('core', '0003_alter_order_date_created_alter_product_price'),
]

operations = [
migrations.AlterModelOptions(
name='order',
options={'ordering': ['-date_created']},
),
migrations.AlterField(
model_name='order',
name='date_created',
field=models.CharField(default=datetime.datetime(2024, 7, 19, 18, 42, 20, 275471), max_length=50),
),
migrations.AlterField(
model_name='order',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='orders', to=settings.AUTH_USER_MODEL),
),
migrations.AlterField(
model_name='product',
name='category',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='products', to='core.category'),
),
]
24 changes: 24 additions & 0 deletions app/core/migrations/0005_rename_product_order_products_and_more.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 4.0.1 on 2024-07-19 18:46

import datetime
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('core', '0004_alter_order_options_alter_order_date_created_and_more'),
]

operations = [
migrations.RenameField(
model_name='order',
old_name='product',
new_name='products',
),
migrations.AlterField(
model_name='order',
name='date_created',
field=models.CharField(default=datetime.datetime(2024, 7, 19, 18, 46, 51, 221412), max_length=50),
),
]
Loading