Skip to content

Commit

Permalink
Merge pull request #18 from HE-Arc/pictures
Browse files Browse the repository at this point in the history
Pictures
  • Loading branch information
lugopi authored Apr 26, 2024
2 parents 2e1c9fb + c6043c0 commit 2509e6e
Show file tree
Hide file tree
Showing 33 changed files with 934 additions and 422 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,4 @@ frontend/package-lock.lock
.vscode/

backend/pictures
backend/schema.yml
1 change: 1 addition & 0 deletions backend/Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ djangorestframework = "3.14.0"
django-cors-headers = "4.3.1"
pillow="10.2.0"
djangorestframework-simplejwt="5.3.1"
drf-spectacular = "0.27.2"

[dev-packages]
black = "24.2.0"
Expand Down
12 changes: 12 additions & 0 deletions backend/kodecupid/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
'corsheaders',
"kodecupidapp",
"rest_framework",
'drf_spectacular',
]

REST_FRAMEWORK = {
Expand All @@ -57,6 +58,7 @@
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}

MIDDLEWARE = [
Expand Down Expand Up @@ -88,6 +90,16 @@
},
]

SPECTACULAR_SETTINGS = {
'TITLE': 'KodeCupid API',
'DESCRIPTION': 'KodeCupid API Documentation',
'VERSION': '1.0.0',
'SERVE_INCLUDE_SCHEMA': False,
}

MEDIA_URL = '/files/'
MEDIA_ROOT = BASE_DIR

WSGI_APPLICATION = 'kodecupid.wsgi.application'

# Database
Expand Down
37 changes: 30 additions & 7 deletions backend/kodecupid/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,43 @@
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from kodecupidapp.views import UserView, TagView, PictureView, LikeView, UserTagView
from django.urls import path, include

from rest_framework import routers

from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView

from kodecupidapp.views import (
UserView,
TagView,
PictureView,
LikeView,
SwipeView,
)

from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)

base_url = 'api/'

router = routers.DefaultRouter()
router.register('users', UserView, basename='user')
router.register('tags', TagView, basename='tag')
router.register('pictures', PictureView, basename='picture')
router.register('likes', LikeView, basename='like')
router.register('swipes', SwipeView, basename='swipe')

urlpatterns = [

path('admin/', admin.site.urls),

path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
path('api/', SpectacularSwaggerView.as_view(url_name='schema'), name='docs'),

path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('api/user/', UserView.as_view(), name='user'),
path('api/picture/', PictureView.as_view(), name='picture'),
path('api/tags/', TagView.as_view(), name='tag-list'),
path('api/like/', LikeView.as_view(), name='like-create'),
path('api/user/tags', UserTagView.as_view(), name='user-tag')

path(base_url, include(router.urls)),
]
22 changes: 22 additions & 0 deletions backend/kodecupidapp/migrations/0004_remove_tag_users_user_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 5.0.4 on 2024-04-03 22:20

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('kodecupidapp', '0003_like_unique_like'),
]

operations = [
migrations.RemoveField(
model_name='tag',
name='users',
),
migrations.AddField(
model_name='user',
name='tags',
field=models.ManyToManyField(related_name='tags', to='kodecupidapp.tag'),
),
]
1 change: 0 additions & 1 deletion backend/kodecupidapp/models/tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@

class Tag(models.Model):
name = models.CharField(max_length=100)
users = models.ManyToManyField('kodecupidapp.User', related_name='tags')
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
1 change: 1 addition & 0 deletions backend/kodecupidapp/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ class User(AbstractUser):
# Add additional fields
bio = models.CharField(max_length=100)
looking_for = models.CharField(max_length=100)
tags = models.ManyToManyField('kodecupidapp.Tag', related_name='tags')
pfp = models.ForeignKey(Picture, related_name='pfp', on_delete=models.CASCADE, null=True, blank=True)
4 changes: 3 additions & 1 deletion backend/kodecupidapp/serializers/picture.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from rest_framework import serializers
from ..models import Picture


class PictureSerializer(serializers.ModelSerializer):

class Meta:
model = Picture
fields = ['id', 'image', 'user']
fields = ['id', 'image', 'user']
5 changes: 3 additions & 2 deletions backend/kodecupidapp/views/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .like import LikeView
from .user import UserView, UserTagView
from .user import UserView
from .tag import TagView
from .picture import PictureView
from .picture import PictureView
from .swipe import SwipeView
13 changes: 7 additions & 6 deletions backend/kodecupidapp/views/like.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from rest_framework.views import APIView
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import CreateModelMixin
from rest_framework.response import Response
from rest_framework import status
from ..serializers import LikeSerializer
from ..models import Like

class LikeView(APIView):
class LikeView(GenericViewSet, CreateModelMixin):
serializer_class = LikeSerializer

def post(self, request):
serializer = LikeSerializer(data=request.data, context={'request': request})
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data, context={'request': request})
if serializer.is_valid():
like_instance = serializer.save()

Expand All @@ -16,9 +18,8 @@ def post(self, request):

match_exists = Like.objects.filter(source_user=target_user, target_user=source_user).exists()


response_data = serializer.data
response_data['match'] = match_exists

