Skip to content

Commit

Permalink
Merge branch 'dev' into feat/zero/I-deul-of-zoo#8
Browse files Browse the repository at this point in the history
  • Loading branch information
airhac authored Oct 30, 2023
2 parents 966b29e + d84ebc4 commit 4be21da
Show file tree
Hide file tree
Showing 14 changed files with 403 additions and 65 deletions.
2 changes: 2 additions & 0 deletions accounts/admin.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from django.contrib import admin

from .models import User
# Register your models here.
admin.site.register(User)
13 changes: 8 additions & 5 deletions accounts/managers.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
import random
import string
from datetime import date
from django.contrib.auth.base_user import BaseUserManager
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from datetime import date
import string
import random

STRING_SEQUENCE = string.ascii_uppercase + string.digits # 새로운 인증 코드 생성


class CustomUserManager(BaseUserManager):
"""
Custom user model manager where email is the unique identifiers
for authentication instead of usernames.
"""
#일반 유저 생성
def create_user(self,username, email, password, **extra_fields):
def create_user(self, username, email, password, **extra_fields):
"""
Create and save a User with the given email and password.
"""
if not email:
raise ValueError(_('The Email must be set'))
raise ValueError(_('email은 필수 영역입니다.'))
if not username:
raise ValueError("username은 필수 영역입니다.")
#email 형태를 동일하게 만들기 위한 함수
user = self.model(
username=username,
email=self.normalize_email(email),
date_joined = timezone.now(),
**extra_fields)

user.auth_code = self.create_auth_code()
Expand Down
115 changes: 95 additions & 20 deletions accounts/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@

# Generated by Django 4.2.6 on 2023-10-28 23:57


from django.db import migrations, models
import django.utils.timezone

Expand All @@ -9,33 +11,106 @@ class Migration(migrations.Migration):
initial = True

dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
("auth", "0012_alter_user_first_name_max_length"),
]

