From b665edf6c0816a221cb31764016d955bc8888667 Mon Sep 17 00:00:00 2001 From: Chaehy Date: Wed, 20 Jul 2022 18:47:31 +0900 Subject: [PATCH] chore: add back files --- backend/__init__.py | 0 backend/backend/settings.py | 98 ++++------------- backend/dockerfile | 2 +- .../rebiketrash/migrations/0001_initial.py | 30 +++--- ...02_alter_trash_kind_updated_at_and_more.py | 23 ++++ ..._trash_image_delete_trashkinds_and_more.py | 43 -------- backend/rebiketrash/migrations/__init__.py | 0 backend/rebiketrash/models.py | 9 +- backend/rebiketrash/serializers.py | 11 +- backend/rebiketrash/urls.py | 21 ++-- backend/rebiketrash/views.py | 101 +++++++++++++----- backend/rebikeuser/JWT_Settings.py | 4 + backend/rebikeuser/__init__.py | 0 backend/rebikeuser/migrations/0001_initial.py | 23 ++-- .../migrations/0002_alter_user_table.py | 18 ---- backend/rebikeuser/models.py | 9 +- backend/rebikeuser/serializers.py | 7 +- backend/rebikeuser/userUtil.py | 35 +++++- backend/rebikeuser/views.py | 26 +++-- backend/requirements.txt | 62 +++++++++-- backend/wait_mysql.py | 29 +++++ docker-compose.yml | 28 +++-- 22 files changed, 324 insertions(+), 255 deletions(-) create mode 100644 backend/__init__.py create mode 100644 backend/rebiketrash/migrations/0002_alter_trash_kind_updated_at_and_more.py delete mode 100644 backend/rebiketrash/migrations/0002_trash_kind_uploaded_trash_image_delete_trashkinds_and_more.py create mode 100644 backend/rebiketrash/migrations/__init__.py create mode 100644 backend/rebikeuser/JWT_Settings.py create mode 100644 backend/rebikeuser/__init__.py delete mode 100644 backend/rebikeuser/migrations/0002_alter_user_table.py create mode 100644 backend/wait_mysql.py diff --git a/backend/__init__.py b/backend/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/backend/settings.py b/backend/backend/settings.py index dcb159b..cd36626 100644 --- a/backend/backend/settings.py +++ b/backend/backend/settings.py @@ -1,10 +1,11 @@ from pathlib import Path - +from datetime import timedelta ####환경변수 설정 import os import environ +is_dev = True # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -12,27 +13,25 @@ # See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! - -####환경변수 세팅 -env = environ.Env(DEBUG=(bool, True)) -environ.Env.read_env( - env_file=os.path.join(BASE_DIR, '.env') -) - -if not env('IS_DEV'): - SECRET_KEY = env('SECRET_KEY') - DB_URL = 'localhost:8989' +# SECURITY WARNING: don't run with debug turned on in production! +# 환경변수 세팅 +if is_dev: + env = environ.Env(DEBUG=(bool, True)) + environ.Env.read_env( + env_file=os.path.join(BASE_DIR, 'dev.env') + ) else: - SECRET_KEY = env('SECRET_KEY') - DB_URL = env('DATABASE_URL') + env = environ.Env(DEBUG=(bool, True)) + environ.Env.read_env( + env_file=os.path.join(BASE_DIR, '.env') + ) -# SECURITY WARNING: don't run with debug turned on in production! +SECRET_KEY = env('SECRET_KEY') DEBUG = env('DEBUG') ALLOWED_HOSTS = ['*'] # Application definition - INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', @@ -42,11 +41,13 @@ 'django.contrib.staticfiles', # add 'rest_framework', + # 'rest_framework_simplejwt', 'corsheaders', 'drf_yasg', # local apps 'rebikeuser', 'rebiketrash', + 'storages', ] MIDDLEWARE = [ @@ -93,6 +94,9 @@ } } +def test(): + return env + # Password validation # https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators @@ -132,64 +136,6 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' -# ================로깅 테스트=================== -# 로깅설정 -# LOGGING = { -# 'version': 1, -# 'disable_existing_loggers': False, -# 'filters': { -# 'require_debug_false': { -# '()': 'django.utils.log.RequireDebugFalse', -# }, -# 'require_debug_true': { -# '()': 'django.utils.log.RequireDebugTrue', -# }, -# }, -# 'formatters': { -# 'django.server': { -# '()': 'django.utils.log.ServerFormatter', -# 'format': '[{server_time}] {message}', -# 'style': '{', -# }, -# 'standard': { -# 'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s' -# }, -# }, -# 'handlers': { -# 'console': { -# 'level': 'INFO', -# 'filters': ['require_debug_true'], -# 'class': 'logging.StreamHandler', -# }, -# 'django.server': { -# 'level': 'INFO', -# 'class': 'logging.StreamHandler', -# 'formatter': 'django.server', -# }, -# 'mail_admins': { -# 'level': 'ERROR', -# 'filters': ['require_debug_false'], -# 'class': 'django.utils.log.AdminEmailHandler' -# }, -# 'file': { -# 'level': 'INFO', -# 'filters': ['require_debug_false'], -# 'class': 'logging.handlers.RotatingFileHandler', -# 'filename': BASE_DIR / 'logs/mylog.log', -# 'maxBytes': 1024*1024*5, # 5 MB -# 'backupCount': 5, -# 'formatter': 'standard', -# }, -# }, -# 'loggers': { -# 'django': { -# 'handlers': ['console', 'mail_admins', 'file'], -# 'level': 'INFO', -# }, -# 'django.server': { -# 'handlers': ['django.server'], -# 'level': 'INFO', -# 'propagate': False, -# }, -# } -# } +AWS_ACCESS_KEY_ID=env('AWS_ACCESS_KEY_ID') +AWS_SECRET_ACCESS_KEY=env('AWS_SECRET_ACCESS_KEY') +AWS_STORAGE_BUCKET_NAME=env('AWS_STORAGE_BUCKET_NAME') \ No newline at end of file diff --git a/backend/dockerfile b/backend/dockerfile index 6a3b72c..bc5eee3 100644 --- a/backend/dockerfile +++ b/backend/dockerfile @@ -4,6 +4,6 @@ WORKDIR /app COPY ./ ./ -# EXPOSE 8080 +EXPOSE 8080 RUN pip install -r requirements.txt \ No newline at end of file diff --git a/backend/rebiketrash/migrations/0001_initial.py b/backend/rebiketrash/migrations/0001_initial.py index b49408c..c8ffbbf 100644 --- a/backend/rebiketrash/migrations/0001_initial.py +++ b/backend/rebiketrash/migrations/0001_initial.py @@ -1,6 +1,7 @@ -# Generated by Django 4.0.6 on 2022-07-13 07:49 +# Generated by Django 4.0.6 on 2022-07-20 13:39 from django.db import migrations, models +import django.db.models.deletion class Migration(migrations.Migration): @@ -8,30 +9,35 @@ class Migration(migrations.Migration): initial = True dependencies = [ + ('rebikeuser', '0001_initial'), ] operations = [ migrations.CreateModel( - name='Trashkinds', + name='trash_kind', fields=[ - ('trash_kind', models.CharField(max_length=30, primary_key=True, serialize=False)), - ('trash_throw_way', models.CharField(max_length=200)), + ('kind', models.CharField(max_length=30, primary_key=True, serialize=False)), + ('way', models.CharField(max_length=200)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now_add=True)), ], options={ - 'db_table': 'TrashKinds', - 'managed': False, + 'db_table': 'trash_kind', }, ), migrations.CreateModel( - name='Uploadedtrash', + name='uploaded_trash_image', fields=[ - ('upload_id', models.AutoField(primary_key=True, serialize=False)), - ('upload_img', models.CharField(max_length=200)), - ('upload_date', models.DateTimeField()), + ('uploaded_trash_image_id', models.AutoField(primary_key=True, serialize=False)), + ('active', models.IntegerField(default=1)), + ('img', models.CharField(max_length=200)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now_add=True)), + ('trash_kind', models.ForeignKey(db_column='trash_kind', on_delete=django.db.models.deletion.CASCADE, to='rebiketrash.trash_kind')), + ('user_id', models.ForeignKey(db_column='user_id', on_delete=django.db.models.deletion.CASCADE, to='rebikeuser.user')), ], options={ - 'db_table': 'UploadedTrash', - 'managed': False, + 'db_table': 'uploaded_trash_image', }, ), ] diff --git a/backend/rebiketrash/migrations/0002_alter_trash_kind_updated_at_and_more.py b/backend/rebiketrash/migrations/0002_alter_trash_kind_updated_at_and_more.py new file mode 100644 index 0000000..d8de4fc --- /dev/null +++ b/backend/rebiketrash/migrations/0002_alter_trash_kind_updated_at_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.0.6 on 2022-07-20 18:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('rebiketrash', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='trash_kind', + name='updated_at', + field=models.DateTimeField(auto_now=True), + ), + migrations.AlterField( + model_name='uploaded_trash_image', + name='updated_at', + field=models.DateTimeField(auto_now=True), + ), + ] diff --git a/backend/rebiketrash/migrations/0002_trash_kind_uploaded_trash_image_delete_trashkinds_and_more.py b/backend/rebiketrash/migrations/0002_trash_kind_uploaded_trash_image_delete_trashkinds_and_more.py deleted file mode 100644 index 2d15ebc..0000000 --- a/backend/rebiketrash/migrations/0002_trash_kind_uploaded_trash_image_delete_trashkinds_and_more.py +++ /dev/null @@ -1,43 +0,0 @@ -# Generated by Django 4.0.6 on 2022-07-14 19:26 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('rebiketrash', '0001_initial'), - ] - - operations = [ - migrations.CreateModel( - name='trash_kind', - fields=[ - ('kind', models.CharField(max_length=30, primary_key=True, serialize=False)), - ('way', models.CharField(max_length=200)), - ], - options={ - 'db_table': 'trash_kind', - 'managed': False, - }, - ), - migrations.CreateModel( - name='uploaded_trash_image', - fields=[ - ('uploaded_trash_image_id', models.AutoField(primary_key=True, serialize=False)), - ('img', models.CharField(max_length=200)), - ('created_at', models.DateTimeField()), - ('updated_at', models.DateTimeField()), - ], - options={ - 'db_table': 'uploaded_trash_image', - 'managed': False, - }, - ), - migrations.DeleteModel( - name='Trashkinds', - ), - migrations.DeleteModel( - name='Uploadedtrash', - ), - ] diff --git a/backend/rebiketrash/migrations/__init__.py b/backend/rebiketrash/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/rebiketrash/models.py b/backend/rebiketrash/models.py index 0d60767..25a8353 100644 --- a/backend/rebiketrash/models.py +++ b/backend/rebiketrash/models.py @@ -1,15 +1,14 @@ from django.db import models -from rebikeuser.models import user +from rebikeuser.models import user class trash_kind(models.Model): kind = models.CharField(primary_key=True, max_length=30) way = models.CharField(max_length=200) created_at = models.DateTimeField(auto_now_add=True, blank=True) - updated_at = models.DateTimeField(auto_now_add=True, blank=True) + updated_at = models.DateTimeField(auto_now=True, blank=True) class Meta: - managed = False db_table = 'trash_kind' @@ -18,11 +17,9 @@ class uploaded_trash_image(models.Model): active = models.IntegerField(default=1) img = models.CharField(max_length=200) created_at = models.DateTimeField(auto_now_add=True, blank=True) - updated_at = models.DateTimeField(auto_now_add=True, blank=True) + updated_at = models.DateTimeField(auto_now=True, blank=True) user_id = models.ForeignKey(user, on_delete=models.CASCADE, db_column='user_id') trash_kind = models.ForeignKey(trash_kind, on_delete=models.CASCADE, db_column='trash_kind') class Meta: - managed = False db_table = 'uploaded_trash_image' - diff --git a/backend/rebiketrash/serializers.py b/backend/rebiketrash/serializers.py index 6496a66..c41699c 100644 --- a/backend/rebiketrash/serializers.py +++ b/backend/rebiketrash/serializers.py @@ -1,17 +1,16 @@ from pyexpat import model from rest_framework import serializers -from .models import trash_kind, uploaded_trash_image +from .models import trash_kind, uploaded_trash_image class TrashkindSerializer(serializers.ModelSerializer) : class Meta : model = trash_kind fields = ('kind', 'way') - class UploadedtrashimageSerializer(serializers.ModelSerializer) : class Meta : model = uploaded_trash_image - fields = ("uploaded_trash_image_id","img") + fields = ("uploaded_trash_image_id", "img", "trash_kind") class UploadedtrashimageDetailSerializer(serializers.ModelSerializer) : class Meta : @@ -27,9 +26,3 @@ def get_cnt(self, model_instance): class Meta : model = uploaded_trash_image fields = ("kind","cnt") - - -class UploadedtrashimageCreateSerializer(serializers.ModelSerializer) : - class Meta : - model = uploaded_trash_image - fields = ('user_id', 'active', 'img', 'trash_kind') diff --git a/backend/rebiketrash/urls.py b/backend/rebiketrash/urls.py index fc967cd..d54b265 100644 --- a/backend/rebiketrash/urls.py +++ b/backend/rebiketrash/urls.py @@ -1,20 +1,17 @@ -from django.urls import path, re_path +from django.urls import path from . import views from django.contrib import admin -from django.urls import include, path, re_path - - urlpatterns =[ - #path('mainpage/users//',views.UploadImage.as_view()), - path('mainpage',views.UploadImage.as_view()), - path('mainpage/images//result',views.ImageResultPage), - path('mainpage/search-words//result',views.SearchResultPage), + path('mainpage/search-words//result',views.searchResultPage), + + path('mainpage/users//result',views.UploadImage.as_view()), - path('mypage/users//images',views.histories, name='histories'), - path('mypage/users//images/',views.UploadedtrashimageListAPI.as_view()), - path('mypage/users//statistics',views.statistics, name='statistics'), + path('mypage/users//images',views.UploadedtrashimageListAPI.as_view()), + path('mypage/users//images/',views.UploadedtrashimageDetailListAPI.as_view()), + path('mypage/users//statistics',views.statistics), + path('mypage/users//statistics/period//',views.statistics_by_date), ] -### 자주 쓰이는 코드 유틸화 trashUtils.py \ No newline at end of file +### 자주 쓰이는 코드 유틸화 trashUtils.py diff --git a/backend/rebiketrash/views.py b/backend/rebiketrash/views.py index 27a0330..cab939d 100644 --- a/backend/rebiketrash/views.py +++ b/backend/rebiketrash/views.py @@ -5,39 +5,44 @@ from .models import trash_kind, uploaded_trash_image from rebikeuser.models import user - - from rest_framework import status, viewsets from rest_framework.response import Response from rest_framework.views import APIView from rest_framework.decorators import api_view -from rest_framework.generics import CreateAPIView - -from .serializers import TrashkindSerializer, UploadedtrashimageSerializer, UploadedtrashimageDetailSerializer, UploadedtrashimageStatisticsSerializer, UploadedtrashimageCreateSerializer +from .serializers import TrashkindSerializer, UploadedtrashimageSerializer, UploadedtrashimageDetailSerializer, UploadedtrashimageStatisticsSerializer +import boto3 +from datetime import datetime, timedelta +from backend.settings import AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY # Create your views here. -@api_view(['GET']) -def histories(request, user_id): - uploadedTrashs = uploaded_trash_image.objects.filter( - user_id=user_id, active=1) - serializer = UploadedtrashimageSerializer(uploadedTrashs, many=True) - return Response(serializer.data) - class UploadedtrashimageListAPI(APIView): + def get(self, request, user_id): + uploadedTrashs = uploaded_trash_image.objects.filter( + user_id=user_id, active=1) + serializer = UploadedtrashimageSerializer(uploadedTrashs, many=True) + return Response(serializer.data) + + +class UploadedtrashimageDetailListAPI(APIView): def get(self, request, user_id, uploaded_trash_image_id): uploaded_trashs = uploaded_trash_image.objects.filter( user_id=user_id, active=1, uploaded_trash_image_id=int(uploaded_trash_image_id)) serializer = UploadedtrashimageDetailSerializer( uploaded_trashs, many=True) return Response(serializer.data) + ############# delete는 데이터 직접 삭제하지 않고 img.active를 0으로,.... + # def delete(self, request, user_id, uploaded_trash_image_id): + # uploaded_trashs = uploaded_trash_image.objects.filter( + # user_id=user_id, active=1, uploaded_trash_image_id=int(uploaded_trash_image_id)) + # uploaded_trashs.delete() + # return Response(status=status.HTTP_204_NO_CONTENT) def delete(self, request, user_id, uploaded_trash_image_id): - uploaded_trashs = uploaded_trash_image.objects.filter( - user_id=user_id, active=1, uploaded_trash_image_id=int(uploaded_trash_image_id)) - uploaded_trashs.delete() + uploaded_trash_image.objects.filter( + user_id=user_id, active=1, uploaded_trash_image_id=int(uploaded_trash_image_id)).update(active=0) return Response(status=status.HTTP_204_NO_CONTENT) @@ -49,22 +54,64 @@ def statistics(request, user_id): uploaded_trashs, many=True) return Response(serializer.data) -class UploadImage(CreateAPIView): - queryset = uploaded_trash_image.objects.all() - serializer_class = UploadedtrashimageCreateSerializer + @api_view(['GET']) -def ImageResultPage(request, uploaded_trash_image_id): - ############## uploaded_trash_image_id 로 ai.. result - result = '유리' - queryset = trash_kind.objects.filter(kind=result) - serializer = TrashkindSerializer(queryset, many=True) +def statistics_by_date(request, user_id, from_date, to_date): + start_date = from_date + end_date = datetime.strptime( + to_date, "%Y-%m-%d").date() + timedelta(days=1) + + uploaded_trashs = uploaded_trash_image.objects.filter( + user_id=user_id, created_at__range=(start_date, end_date)).values('trash_kind').annotate(cnt=Count('trash_kind')) + serializer = UploadedtrashimageStatisticsSerializer( + uploaded_trashs, many=True) return Response(serializer.data) + +############################## main page api ############################## +################################## under ################################## + + @api_view(['GET']) -def SearchResultPage(request, search_word): - ############## search_word - result = search_word - queryset = trash_kind.objects.filter(kind=result) +def searchResultPage(request, search_word): + # search_word + ai_result = search_word + queryset = trash_kind.objects.filter(kind=ai_result) serializer = TrashkindSerializer(queryset, many=True) return Response(serializer.data) + + +class UploadImage(APIView): + def post(self, request, user_id): + s3_client = boto3.client( + 's3', + aws_access_key_id=AWS_ACCESS_KEY_ID, + aws_secret_access_key=AWS_SECRET_ACCESS_KEY + ) + + image = request.FILES['filename'] + image_time = (str(datetime.now())).replace(" ", "") + image_type = (image.content_type).split("/")[1] + s3_client.upload_fileobj( + image, + "image-bucket2", + image_time+"."+image_type, + ExtraArgs={ + "ContentType": image.content_type + } + ) + image_url = "http://image-bucket2.s3.ap-northeast-2.amazonaws.com/" + \ + image_time+"."+image_type + image_url = image_url.replace(" ", "/") + + ai_result = "플라스틱" + + user_info = user.objects.get(id=user_id) + + uploaded_trash_image.objects.create( + active=user_info.save_img, img=image_url, user_id=user_info, trash_kind=trash_kind.objects.get(kind=ai_result)) + + trash_info = trash_kind.objects.filter(kind=ai_result) + serializer = TrashkindSerializer(trash_info, many=True) + return Response(serializer.data) diff --git a/backend/rebikeuser/JWT_Settings.py b/backend/rebikeuser/JWT_Settings.py new file mode 100644 index 0000000..92583cf --- /dev/null +++ b/backend/rebikeuser/JWT_Settings.py @@ -0,0 +1,4 @@ +SECRET_KEY = 'asweif' +ALGORITHM = 'HS256' +jWT_EXPIRATION_DELTA = 'datetime.timedelta(secs=60)' +JWT_REFRESH_EXPIRATION_DELTA='datetime.timedelta(days=7)' \ No newline at end of file diff --git a/backend/rebikeuser/__init__.py b/backend/rebikeuser/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/rebikeuser/migrations/0001_initial.py b/backend/rebikeuser/migrations/0001_initial.py index 503feb8..3e259c3 100644 --- a/backend/rebikeuser/migrations/0001_initial.py +++ b/backend/rebikeuser/migrations/0001_initial.py @@ -1,6 +1,7 @@ -# Generated by Django 4.0.6 on 2022-07-13 07:51 +# Generated by Django 4.0.6 on 2022-07-20 13:39 from django.db import migrations, models +import uuid class Migration(migrations.Migration): @@ -12,17 +13,21 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name='User', + name='user', fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), - ('user_name', models.CharField(max_length=20, unique=True)), - ('user_alias', models.CharField(max_length=20, unique=True)), - ('user_pw', models.CharField(max_length=64)), - ('user_email', models.CharField(max_length=50, unique=True)), + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('name', models.CharField(blank=True, max_length=20, null=True, unique=True)), + ('alias', models.CharField(max_length=20, unique=True)), + ('pw', models.BinaryField(max_length=60)), + ('salt', models.BinaryField(max_length=29)), + ('email', models.CharField(max_length=50)), + ('active', models.IntegerField(default=1)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('save_img', models.IntegerField(default=1)), ], options={ - 'db_table': 'User', - 'managed': False, + 'db_table': 'user', }, ), ] diff --git a/backend/rebikeuser/migrations/0002_alter_user_table.py b/backend/rebikeuser/migrations/0002_alter_user_table.py deleted file mode 100644 index e629f05..0000000 --- a/backend/rebikeuser/migrations/0002_alter_user_table.py +++ /dev/null @@ -1,18 +0,0 @@ - -# Generated by Django 4.0.6 on 2022-07-14 18:12 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('rebikeuser', '0001_initial'), - ] - - operations = [ - migrations.AlterModelTable( - name='user', - table='user', - ), - ] diff --git a/backend/rebikeuser/models.py b/backend/rebikeuser/models.py index 86ecaa1..6fcfb0f 100644 --- a/backend/rebikeuser/models.py +++ b/backend/rebikeuser/models.py @@ -1,6 +1,7 @@ from django.db import models import uuid + class user(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField(unique=True, max_length=20, null=True, blank=True) @@ -10,12 +11,8 @@ class user(models.Model): email = models.CharField(max_length=50) active = models.IntegerField(default=1) save_img = models.IntegerField(default=1) - created_at = models.DateTimeField() - updated_at = models.DateTimeField() - save_img = models.IntegerField(default=1) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) class Meta: - managed = False db_table = 'user' -#, default=str(uuid.uuid4()) - diff --git a/backend/rebikeuser/serializers.py b/backend/rebikeuser/serializers.py index 90a39aa..ca4b52e 100644 --- a/backend/rebikeuser/serializers.py +++ b/backend/rebikeuser/serializers.py @@ -22,9 +22,14 @@ class Meta: class SignupInput(serializers.ModelSerializer): # 검증부 + email = serializers.CharField(max_length=50) + pw = serializers.CharField(max_length=60) + alias = serializers.CharField(max_length=20) + name = serializers.CharField(max_length=20) + class Meta: model = user - fields = ['email', 'pw', 'alias', 'name'] + fields = ('email','pw','alias','name') # 프론트에주는 값 class AutoUpload(serializers.ModelSerializer): diff --git a/backend/rebikeuser/userUtil.py b/backend/rebikeuser/userUtil.py index a7975dc..9f9c76b 100644 --- a/backend/rebikeuser/userUtil.py +++ b/backend/rebikeuser/userUtil.py @@ -1,10 +1,38 @@ import uuid import bcrypt +import jwt +from .JWT_Settings import ALGORITHM, SECRET_KEY, jWT_EXPIRATION_DELTA from .models import user -from django.http import HttpResponse +from django.http import HttpResponse, JsonResponse +from datetime import datetime, timedelta +# 로그인 인증 데코레이터 필요한 경우 @login_check으로 실행 +def login_check(func): + def wrapper(request, *args, **kwargs): + try: + access_token = request.headers.get('Authorization', None) + payload = jwt.decode(access_token, SECRET_KEY, algorithms=ALGORITHM) + user_name = user.objects.get(name=payload['name']) + request.user = user_name + except jwt.exceptions.DecodeError: + return JsonResponse({'message': 'INVALID TOKEN'}, status=400) + except user.DoesNotExist: + return JsonResponse({'message': 'INVALID USER'}, status=400) + except jwt.exceptions.ExpiredSignatureError: + return JsonResponse({'message': 'INVALID TOKEN'}, status=400) + return func(request, *args, **kwargs) + + return wrapper + + +def generate_access_token(user, SECRET_KEY, ALGORITHM): + return jwt.encode({'name': user.name, 'exp': datetime.utcnow() + timedelta(seconds=1200)}, SECRET_KEY, ALGORITHM) + + +# def login_check(func): + # def user_change_alias(user, alias): if user and alias: @@ -53,13 +81,14 @@ def user_find_by_name(name): qs = user.objects.all() return qs.filter(name=name) + def user_find_by_email(email): return user.objects.all().filter(email=email) + # def user_find_by_alias(alias): - qs = user.objects.all() - return qs.filter(alias=alias) + return user.objects.all().filter(alias=alias) # diff --git a/backend/rebikeuser/views.py b/backend/rebikeuser/views.py index 994f0db..952ed92 100644 --- a/backend/rebikeuser/views.py +++ b/backend/rebikeuser/views.py @@ -3,13 +3,17 @@ from rest_framework.decorators import api_view from .serializers import UserSerializer, UserSignupResponse, SignupInput, AutoUpload -from .userUtil import user_find_by_name, user_compPW, user_create_client, user_change_pw, user_change_alias +from .userUtil import user_find_by_name, user_compPW, user_create_client, user_change_pw, user_change_alias, \ + login_check, generate_access_token from rest_framework.views import APIView from rest_framework.response import Response from django.http import HttpResponse from .models import user +from .JWT_Settings import ALGORITHM, SECRET_KEY +import jwt + @api_view(['POST']) def user_login(request): @@ -17,21 +21,24 @@ def user_login(request): input_pw = request.data['pw'] is_login = False user_data = None + access_token = None - data = {"user": None, "is_login": is_login} + data = {"user": None, "is_login": is_login, "access_token": access_token} if input_pw and input_name: user = user_find_by_name(input_name).first() if user: if user_compPW(input_pw, user): + access_token = generate_access_token(user, SECRET_KEY, ALGORITHM) temp = UserSerializer(data={'name': user.name, 'alias': user.alias, 'email': user.email}) if temp.is_valid(): user_data = temp.data is_login = True data = { "user": user_data, - "is_login": is_login + "is_login": is_login, + "access_token": access_token } - return JsonResponse(data) + return Response(data) # rebikeuser/views.py @@ -53,15 +60,9 @@ def post(self, request): serializer2 = UserSignupResponse(str, many=False) return Response(serializer2.data) # Only name - # return redirect('/user/signup/') - - -# get으로 회원가입 폼 화면 가져오기 -# def get(self, request): -# return HttpResponse('회원가입 폼 페이지 연결') - @api_view(['POST']) +@login_check def user_pw_change(request): input_name = request.data['name'] input_pw = request.data['pw'] # 새 비밀번호 @@ -79,6 +80,7 @@ def user_pw_change(request): @api_view(['POST']) +@login_check def user_alias_change(request): input_name = request.data['name'] input_alias = request.data['alias'] @@ -92,6 +94,7 @@ def user_alias_change(request): @api_view(['POST']) +@login_check def deactivateUser(request): name = request.data['name'] pw = request.data['pw'] @@ -115,6 +118,7 @@ def on_login(request): # @api_view(['POST']) +@login_check def isAutoSave(request): name = request.data['name'] is_login = request.data['is_login'] diff --git a/backend/requirements.txt b/backend/requirements.txt index 928d92e..e835d46 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -1,14 +1,54 @@ -django==4.0.6 -Pillow==9.2.0 +asgiref==3.5.2 +bcrypt==3.2.2 +certifi==2022.6.15 +cffi==1.15.1 +charset-normalizer==2.1.0 +coreapi==2.3.3 +coreschema==0.0.4 +distlib==0.3.4 +Django==4.0.6 +django-cors-headers==3.13.0 django-environ==0.9.0 -PyMySQL==1.0.2 -mysql-connector-python==8.0.23 -setuptools==58.1.0 -mysqlclient==2.1.1 -djangorestframework==3.13.1 django-filter==22.1 -django-rest-swagger==2.2.0 +djangorestframework==3.13.1 +djangorestframework-jwt==1.11.0 drf-yasg==1.21.0 -bcrypt==3.2.2 -pygments -django-cors-headers==3.13.0 +environ==1.0 +filelock==3.7.1 +idna==3.3 +inflection==0.5.1 +itypes==1.2.0 +Jinja2==3.1.2 +MarkupSafe==2.1.1 +mouse==0.7.1 +MouseInfo==0.1.3 +mysql-connector-python==8.0.29 +mysqlclient==2.1.1 +packaging==21.3 +Pillow==9.2.0 +platformdirs==2.5.2 +PyAutoGUI==0.9.53 +pycparser==2.21 +PyGetWindow==0.0.9 +PyJWT==1.7.1 +PyMsgBox==1.0.9 +PyMySQL==1.0.2 +pyparsing==3.0.9 +pyperclip==1.8.2 +PyRect==0.1.4 +PyScreeze==0.1.28 +pytweening==1.0.4 +pytz==2022.1 +requests==2.28.1 +ruamel.yaml==0.17.21 +ruamel.yaml.clib==0.2.6 +six==1.16.0 +sqlparse==0.4.2 +tzdata==2022.1 +uritemplate==4.1.1 +urllib3==1.26.10 +virtualenv==20.15.1 +#jwt==1.3.1 +cryptography==37.0.4 +boto3==1.24.33 +django-storages==1.12.3 diff --git a/backend/wait_mysql.py b/backend/wait_mysql.py new file mode 100644 index 0000000..7eb9cd9 --- /dev/null +++ b/backend/wait_mysql.py @@ -0,0 +1,29 @@ +import pymysql +from time import time, sleep +import logging + + +def mysql_is_ready(): + check_timeout = 30 + check_interval = 1 + + start_time = time() + logger = logging.getLogger() + logger.setLevel(logging.INFO) + logger.addHandler(logging.StreamHandler()) + + port = 3306 + host = 'mysqldb' + + while time() - start_time < check_timeout: + try: + pymysql.connect(host=host, port=port, user='root', passwd='root', db='test') + print("success") + return True + except pymysql.err.OperationalError: + sleep(check_interval) + logger.error(f"We could not connect to {host}:{port} within {check_timeout} seconds.") + return False + + +mysql_is_ready() \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 210b499..eea5093 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,14 +1,30 @@ version: "3" -services: +volumes: + mysql_data: +services: + mysqldb: + build: ./db + env_file: + - "./db/db.env" + ports: + - "8989:3306" + volumes: + - "mysql_data:/var/lib/mysql" backend: build: ./backend - command: [ "python","manage.py","runserver","0.0.0.0:8080" ] + command: > + bash -c "python wait_mysql.py && + python manage.py makemigrations && + python manage.py migrate && + python manage.py runserver 0.0.0.0:8080" ports: - "8080:8080" volumes: - ./backend:/app + depends_on: + - mysqldb frontend: build: ./frontend command: ["npm", "start"] @@ -16,11 +32,3 @@ services: - 3000:3000 volumes: - ./frontend:/app - mysqldb: - build: ./db - env_file: - - "./db/db.env" - ports: - - "8989:3306" - volumes: - - "./data/db/mysql:/var/lib/mysql" \ No newline at end of file