return Response(response_data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
68 changes: 39 additions & 29 deletions backend/kodecupidapp/views/picture.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,51 @@
from rest_framework.views import APIView
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import CreateModelMixin, RetrieveModelMixin, ListModelMixin, DestroyModelMixin
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from ..models import Picture
from ..serializers import PictureSerializer

import random
from django.http import HttpResponse

class PictureView(APIView):
import os


class PictureView(GenericViewSet, CreateModelMixin, RetrieveModelMixin, DestroyModelMixin):
queryset = Picture.objects.all()
serializer_class = PictureSerializer
permission_classes = [IsAuthenticated]

def post(self, request):
serializer = PictureSerializer(data=request.data)
def create(self, request):
modified_data = request.data.copy()
modified_data['user'] = request.user.id

serializer = self.get_serializer(data=modified_data)
if serializer.is_valid():
if request.user.id == int(request.data["user"]):
serializer.save()
return Response({"message": "Picture added successfully."}, status=status.HTTP_201_CREATED)
return Response({"message": "Picture cannot be added to another user."}, status=status.HTTP_403_FORBIDDEN)
instance = serializer.save()
# Access the ID of the newly created instance
new_id = instance.id
return Response({"message": "Picture added successfully.", "id": new_id}, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

def get(self, request):
id = request.data["id"]
if Picture.objects.filter(id = id).exists():
pic = Picture.objects.get(id = id)
serializer = PictureSerializer(pic, many=False)
return Response(serializer.data, status=status.HTTP_200_OK)
else:
return Response({"message": "Picture not found."}, status=status.HTTP_404_NOT_FOUND)

def delete(self, request):
id = int(request.data["id"])
if Picture.objects.filter(id = id).exists():
pic = Picture.objects.get(id = id)
if request.user.id == pic.user.id:
pic.delete()
return Response({"message": "Picture successfully deleted."},status=status.HTTP_204_NO_CONTENT)
return Response({"message": "Picture cannot be deleted by another user."}, status=status.HTTP_403_FORBIDDEN)
return Response({"message": "Picture not found."}, status=status.HTTP_404_NOT_FOUND)


def retrieve(self, request, pk=None):
instance = self.get_object()

# Get the image path
image_path = instance.image.path
# Read the image data
with open(image_path, 'rb') as image_file:
image_data = image_file.read()

# Return the image data in an HTTP response
response = HttpResponse(image_data, content_type='image/jpeg')
response['Content-Disposition'] = 'attachment; filename="image.jpg"'
return response


def destroy(self, request):
instance = self.get_object()
if request.user.id == instance.user.id:
self.perform_destroy(instance)
return Response({"message": "Picture successfully deleted."}, status=status.HTTP_204_NO_CONTENT)
return Response({"message": "Picture cannot be deleted by another user."}, status=status.HTTP_403_FORBIDDEN)
58 changes: 58 additions & 0 deletions backend/kodecupidapp/views/swipe.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.decorators import action

from drf_spectacular.utils import extend_schema, OpenApiParameter

from rest_framework.viewsets import GenericViewSet

from ..serializers import UserSerializer

from ..models import User, Like

import random



class SwipeView(GenericViewSet):
permission_classes = [IsAuthenticated]
serializer_class = UserSerializer

@action(detail=False, methods=['get'],url_path='<int:pk>')
def user_by_id(self,request, pk):
if User.objects.filter(id = pk).exists():
user = User.objects.get(id = pk)
serializer = self.serializer_class(user, many=False)
return Response(serializer.data, status=status.HTTP_200_OK)
else:
return Response({"message": "User not found."}, status=status.HTTP_404_NOT_FOUND)

@action(detail=False, methods=['get'])
def matches(self, request):
user = request.user

likes_target_user = Like.objects.filter(target_user=user).values_list('source_user', flat=True)
users = User.objects.filter(id__in=likes_target_user)

serializer = self.serializer_class(users, many=True)

return Response(serializer.data, status=status.HTTP_200_OK)

@action(detail=False, methods=['get'])
def random_user(self,request):
users = User.objects.exclude(id=request.user.id)

likes_source_user = Like.objects.filter(source_user=request.user).values_list('target_user', flat=True)
users = users.exclude(id__in=likes_source_user)

if len(users) == 0:
return Response({"message": "Looks like you liked them all"}, status=status.HTTP_404_NOT_FOUND)

user = random.choice(users)

serializer = self.serializer_class(user, many=False)

return Response(serializer.data, status=status.HTTP_200_OK)


55 changes: 8 additions & 47 deletions backend/kodecupidapp/views/tag.py
Original file line number Diff line number Diff line change
@@ -1,54 +1,15 @@
from rest_framework.views import APIView
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
from rest_framework import status
from ..models import Tag
from ..serializers import TagSerializer
from ..models import User

class TagView(GenericViewSet, ListModelMixin):
queryset = Tag.objects.all()
serializer_class = TagSerializer

class TagView(APIView):

def get(self, request):
tags = Tag.objects.all()
serializer = TagSerializer(tags, many=True)
def list(self, request, *args, **kwargs):
queryset = self.get_queryset()
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)

def post(self, request):

serializer = TagSerializer(data=request.data)

if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

user = request.user

tag_name = serializer.validated_data['name']
tag = get_object_or_404(Tag, name=tag_name)

if user in tag.users.all():
return Response({'message': 'User already has tag'}, status=status.HTTP_400_BAD_REQUEST)

tag.users.add(user)

return Response({'message': 'Tag added to user'}, status=status.HTTP_201_CREATED)


def delete(self, request):

serializer = TagSerializer(data=request.data)

if not serializer.is_valid():
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

user = request.user

tag_name = serializer.validated_data['name']
tag = get_object_or_404(Tag, name=tag_name)

if user not in tag.users.all():
return Response({'message': 'User does not have tag'}, status=status.HTTP_400_BAD_REQUEST)

tag.users.remove(user)

return Response({'message': 'Tag removed from user'}, status=status.HTTP_204_NO_CONTENT)
Loading

0 comments on commit 2509e6e

Please sign in to comment.