10
codes/serializers.py
Normal file
10
codes/serializers.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from django.utils.timezone import now
|
||||||
|
|
||||||
|
from .models import *
|
||||||
|
from rest_framework import serializers
|
||||||
|
from common.utils.codeManger import set_expire, generate_code
|
||||||
|
|
||||||
|
|
||||||
|
class CertificateCodeSerializer(serializers.Serializer):
|
||||||
|
identifier = serializers.CharField(max_length=40, write_only=True)
|
||||||
|
code = serializers.CharField(max_length=6, write_only=True, required=False)
|
||||||
82
codes/services.py
Normal file
82
codes/services.py
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import random
|
||||||
|
import string
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from django.db import IntegrityError
|
||||||
|
from django.conf import settings
|
||||||
|
from django.utils.timezone import now
|
||||||
|
|
||||||
|
from rest_framework.views import APIView
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework import status
|
||||||
|
|
||||||
|
from .models import CertificationCode
|
||||||
|
|
||||||
|
from common.models.choiceModels import CertificateCodeUseType
|
||||||
|
from common.utils.codeManger import set_expire
|
||||||
|
|
||||||
|
from solapi import SolapiMessageService
|
||||||
|
from solapi.model import RequestMessage
|
||||||
|
|
||||||
|
# from .schemas import send_sms_post_schema # Swagger나 drf-spectacular 등에 사용되는 데코레이터
|
||||||
|
|
||||||
|
class CertificateService:
|
||||||
|
@staticmethod
|
||||||
|
def send(code, identifier):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 유효시간 5분 설정해서 저장, 이전 같은 번호 sms 요청 값들 is_used=True로 바꾸기
|
||||||
|
@staticmethod
|
||||||
|
def save_certificate_info(use_type: CertificateCodeUseType, code, identifier):
|
||||||
|
try:
|
||||||
|
befores = CertificationCode.objects.filter(
|
||||||
|
use_type=use_type,
|
||||||
|
identifier=identifier,
|
||||||
|
is_used=False
|
||||||
|
).update(is_used=True)
|
||||||
|
instance = CertificationCode.objects.create(
|
||||||
|
use_type = use_type,
|
||||||
|
code = code,
|
||||||
|
expire_at = set_expire(5),
|
||||||
|
identifier = identifier
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
except IntegrityError as e:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# code 체크 후 is_used=True로 설정
|
||||||
|
@staticmethod
|
||||||
|
def check_code(use_type: CertificateCodeUseType, code, identifier):
|
||||||
|
if check := CertificationCode.objects.filter(
|
||||||
|
use_type=use_type,
|
||||||
|
identifier=identifier,
|
||||||
|
is_used=False,
|
||||||
|
expire_at__gte=now()
|
||||||
|
).order_by('-created_at').first():
|
||||||
|
|
||||||
|
if check.code == code:
|
||||||
|
check.is_used=True
|
||||||
|
check.save()
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
class SmsService(CertificateService):
|
||||||
|
# 같은 전번에 대해 요청 텀 설정은 views 단에서 하자.
|
||||||
|
@staticmethod
|
||||||
|
def send(code, identifier):
|
||||||
|
message_service = SolapiMessageService(
|
||||||
|
api_key = settings.SOLAPI_API_KEY, api_secret = settings.SOLAPI_API_SECRET
|
||||||
|
)
|
||||||
|
|
||||||
|
message = RequestMessage(
|
||||||
|
from_ = settings.FROM_PHONE_NUMBER,
|
||||||
|
to = identifier,
|
||||||
|
text = "colio 서비스 회원가입 인증번호는 " + code +" 입니다."
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
res = message_service.send(message)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"메시지 발송 실패: {str(e)}")
|
||||||
|
return False
|
||||||
10
codes/urls.py
Normal file
10
codes/urls.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from .views import *
|
||||||
|
|
||||||
|
app_name = 'codes'
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('certificate/', CertificationAPIView.as_view()),
|
||||||
|
# path('invite/', )
|
||||||
|
]
|
||||||
@@ -1,3 +1,56 @@
|
|||||||
from django.shortcuts import render
|
from django.shortcuts import get_object_or_404
|
||||||
|
|
||||||
# Create your views here.
|
from rest_framework.views import APIView
|
||||||
|
from rest_framework.permissions import AllowAny, IsAuthenticated
|
||||||
|
|
||||||
|
from rest_framework import status
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from django.core.mail import EmailMessage
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
|
from .serializers import *
|
||||||
|
from .services import *
|
||||||
|
from common.models.choiceModels import CertificateCodeUseType
|
||||||
|
from common.utils.codeManger import generate_code
|
||||||
|
|
||||||
|
|
||||||
|
certificate_use_type = {
|
||||||
|
"phone": SmsService,
|
||||||
|
# "email": EmailService
|
||||||
|
}
|
||||||
|
|
||||||
|
class CertificationAPIView(APIView):
|
||||||
|
permission_classes = [AllowAny]
|
||||||
|
|
||||||
|
# 인증 발송
|
||||||
|
@transaction.atomic
|
||||||
|
def post(self, request):
|
||||||
|
use_type = request.query_params.get("type")
|
||||||
|
serv = certificate_use_type[use_type]
|
||||||
|
serializer = CertificateCodeSerializer(data=request.data)
|
||||||
|
if serializer.is_valid():
|
||||||
|
create_code = generate_code(6)
|
||||||
|
if serv.save_certificate_info(use_type, create_code, serializer.validated_data['identifier']):
|
||||||
|
if serv.send(create_code, serializer.validated_data['identifier']):
|
||||||
|
return Response({'message': "success send and save"})
|
||||||
|
else: # 전송 실패
|
||||||
|
return Response({"message": "failed send"})
|
||||||
|
else: # 코드 저장 실패
|
||||||
|
return Response({'message': "failed save"}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
|
# 인증 확인
|
||||||
|
@transaction.atomic
|
||||||
|
def patch(self, request):
|
||||||
|
use_type = request.query_params.get("type")
|
||||||
|
serv = certificate_use_type[use_type]
|
||||||
|
code = request.data.get('code', None)
|
||||||
|
if not code:
|
||||||
|
return Response({"message": "no code"}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
serializer = CertificateCodeSerializer(data=request.data)
|
||||||
|
if serializer.is_valid():
|
||||||
|
if serv.check_code(use_type, code, serializer.validated_data['identifier']):
|
||||||
|
return Response({"message": "certificated successfully"}, status=status.HTTP_200_OK)
|
||||||
|
return Response({"message": "wrong code, please retry"}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ class GenderChoices(models.TextChoices):
|
|||||||
WOMAN = '여', '여성'
|
WOMAN = '여', '여성'
|
||||||
|
|
||||||
class CertificateCodeUseType(models.TextChoices):
|
class CertificateCodeUseType(models.TextChoices):
|
||||||
EMAIL = '이메일', '이메일'
|
EMAIL = 'email', 'email'
|
||||||
PHONE = '휴대폰', '휴대폰'
|
PHONE = 'phone', 'phone'
|
||||||
|
|
||||||
class InviteCodeUseType(models.TextChoices):
|
class InviteCodeUseType(models.TextChoices):
|
||||||
PROJECT = '프로젝트', '프로젝트'
|
PROJECT = '프로젝트', '프로젝트'
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ environ.Env.read_env(os.path.join(BASE_DIR, '.env'))
|
|||||||
|
|
||||||
SECRET_KEY = env('SECRET_KEY')
|
SECRET_KEY = env('SECRET_KEY')
|
||||||
|
|
||||||
|
SOLAPI_API_KEY = env('SOLAPI_API_KEY')
|
||||||
|
SOLAPI_API_SECRET = env('SOLAPI_API_SECRET')
|
||||||
|
FROM_PHONE_NUMBER = env('FROM_PHONE_NUMBER')
|
||||||
|
|
||||||
DEBUG = env.bool('DEBUG')
|
DEBUG = env.bool('DEBUG')
|
||||||
|
|
||||||
ALLOWED_HOSTS = ['*']
|
ALLOWED_HOSTS = ['*']
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from django.conf.urls.static import static
|
|||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
path('api/user/', include('users.urls')),
|
path('api/user/', include('users.urls')),
|
||||||
# path('api/code/', include('codes.urls')),
|
path('api/code/', include('codes.urls')),
|
||||||
path('api/portfolio/', include('portfolios.urls')),
|
path('api/portfolio/', include('portfolios.urls')),
|
||||||
path('api/project/', include('projects.urls')),
|
path('api/project/', include('projects.urls')),
|
||||||
path('api/notification/', include('notifications.urls')),
|
path('api/notification/', include('notifications.urls')),
|
||||||
|
|||||||
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
Reference in New Issue
Block a user