diff --git a/api/models.py b/api/models.py index 4933a5e..74bae12 100644 --- a/api/models.py +++ b/api/models.py @@ -14,11 +14,11 @@ def generate_unique_code(): # Create your models here. class Room(models.Model): - code = models.CharField(max_length=8, default="", unique=True) + code = models.CharField(max_length=8, default=generate_unique_code, unique=True) host = models.CharField(max_length=50, unique=True) guest_can_pause = models.BooleanField(null=False, default=False) votes_to_skip = models.IntegerField(null=False, default=0) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): - return f'Room ({self.code}' + return f'Room ({self.code})' diff --git a/api/serializers.py b/api/serializers.py index 4c8c862..c3b32e8 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -4,4 +4,16 @@ from .models import Room class RoomSerializer(serializers.ModelSerializer): class Meta: model = Room - fields = ('id', 'code', 'host', 'guest_can_pause', 'votes_to_skip', 'created_at') \ No newline at end of file + fields = ('id', 'code', 'host', 'guest_can_pause', 'votes_to_skip', 'created_at') + +class CreateRoomSerializer(serializers.ModelSerializer): + class Meta: + model = Room + fields = ('guest_can_pause', 'votes_to_skip') + +class UpdateRoomSerializer(serializers.ModelSerializer): + code = serializers.CharField(validators=[]) + + class Meta: + model = Room + fields = ('guest_can_pause', 'votes_to_skip', 'code') \ No newline at end of file diff --git a/api/urls.py b/api/urls.py index 3e7ee13..506ded9 100644 --- a/api/urls.py +++ b/api/urls.py @@ -2,5 +2,11 @@ from django.urls import path from . import views urlpatterns = [ - path('rooms', views.RoomView.as_view(), name="rooms") + path('rooms', views.RoomView.as_view(), name="rooms"), + path('rooms/create', views.CreateRoomView.as_view(), name="create-room"), + path('rooms/get', views.GetRoom.as_view(), name="get-room"), + path('rooms/join', views.JoinRoom.as_view(), name="join-room"), + path('rooms/leave', views.LeaveRoom.as_view(), name='leave-room'), + path('rooms/update', views.UpdateRoomView.as_view(), name='update-room'), + path('rooms/user-details', views.UserDetails.as_view(), name='user-details') ] diff --git a/api/views.py b/api/views.py index 3f1a2ab..6945d8b 100644 --- a/api/views.py +++ b/api/views.py @@ -1,16 +1,124 @@ from django.shortcuts import render -from rest_framework.generics import CreateAPIView +from django.http import JsonResponse +from rest_framework.views import APIView +from rest_framework.generics import ListAPIView +from rest_framework import status from rest_framework.response import Response -from .serializers import RoomSerializer +from .serializers import RoomSerializer, CreateRoomSerializer, UpdateRoomSerializer from .models import Room # Create your views here. -class RoomView(CreateAPIView): +class RoomView(ListAPIView): queryset = Room.objects.all() serializer_class = RoomSerializer +class GetRoom(APIView): + serializer_class = RoomSerializer + lookup_url_kwarg = 'code' + def get(self, request, format=None): - rooms = Room.objects.all() - serializer = RoomSerializer(rooms, many=True) - return Response(serializer.data) \ No newline at end of file + code = request.GET.get(self.lookup_url_kwarg) + if code != None: + room = Room.objects.filter(code=code) + if room.exists(): + data = RoomSerializer(room[0]).data + data['is_host'] = self.request.session.session_key == room[0].host + return Response(data, status=status.HTTP_200_OK) + else: + return Response({'Room Not Found': 'Invalid Room Code.'}, status=status.HTTP_400_BAD_REQUEST) + +class JoinRoom(APIView): + lookup_url_kwarg = 'code' + + def post(self, request, format=None): + if not self.request.session.exists(self.request.session.session_key): + self.request.session.create() + + code = request.data.get(self.lookup_url_kwarg) + if code != None: + room_set = Room.objects.filter(code=code) + if room_set.exists(): + room = room_set[0] + self.request.session['code'] = code + return Response({'message': 'Room Joined.'}, status=status.HTTP_200_OK) + else: + return Response({'Bad Request': 'Invalid room code'}, status=status.HTTP_400_BAD_REQUEST) + else: + return Response({'Bad Request': 'Invalid data, did not find code'}, status=status.HTTP_400_BAD_REQUEST) + +class LeaveRoom(APIView): + def patch(self, request, format=None): + if 'code' in self.request.session: + self.request.session.pop('code') + host = self.request.session.session_key + room_set = Room.objects.filter(host=host) + if room_set.exists(): + room = room_set[0] + room.delete() + + return Response({'message': 'Success'}, status=status.HTTP_200_OK) + +class CreateRoomView(APIView): + serializer_class = CreateRoomSerializer + + def post(self, request, format=None): + if not self.request.session.exists(self.request.session.session_key): + self.request.session.create() + + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(): + guest_can_pause = serializer.data.get("guest_can_pause") + votes_to_skip = serializer.data.get("votes_to_skip") + host = self.request.session.session_key + queryset = Room.objects.filter(host=host) + if queryset.exists(): + room = queryset[0] + room.guest_can_pause = guest_can_pause + room.votes_to_skip = votes_to_skip + room.save(update_fields=['guest_can_pause', 'votes_to_skip']) + self.request.session['code'] = room.code + return Response(RoomSerializer(room).data, status=status.HTTP_200_OK) + else: + room = Room(host=host, guest_can_pause=guest_can_pause, votes_to_skip=votes_to_skip) + room.save() + self.request.session['code'] = room.code + return Response(RoomSerializer(room).data, status=status.HTTP_201_CREATED) + else: + return Response({'Bad Request': 'Invalid data...'}, status=status.HTTP_400_BAD_REQUEST) + +class UpdateRoomView(APIView): + serializer_class = UpdateRoomSerializer + def patch(self, request, format=None): + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(): + guest_can_pause = serializer.data.get('guest_can_pause') + votes_to_skip = serializer.data.get('votes_to_skip') + code = serializer.data.get('code') + + room_set = Room.objects.filter(code=code) + if room_set.exists(): + room = room_set[0] + user_id = self.request.session.session_key + if room.host != user_id: + return Response({'message': 'You are not the host of this room.'}, status = status.HTTP_403_FORBIDDEN) + + room.guest_can_pause = guest_can_pause + room.votes_to_skip = votes_to_skip + room.code = code + room.save(update_fields=['guest_can_pause', 'votes_to_skip']) + return Response(RoomSerializer(room).data, status=status.HTTP_200_OK) + else: + return Response({'Bad Request': 'No room was found'}, status=status.HTTP_404_NOT_FOUND) + + return Response({'Bad Request': 'Invalid data'}, status=status.HTTP_400_BAD_REQUEST) + + +class UserDetails(APIView): + def get(self, request, format=None): + if not self.request.session.exists(self.request.session.session_key): + self.request.session.create() + data = { + 'code': self.request.session.get('code') + } + return JsonResponse(data, status=status.HTTP_200_OK) \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index f4531b0..ce32feb 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -31,6 +31,9 @@ "@babel/plugin-proposal-class-properties": "^7.12.1", "@material-ui/core": "^4.11.2", "@material-ui/icons": "^4.11.2", + "@material-ui/lab": "^4.0.0-alpha.57", + "eslint-config-react-app": "^6.0.0", + "eslint-plugin-jest": "^24.1.3", "react-router-dom": "^5.2.0" } } diff --git a/frontend/src/App.js b/frontend/src/App.js index 4146e1f..a6b43db 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,46 +1,22 @@ -import React, { useEffect, useState } from "react"; -import Hello from "./components/Hello"; -import { useFetch } from "./useFetch"; -import { useForm } from "./useForm"; +import React from "react"; +import { BrowserRouter as Router, Route, Switch } from "react-router-dom"; +import CreateRoom from "./components/CreateRoom"; +import Home from "./components/Home"; +import JoinRoom from "./components/JoinRoom"; +import Room from "./components/Room"; const App = (props) => { - const [values, handleChange] = useForm({ - firstName: "", - email: "", - password: "", - }); - - const [count, setCount] = useState(0); - const { data, loading } = useFetch(`http://numbersapi.com/${count}/math`); return ( - <> -