diff --git a/.idea/.idea/.gitignore b/.idea/.idea/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/.idea/.idea/.idea.iml b/.idea/.idea/.idea.iml new file mode 100644 index 0000000..d0876a7 --- /dev/null +++ b/.idea/.idea/.idea.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea/inspectionProfiles/Project_Default.xml b/.idea/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..5204d19 --- /dev/null +++ b/.idea/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea/inspectionProfiles/profiles_settings.xml b/.idea/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea/misc.xml b/.idea/.idea/misc.xml new file mode 100644 index 0000000..50dc922 --- /dev/null +++ b/.idea/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea/modules.xml b/.idea/.idea/modules.xml new file mode 100644 index 0000000..08f54a6 --- /dev/null +++ b/.idea/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea/workspace.xml b/.idea/.idea/workspace.xml new file mode 100644 index 0000000..0b98e2e --- /dev/null +++ b/.idea/.idea/workspace.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + 1691050027413 + + + + + + + + + + file://$PROJECT_DIR$/main.py + 8 + + + + + \ No newline at end of file diff --git a/.idea/.vs/.idea/v16/.suo b/.idea/.vs/.idea/v16/.suo new file mode 100644 index 0000000..8208ead Binary files /dev/null and b/.idea/.vs/.idea/v16/.suo differ diff --git a/.idea/.vs/ProjectSettings.json b/.idea/.vs/ProjectSettings.json new file mode 100644 index 0000000..f8b4888 --- /dev/null +++ b/.idea/.vs/ProjectSettings.json @@ -0,0 +1,3 @@ +{ + "CurrentProjectSetting": null +} \ No newline at end of file diff --git a/.idea/.vs/VSWorkspaceState.json b/.idea/.vs/VSWorkspaceState.json new file mode 100644 index 0000000..6b61141 --- /dev/null +++ b/.idea/.vs/VSWorkspaceState.json @@ -0,0 +1,6 @@ +{ + "ExpandedNodes": [ + "" + ], + "PreviewInSolutionExplorer": false +} \ No newline at end of file diff --git a/.idea/.vs/slnx.sqlite b/.idea/.vs/slnx.sqlite new file mode 100644 index 0000000..fde3847 Binary files /dev/null and b/.idea/.vs/slnx.sqlite differ diff --git a/.idea/main.py b/.idea/main.py new file mode 100644 index 0000000..5596b44 --- /dev/null +++ b/.idea/main.py @@ -0,0 +1,16 @@ +# This is a sample Python script. + +# Press Shift+F10 to execute it or replace it with your code. +# Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings. + + +def print_hi(name): + # Use a breakpoint in the code line below to debug your script. + print(f'Hi, {name}') # Press Ctrl+F8 to toggle the breakpoint. + + +# Press the green button in the gutter to run the script. +if __name__ == '__main__': + print_hi('PyCharm') + +# See PyCharm help at https://www.jetbrains.com/help/pycharm/ diff --git a/Exer/__pycache__/models.cpython-310.pyc b/Exer/__pycache__/models.cpython-310.pyc index d18e80e..cae4467 100644 Binary files a/Exer/__pycache__/models.cpython-310.pyc and b/Exer/__pycache__/models.cpython-310.pyc differ diff --git a/Exer/__pycache__/serializers.cpython-310.pyc b/Exer/__pycache__/serializers.cpython-310.pyc index d2aa1c0..3decf9e 100644 Binary files a/Exer/__pycache__/serializers.cpython-310.pyc and b/Exer/__pycache__/serializers.cpython-310.pyc differ diff --git a/Exer/__pycache__/views.cpython-310.pyc b/Exer/__pycache__/views.cpython-310.pyc index 03e9d09..2a47620 100644 Binary files a/Exer/__pycache__/views.cpython-310.pyc and b/Exer/__pycache__/views.cpython-310.pyc differ diff --git a/Exer/models.py b/Exer/models.py index 4eed0c2..1d35b4e 100644 --- a/Exer/models.py +++ b/Exer/models.py @@ -3,11 +3,13 @@ class Exercise(models.Model): exercise_id = models.IntegerField(primary_key=True) usebody = models.ForeignKey('usebody.Usebody', on_delete=models.CASCADE, max_length=11) + exerciseName_English= models.CharField(max_length=50, blank=True, null=True) exerciseName_Korean = models.CharField(max_length=50, blank=True, null=True) equipment_name = models.CharField(max_length=50, blank=True, null=True) videolink = models.CharField(max_length=150, blank=True, null=True) + class Meta: managed = False db_table = 'exercise' diff --git a/Exer/serializers.py b/Exer/serializers.py index f73aba0..96afb9f 100644 --- a/Exer/serializers.py +++ b/Exer/serializers.py @@ -1,12 +1,22 @@ from rest_framework import serializers from .models import Exercise +from usebody.models import Usebody +class BodySerializer(serializers.ModelSerializer): + class Meta: + model = Usebody + fields= '__all__' class ExerciseDetailSerializer(serializers.ModelSerializer): class Meta: model = Exercise - fields = ['exerciseName_English', 'exerciseName_Korean', 'equipment_name', 'videolink'] + fields = ['usebody_id','exerciseName_English', 'exerciseName_Korean', 'equipment_name', 'videolink'] class ExerciseSerializer(serializers.ModelSerializer): + #usebody_name = serializers.SerializerMethodField() + + # def get_usebody_name(self, obj): + # return obj.usebody_name class Meta: model = Exercise + fields = ['usebody_id', 'exerciseName_English', 'exerciseName_Korean'] diff --git a/Exer/views.py b/Exer/views.py index 29e3a32..1c3b4d4 100644 --- a/Exer/views.py +++ b/Exer/views.py @@ -7,16 +7,28 @@ from Exer.serializers import ExerciseDetailSerializer from django.shortcuts import get_object_or_404 +from django.db import connection #03-01 부위별 운동 간단 조회 -#usebody의 id 대신 name이 나오게 하려면 model을 수정해야 할 것으로 보임 class ExerciseBodyAPIiew(APIView): def get_object(self,pk): return Exercise.objects.filter(usebody_id=pk) def get(self,request,pk): + #pk를 usebody_id를 가지는 객체를 가져온다 + cursor = connection.cursor() + sql = "select usebody_name from usebody where usebody_id = %s" + cursor.execute(sql, [pk]) + result = cursor.fetchall() + exercise = self.get_object(pk) serializer = ExerciseSerializer(exercise, many=True) + + for i in serializer.data: + key = f'usebody_name' + value= result[0][0] + i[key] = value + return Response(serializer.data) @@ -33,12 +45,36 @@ def get(self, request,pk): #03-03 운동 검색 class ExerciseSearchAPIView(APIView): def post(self,request): - data = request.data + if request.body: + objectsKor = Exercise.objects.filter(exerciseName_English__icontains=request.data.get('searchData')) + objectsEng = Exercise.objects.filter(exerciseName_Korean__icontains=request.data.get('searchData')) + + combined_objects = list(objectsKor) + list(objectsEng) + + body = [] - exercise = Exercise.objects.filter(exerciseName_Korean=data) - serializer = ExerciseSerializer(exercise) + for i in combined_objects: + u_id = i.usebody_id + + cursor = connection.cursor() + sql = "select usebody_name from usebody where usebody_id = %s" + cursor.execute(sql, [u_id]) + result = cursor.fetchall() + body.append(result[0][0]) + + serializer = ExerciseSerializer(combined_objects, many=True) + + index = 0 + for i in serializer.data: + + key = f'usebody_name' + value = body[index] + i[key] = value + index+=1 - if serializer.is_valid(): return Response(serializer.data) - return Response(serializer.errors) + else: + objects = Exercise.objects.all() + serializer = ExerciseSerializer(objects, many=True) + return Response(serializer.data) diff --git a/__pycache__/my_settings.cpython-310.pyc b/__pycache__/my_settings.cpython-310.pyc index a54f124..6d6daec 100644 Binary files a/__pycache__/my_settings.cpython-310.pyc and b/__pycache__/my_settings.cpython-310.pyc differ diff --git a/accounts/__pycache__/__init__.cpython-311.pyc b/accounts/__pycache__/__init__.cpython-311.pyc index 0fa8d19..3116271 100644 Binary files a/accounts/__pycache__/__init__.cpython-311.pyc and b/accounts/__pycache__/__init__.cpython-311.pyc differ diff --git a/accounts/__pycache__/admin.cpython-311.pyc b/accounts/__pycache__/admin.cpython-311.pyc index 6ae62fb..13a6519 100644 Binary files a/accounts/__pycache__/admin.cpython-311.pyc and b/accounts/__pycache__/admin.cpython-311.pyc differ diff --git a/accounts/__pycache__/apps.cpython-311.pyc b/accounts/__pycache__/apps.cpython-311.pyc index c4fcda8..e52b135 100644 Binary files a/accounts/__pycache__/apps.cpython-311.pyc and b/accounts/__pycache__/apps.cpython-311.pyc differ diff --git a/accounts/__pycache__/backends.cpython-310.pyc b/accounts/__pycache__/backends.cpython-310.pyc new file mode 100644 index 0000000..19aee23 Binary files /dev/null and b/accounts/__pycache__/backends.cpython-310.pyc differ diff --git a/accounts/__pycache__/backends.cpython-311.pyc b/accounts/__pycache__/backends.cpython-311.pyc new file mode 100644 index 0000000..99fc45a Binary files /dev/null and b/accounts/__pycache__/backends.cpython-311.pyc differ diff --git a/accounts/__pycache__/models.cpython-310.pyc b/accounts/__pycache__/models.cpython-310.pyc index 032892a..7be31ab 100644 Binary files a/accounts/__pycache__/models.cpython-310.pyc and b/accounts/__pycache__/models.cpython-310.pyc differ diff --git a/accounts/__pycache__/models.cpython-311.pyc b/accounts/__pycache__/models.cpython-311.pyc index 7be3c70..4f708ac 100644 Binary files a/accounts/__pycache__/models.cpython-311.pyc and b/accounts/__pycache__/models.cpython-311.pyc differ diff --git a/accounts/__pycache__/serializers.cpython-310.pyc b/accounts/__pycache__/serializers.cpython-310.pyc new file mode 100644 index 0000000..c148aa9 Binary files /dev/null and b/accounts/__pycache__/serializers.cpython-310.pyc differ diff --git a/accounts/__pycache__/serializers.cpython-311.pyc b/accounts/__pycache__/serializers.cpython-311.pyc new file mode 100644 index 0000000..2336dae Binary files /dev/null and b/accounts/__pycache__/serializers.cpython-311.pyc differ diff --git a/accounts/__pycache__/urls.cpython-310.pyc b/accounts/__pycache__/urls.cpython-310.pyc new file mode 100644 index 0000000..756a16e Binary files /dev/null and b/accounts/__pycache__/urls.cpython-310.pyc differ diff --git a/accounts/__pycache__/urls.cpython-311.pyc b/accounts/__pycache__/urls.cpython-311.pyc new file mode 100644 index 0000000..ca48bc4 Binary files /dev/null and b/accounts/__pycache__/urls.cpython-311.pyc differ diff --git a/accounts/__pycache__/utils.cpython-310.pyc b/accounts/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000..9a133bd Binary files /dev/null and b/accounts/__pycache__/utils.cpython-310.pyc differ diff --git a/accounts/__pycache__/utils.cpython-311.pyc b/accounts/__pycache__/utils.cpython-311.pyc new file mode 100644 index 0000000..b536f2c Binary files /dev/null and b/accounts/__pycache__/utils.cpython-311.pyc differ diff --git a/accounts/__pycache__/views.cpython-310.pyc b/accounts/__pycache__/views.cpython-310.pyc new file mode 100644 index 0000000..4bb9c9b Binary files /dev/null and b/accounts/__pycache__/views.cpython-310.pyc differ diff --git a/accounts/__pycache__/views.cpython-311.pyc b/accounts/__pycache__/views.cpython-311.pyc new file mode 100644 index 0000000..e79ff24 Binary files /dev/null and b/accounts/__pycache__/views.cpython-311.pyc differ diff --git a/accounts/backends.py b/accounts/backends.py new file mode 100644 index 0000000..97d7780 --- /dev/null +++ b/accounts/backends.py @@ -0,0 +1,18 @@ +import bcrypt +from django.contrib.auth import get_user_model +from django.contrib.auth.backends import ModelBackend +from django.contrib.auth.hashers import check_password +from django.db.models import Q + + +class EmailBackend(ModelBackend): + def authenticate(self, request, username=None, password=None, **kwargs): + UserModel = get_user_model() + try: + user = UserModel.objects.get(email=username) + except UserModel.DoesNotExist: + return None + else: + if user.check_password(password): + return user + return None \ No newline at end of file diff --git a/accounts/migrations/0001_initial.py b/accounts/migrations/0001_initial.py new file mode 100644 index 0000000..3d97d95 --- /dev/null +++ b/accounts/migrations/0001_initial.py @@ -0,0 +1,35 @@ +# Generated by Django 4.2.3 on 2023-08-15 16:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + 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')), + ('email', models.EmailField(blank=True, max_length=100, unique=True)), + ('nickname', models.CharField(blank=True, max_length=20, unique=True)), + ('is_superuser', models.BooleanField(default=False)), + ('is_active', models.BooleanField(default=True)), + ('is_staff', models.BooleanField(default=False)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=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={ + 'abstract': False, + }, + ), + ] diff --git a/accounts/migrations/__pycache__/0001_initial.cpython-310.pyc b/accounts/migrations/__pycache__/0001_initial.cpython-310.pyc new file mode 100644 index 0000000..74b4ffe Binary files /dev/null and b/accounts/migrations/__pycache__/0001_initial.cpython-310.pyc differ diff --git a/accounts/migrations/__pycache__/0001_initial.cpython-311.pyc b/accounts/migrations/__pycache__/0001_initial.cpython-311.pyc new file mode 100644 index 0000000..6f5d180 Binary files /dev/null and b/accounts/migrations/__pycache__/0001_initial.cpython-311.pyc differ diff --git a/accounts/migrations/__pycache__/__init__.cpython-311.pyc b/accounts/migrations/__pycache__/__init__.cpython-311.pyc index 33b3d36..221fc72 100644 Binary files a/accounts/migrations/__pycache__/__init__.cpython-311.pyc and b/accounts/migrations/__pycache__/__init__.cpython-311.pyc differ diff --git a/accounts/models.py b/accounts/models.py index 988363b..bffbea0 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -1,24 +1,82 @@ +from django.contrib.auth.base_user import BaseUserManager from django.db import models +from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin -# Create your models here. -class User(models.Model): - user_id = models.IntegerField(primary_key=True) - nickname = models.CharField(max_length=10, blank=True, null=True) - password = models.CharField(max_length=20, blank=True, null=True) - email = models.CharField(max_length=100, blank=True, null=True) - class Meta: - managed = False - db_table = 'user' +# class User(models.Model): +# user_id = models.IntegerField(primary_key=True) +# nickname = models.CharField(max_length=10, blank=True, null=True) +# password = models.CharField(max_length=20, blank=True, null=True) +# email = models.CharField(max_length=100, blank=True, null=True) +# +# # USERNAME_FIELD = 'email' +# # REQUIRED_FIELDS = ['username'] +# +# class Meta: +# managed = False +# db_table = 'user' +# db_table_comment = '사용자 데이터' + + +class UserManager(BaseUserManager): + def create_user(self, email, nickname, password, **kwargs): + if not email: + raise ValueError('Users must have an email address') + + user = self.model( + email=self.normalize_email(email), + nickname=nickname + ) + user.set_password(password) + user.save(using=self._db) + return user + + def create_superuser(self, email=None, nickname=None, password=None): + superuser = self.create_user( + email=email, + nickname=nickname, + password=password, + ) + superuser.is_staff = True + superuser.is_superuser = True + superuser.is_active = True + superuser.save(using=self._db) + return superuser + +class User(AbstractBaseUser, PermissionsMixin): + objects = UserManager() + + email = models.EmailField(max_length=100, blank=False, null=False, unique=True) + nickname = models.CharField(max_length=20, blank=False, null=False, unique=True) + + is_superuser = models.BooleanField(default=False) + is_active = models.BooleanField(default=True) + is_staff = models.BooleanField(default=False) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + USERNAME_FIELD = 'email' + REQUIRED_FIELDS = ['nickname'] class Userinfo(models.Model): - user = models.ForeignKey(User, models.DO_NOTHING, blank=True, null=True) + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="user") height = models.IntegerField(blank=True, null=True) weight = models.FloatField(blank=True, null=True) bmi = models.FloatField(blank=True, null=True) - info = models.CharField(max_length=100, blank=True, null=True) - accvisibility = models.IntegerField(db_column='accVisibility', blank=True, null=True) # Field name made lowercase. + info = models.CharField(max_length=150, blank=True, null=True) + acc_visibility = models.IntegerField() class Meta: managed = False db_table = 'userinfo' + + +class Follow(models.Model): + id = models.AutoField(primary_key=True) + follower = models.ForeignKey(User, related_name='follower', on_delete=models.CASCADE) + following = models.ForeignKey(User, related_name='following', on_delete=models.CASCADE) + created_at = models.DateTimeField(auto_now_add=True) + + class Meta: + managed = False + db_table = 'follow' diff --git a/accounts/serializers.py b/accounts/serializers.py index e69de29..e1c012b 100644 --- a/accounts/serializers.py +++ b/accounts/serializers.py @@ -0,0 +1,29 @@ +import requests +from rest_framework import serializers + +from accounts.models import User, Follow, Userinfo + + +class UserSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = '__all__' + + def create(self, validated_data): + user = User.objects.create_user( + email=validated_data['email'], + nickname=validated_data['nickname'], + password=validated_data['password'] + ) + return user + + +class FollowSerializer(serializers.ModelSerializer): + class Meta: + model = Follow + fields = '__all__' + +class UserinfoSerializer(serializers.ModelSerializer): + class Meta: + model = Userinfo + fields = '__all__' diff --git a/accounts/urls.py b/accounts/urls.py new file mode 100644 index 0000000..a34cb24 --- /dev/null +++ b/accounts/urls.py @@ -0,0 +1,13 @@ +from django.urls import path, include + +from accounts.views import SigninAPIView, AuthAPIView, FollowAPIView, UserinfoAPIView, UserDetailAPIView + +urlpatterns = [ + # path('', include('dj_rest_auth.urls')), + # path('signin/', include('dj_rest_auth.registration.urls')), + path('signin/', SigninAPIView.as_view()), + path('auth/', AuthAPIView.as_view()), + path('follow/', FollowAPIView.as_view()), + path('info/', UserinfoAPIView.as_view()), + path('/', UserDetailAPIView.as_view()), +] \ No newline at end of file diff --git a/accounts/utils.py b/accounts/utils.py new file mode 100644 index 0000000..a216da4 --- /dev/null +++ b/accounts/utils.py @@ -0,0 +1,25 @@ +import jwt +import json + +from django.http import JsonResponse +from rest_framework import status +from rest_framework.response import Response + +from accounts.models import User +from my_settings import SECRET_KEY + + +def login_check(func): + def wrapper(self, request, *args, **kwargs): + try: + access = request.COOKIES.get('access') + # access_token = request.headers.get('Authorization', None) + payload = jwt.decode(access, SECRET_KEY, algorithms='HS256') + user = User.objects.get(id=payload['user_id']) + request.user = user + except jwt.exceptions.DecodeError: + return Response({'message': 'INVALID TOKEN'}, status=status.HTTP_400_BAD_REQUEST) + except User.DoesNotExist: + return Response({'message': 'INVALID USER'}, status=status.HTTP_400_BAD_REQUEST) + return func(self, request, *args, **kwargs) + return wrapper diff --git a/accounts/views.py b/accounts/views.py index 91ea44a..939efe1 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,3 +1,231 @@ -from django.shortcuts import render +import jwt +from django.contrib.auth import authenticate +from django.shortcuts import get_object_or_404 +from rest_framework import status +from rest_framework.response import Response +from rest_framework.views import APIView +from rest_framework_simplejwt.serializers import TokenObtainPairSerializer, TokenRefreshSerializer -# Create your views here. +from accounts.models import User, Follow, Userinfo +from accounts.serializers import UserSerializer, FollowSerializer, UserinfoSerializer +from accounts.utils import login_check +from my_settings import SECRET_KEY + + +# 01-01 이메일 회원가입 +class SigninAPIView(APIView): + def post(self, request): + serializer = UserSerializer(data=request.data) + if serializer.is_valid(): + user = serializer.save() + + # JWT 토큰 + token = TokenObtainPairSerializer.get_token(user) + refresh_token = str(token) + access_token = str(token.access_token) + res = Response( + { + "user": serializer.data, + "message": "Signin Success", + "token": { + "access": access_token, + "refresh": refresh_token, + }, + }, + status=status.HTTP_200_OK + ) + + res.set_cookie("access", access_token, httponly=True) + res.set_cookie("refresh", refresh_token, httponly=True) + + return res + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + +class AuthAPIView(APIView): + # 01 token에 따른 user 정보 가져오기 + def get(self, request): + try: + access = request.COOKIES.get('access') + payload = jwt.decode(access, SECRET_KEY, algorithms=['HS256']) + pk = payload.get('user_id') + user = get_object_or_404(User, pk=pk) + serializer = UserSerializer(instance=user) + return Response(serializer.data, status=status.HTTP_200_OK) + # token이 만료되었을 때 + # except(jwt.exceptions.ExpiredSignatureError): + # data = {'refresh': request.COOKIES.get('refresh', None)} + # serializer = TokenRefreshSerializer(data=data) + # if serializer.is_valid(raise_exception=True): + # access = serializer.data.get('access', None) + # refresh = serializer.data.get('refresh', None) + # payload = jwt.decode(access, SECRET_KEY, algorithms=['HS256']) + # pk = payload.get('user_id') + # user = get_object_or_404(User, pk=pk) + # serializer = UserSerializer(instance=user) + # res = Response(serializer.data, status=status.HTTP_200_OK) + # res.set_cookie('access', access) + # res.set_cookie('refresh', refresh) + # return res + # raise jwt.exceptions.InvalidTokenError + except(jwt.exceptions.ExpiredSignatureError): + data = {'refresh': request.COOKIES.get('refresh', None)} + serializer = TokenObtainPairSerializer(data=data) + if serializer.is_valid(raise_exception=True): + access = serializer.data.get('access_token', None) + refresh = serializer.data.get('refresh_token', None) + payload = jwt.decode(access, SECRET_KEY, algorithms=['HS256']) + pk = payload.get('user_id') + user = get_object_or_404(User, pk=pk) + serializer = UserSerializer(instance=user) + res = Response(serializer.data, status=status.HTTP_200_OK) + res.set_cookie('access_token', access) + res.set_cookie('refresh_token', refresh) + return res + raise jwt.exceptions.InvalidTokenError + # 사용 불가능한 토큰일 때 + except(jwt.exceptions.InvalidTokenError): + return Response(status=status.HTTP_400_BAD_REQUEST) + + # 01-02 이메일 로그인 + def post(self, request): + # user 인증 + user = authenticate( + username=request.data.get("email"), password=request.data.get("password") + ) + + # 회원가입한 user일 경우 + if user is not None: + serializer = UserSerializer(user) + # JWT 토큰 + token = TokenObtainPairSerializer.get_token(user) + refresh_token = str(token) + access_token = str(token.access_token) + res = Response( + { + "user": serializer.data, + "message": "Login Success", + "token": { + "access": access_token, + "refresh": refresh_token + }, + }, + status=status.HTTP_200_OK + ) + # JWT 토큰을 Cookie에 저장 + res.set_cookie("access", access_token, httponly=True) + res.set_cookie("refresh", refresh_token, httponly=True) + return res + else: + return Response(status=status.HTTP_400_BAD_REQUEST) + + # 01-03 이메일 로그아웃 + def delete(self, request): + response = Response({ + "message": "Logout Success" + }, status=status.HTTP_200_OK) + response.delete_cookie("access") + response.delete_cookie("refresh") + return response + + +class FollowAPIView(APIView): + # API 08-01 팔로잉 조회 + @login_check + def get(self, request): + user_id = request.user.id + following = Follow.objects.filter(follower_id=user_id) + serializer = FollowSerializer(following, many=True) + return Response(serializer.data) + + # API 08-02, 08-03 팔로우, 언팔로우 + @login_check + def post(self, request): + following_id = request.data.get('following_id') + user_following = get_object_or_404(User, id=following_id) + + if user_following == request.user: + return Response({'message': "Can't Follow Self"}, status=status.HTTP_400_BAD_REQUEST) + + is_following = Follow.objects.filter(follower=request.user, following=user_following).exists() + + if is_following: + # 팔로잉 중인 상태: unfollow + follow = Follow.objects.get(follower=request.user, following=user_following) + follow.delete() + message = 'Unfollowed Successfully' + else: + # 팔로잉 되어 있지 않은 상태: follow + Follow.objects.create(follower=request.user, following=user_following) + message = 'Followed Successfully' + + return Response({'messages': message}, status=status.HTTP_200_OK) + + +class UserinfoAPIView(APIView): + # API 02-01 회원 정보 입력 + @login_check + def post(self, request): + # User의 userinfo가 존재하는 지 확인 + is_exist = Userinfo.objects.filter(user_id=request.user.id) + if is_exist: + return Response({'message': 'User already had Userinfo'}, status=status.HTTP_400_BAD_REQUEST) + + # user 설정 + request.data['user'] = request.user.id + + # bmi 계산 + weight = request.data.get('weight') + height = request.data.get('height') * 0.01 + bmi = round(weight / (height * height), 2) + request.data['bmi'] = bmi + + serializer = UserinfoSerializer(data=request.data) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data, status=status.HTTP_200_OK) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + + # API 02-03 회원 정보 수정 + # PUT vs PATCH + # PUT : 모든 속성 수정 / PATCH : 일부 속성 수정 + @login_check + def put(self, request): + # User의 userinfo가 존재하는 지 확인 + is_exist = Userinfo.objects.filter(user_id=request.user.id) + if not is_exist: + return Response({'message': 'No Userinfo'}, status=status.HTTP_400_BAD_REQUEST) + + request.data['user'] = request.user.id + + userinfo = Userinfo.objects.get(user_id=request.user.id) + + # bmi 계산 + weight = request.data.get('weight') + height = request.data.get('height') * 0.01 + bmi = round(weight / (height * height), 2) + request.data['bmi'] = bmi + + serializer = UserinfoSerializer(userinfo, data=request.data) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data, status=status.HTTP_200_OK) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + +class UserDetailAPIView(APIView): + # user_id -> 해당 유저의 상세 정보 조회 + def get_object(self, pk): + return get_object_or_404(User, pk=pk) + + # API 02-02 회원 정보 조회 + def get(self, request, pk): + userinfo = Userinfo.objects.get(user_id=pk) + + # 계정 비공개 일 경우 + if userinfo.acc_visibility == 0: + return Response({'message': 'This account is Private account'}, status=status.HTTP_400_BAD_REQUEST) + + serializer = UserinfoSerializer(userinfo) + return Response(serializer.data, status=status.HTTP_200_OK) \ No newline at end of file diff --git a/broccoli/__pycache__/settings.cpython-310.pyc b/broccoli/__pycache__/settings.cpython-310.pyc index 3f113d6..c42abd5 100644 Binary files a/broccoli/__pycache__/settings.cpython-310.pyc and b/broccoli/__pycache__/settings.cpython-310.pyc differ diff --git a/broccoli/__pycache__/settings.cpython-311.pyc b/broccoli/__pycache__/settings.cpython-311.pyc index b6b7875..63ff606 100644 Binary files a/broccoli/__pycache__/settings.cpython-311.pyc and b/broccoli/__pycache__/settings.cpython-311.pyc differ diff --git a/broccoli/__pycache__/urls.cpython-310.pyc b/broccoli/__pycache__/urls.cpython-310.pyc index 2d57a1a..a2a316e 100644 Binary files a/broccoli/__pycache__/urls.cpython-310.pyc and b/broccoli/__pycache__/urls.cpython-310.pyc differ diff --git a/broccoli/__pycache__/urls.cpython-311.pyc b/broccoli/__pycache__/urls.cpython-311.pyc index 6a7a49e..321d621 100644 Binary files a/broccoli/__pycache__/urls.cpython-311.pyc and b/broccoli/__pycache__/urls.cpython-311.pyc differ diff --git a/broccoli/settings.py b/broccoli/settings.py index 7376f59..baee38f 100644 --- a/broccoli/settings.py +++ b/broccoli/settings.py @@ -9,7 +9,7 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/4.2/ref/settings/ """ - +from datetime import timedelta from pathlib import Path import my_settings @@ -28,11 +28,26 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] +#나중에 보안 상의 문제를 수정하려면 *를 삭제해야 함 +ALLOWED_HOSTS = ['*'] # Application definition +#user 설정 +AUTH_USER_MODEL = 'accounts.User' + +AUTHENTICATION_BACKENDS = [ + 'accounts.backends.EmailBackend', + 'django.contrib.auth.backends.ModelBackend', +] + +PASSWORD_HASHERS = [ + 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', + 'django.contrib.auth.hashers.PBKDF2PasswordHasher', + 'django.contrib.auth.hashers.Argon2PasswordHasher', +] + INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', @@ -40,9 +55,23 @@ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + + #라이브러리 'rest_framework', - 'Exer.apps.ExerConfig', + 'rest_framework_simplejwt', + + + # 'allauth', + # 'allauth.socialaccount', + # 'allauth.account', + 'rest_framework.authtoken', + # 'rest_auth.registration', + + #연동 + 'corsheaders', + #앱 'usebody.apps.UsebodyConfig', + 'Exer.apps.ExerConfig', 'routine.apps.RoutineConfig', 'accounts.apps.AccountsConfig', ] @@ -54,9 +83,31 @@ 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', + 'corsheaders.middleware.CorsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] +CORS_ORIGIN_ALLOW_ALL = False +CORS_ORIGIN_WHITELIST= ( + 'http://localhost:8080', + 'http://192.168.8.139:8080', +) + +REST_FRAMEWORK = { + 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'rest_framework_simplejwt.authentication.JWTAuthentication', + ), +} + +#JWT 설정 +SIMPLE_JWT = { + 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=30), + 'REFRESH_TOKEN_LIFETIME': timedelta(days=7), + 'ALGORITHM': 'HS256', + 'SIGNING_KEY': SECRET_KEY, + 'AUTH_HEADER_TYPES': ('JWT',), +} + ROOT_URLCONF = 'broccoli.urls' TEMPLATES = [ diff --git a/broccoli/urls.py b/broccoli/urls.py index b45c9f1..1fd896a 100644 --- a/broccoli/urls.py +++ b/broccoli/urls.py @@ -22,4 +22,5 @@ path('exercise/', include('Exer.urls')), path('usebody/', include('usebody.urls')), path('routine/', include('routine.urls')), + path('accounts/', include('accounts.urls')), ] diff --git a/my_settings.py b/my_settings.py index 8519ed8..05817be 100644 --- a/my_settings.py +++ b/my_settings.py @@ -6,7 +6,7 @@ 'USER': 'root', 'PASSWORD': 'apolonlee9', 'HOST': 'localhost', - 'PORT': '3308', + 'PORT': '3306', } } diff --git a/routine/__pycache__/models.cpython-310.pyc b/routine/__pycache__/models.cpython-310.pyc index f349bb2..e0e2b08 100644 Binary files a/routine/__pycache__/models.cpython-310.pyc and b/routine/__pycache__/models.cpython-310.pyc differ diff --git a/routine/__pycache__/serializers.cpython-310.pyc b/routine/__pycache__/serializers.cpython-310.pyc index da65e99..674591c 100644 Binary files a/routine/__pycache__/serializers.cpython-310.pyc and b/routine/__pycache__/serializers.cpython-310.pyc differ diff --git a/routine/__pycache__/urls.cpython-310.pyc b/routine/__pycache__/urls.cpython-310.pyc index 3b992c7..cbcea1c 100644 Binary files a/routine/__pycache__/urls.cpython-310.pyc and b/routine/__pycache__/urls.cpython-310.pyc differ diff --git a/routine/__pycache__/views.cpython-310.pyc b/routine/__pycache__/views.cpython-310.pyc index 7396370..04f0420 100644 Binary files a/routine/__pycache__/views.cpython-310.pyc and b/routine/__pycache__/views.cpython-310.pyc differ diff --git a/routine/models.py b/routine/models.py index 255d96c..a0cc211 100644 --- a/routine/models.py +++ b/routine/models.py @@ -29,7 +29,7 @@ class Meta: class RoutineBox(models.Model): box_id = models.IntegerField(primary_key=True) - user = models.ForeignKey('User.User', on_delete=models.CASCADE, max_length=11) + user = models.ForeignKey('accounts.User', on_delete=models.CASCADE, max_length=11) routine = models.ForeignKey('Routine', on_delete=models.CASCADE, max_length=11) class Meta: diff --git a/routine/serializers.py b/routine/serializers.py index 430e81e..e71d456 100644 --- a/routine/serializers.py +++ b/routine/serializers.py @@ -1,6 +1,7 @@ from rest_framework import serializers from .models import Routine from .models import RoutineDetail +from .models import RoutineBox class RoutineModifySerializer(serializers.ModelSerializer): def update(self, instance, validated_data): @@ -23,25 +24,52 @@ class Meta: class RoutineSerializer(serializers.ModelSerializer): class Meta: model = Routine - fields = ['routine_name', 'routine_comment', 'routine_day', 'owner_id'] + fields = ['routine_name', 'routine_comment', 'recommend_count','routine_day', 'owner_id'] class RoutineDetailSerializer(serializers.ModelSerializer): # def create(self, validated_data): # instance = RoutineDetail.objects.create(**validated_data) # return instance - def update(self, instance, validated_data): - instance.exercise_id = validated_data.get(' ', instance.exercise_id) - instance.usebody_id = validated_data.get(' ', instance.usebody_id) - class Meta: model= RoutineDetail - fields= ['routine', 'exercise', 'usebody', 'day'] + fields= ['routine', 'day'] + #뒤에 _id 안붙여도 되나? +class RoutineDetailCreateSerializer(serializers.ModelSerializer): + def update(self, instance, validated_data): + instance.exercise_id = validated_data.get(' ', instance.exercise_id) + instance.usebody_id = validated_data.get(' ', instance.usebody_id) + instance.routine_id = validated_data.get(' ', instance.routine_id) + class Meta: + model = RoutineDetail + fields= ['routine', 'exercise', 'usebody', 'day'] + class RoutineBoxSerializer(serializers.ModelSerializer): class Meta: model= RoutineBox fields= ['user', 'routine'] + def create(self, validated_data): + user = validated_data['user'] + routine= validated_data['routine'] + + if RoutineBox.objects.filter(user= user, routine=routine).exists(): + raise serializers.ValidationError("이미 존재하는 루틴입니다.") + + return RoutineBox.objects.create(**validated_data) + +class RoutinePopRecommendSerializer(serializers.ModelSerializer): + class Meta: + model= Routine + fields= ['routine_id', 'routine_name', 'routine_comment', 'recommend_count', 'routine_day', 'owner_id'] + + +class RoutineSearchSerializer(serializers.ModelSerializer): + + class Meta: + model= Routine + fields=['routine_name', 'routine_comment', 'owner_id'] + + - #request.user.id -> id 만 불러오고 \ No newline at end of file diff --git a/routine/urls.py b/routine/urls.py index 90c1654..7ebeb67 100644 --- a/routine/urls.py +++ b/routine/urls.py @@ -10,10 +10,14 @@ path('detail/', views.RoutineDetailCreateAPIView.as_view()), path('detail/check//', views.RoutineDetailCheckAPIView.as_view()), #path('detail/modify//', views.RoutineDetailModifyAPIView.as_view()), - path('detail/delete//', views.RoutineDetailDeleteAPIView.as_view()), + path('detail/delete/', views.RoutineDetailDeleteAPIView.as_view()), - path('box//', views.RoutineBoxCreateAPIView.as_view()), - path('box/check//', views.RoutineBoxCheckAPIView.as_view()), - path('box/delete//', views.RoutineBoxDeleteAPIView.as_view()), + path('box/', views.RoutineBoxCreateAPIView.as_view()), + path('box/check/', views.RoutineBoxCheckAPIView.as_view()), + path('box/delete/', views.RoutineBoxDeleteAPIView.as_view()), + path('recommend/pop/', views.PopularRecommendAPIView.as_view()), + path('recommend/follow/', views.FollowRecommendAPIView.as_view()), + + path('search/', views.RoutineSearchAPIView.as_view()), ] \ No newline at end of file diff --git a/routine/views.py b/routine/views.py index dc2f1ad..fed8272 100644 --- a/routine/views.py +++ b/routine/views.py @@ -1,5 +1,6 @@ from django.shortcuts import render +from accounts.utils import login_check # Create your views here. from rest_framework.views import APIView from rest_framework.response import Response @@ -9,15 +10,21 @@ from routine.models import RoutineDetail from routine.models import RoutineBox from usebody.models import Usebody +from accounts.models import Follow from routine.serializers import RoutineSerializer from routine.serializers import RoutinecheckSerializer from routine.serializers import RoutineModifySerializer from routine.serializers import RoutineDetailSerializer from routine.serializers import RoutineBoxSerializer +from routine.serializers import RoutinePopRecommendSerializer +from routine.serializers import RoutineSearchSerializer +from routine.serializers import RoutineDetailCreateSerializer from django.shortcuts import get_object_or_404 from django.shortcuts import get_list_or_404 +from django.http import JsonResponse +from django.db import connection @@ -27,6 +34,9 @@ def post(self,request): routine_data = { 'routine_name' : request.data.get('routine_name'), 'routine_comment' : request.data.get('routine_comment'), + #임시 + 'recommend_count' : request.data.get('recommend_count'), + 'routine_day' : request.data.get('routine_day'), 'owner_id' : request.data.get('owner_id'), } @@ -39,16 +49,27 @@ def post(self,request): #내가 담은 루틴 리스트 조회 5-2 class RoutineBoxCheckAPIView(APIView): - def get(self, request, pk): - box = get_list_or_404(RoutineBox, user_id=pk) + @login_check + def get(self, request): + box = get_list_or_404(RoutineBox, user_id=request.user.id) serializer = RoutineBoxSerializer(box, many=True) return Response(serializer.data) #내가 담은 루틴 리스트에 추가 5-3 class RoutineBoxCreateAPIView(APIView): - def post(self, request,pk): + @login_check + def post(self, request): + # box_data = { + # 'user_id': request.user.id, + # 'routine': request.data.get('routine'), + # } + + request.data['user'] = request.user.id serializer = RoutineBoxSerializer(data=request.data) + + + #serializer = RoutineBoxSerializer(data=box_data) #pk를 user_id로 넣고 request로 받은건 routine_id만 if serializer.is_valid(): serializer.save() @@ -56,9 +77,32 @@ def post(self, request,pk): return Response(serializer.errors) #내가 담은 루틴 리스트에서 삭제 5-4 -#class RoutineBoxDeleteAPIView(APIView): - # def delete(self,request,pk): +class RoutineBoxDeleteAPIView(APIView): + @login_check + def post(self,request): + request.data['user'] = request.user.id + + f1 = request.data.get('user') + f2 = request.data.get('routine') + + + queryset = RoutineBox.objects.filter(user=f1, routine=f2) + temp = queryset + deleted_data = { + 'message': '삭제 완료', + 'deleted_data': temp + } + + not_deleted= { + 'message' : '해당 루틴이 존재하지 않음' + } + + if queryset.exists(): + queryset.delete() + return Response(deleted_data, status=204) + else: + return Response(not_deleted, status=404) #루틴 조회 5-5 @@ -73,66 +117,135 @@ def get(self, request,pk): #루틴 수정 5-6 class RoutinePutAPIView(APIView): - def get_object(self,pk): - return get_object_or_404(Routine, pk=pk) + @login_check + def post(self,request, pk): + routine = get_object_or_404(Routine, pk=pk) - def put(self,request, pk): - routine = self.get_object(pk) serializer = RoutineModifySerializer(routine, data=request.data) + fail = { + "message": "수정 권한이 없습니다." + } + if serializer.is_valid(): - serializer.save() - return Response(serializer.data) + if request.user.id != routine.owner_id: + return Response(fail, status=404) + else: + serializer.save() + return Response(serializer.data) return Response(serializer.errors, status=400) #루틴 삭제 5-7 #루틴을 삭제할 때 루틴 세부 정보들도 함께 삭제해야 함 class RoutineDeleteAPIView(APIView): - def get_object(self,pk): - return get_object_or_404(Routine, pk=pk) - - def get_DetailObject(self, pk): - return get_list_or_404(RoutineDetail, routine_id=pk) - + @login_check def delete(self, request, pk): - routine = self.get_object(pk) - routineDetail = self.get_DetailObject(pk) + routine = get_object_or_404(Routine, pk=pk) + routineDetail = RoutineDetail.objects.filter(routine_id=pk) - #루틴 정보 삭제 - routine.delete() + if request.user.id == routine.owner_id: + # 루틴 정보 삭제 + routine.delete() - #루틴 세부 정보들도 함께 삭제 - for obj in routineDetail: - obj.delete() - - return Response(status=204) + # 루틴 세부 정보들도 함께 삭제 + for obj in routineDetail: + obj.delete() + success= { "message": "삭제 성공" } + return Response(success, status=204) + else: + fail = { "message": "삭제할 권한이 없습니다."} + return Response(fail, status=404) #루틴 세부사항 생성 5-8 class RoutineDetailCreateAPIView(APIView): + @login_check def post(self, request): - # 전달되는 값들 + cursor = connection.cursor() + sql = "select owner_id from routine where routine_id = %s" + sql2 = "select usebody_id from exercise where exercise_id= %s" + + cursor.execute(sql, [request.data.get('routine')]) + result = cursor.fetchall() + + cursor.execute(sql2, [request.data.get('exercise')]) + u_id = cursor.fetchall() + + r = request.data.get('routine') + e = request.data.get('exercise') + d = request.data.get('day') + routineDetail_data = { - 'routine' : request.data.get('routine'), - 'exercise': request.data.get('exercise'), - 'usebody': request.data.get('usebody'), - 'day': request.data.get('day'), + 'routine' : r, + 'exercise': e, + 'usebody': u_id[0][0], + 'day': d, } - serializer = RoutineDetailSerializer(data=routineDetail_data) - if serializer.is_valid(): - serializer.save() - return Response(serializer.data, status=201) - return Response(serializer.errors) + if result[0][0] == request.user.id: + if not RoutineDetail.objects.filter(exercise= e, routine = r, day = d): + serializer = RoutineDetailCreateSerializer(data=routineDetail_data) + + if serializer.is_valid(): + serializer.save() + return Response(serializer.data, status=201) + return Response(serializer.errors) + else: + over = {"message": "완전히 중복된 일정입니다."} + return Response(over, status = 404) + else: + NP= { + "message": "생성할 권한이 없습니다." + } + return Response(NP, status=404) #루틴 세부사항 조회 5-9 class RoutineDetailCheckAPIView(APIView): def get(self, request,pk): - routineDetail = get_list_or_404(RoutineDetail, routine_id=pk) - serializer = RoutineDetailSerializer(routineDetail, many=True) - return Response(serializer.data) + routineDetail = RoutineDetail.objects.filter(routine_id=pk) + + if routineDetail.exists() == False: + fail = { + "message": "루틴 세부 존재하지 않음" + } + return Response(fail , status = 404) + else: + r1, r2, r3 = '', '', '' + + for i in routineDetail: + cursor = connection.cursor() + sqlR = "select routine_name from routine where routine_id = %s" + sqlU = "select usebody_name from usebody where usebody_id = %s" + sqlE = "select exerciseName_english from exercise where exercise_id = %s" + #한글 번역 너무 구려서 영어로 함 + + cursor.execute(sqlR, [i.routine_id]) + r1 = (cursor.fetchall())[0][0] + + cursor.execute(sqlU, [i.usebody_id]) + r2 = (cursor.fetchall())[0][0] + + cursor.execute(sqlE, [i.exercise_id]) + r3 = (cursor.fetchall())[0][0] + + serializer = RoutineDetailSerializer(routineDetail, many=True) + + for i in serializer.data: + key1 = f'routine_name' + key2 = f'usebody_name' + key3 = f'exercise_name' + + value1 = r1 + value2 = r2 + value3 = r3 + + i[key1] = value1 + i[key2] = value2 + i[key3] = value3 + + return Response(serializer.data) #루틴 세부사항 수정 5-10 @@ -153,21 +266,112 @@ def get(self, request,pk): # 처음부터 url에 루틴 id를 넘겨주고 # 수정 시 해당 루틴에 해당하는 상세사항들만 불러와서 # day 몇을 어떤 운동으로 수정할거냐? 같은 느낌 -# -# day 몇에 있는 운동을 추가하거나 삭제하는 것. -# 그것이 생성 또는 삭제를 의미함. -# -# 삭제는 해당 루틴에 따른 운동을 모두 삭제한다. - #루틴 세부사항 삭제 5-11 class RoutineDetailDeleteAPIView(APIView): - def delete(self, request,pk): - routineDetail = get_object_or_404(RoutineDetail, pk= pk) - routineDetail.delete() + @login_check + def post(self, request): + routine_Detail = RoutineDetail.objects.filter(routine_detail_id= request.data.get('deleteData')) + + #어차피 하나만 검색됨 + for i in routine_Detail: + r_id = i.routine_id + + cursor = connection.cursor() + sql = "select owner_id from routine where routine_id = %s" + cursor.execute(sql, [r_id]) + result = cursor.fetchall() + + o_id = result[0][0] - return Response(status=204) + if o_id == request.user.id: + routine_Detail.delete() + success = { + "message": "삭제 성공" + } + return Response(success, status=204) + else: + fail = { + "message": "삭제 권한 없음" + } + return Response(fail, status=404) +#06-01 루틴 추천(팔로잉 중인 유저) +class FollowRecommendAPIView(APIView): + @login_check + def get(self, request): + user_id = request.user.id + objects = get_list_or_404(Follow, follower_id = user_id) + matching_ids = [obj.following_id for obj in objects] + r_objects= [] + + for i in matching_ids: + r_objects += list(Routine.objects.filter(owner_id= i)) + + serializer = RoutinecheckSerializer(r_objects, many=True) + + return Response(serializer.data) + + +#06-02 루틴 추천(인기순) +class PopularRecommendAPIView(APIView): + def get(self, request): + recom = Routine.objects.all().order_by('-recommend_count') + + serializer = RoutinePopRecommendSerializer(recom, many=True) + + return Response(serializer.data) + +#07-01 루틴 검색 +#routine_comment, routine_name, owner_id에 대해 검색 +class RoutineSearchAPIView(APIView): + def post(self, request): + if request.body: + # routine_name, comment, id 각각 검사 후 반환 + objectsName = Routine.objects.filter(routine_name__icontains=request.data.get('searchData')) + objectsComment = Routine.objects.filter(routine_comment__icontains=request.data.get('searchData')) + objectsId = Routine.objects.filter(owner_id__icontains=request.data.get('searchData')) + + combined_objects = list(objectsName)+ list(objectsComment) + list(objectsId) + + serializer = RoutineSearchSerializer(combined_objects, many=True) + + return Response(serializer.data) + else: + #검색에 아무것도 안 넣었을 경우 모든 루틴 반환 + objects = Routine.objects.all() + serializer = RoutineSearchSerializer(objects, many=True) + + return Response(serializer.data) + #각각 request 3개씩 해놓고 하는 방법 + # routineSearch_data = { + # 'routine_name': request.data.get('routine_name'), + # 'routine_comment': request.data.get('routine_comment'), + # 'owner_id': request.data.get('owner_id'), + # } + # + # if routineSearch_data['routine_name'] is not None: + # objects = Routine.objects.filter(routine_name = routineSearch_data['routine_name']) + # else: + # objects = Routine.objects.all() + # + # if routineSearch_data['routine_comment'] is not None: + # objects2 = [item for item in objects if item.routine_comment == routineSearch_data['routine_comment']] + # else: + # objects2 = objects + # + # if routineSearch_data['owner_id'] is not None: + # objects3 = [item for item in objects2 if item.owner_id == routineSearch_data['owner_id']] + # else: + # objects3 = objects2 + # + # serializer = RoutinecheckSerializer(objects3, many=True) + # + # #routine_name = routineSearch_data['routine_name'] + # #이런식으로 접근 할 것 + # #RoutineSearchSerializer(routineSearch_data, many=true) + # + # return Response(serializer.data) diff --git a/usebody/__pycache__/__init__.cpython-311.pyc b/usebody/__pycache__/__init__.cpython-311.pyc index 011c09e..dfa10ee 100644 Binary files a/usebody/__pycache__/__init__.cpython-311.pyc and b/usebody/__pycache__/__init__.cpython-311.pyc differ diff --git a/usebody/__pycache__/admin.cpython-311.pyc b/usebody/__pycache__/admin.cpython-311.pyc index 663961d..8316f7b 100644 Binary files a/usebody/__pycache__/admin.cpython-311.pyc and b/usebody/__pycache__/admin.cpython-311.pyc differ diff --git a/usebody/__pycache__/apps.cpython-311.pyc b/usebody/__pycache__/apps.cpython-311.pyc index e8f946e..90a19a8 100644 Binary files a/usebody/__pycache__/apps.cpython-311.pyc and b/usebody/__pycache__/apps.cpython-311.pyc differ diff --git a/usebody/__pycache__/models.cpython-311.pyc b/usebody/__pycache__/models.cpython-311.pyc index 8dcfda5..61d865e 100644 Binary files a/usebody/__pycache__/models.cpython-311.pyc and b/usebody/__pycache__/models.cpython-311.pyc differ diff --git a/usebody/__pycache__/serializers.cpython-311.pyc b/usebody/__pycache__/serializers.cpython-311.pyc index 8ec2747..4355538 100644 Binary files a/usebody/__pycache__/serializers.cpython-311.pyc and b/usebody/__pycache__/serializers.cpython-311.pyc differ diff --git a/usebody/__pycache__/urls.cpython-311.pyc b/usebody/__pycache__/urls.cpython-311.pyc index b8339aa..d50dafe 100644 Binary files a/usebody/__pycache__/urls.cpython-311.pyc and b/usebody/__pycache__/urls.cpython-311.pyc differ diff --git a/usebody/__pycache__/views.cpython-311.pyc b/usebody/__pycache__/views.cpython-311.pyc index 2701fca..394c574 100644 Binary files a/usebody/__pycache__/views.cpython-311.pyc and b/usebody/__pycache__/views.cpython-311.pyc differ diff --git a/usebody/migrations/__pycache__/0001_initial.cpython-311.pyc b/usebody/migrations/__pycache__/0001_initial.cpython-311.pyc index 3b507b2..ee3a983 100644 Binary files a/usebody/migrations/__pycache__/0001_initial.cpython-311.pyc and b/usebody/migrations/__pycache__/0001_initial.cpython-311.pyc differ diff --git a/usebody/migrations/__pycache__/__init__.cpython-311.pyc b/usebody/migrations/__pycache__/__init__.cpython-311.pyc index 3fa9a23..9a43af1 100644 Binary files a/usebody/migrations/__pycache__/__init__.cpython-311.pyc and b/usebody/migrations/__pycache__/__init__.cpython-311.pyc differ