operations = [
migrations.CreateModel(
name='User',
name="User",
name="User",
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('email', models.EmailField(max_length=254, verbose_name='email address')),
('username', models.CharField(max_length=30, unique=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('auth_code', models.CharField(blank=True, max_length=7, null=True)),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("password", models.CharField(max_length=128, verbose_name="password")),
(
"last_login",
models.DateTimeField(
blank=True, null=True, verbose_name="last login"
),
),
(
"is_superuser",
models.BooleanField(
default=False,
help_text="Designates that this user has all permissions without explicitly assigning them.",
verbose_name="superuser status",
),
),
(
"first_name",
models.CharField(
blank=True, max_length=150, verbose_name="first name"
),
),
(
"last_name",
models.CharField(
blank=True, max_length=150, verbose_name="last name"
),
),
(
"is_staff",
models.BooleanField(
default=False,
help_text="Designates whether the user can log into this admin site.",
verbose_name="staff status",
),
),
(
"is_active",
models.BooleanField(
default=True,
help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
verbose_name="active",
),
),
(
"date_joined",
models.DateTimeField(
default=django.utils.timezone.now, verbose_name="date joined"
),
),
(
"email",
models.EmailField(max_length=254, verbose_name="email address"),
),
("username", models.CharField(max_length=30, unique=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("auth_code", models.CharField(blank=True, max_length=6, null=True)),
(
"groups",
models.ManyToManyField(
blank=True,
help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
related_name="user_set",
related_query_name="user",
to="auth.group",
verbose_name="groups",
),
),
(
"user_permissions",
models.ManyToManyField(
blank=True,
help_text="Specific permissions for this user.",
related_name="user_set",
related_query_name="user",
to="auth.permission",
verbose_name="user permissions",
),
),
],
options={
'verbose_name': 'user',
'verbose_name_plural': 'users',
'abstract': False,
"verbose_name": "user",
"verbose_name_plural": "users",
"abstract": False,
},
),
]
8 changes: 6 additions & 2 deletions accounts/models.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import string
import random
from django.db import models
from django.contrib.auth.models import AbstractUser

from .managers import CustomUserManager



class User(AbstractUser):
objects = CustomUserManager()

Expand All @@ -14,7 +17,7 @@ class User(AbstractUser):

##user model에서 각 row를 식별해줄 key를 설정
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = []
REQUIRED_FIELDS = ['email'] #? 관리자 유저 생성시 에러나서 추가

#파이썬에서 어떤값(또는 객체)을 문자열로 변환하는데 사용하는 str()
#내장 함수가 아닌 파이썬 내장 클래스
Expand All @@ -25,6 +28,7 @@ def get_hashtag(self):
return f"#{self.username}"

def is_authcode_certified(self):

if self.auth_code:
return False
return True
28 changes: 19 additions & 9 deletions accounts/serializers.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
from .models import User
from dj_rest_auth.registration.serializers import RegisterSerializer

from rest_framework import serializers
from .models import CustomUserManager
from django.contrib.auth import get_user_model

from dj_rest_auth.registration.serializers import RegisterSerializer
from dj_rest_auth.serializers import LoginSerializer
##연습용 Serializer
from rest_framework.serializers import ModelSerializer
from datetime import datetime

class CustomRegisterSerializer(RegisterSerializer):

class UserApprovalSerializer(ModelSerializer):
class Meta:
model = User
fields = [
"username",
"email",
"password",
]
model = get_user_model()
fields = ['username', 'email', 'auth_code']
read_only_fields = ['email']

class CustomRegisterSerializer(RegisterSerializer):
def save(self, request):
user = super().save(request) # userame, email, password는 RegisterSerializer에서 진행됨
# 사용자 생성 이후에 인증 코드를 설정
user.auth_code = CustomUserManager.create_auth_code()
user.save()

return user

class CustomLoginSerializer(LoginSerializer):
# email 필드를 제거
Expand Down
8 changes: 6 additions & 2 deletions accounts/urls.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@

from django.urls import include, path
from . import views
from .views import CustomLoginView
from .views import UserApprovalView, SendEmailView, CustomLoginView


app_name = "auth"
# base_url: v1/accounts/

urlpatterns = [
path('login/', CustomLoginView.as_view(), name='custom-login'),
path('', include('dj_rest_auth.urls'), name='dj_rest_auth'),
#가입승인 url
path('registration/', include('dj_rest_auth.registration.urls'), name='registration'),
path('code/', UserApprovalView.as_view(), name='user-approval'),
path('<str:username>/', SendEmailView.as_view(), name='send-email'),
]
108 changes: 104 additions & 4 deletions accounts/views.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,111 @@
from dj_rest_auth.views import LoginView
from rest_framework.response import Response
from rest_framework.views import APIView
from dj_rest_auth.views import LoginView
from rest_framework.generics import CreateAPIView, RetrieveAPIView
from django.shortcuts import get_object_or_404
from rest_framework.permissions import AllowAny, IsAuthenticatedOrReadOnly
from django.core.mail import EmailMessage
from rest_framework import status
from .serializers import CustomLoginSerializer # 커스텀 시리얼라이저를 가져옴
from .models import User
from .serializers import UserApprovalSerializer, CustomLoginSerializer


# Create your views here.
#! /auth/registration/ -> 테스트용
# class UserCreateView(CreateAPIView):
# serializer_class = UserCreateSerializer

# def perform_create(self, serializer):
# data = serializer.validated_data
# username = data['username']
# email = data['email']
# password = data['password']

# user = User.objects.create_user(username=username, email=email, password=password)

# user.auth_code = User.objects.create_auth_code()
# # message = f'가입 승인 코드: {user.auth_code}'
# user.save()


# # Response 확인용
# response_data = {
# 'username': username,
# 'auth_code': user.auth_code,
# 'from_email': email,
# }

# print("response_data: ", response_data)
# # send_mail(subject, message, from_email) #* 이메일 발송은 생략 -> 회원생성과 동시에 이메일 발송할 경우
# return Response(response_data, status = status.HTTP_201_CREATED)

#? /auth/code/ : 가입승인코드 일치 확인
class UserApprovalView(APIView): # 가입승인코드 확인
permission_classes = [AllowAny] #로그인 안된 유저도 사용할 수 있게 권한부여
serializer_class = UserApprovalSerializer
def post(self, request):

user = request.data.get('username')
auth_code = request.data.get('auth_code')
# email = request.data.get('email') # 이메일 입력도 필요할 경우 사용
try:
user = User.objects.get(username=user)
if user.auth_code == auth_code:
user.auth_code = None # 인증된 유저는 인증코드 삭제
user.is_active = True
user.save()
return Response({'message': '가입승인이 완료되었습니다.'}, status=status.HTTP_200_OK)
else:
return Response({'message': '올바르지 않은 가입승인 코드입니다.'}, status=status.HTTP_400_BAD_REQUEST)
except User.DoesNotExist:
return Response({'message': '사용자를 찾을 수 없습니다.'}, status=status.HTTP_400_BAD_REQUEST)


#? /auth/<username>/ : username로 인증코드 메일전송 -> 이메일 재발송이 필요한경우
class SendEmailView(RetrieveAPIView):
permission_classes = [IsAuthenticatedOrReadOnly]
serializer = UserApprovalSerializer
lookup_field = 'username'

def get(self, request, username):
# user = self.get_queryset()
user = get_object_or_404(User, username=username)
if user.auth_code:
try:
subject = "메일제목"
email = user.email
auth_code = user.auth_code
to = [email]
message = auth_code # 메일 내용 #최초 회원가입시도시 생성된 인증코드

#* EmailMessage(subject=subject, body=message, to=to).send() # 메일 보내기

# Response 확인용
response_data = {
'subject': subject,
'message': message,
'to': to,
}
return Response({'메일 전송 완료':response_data}, status=status.HTTP_200_OK)
except Exception as e:
return Response({'message': '메일 전송 중 오류가 발생했습니다.'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
else:
return Response({'message': '사용자를 찾을 수 없거나 인증 코드가 존재하지 않습니다.'}, status=status.HTTP_404_NOT_FOUND)

def get_queryset(self):
username = self.kwargs['username']
try:
user = User.objects.get(username=username)
except Exception as e:
return 0

return user


class CustomLoginView(LoginView):
serializer_class = CustomLoginSerializer # 커스텀 시리얼라이저를 사용

def post(self, request, *args, **kwargs):
# 로그인 로직을 그대로 유지
return super(CustomLoginView, self).post(request, *args, **kwargs)
return super(CustomLoginView, self).post(request, *args, **kwargs)

Loading

0 comments on commit 4be21da

Please sign in to comment.