diff --git a/README.md b/README.md index 8fb1b86..5dc1ef2 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,54 @@ # oz_03_collabo-002-BE 합동 프로젝트 2팀 리포지토리입니다. + +www.malazoo.kr + +https://api.malazoo.kr/v1/schema/redoc + +## ⚙️ 사용 기술 + +### BackEnd + +![python](https://img.shields.io/badge/Python-3776AB?style=for-the-badge&logo=python&logoColor=white) +![django](https://img.shields.io/badge/Django-092E20?style=for-the-badge&logo=django&logoColor=white) +![postgres](https://img.shields.io/badge/PostgreSQL-316192?style=for-the-badge&logo=postgresql&logoColor=white) +![Poetry](https://img.shields.io/badge/Poetry-%233B82F6.svg?style=for-the-badge&logo=poetry&logoColor=0B3D8D) +![DjangoREST](https://img.shields.io/badge/DJANGO-REST-ff1709?style=for-the-badge&logo=django&logoColor=white&color=ff1709&labelColor=gray) +![JWT](https://img.shields.io/badge/JWT-black?style=for-the-badge&logo=JSON%20web%20tokens) +![Docker](https://img.shields.io/badge/docker-%230db7ed.svg?style=for-the-badge&logo=docker&logoColor=white) +![GitHub Actions](https://img.shields.io/badge/github%20actions-%232671E5.svg?style=for-the-badge&logo=githubactions&logoColor=white) + + +![PayPal](https://img.shields.io/badge/PayPal-00457C?style=for-the-badge&logo=paypal&logoColor=white) + + +## 🗓프로젝트 기간 +- **기본요구사항 : 24.08.06 ~ 24.09.09** + +## 👤멤버 구성 + +### Team +||| +|:-:|:-:| +|[@im-niber](https://github.com/im-niber)|[@Gomnonix](https://github.com/Gomnonix)| + + +## 구현 기능 +- 일일 클래스 정보 구현 +- 클래스 예약 기능 구현 +- 프로필 사진 변경, 닉네임 변경 및 소셜로그인 구현 +- 포토리뷰, 리뷰 좋아요, 즐겨찾기 클래스 기능 구현 +- django admin 커스텀 기능 추가(최근 수정 내역 알림기능) +- 무중단 배포 및 CI 구현 + +## ERD + +![erd.png](images/erd.png) + +## Architecture + +![architecture.png](images/architecture.png) + + + diff --git a/customk/users/services/token_service.py b/customk/users/services/token_service.py index b5d960f..dbd8301 100644 --- a/customk/users/services/token_service.py +++ b/customk/users/services/token_service.py @@ -22,8 +22,36 @@ def generate_tokens(user: User) -> Token: return Token(str(refresh), str(refresh.access_token)) # type: ignore +def get_cookie_domain(env: str) -> str | None: + if env == "production": + return os.environ.get("DOMAIN_NAME") + return None + + +def set_token_cookie( + response: Response, name: str, token: str, max_age: int, front_env: str +) -> None: + domain = get_cookie_domain(front_env) + + response.set_cookie( + key=name, + value=token, + max_age=max_age, + httponly=True, + secure=(front_env != "development"), + samesite="Lax" if front_env == "development" else "None", + domain=domain if domain else None, + ) + + def set_cookies(request: Request, response: Response, token: Token) -> Response: - logger.info("Set cookie") + host = request.get_host() + logger.info(f"Setting cookies domain: {host}") + + if host and str(os.getenv("DOMAIN_NAME")) in host: + front_env = "production" + else: + front_env = "development" access_max_age = int( cast(timedelta, settings.SIMPLE_JWT["ACCESS_TOKEN_LIFETIME"]).total_seconds() @@ -32,31 +60,11 @@ def set_cookies(request: Request, response: Response, token: Token) -> Response: cast(timedelta, settings.SIMPLE_JWT["REFRESH_TOKEN_LIFETIME"]).total_seconds() ) - response.set_cookie( - "access_token", - token.access_token, - max_age=access_max_age, - secure=True, - httponly=True, - domain=os.environ.get("DOMAIN_NAME"), + set_token_cookie( + response, "access_token", token.access_token, access_max_age, front_env ) - - response.set_cookie( - "refresh_token", - token.refresh_token, - max_age=refresh_max_age, - secure=True, - httponly=True, - domain=os.environ.get("DOMAIN_NAME"), + set_token_cookie( + response, "refresh_token", token.refresh_token, refresh_max_age, front_env ) - if hasattr(response, "data"): - response.data["access_token"] = token.access_token - response.data["refresh_token"] = token.refresh_token - else: - response.data = { - "access_token": token.access_token, - "refresh_token": token.refresh_token, - } - return response diff --git a/customk/users/views/token.py b/customk/users/views/token.py index e2b5d7e..bb2617f 100644 --- a/customk/users/views/token.py +++ b/customk/users/views/token.py @@ -1,6 +1,4 @@ -import os -from datetime import timedelta -from typing import Any, cast +from typing import Any from drf_spectacular.utils import ( OpenApiExample, @@ -14,8 +12,8 @@ from rest_framework_simplejwt.exceptions import InvalidToken from rest_framework_simplejwt.views import TokenRefreshView, TokenVerifyView -from config import settings from config.logger import logger +from users.services.token_service import Token, set_cookies class CustomTokenRefreshView(TokenRefreshView): @@ -70,22 +68,12 @@ def post(self, request: Request, *args: Any, **kwargs: Any) -> Response: response = super().post(request) if response.status_code == 200: - access_token = response.data.get("access") - - domain = os.environ.get("DOMAIN_NAME") - access_max_age = int( - cast( - timedelta, settings.SIMPLE_JWT["ACCESS_TOKEN_LIFETIME"] - ).total_seconds() - ) - response.set_cookie( - key="access_token", - value=access_token, - max_age=access_max_age, - domain=domain, - httponly=True, - secure=True, - ) + new_refresh_token = response.data.get("refresh") + new_access_token = response.data.get("access") + tokens = Token(new_refresh_token, new_access_token) + + response = set_cookies(request, response, tokens) + del response.data["access"] del response.data["refresh"] diff --git a/images/architecture.png b/images/architecture.png new file mode 100644 index 0000000..1a13336 Binary files /dev/null and b/images/architecture.png differ diff --git a/images/erd.png b/images/erd.png new file mode 100644 index 0000000..382463c Binary files /dev/null and b/images/erd.png differ