Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
27 changes: 27 additions & 0 deletions app/app/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

from pathlib import Path

from drf_yasg.openapi import Contact, Info

from app import env

# Build paths inside the project like this: BASE_DIR / 'subdir'.
Expand Down Expand Up @@ -70,8 +72,11 @@
# Application definition

INSTALLED_APPS = [
'drf_yasg',
'rest_framework',

'doc',

'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
Expand Down Expand Up @@ -162,3 +167,25 @@
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'


# drf-yasg settings
# https://drf-yasg.readthedocs.io/en/stable/settings.html
SWAGGER_SETTINGS = {
# NOTE: DEFAULT_INFO 설정을 해두어야 `generate_swagger` management command를 사용할 수 있음에 유의.
"DEFAULT_INFO": "app.settings.OPEN_API_INFO",
}

REDOC_SETTINGS = {
"LAZY_RENDERING": True,
}

OPEN_API_INFO = Info(
title="Time Limit Exceeded :: Authentication API",
default_version='v1',
description=(
"This API provides authentication endpoints and related features for the Time Limit Exceeded application, "
"including user login, registration, and token management."
),
contact=Contact(email="hepheir@gmail.com"),
)
3 changes: 2 additions & 1 deletion app/app/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
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 include, path

urlpatterns = [
path('admin/', admin.site.urls),
path('doc/', include('doc.urls')),
]
Empty file added app/doc/__init__.py
Empty file.
6 changes: 6 additions & 0 deletions app/doc/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class DocConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'doc'
58 changes: 58 additions & 0 deletions app/doc/test_urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from django.test import TestCase, override_settings
from rest_framework import status


class DocEndpointsDebugModeTestCase(TestCase):
"""DEBUG=True일 때 문서 엔드포인트 접근 가능 여부 테스트"""

@override_settings(DEBUG=True)
def test_swagger_ui_accessible_in_debug_mode(self):
"""DEBUG 모드에서 Swagger UI 접근 가능"""
response = self.client.get('/doc/swagger/')
self.assertEqual(response.status_code, status.HTTP_200_OK)

@override_settings(DEBUG=True)
def test_redoc_ui_accessible_in_debug_mode(self):
"""DEBUG 모드에서 ReDoc UI 접근 가능"""
response = self.client.get('/doc/redoc/')
self.assertEqual(response.status_code, status.HTTP_200_OK)

@override_settings(DEBUG=True)
def test_schema_json_accessible_in_debug_mode(self):
"""DEBUG 모드에서 스키마 JSON 접근 가능"""
response = self.client.get('/doc/swagger.json/')
self.assertEqual(response.status_code, status.HTTP_200_OK)

@override_settings(DEBUG=True)
def test_schema_yaml_accessible_in_debug_mode(self):
"""DEBUG 모드에서 스키마 YAML 접근 가능"""
response = self.client.get('/doc/swagger.yaml/')
self.assertEqual(response.status_code, status.HTTP_200_OK)


class DocEndpointsProductionModeTestCase(TestCase):
"""DEBUG=False일 때 문서 엔드포인트 접근 제한 테스트"""

@override_settings(DEBUG=False, ALLOWED_HOSTS=['testserver'])
def test_swagger_ui_not_accessible_in_production(self):
"""프로덕션 모드에서 Swagger UI 접근 불가"""
response = self.client.get('/doc/swagger/')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

@override_settings(DEBUG=False, ALLOWED_HOSTS=['testserver'])
def test_redoc_ui_not_accessible_in_production(self):
"""프로덕션 모드에서 ReDoc UI 접근 불가"""
response = self.client.get('/doc/redoc/')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

@override_settings(DEBUG=False, ALLOWED_HOSTS=['testserver'])
def test_schema_json_not_accessible_in_production(self):
"""프로덕션 모드에서 스키마 JSON 접근 불가"""
response = self.client.get('/doc/swagger.json/')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

@override_settings(DEBUG=False, ALLOWED_HOSTS=['testserver'])
def test_schema_yaml_not_accessible_in_production(self):
"""프로덕션 모드에서 스키마 YAML 접근 불가"""
response = self.client.get('/doc/swagger.yaml/')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
26 changes: 26 additions & 0 deletions app/doc/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""
URL configuration for doc app.

The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.urls import path

from . import views


urlpatterns = [
path('swagger<str:format>/', views.schema_format_view),
path('swagger/', views.swagger_view),
path('redoc/', views.redoc_view),
]
24 changes: 24 additions & 0 deletions app/doc/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from django.conf import settings
from drf_yasg.views import get_schema_view
from rest_framework.permissions import BasePermission


class IsDebug(BasePermission):
"""
Permission class that allows access only when Django's DEBUG mode is enabled.
Useful for restricting certain endpoints to development environments.
"""
def has_permission(self, request, view):
return settings.DEBUG


SchemaView = get_schema_view(
info=settings.OPEN_API_INFO,
permission_classes=[IsDebug],
public=True,
)


redoc_view = SchemaView.with_ui('redoc')
swagger_view = SchemaView.with_ui('swagger')
schema_format_view = SchemaView.without_ui()
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
django
djangorestframework
drf-yasg
pytest-django
python-dotenv