diff --git a/.idea/dictionaries/project.xml b/.idea/dictionaries/project.xml
new file mode 100644
index 0000000..779eda8
--- /dev/null
+++ b/.idea/dictionaries/project.xml
@@ -0,0 +1,8 @@
+
+
+
+ mpaa
+ viewset
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 9a8f74c..f6f7e02 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,7 +3,9 @@
-
+
+
+
\ No newline at end of file
diff --git a/movie_manager/permissions.py b/movie_manager/permissions.py
new file mode 100644
index 0000000..3dae833
--- /dev/null
+++ b/movie_manager/permissions.py
@@ -0,0 +1,6 @@
+from rest_framework import permissions
+from rest_framework.permissions import SAFE_METHODS
+
+class ReadOnly(permissions.BasePermission):
+ def has_permission(self, request, view):
+ return request.method in SAFE_METHODS
diff --git a/movie_manager/views.py b/movie_manager/views.py
index 2d606ea..e69de29 100644
--- a/movie_manager/views.py
+++ b/movie_manager/views.py
@@ -1,235 +0,0 @@
-import datetime
-
-from django.db.models import QuerySet
-from django.http import JsonResponse
-from django.contrib.auth.models import User
-from django.utils.dateparse import parse_datetime
-from django.db import models
-from rest_framework import permissions, viewsets
-from knox.auth import TokenAuthentication
-from rest_framework.decorators import action, api_view
-from rest_framework.exceptions import NotFound
-from rest_framework.permissions import AllowAny, SAFE_METHODS
-
-from movie_db.db_providers.omdb import OMDb
-from movie_manager.models import Movie, MovieList, Schedule, Showing
-from movie_manager.serializers import (
- MovieListSerializer,
- MovieSerializer,
- ScheduleSerializer,
- ShowingSerializer, MovieListListSerializer,
-)
-
-
-class ReadOnly(permissions.BasePermission):
- def has_permission(self, request, view):
- return request.method in SAFE_METHODS
-
-
-# Create your views here.
-class MovieViewset(viewsets.ModelViewSet):
- queryset = Movie.objects.all().order_by("title")
- authentication_classes = [TokenAuthentication]
- permission_classes = [permissions.IsAuthenticated]
-
- serializer_class = MovieSerializer
-
- def update(self, request, pk=None, *args, **kwargs):
- omdb = OMDb()
- updated_movie = omdb.search(request.data.get("imdb_id"), {"type": "imdb_id"})
-
- movie = Movie.objects.get(pk=pk)
-
- movie.title = updated_movie["title"]
- movie.actors = updated_movie["actors"]
- movie.year = updated_movie["year"]
- movie.critic_scores = updated_movie["critic_scores"]
- movie.mpaa_rating = updated_movie["mpaa_rating"]
- movie.director = updated_movie["director"]
- movie.poster = updated_movie["poster"]
- movie.plot = updated_movie["plot"]
- movie.genre = updated_movie["genre"]
-
- movie.save()
-
- return JsonResponse(MovieSerializer(movie).data)
-
-
-class MovieListViewset(viewsets.ModelViewSet):
- queryset = MovieList.objects.all()
- authentication_classes = [TokenAuthentication]
- permission_classes = [permissions.IsAuthenticated | ReadOnly]
-
- def get_serializer_class(self):
- if self.action == "list":
- return MovieListListSerializer
- else:
- return MovieListSerializer
-
- def get_queryset(self):
- base_qs = MovieList.objects.all()
-
- if self.action == "list":
- if self.request.user.is_authenticated:
- return base_qs.filter(
- models.Q(public=True) |
- models.Q(owner=self.request.user)
- ).order_by("name")
-
- return base_qs.filter(public=True).order_by("name")
- else:
- return MovieList.objects.prefetch_related(
- "movies",
- "movies__showing_set"
- ).order_by("name")
-
- def perform_create(self, serializer):
- serializer.save(owner=self.request.user)
-
- def get_permissions(self):
- if self.action in ['update', 'partial_update', 'destroy']:
- self.permission_classes = [permissions.IsAuthenticated]
- return super().get_permissions()
-
- def create(self, request, *args, **kwargs):
- movie_list = MovieList.objects.create(
- name=request.data.get("name"),
- owner=request.user,
- )
-
- return JsonResponse(MovieListSerializer(movie_list).data)
-
- def update(self, request, pk=None, *args, **kwargs):
- movie_list = MovieList.objects.get(pk=pk)
- movie_list.name = request.data.get("name")
- movie_list.owner = User.objects.get(pk=request.data.get("owner"))
-
- if request.data.get("movies"):
- movie_ids = request.data.get("movies")
- for movie_id in movie_ids:
- try:
- movie = Movie.objects.get(pk=movie_id)
- movie_list.movies.add(movie)
- except Movie.DoesNotExist:
- raise NotFound(f"Movie {movie_id} does not exist")
-
- removed_movies = Movie.objects.exclude(id__in=movie_ids)
- for removed_movie in removed_movies:
- removed_movie.delete()
-
- movie_list.save()
-
- return JsonResponse(MovieListSerializer(movie_list).data)
-
- @action(
- detail=True, methods=["put", "delete"], url_path="movie/(?Ptt[0-9]+)"
- )
- def add_movie(self, request, pk=None, imdb_id=None, *args, **kwargs):
- if request.method == "DELETE":
- return self.remove_movie(request, pk, imdb_id)
-
- movie_list = MovieList.objects.get(pk=pk)
- try:
- new_movie = Movie.objects.get(imdb_id=imdb_id)
- except Movie.DoesNotExist:
- omdb = OMDb()
- movie = omdb.search(imdb_id, {"type": "imdb_id"})
-
- new_movie = Movie.objects.create(
- title=movie["title"],
- actors=movie["actors"],
- year=movie["year"],
- imdb_id=movie["imdb_id"],
- poster=movie["poster"],
- plot=movie["plot"],
- genre=movie["genre"],
- critic_scores=movie["critic_scores"],
- mpaa_rating=movie["mpaa_rating"],
- director=movie["director"],
- added_by_id=request.user.id,
- )
-
- movie_list.movies.add(new_movie)
-
- return JsonResponse(MovieListSerializer(movie_list).data)
-
- def remove_movie(self, request, pk=None, imdb_id=None, *args, **kwargs):
- movie = Movie.objects.filter(imdb_id=imdb_id).first()
-
- movie_list = MovieList.objects.get(pk=pk)
- movie_list.movies.remove(movie)
-
- return JsonResponse(MovieListSerializer(movie_list).data)
-
-
-class ScheduleViewset(viewsets.ModelViewSet):
- queryset = Schedule.objects.all().order_by("name")
- authentication_classes = [TokenAuthentication]
- permission_classes = [permissions.IsAuthenticated | ReadOnly]
-
- serializer_class = ScheduleSerializer
-
- def retrieve(self, request, pk=None, *args, **kwargs):
- # Get the schedule instance
- instance = self.get_object()
- now = datetime.datetime.now()
- # get time from start of day
- today = datetime.datetime(now.year, now.month, now.day)
-
- upcoming_showings = Showing.objects.filter(
- showtime__gte=today, schedule=instance
- )
-
- # Create a serialized response
- serializer = self.get_serializer(instance)
- data = serializer.data
-
- # Replace all showings with only future showings
- data["showings"] = ShowingSerializer(upcoming_showings, many=True).data
-
- if request.GET.get("past_showings") == "true":
- past_showings = Showing.objects.filter(
- showtime__lt=today, schedule=instance
- )
-
- # Add both to the response
- data["past_showings"] = [
- {
- "id": showing.id,
- "showtime": showing.showtime.isoformat(),
- "movie": MovieSerializer(showing.movie).data,
- }
- for showing in past_showings
- ]
- else:
- data["past_showings"] = []
-
- return JsonResponse(data)
-
-
-class ShowingViewset(viewsets.ModelViewSet):
- queryset = Showing.objects.all().order_by("showtime")
- authentication_classes = [TokenAuthentication]
- permission_classes = [permissions.IsAuthenticated | ReadOnly]
-
- serializer_class = ShowingSerializer
-
- def create(self, request, *args, **kwargs):
- movie_id = request.data.get("movie")
- movie = Movie.objects.get(pk=movie_id)
-
- schedule_id = request.data.get("schedule")
- schedule = Schedule.objects.get(pk=schedule_id)
-
- showtime_str = request.data.get("showtime")
- showtime = parse_datetime(showtime_str)
-
- showing = Showing.objects.create(
- movie=movie,
- schedule=schedule,
- showtime=showtime,
- public=request.data.get("public"),
- owner=request.user,
- )
-
- return JsonResponse(ShowingSerializer(showing).data)
diff --git a/movie_manager/viewsets/__init__.py b/movie_manager/viewsets/__init__.py
new file mode 100644
index 0000000..da282d0
--- /dev/null
+++ b/movie_manager/viewsets/__init__.py
@@ -0,0 +1,11 @@
+from .movie import MovieViewset
+from .movie_list import MovieListViewset
+from .schedule import ScheduleViewset
+from .showing import ShowingViewset
+
+__all__ = [
+ "MovieViewset",
+ "MovieListViewset",
+ "ScheduleViewset",
+ "ShowingViewset",
+]
diff --git a/movie_manager/viewsets/movie.py b/movie_manager/viewsets/movie.py
new file mode 100644
index 0000000..c7b6977
--- /dev/null
+++ b/movie_manager/viewsets/movie.py
@@ -0,0 +1,37 @@
+from django.http import JsonResponse
+from rest_framework import permissions, viewsets
+
+from movie_db.db_providers.omdb import OMDb
+from movie_manager.models import Movie
+
+from knox.auth import TokenAuthentication
+
+from movie_manager.serializers import MovieSerializer
+
+
+class MovieViewset(viewsets.ModelViewSet):
+ queryset = Movie.objects.all().order_by("title")
+ authentication_classes = [TokenAuthentication]
+ permission_classes = [permissions.IsAuthenticated]
+
+ serializer_class = MovieSerializer
+
+ def update(self, request, pk=None, *args, **kwargs):
+ omdb = OMDb()
+ updated_movie = omdb.search(request.data.get("imdb_id"), {"type": "imdb_id"})
+
+ movie = Movie.objects.get(pk=pk)
+
+ movie.title = updated_movie["title"]
+ movie.actors = updated_movie["actors"]
+ movie.year = updated_movie["year"]
+ movie.critic_scores = updated_movie["critic_scores"]
+ movie.mpaa_rating = updated_movie["mpaa_rating"]
+ movie.director = updated_movie["director"]
+ movie.poster = updated_movie["poster"]
+ movie.plot = updated_movie["plot"]
+ movie.genre = updated_movie["genre"]
+
+ movie.save()
+
+ return JsonResponse(MovieSerializer(movie).data)
diff --git a/movie_manager/viewsets/movie_list.py b/movie_manager/viewsets/movie_list.py
new file mode 100644
index 0000000..75730b6
--- /dev/null
+++ b/movie_manager/viewsets/movie_list.py
@@ -0,0 +1,120 @@
+from django.http import JsonResponse
+from django.db import models
+from django.contrib.auth.models import User
+from rest_framework import permissions, viewsets
+from rest_framework.decorators import action
+from rest_framework.exceptions import NotFound
+
+from movie_db.db_providers.omdb import OMDb
+from movie_manager.models import MovieList, Movie
+
+from knox.auth import TokenAuthentication
+
+from movie_manager.permissions import ReadOnly
+from movie_manager.serializers import MovieListSerializer, MovieListListSerializer
+
+
+class MovieListViewset(viewsets.ModelViewSet):
+ queryset = MovieList.objects.all()
+ authentication_classes = [TokenAuthentication]
+ permission_classes = [permissions.IsAuthenticated | ReadOnly]
+
+ def get_serializer_class(self):
+ if self.action == "list":
+ return MovieListListSerializer
+ else:
+ return MovieListSerializer
+
+ def get_queryset(self):
+ base_qs = MovieList.objects.all()
+
+ if self.action == "list":
+ if self.request.user.is_authenticated:
+ return base_qs.filter(
+ models.Q(public=True) | models.Q(owner=self.request.user)
+ ).order_by("name")
+
+ return base_qs.filter(public=True).order_by("name")
+ else:
+ return MovieList.objects.prefetch_related(
+ "movies", "movies__showing_set"
+ ).order_by("name")
+
+ def perform_create(self, serializer):
+ serializer.save(owner=self.request.user)
+
+ def get_permissions(self):
+ if self.action in ["update", "partial_update", "destroy"]:
+ self.permission_classes = [permissions.IsAuthenticated]
+ return super().get_permissions()
+
+ def create(self, request, *args, **kwargs):
+ movie_list = MovieList.objects.create(
+ name=request.data.get("name"),
+ owner=request.user,
+ )
+
+ return JsonResponse(MovieListSerializer(movie_list).data)
+
+ def update(self, request, pk=None, *args, **kwargs):
+ movie_list = MovieList.objects.get(pk=pk)
+ movie_list.name = request.data.get("name")
+ movie_list.owner = User.objects.get(pk=request.data.get("owner"))
+
+ if request.data.get("movies"):
+ movie_ids = request.data.get("movies")
+ for movie_id in movie_ids:
+ try:
+ movie = Movie.objects.get(pk=movie_id)
+ movie_list.movies.add(movie)
+ except Movie.DoesNotExist:
+ raise NotFound(f"Movie {movie_id} does not exist")
+
+ removed_movies = Movie.objects.exclude(id__in=movie_ids)
+ for removed_movie in removed_movies:
+ removed_movie.delete()
+
+ movie_list.save()
+
+ return JsonResponse(MovieListSerializer(movie_list).data)
+
+ @action(
+ detail=True, methods=["put", "delete"], url_path="movie/(?Ptt[0-9]+)"
+ )
+ def add_movie(self, request, pk=None, imdb_id=None, *args, **kwargs):
+ if request.method == "DELETE":
+ return self.remove_movie(request, pk, imdb_id)
+
+ movie_list = MovieList.objects.get(pk=pk)
+ try:
+ new_movie = Movie.objects.get(imdb_id=imdb_id)
+ except Movie.DoesNotExist:
+ omdb = OMDb()
+ movie = omdb.search(imdb_id, {"type": "imdb_id"})
+
+ new_movie = Movie.objects.create(
+ title=movie["title"],
+ actors=movie["actors"],
+ year=movie["year"],
+ imdb_id=movie["imdb_id"],
+ poster=movie["poster"],
+ plot=movie["plot"],
+ genre=movie["genre"],
+ critic_scores=movie["critic_scores"],
+ mpaa_rating=movie["mpaa_rating"],
+ director=movie["director"],
+ added_by_id=request.user.id,
+ )
+
+ movie_list.movies.add(new_movie)
+
+ return JsonResponse(MovieListSerializer(movie_list).data)
+
+ @staticmethod
+ def remove_movie(request, pk=None, imdb_id=None, *args, **kwargs):
+ movie = Movie.objects.filter(imdb_id=imdb_id).first()
+
+ movie_list = MovieList.objects.get(pk=pk)
+ movie_list.movies.remove(movie)
+
+ return JsonResponse(MovieListSerializer(movie_list).data)
diff --git a/movie_manager/viewsets/schedule.py b/movie_manager/viewsets/schedule.py
new file mode 100644
index 0000000..856605a
--- /dev/null
+++ b/movie_manager/viewsets/schedule.py
@@ -0,0 +1,58 @@
+import datetime
+
+from django.http import JsonResponse
+from knox.auth import TokenAuthentication
+from rest_framework import viewsets, permissions
+
+from movie_manager.models import Schedule, Showing
+from movie_manager.permissions import ReadOnly
+from movie_manager.serializers import (
+ ScheduleSerializer,
+ ShowingSerializer,
+ MovieSerializer,
+)
+
+
+class ScheduleViewset(viewsets.ModelViewSet):
+ queryset = Schedule.objects.all().order_by("name")
+ authentication_classes = [TokenAuthentication]
+ permission_classes = [permissions.IsAuthenticated | ReadOnly]
+
+ serializer_class = ScheduleSerializer
+
+ def retrieve(self, request, pk=None, *args, **kwargs):
+ # Get the schedule instance
+ instance = self.get_object()
+ now = datetime.datetime.now()
+ # get time from start of day
+ today = datetime.datetime(now.year, now.month, now.day)
+
+ upcoming_showings = Showing.objects.filter(
+ showtime__gte=today, schedule=instance
+ )
+
+ # Create a serialized response
+ serializer = self.get_serializer(instance)
+ data = serializer.data
+
+ # Replace all showings with only future showings
+ data["showings"] = ShowingSerializer(upcoming_showings, many=True).data
+
+ if request.GET.get("past_showings") == "true":
+ past_showings = Showing.objects.filter(
+ showtime__lt=today, schedule=instance
+ )
+
+ # Add both to the response
+ data["past_showings"] = [
+ {
+ "id": showing.id,
+ "showtime": showing.showtime.isoformat(),
+ "movie": MovieSerializer(showing.movie).data,
+ }
+ for showing in past_showings
+ ]
+ else:
+ data["past_showings"] = []
+
+ return JsonResponse(data)
diff --git a/movie_manager/viewsets/showing.py b/movie_manager/viewsets/showing.py
new file mode 100644
index 0000000..1f3c887
--- /dev/null
+++ b/movie_manager/viewsets/showing.py
@@ -0,0 +1,36 @@
+from django.http import JsonResponse
+from django.utils.dateparse import parse_datetime
+from knox.auth import TokenAuthentication
+from rest_framework import viewsets, permissions
+
+from movie_manager.models import Showing, Movie, Schedule
+from movie_manager.permissions import ReadOnly
+from movie_manager.serializers import ShowingSerializer
+
+
+class ShowingViewset(viewsets.ModelViewSet):
+ queryset = Showing.objects.all().order_by("showtime")
+ authentication_classes = [TokenAuthentication]
+ permission_classes = [permissions.IsAuthenticated | ReadOnly]
+
+ serializer_class = ShowingSerializer
+
+ def create(self, request, *args, **kwargs):
+ movie_id = request.data.get("movie")
+ movie = Movie.objects.get(pk=movie_id)
+
+ schedule_id = request.data.get("schedule")
+ schedule = Schedule.objects.get(pk=schedule_id)
+
+ showtime_str = request.data.get("showtime")
+ showtime = parse_datetime(showtime_str)
+
+ showing = Showing.objects.create(
+ movie=movie,
+ schedule=schedule,
+ showtime=showtime,
+ public=request.data.get("public"),
+ owner=request.user,
+ )
+
+ return JsonResponse(ShowingSerializer(showing).data)
diff --git a/movienight/urls.py b/movienight/urls.py
index 22a5c6a..c07c5b5 100644
--- a/movienight/urls.py
+++ b/movienight/urls.py
@@ -10,25 +10,33 @@ from django.conf.urls.static import static
from django.conf import settings
from rest_framework.routers import DefaultRouter
+from movie_manager.viewsets import (
+ MovieViewset,
+ MovieListViewset,
+ ScheduleViewset,
+ ShowingViewset,
+)
from users import views as user_views
-from movie_manager import views as movie_views
from movie_db import views as movie_db_views
from rest_framework.authtoken.views import obtain_auth_token
+from users.viewsets.user import register
+from users.viewsets import UserViewSet, GroupViewSet
+
router = DefaultRouter()
-router.register(r"v1/users", user_views.UserViewSet)
-router.register(r"v1/groups", user_views.GroupViewSet)
-router.register(r"v1/movies", movie_views.MovieViewset)
-router.register(r"v1/lists", movie_views.MovieListViewset)
-router.register(r"v1/schedules", movie_views.ScheduleViewset)
-router.register(r"v1/showings", movie_views.ShowingViewset)
+router.register(r"v1/users", UserViewSet)
+router.register(r"v1/groups", GroupViewSet)
+router.register(r"v1/movies", MovieViewset)
+router.register(r"v1/lists", MovieListViewset)
+router.register(r"v1/schedules", ScheduleViewset)
+router.register(r"v1/showings", ShowingViewset)
urlpatterns = [
path("", include(router.urls)),
path("admin/", admin.site.urls),
path(r"v1/auth/token/", obtain_auth_token),
path(r"v1/auth/login/", user_views.LoginView.as_view(), name="knox_login"),
- path(r"v1/auth/register/", user_views.register, name="register"),
+ path(r"v1/auth/register/", register, name="register"),
path(r"v1/movies/search", movie_db_views.omdb_search, name="omdb_search"),
path(r"v1/auth/", include("knox.urls")),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
diff --git a/requirements.txt b/requirements.txt
index 456b8f8..7350802 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,4 @@
-django==5.1.4
+django==5.2.2
djangorestframework
django-rest-knox
markdown
diff --git a/users/views.py b/users/views.py
index bcc7f13..f231eee 100644
--- a/users/views.py
+++ b/users/views.py
@@ -1,40 +1,9 @@
from django.contrib.auth import login
-from django.contrib.auth.models import Group, User, AnonymousUser
-from rest_framework import permissions, viewsets, status
-from knox.auth import TokenAuthentication
+from rest_framework import permissions
from knox.views import LoginView as KnoxLoginView
from rest_framework.authtoken.serializers import AuthTokenSerializer
-from rest_framework.response import Response
-from rest_framework.decorators import api_view
-from users.serializers import GroupSerializer, UserSerializer
-
-
-class UserViewSet(viewsets.ModelViewSet):
- authentication_classes = [TokenAuthentication]
- permission_classes = [permissions.IsAuthenticated]
-
- queryset = User.objects.all().order_by("-date_joined")
- serializer_class = UserSerializer
-
-
-class GroupViewSet(viewsets.ModelViewSet):
- authentication_classes = [TokenAuthentication]
- permission_classes = [permissions.IsAuthenticated]
-
- queryset = Group.objects.all().order_by("name")
- serializer_class = GroupSerializer
-
-
-@api_view(["POST"])
-def register(request):
- user_data = UserSerializer(data=request.data)
-
- if user_data.is_valid():
- User.objects.create_user(**user_data.validated_data)
- return Response(request.data, status=status.HTTP_201_CREATED)
- else:
- return Response([], status=status.HTTP_400_BAD_REQUEST)
+from users.serializers import UserSerializer
class LoginView(KnoxLoginView):
diff --git a/users/viewsets/__init__.py b/users/viewsets/__init__.py
new file mode 100644
index 0000000..a3d0f22
--- /dev/null
+++ b/users/viewsets/__init__.py
@@ -0,0 +1,4 @@
+from .group import GroupViewSet
+from .user import UserViewSet
+
+__all__ = ["GroupViewSet", "UserViewSet"]
diff --git a/users/viewsets/group.py b/users/viewsets/group.py
new file mode 100644
index 0000000..7bbc91d
--- /dev/null
+++ b/users/viewsets/group.py
@@ -0,0 +1,13 @@
+from knox.auth import TokenAuthentication
+from django.contrib.auth.models import Group
+from rest_framework import viewsets, permissions, status
+
+from users.serializers import GroupSerializer
+
+
+class GroupViewSet(viewsets.ModelViewSet):
+ authentication_classes = [TokenAuthentication]
+ permission_classes = [permissions.IsAuthenticated]
+
+ queryset = Group.objects.all().order_by("name")
+ serializer_class = GroupSerializer
diff --git a/users/viewsets/user.py b/users/viewsets/user.py
new file mode 100644
index 0000000..c2e2063
--- /dev/null
+++ b/users/viewsets/user.py
@@ -0,0 +1,26 @@
+from django.contrib.auth.models import User, Group
+from knox.auth import TokenAuthentication
+from rest_framework import viewsets, permissions, status
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+
+from users.serializers import UserSerializer, GroupSerializer
+
+
+class UserViewSet(viewsets.ModelViewSet):
+ authentication_classes = [TokenAuthentication]
+ permission_classes = [permissions.IsAuthenticated]
+
+ queryset = User.objects.all().order_by("-date_joined")
+ serializer_class = UserSerializer
+
+
+@api_view(["POST"])
+def register(request):
+ user_data = UserSerializer(data=request.data)
+
+ if user_data.is_valid():
+ User.objects.create_user(**user_data.validated_data)
+ return Response(request.data, status=status.HTTP_201_CREATED)
+ else:
+ return Response([], status=status.HTTP_400_BAD_REQUEST)