Merge pull request #20 from plers-org/Feat/#13

Feat/#13
This commit is contained in:
NKEY
2025-04-08 01:11:20 +09:00
committed by GitHub
6 changed files with 138 additions and 7 deletions

View File

@@ -8,12 +8,12 @@ from common.utils.codeManger import set_expire
class CertificationCode(BaseModel):
use_type = models.CharField(choices=CertificateCodeUseType.choices, max_length=5)
code = models.CharField(max_length=6)
expire_at = models.DateTimeField(default=set_expire(minutes=5))
expire_at = models.DateTimeField(default=set_expire)
is_used = models.BooleanField(default=False)
identifier = models.CharField(max_length=40)
class InviteCode(BaseModel):
use_type = models.CharField(choices=InviteCodeUseType.choices, max_length=5)
code = models.CharField(max_length=10)
expire_at = models.DateTimeField(default=set_expire(minutes=10080)) # 일주일은 10080분
expire_at = models.DateTimeField(default=set_expire) # 일주일은 10080분
identifier = models.CharField(max_length=40)

Binary file not shown.

View File

@@ -28,18 +28,20 @@ class UserManager(BaseUserManager):
class User(BaseModel, AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
is_email_verified = models.BooleanField(default=False)
realname = models.CharField(max_length=10, blank=True)
# is_email_verified = models.BooleanField(default=False)
is_plers_terms_of_service = models.BooleanField(default=False)
is_terms_of_service_colio = models.BooleanField(default=False)
is_consent_personal_info = models.BooleanField(default=False)
is_consent_third_party_sharing = models.BooleanField(default=False)
is_consent_marketing = models.BooleanField(default=False)
phone = models.CharField(max_length=11, blank=True)
is_phone_verified = models.BooleanField(default=False)
# is_phone_verified = models.BooleanField(default=False)
nickname = models.CharField(max_length=20, blank=True)
gender = models.CharField(choices=GenderChoices.choices, max_length=1, blank=True)
birth_date = models.CharField(max_length=10, blank=True)
custom_url = models.CharField(max_length=20, blank=True)
is_custom_url = models.BooleanField(default=False)
job_and_interests = ArrayField(models.CharField(max_length=20), default=list, blank=True)
skills = ArrayField(models.CharField(max_length=20), default=list, blank=True)
external_links = ArrayField(models.TextField(), default=list, blank=True)
@@ -47,7 +49,7 @@ class User(BaseModel, AbstractBaseUser, PermissionsMixin):
profile_image = models.ImageField(upload_to='', blank=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
objects = UserManager()

23
users/serializers.py Normal file
View File

@@ -0,0 +1,23 @@
from .models import *
from rest_framework import serializers
class JoinSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = [
'email',
'password',
'is_plers_terms_of_service',
'is_terms_of_service_colio',
'is_consent_personal_info',
'is_consent_third_party_sharing',
'is_consent_marketing',
'realname',
'phone',
'nickname',
'gender',
'birth_date'
]
def create(self, validated_data):
return User.objects.create_user(**validated_data)

12
users/urls.py Normal file
View File

@@ -0,0 +1,12 @@
from django.urls import path
from .views import *
app_name = 'users'
urlpatterns = [
path('refresh-token/', RefreshAPIView.as_view()),
path('join/', JoinAPIView.as_view()),
path('login/', LoginAPIView.as_view()),
path('check/', NicknameAPIView.as_view()),
]

View File

@@ -1,3 +1,97 @@
from django.shortcuts import render
from django.shortcuts import get_object_or_404
from rest_framework.views import APIView
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer, TokenRefreshSerializer
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework_simplejwt.exceptions import TokenError, InvalidToken
from rest_framework import status
from rest_framework.response import Response
from rest_framework.permissions import AllowAny, IsAuthenticated
from django.contrib.auth import authenticate
from .models import *
from .serializers import *
class RefreshAPIView(APIView):
permission_classes = [AllowAny]
# access token 재발급
def post(self, request):
refresh = request.COOKIES.get("refresh")
if not refresh:
return Response({"message": "No refresh token"}, status=status.HTTP_400_BAD_REQUEST)
if request.data.get("user_id", None) != RefreshToken(refresh).payload.get("user_id", None):
return Response({"message": "Wrong userid"}, status=status.HTTP_400_BAD_REQUEST)
try:
serializer = TokenRefreshSerializer(data={'refresh': refresh})
if serializer.is_valid():
res = Response({"access": serializer.validated_data['access']}, status=status.HTTP_200_OK)
res.set_cookie("refresh", serializer.validated_data['refresh'], httponly=True, samesite="Lax", secure=True)
return res
except TokenError as e:
return Response({"message": f"Invalid token: {e}"}, status=status.HTTP_401_UNAUTHORIZED)
class JoinAPIView(APIView):
permission_classes = [AllowAny]
# 회원가입
def post(self, request):
serializer = JoinSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
res = Response({"message": "회원가입이 완료되었습니다."}, status=status.HTTP_200_OK)
return res
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class LoginAPIView(APIView):
permission_classes = [AllowAny]
# 로그인
def post(self, request):
email=request.data.get("email", None)
password=request.data.get("password", None)
# 로그인 전 쿠키에 있는 리프레시 토큰 무효화
try:
refresh = request.COOKIES.get('refresh')
if refresh:
refresh_token = RefreshToken(refresh)
refresh_token.blacklist()
except TokenError as e:
pass
if user := authenticate(email=email, password=password):
serializer = TokenObtainPairSerializer(data={'email': email, 'password': password})
# id, 비번 맞나 틀리나 검사
if serializer.is_valid():
res = Response(
{
"message": "login success",
"user_id": user.id,
"nickname": user.nickname,
"access": serializer.validated_data['access'],
"is_custom_url": user.is_custom_url
},
status=status.HTTP_200_OK,
)
res.set_cookie("refresh", serializer.validated_data['refresh'], httponly=True, samesite="Lax", secure=True)
return res
else:
return Response(serializer.errors)
else: # id, 비번 둘 중 하나가 틀렸을 때
return Response({"message": "아이디 혹은 비밀번호가 맞지 않습니다."}, status=status.HTTP_400_BAD_REQUEST)
class NicknameAPIView(APIView):
permission_classes = [AllowAny]
# 닉네임 중복 체크
def get(self, request):
nickname = request.GET.get('nickname', None)
if not nickname:
return Response({"message": "닉네임을 입력하세요."}, status=status.HTTP_400_BAD_REQUEST)
try:
get_object_or_404(User, nickname=nickname)
return Response({"message": "해당 닉네임은 사용할 수 없습니다."}, status=status.HTTP_400_BAD_REQUEST)
except:
return Response({"message": "사용할 수 있는 닉네임입니다."}, status=status.HTTP_200_OK)
# Create your views here.