From da4d286a6e15e97b097918afe3a6ecf2535e6038 Mon Sep 17 00:00:00 2001 From: Volodymyr Pankiv Date: Mon, 16 Dec 2024 00:13:06 +0200 Subject: [PATCH] solution --- cinema/models.py | 2 +- cinema/permissions.py | 13 ++++++++ cinema/serializers.py | 11 ++----- cinema/urls.py | 12 ++----- cinema/views.py | 65 +++++++++++++++++++++++++------------- cinema_service/settings.py | 2 +- cinema_service/urls.py | 3 +- user/serializers.py | 24 +++++++++++++- user/urls.py | 13 +++++++- user/views.py | 25 ++++++++++++++- 10 files changed, 124 insertions(+), 46 deletions(-) create mode 100644 cinema/permissions.py diff --git a/cinema/models.py b/cinema/models.py index e9b22ecd..04a349bd 100644 --- a/cinema/models.py +++ b/cinema/models.py @@ -1,6 +1,6 @@ +from django.conf import settings from django.core.exceptions import ValidationError from django.db import models -from django.conf import settings class CinemaHall(models.Model): diff --git a/cinema/permissions.py b/cinema/permissions.py new file mode 100644 index 00000000..763ad777 --- /dev/null +++ b/cinema/permissions.py @@ -0,0 +1,13 @@ +from rest_framework.permissions import SAFE_METHODS, BasePermission + + +class IsAdminOrIfAuthenticatedReadOnly(BasePermission): + def has_permission(self, request, view): + return bool( + ( + request.method in SAFE_METHODS + and request.user + and request.user.is_authenticated + ) + or (request.user and request.user.is_staff) + ) diff --git a/cinema/serializers.py b/cinema/serializers.py index 7a6ae20c..48f48567 100644 --- a/cinema/serializers.py +++ b/cinema/serializers.py @@ -1,15 +1,8 @@ from django.db import transaction from rest_framework import serializers -from cinema.models import ( - Genre, - Actor, - CinemaHall, - Movie, - MovieSession, - Ticket, - Order, -) +from cinema.models import (Actor, CinemaHall, Genre, Movie, MovieSession, + Order, Ticket) class GenreSerializer(serializers.ModelSerializer): diff --git a/cinema/urls.py b/cinema/urls.py index 5ad6fb5b..15188e0a 100644 --- a/cinema/urls.py +++ b/cinema/urls.py @@ -1,14 +1,8 @@ -from django.urls import path, include +from django.urls import include, path from rest_framework import routers -from cinema.views import ( - GenreViewSet, - ActorViewSet, - CinemaHallViewSet, - MovieViewSet, - MovieSessionViewSet, - OrderViewSet, -) +from cinema.views import (ActorViewSet, CinemaHallViewSet, GenreViewSet, + MovieSessionViewSet, MovieViewSet, OrderViewSet) router = routers.DefaultRouter() router.register("genres", GenreViewSet) diff --git a/cinema/views.py b/cinema/views.py index a191bf5f..5ebaadeb 100644 --- a/cinema/views.py +++ b/cinema/views.py @@ -1,44 +1,57 @@ from datetime import datetime -from django.db.models import F, Count -from rest_framework import viewsets +from django.db.models import Count, F +from rest_framework import mixins, viewsets +from rest_framework.authentication import TokenAuthentication from rest_framework.pagination import PageNumberPagination +from rest_framework.permissions import IsAuthenticated -from cinema.models import Genre, Actor, CinemaHall, Movie, MovieSession, Order +from cinema.models import Actor, CinemaHall, Genre, Movie, MovieSession, Order +from cinema.permissions import IsAdminOrIfAuthenticatedReadOnly +from cinema.serializers import (ActorSerializer, CinemaHallSerializer, + GenreSerializer, MovieDetailSerializer, + MovieListSerializer, MovieSerializer, + MovieSessionDetailSerializer, + MovieSessionListSerializer, + MovieSessionSerializer, OrderListSerializer, + OrderSerializer) -from cinema.serializers import ( - GenreSerializer, - ActorSerializer, - CinemaHallSerializer, - MovieSerializer, - MovieSessionSerializer, - MovieSessionListSerializer, - MovieDetailSerializer, - MovieSessionDetailSerializer, - MovieListSerializer, - OrderSerializer, - OrderListSerializer, -) - -class GenreViewSet(viewsets.ModelViewSet): +class GenreViewSet(viewsets.GenericViewSet, + mixins.ListModelMixin, mixins.CreateModelMixin): queryset = Genre.objects.all() serializer_class = GenreSerializer + authentication_classes = (TokenAuthentication,) + permission_classes = (IsAdminOrIfAuthenticatedReadOnly,) -class ActorViewSet(viewsets.ModelViewSet): +class ActorViewSet(viewsets.GenericViewSet, + mixins.ListModelMixin, mixins.CreateModelMixin): queryset = Actor.objects.all() serializer_class = ActorSerializer + authentication_classes = (TokenAuthentication,) + permission_classes = (IsAdminOrIfAuthenticatedReadOnly,) -class CinemaHallViewSet(viewsets.ModelViewSet): +class CinemaHallViewSet( + viewsets.GenericViewSet, + mixins.ListModelMixin, + mixins.CreateModelMixin +): queryset = CinemaHall.objects.all() serializer_class = CinemaHallSerializer + authentication_classes = (TokenAuthentication,) + permission_classes = (IsAdminOrIfAuthenticatedReadOnly,) -class MovieViewSet(viewsets.ModelViewSet): +class MovieViewSet(viewsets.GenericViewSet, + mixins.ListModelMixin, + mixins.CreateModelMixin, + mixins.RetrieveModelMixin): queryset = Movie.objects.prefetch_related("genres", "actors") serializer_class = MovieSerializer + authentication_classes = (TokenAuthentication,) + permission_classes = (IsAdminOrIfAuthenticatedReadOnly,) @staticmethod def _params_to_ints(qs): @@ -87,6 +100,8 @@ class MovieSessionViewSet(viewsets.ModelViewSet): ) ) serializer_class = MovieSessionSerializer + authentication_classes = (TokenAuthentication,) + permission_classes = (IsAdminOrIfAuthenticatedReadOnly,) def get_queryset(self): date = self.request.query_params.get("date") @@ -118,12 +133,18 @@ class OrderPagination(PageNumberPagination): max_page_size = 100 -class OrderViewSet(viewsets.ModelViewSet): +class OrderViewSet( + mixins.ListModelMixin, + mixins.CreateModelMixin, + viewsets.GenericViewSet +): queryset = Order.objects.prefetch_related( "tickets__movie_session__movie", "tickets__movie_session__cinema_hall" ) serializer_class = OrderSerializer pagination_class = OrderPagination + authentication_classes = (TokenAuthentication,) + permission_classes = (IsAuthenticated,) def get_queryset(self): return Order.objects.filter(user=self.request.user) diff --git a/cinema_service/settings.py b/cinema_service/settings.py index 29ea7dea..062c0ac0 100644 --- a/cinema_service/settings.py +++ b/cinema_service/settings.py @@ -125,7 +125,7 @@ USE_I18N = True -USE_TZ = False +USE_TZ = True # Static files (CSS, JavaScript, Images) diff --git a/cinema_service/urls.py b/cinema_service/urls.py index bf903c00..34e7b5bb 100644 --- a/cinema_service/urls.py +++ b/cinema_service/urls.py @@ -1,8 +1,9 @@ from django.contrib import admin -from django.urls import path, include +from django.urls import include, path urlpatterns = [ path("admin/", admin.site.urls), path("api/cinema/", include("cinema.urls", namespace="cinema")), path("__debug__/", include("debug_toolbar.urls")), + path("api/user/", include("user.urls", namespace="user")), ] diff --git a/user/serializers.py b/user/serializers.py index fa56336e..6308a29b 100644 --- a/user/serializers.py +++ b/user/serializers.py @@ -1 +1,23 @@ -# write your code here +from django.contrib.auth import get_user_model +from rest_framework import serializers + + +class UserSerializer(serializers.ModelSerializer): + class Meta: + model = get_user_model() + fields = ("id", "username", "email", "password", "is_staff") + read_only_fields = ("id", "is_staff") + extra_kwargs = {"password": {"write_only": True, "min_length": 5}} + + def create(self, validated_data): + return get_user_model().objects.create_user(**validated_data) + + def update(self, instance, validated_data): + password = validated_data.pop("password", None) + user = super().update(instance, validated_data) + + if password: + user.set_password(password) + user.save() + + return user diff --git a/user/urls.py b/user/urls.py index fa56336e..67b2f62d 100644 --- a/user/urls.py +++ b/user/urls.py @@ -1 +1,12 @@ -# write your code here +from django.urls import path + +from user.views import CreateUserView, LoginUserView, ManageUserView + +urlpatterns = [ + path("register/", CreateUserView.as_view(), name="create"), + path("login/", LoginUserView.as_view(), name="login"), + path("me/", ManageUserView.as_view(), name="manage") + +] + +app_name = "user" diff --git a/user/views.py b/user/views.py index fa56336e..5e3ab1d3 100644 --- a/user/views.py +++ b/user/views.py @@ -1 +1,24 @@ -# write your code here +from rest_framework import generics +from rest_framework.authentication import TokenAuthentication +from rest_framework.authtoken.views import ObtainAuthToken +from rest_framework.permissions import IsAuthenticated +from rest_framework.settings import api_settings + +from user.serializers import UserSerializer + + +class CreateUserView(generics.CreateAPIView): + serializer_class = UserSerializer + + +class LoginUserView(ObtainAuthToken): + renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES + + +class ManageUserView(generics.RetrieveUpdateDestroyAPIView): + serializer_class = UserSerializer + authentication_classes = (TokenAuthentication,) + permission_classes = (IsAuthenticated,) + + def get_object(self): + return self.request.user