Skip to content

Commit

Permalink
Add News post and comment
Browse files Browse the repository at this point in the history
  • Loading branch information
TheSuncatcher222 committed Nov 25, 2023
1 parent aa09613 commit 76bb131
Show file tree
Hide file tree
Showing 3 changed files with 235 additions and 11 deletions.
56 changes: 54 additions & 2 deletions backend/api/v1/schemas_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@
from rest_framework_simplejwt.serializers import (
TokenObtainPairSerializer, TokenRefreshSerializer,
)
from drf_spectacular.utils import inline_serializer, extend_schema, OpenApiParameter
from drf_spectacular.utils import (
OpenApiParameter,
inline_serializer, extend_schema,
)

from user.validators import (
PASS_ERROR, USER_FIRST_NAME_ERROR, USER_LAST_NAME_ERROR,
)
from api.v1.serializers import (
AppealAdminSerializer, AppealAnswerSerializer, AppealRatingSerializer,
AppealUserSerializer, AppealUserPostSerializer, NewsSerializer,
AppealUserSerializer, AppealUserPostSerializer,
NewsSerializer, NewsPostSerializer,
UserFullSerializer, UserRegisterSerializer,
)

Expand Down Expand Up @@ -194,6 +198,54 @@
),
},
),
'create': extend_schema(
description='Создает новость.',
summary='Создать новость.',
request=NewsPostSerializer,
responses={
status.HTTP_201_CREATED: NewsSerializer,
status.HTTP_400_BAD_REQUEST: inline_serializer(
name='news_create_error_400',
fields={
'category': serializers.CharField(
default=DEFAULT_400_REQUIRED,
),
'text': serializers.CharField(
default=DEFAULT_400_REQUIRED,
),
'address': serializers.CharField(
default=DEFAULT_400_REQUIRED,
),
'quiz': serializers.CharField(
default={
'answers': {
'answers': (
'В опросе не может быть менее 2 '
'вариантов ответа.'
)
},
},
),
},
),
status.HTTP_401_UNAUTHORIZED: inline_serializer(
name='news_post_error_401',
fields={
'detail': serializers.CharField(
default=DEFAULT_401,
),
},
),
status.HTTP_403_FORBIDDEN: inline_serializer(
name='news_post_error_403',
fields={
'detail': serializers.CharField(
default=DEFAULT_403,
),
},
),
},
),
}

TOKEN_OBTAIN_SCHEMA: dict[str, str] = {
Expand Down
130 changes: 127 additions & 3 deletions backend/api/v1/serializers.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
from django.db import transaction
from drf_spectacular.utils import extend_schema_field
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework import serializers

from info.models import Appeal, Answer, News, NewsComment, NewsPicture, Quiz
from info.models import (
Appeal, Answer, News, NewsComment, NewsPicture, ServiceCategory, Quiz,
)
from urban_utopia_2024.app_data import QUIZ_ANSWER_MAX_LEN
from user.models import Address, User


Expand Down Expand Up @@ -215,6 +219,7 @@ class Meta:
'address',
)

@transaction.atomic
def create(self, validated_data):
address, _ = Address.objects.get_or_create(
**validated_data.get('address')
Expand Down Expand Up @@ -245,8 +250,29 @@ class Meta:
)


class ServiceCategorySerializer(serializers.ModelSerializer):
"""Сериализатор представления категории услуг."""

class Meta:
model = ServiceCategory
fields = (
'id',
'name',
)


class NewsCommentSerializer(serializers.ModelSerializer):
"""Сериализатор получения картинок новости."""
"""Сериализатор валидации комментария новости."""

class Meta:
model = NewsComment
fields = (
'text',
)


class NewsCommentFullSerializer(serializers.ModelSerializer):
"""Сериализатор получения комментариев новости."""

author = UserShortSerializer()

Expand Down Expand Up @@ -290,14 +316,16 @@ class NewsSerializer(serializers.ModelSerializer):

address = AddressSerializer()
category = serializers.CharField(source='category.name')
comment = NewsCommentSerializer(many=True)
comment = NewsCommentFullSerializer(many=True)
municipal = MunicipalSerializer()
quiz = QuizSerializer()
picture = NewsPictureSerializer(many=True)

class Meta:
model = News
fields = (
'id',
'municipal',
'category',
'text',
'address',
Expand All @@ -308,6 +336,102 @@ class Meta:
)


class QuizPostSerializer(serializers.ModelSerializer):
"""Сериализатор создания опроса при создании новости."""

answers = serializers.ListField(child=serializers.CharField())

class Meta:
model = Quiz
fields = (
'title',
'answers',
)

def validate_answers(self, value):
"""Производит валидацию вариантов ответа к опросу."""
if len(value) < 2:
raise serializers.ValidationError(
detail={
"answers": (
'В опросе не может быть менее 2 вариантов ответа.'
)
},
)
for row in value:
if len(row) > QUIZ_ANSWER_MAX_LEN:
raise serializers.ValidationError(
detail={
"answers": (
'Длина варианта ответа не может превышать '
f'{QUIZ_ANSWER_MAX_LEN} символов.'
)
},
)
return value


class NewsPostSerializer(serializers.ModelSerializer):
"""Сериализатор публикации новости."""

address = AddressSerializer()
category = serializers.CharField()
quiz = QuizPostSerializer(required=False)
pictures = NewsPictureSerializer(many=True, required=False)

class Meta:
model = News
fields = (
'category',
'text',
'address',
'quiz',
'pictures',
)

def validate_category(self, value):
category: ServiceCategory = ServiceCategory.objects.filter(
name=value,
)
if not category.exists():
raise serializers.ValidationError(
detail='Указанной категории новостей не существует.'
)
return category.first()

@transaction.atomic
def create(self, validated_data):
address, _ = Address.objects.get_or_create(
**validated_data.get('address')
)
municipal: User = User.objects.get(id=self.context.get('municipal_id'))
news: News = News.objects.create(
municipal=municipal,
category=validated_data.get('category'),
text=validated_data.get('text'),
address=address,
)
quiz_data: dict[str, str] = validated_data.get('quiz')
if quiz_data:
quiz: Quiz = Quiz.objects.create(title=quiz_data.get('title'))
for answer in quiz_data.get('answers'):
Answer.objects.create(quiz=quiz, text=answer)
news.quiz: Quiz = quiz
news.save()
pictures_data: dict[str, str] = validated_data.get('pictures')
if pictures_data:
pictures_add: list[NewsPicture] = []
for picture in pictures_data:
pictures_add.append(
NewsPicture(
news=news,
picture=picture.get('picture'),
)
)
NewsPicture.objects.bulk_create(pictures_add)
return news


class UserRegisterSerializer(serializers.ModelSerializer):
"""Сериализатор регистрации пользователя."""

Expand Down
60 changes: 54 additions & 6 deletions backend/api/v1/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@
from api.v1.serializers import (
AppealAdminSerializer, AppealAnswerSerializer, AppealMunicipalSerializer,
AppealRatingSerializer, AppealUserSerializer, AppealUserPostSerializer,
NewsSerializer, UserFullSerializer, UserRegisterSerializer,
NewsSerializer, NewsCommentSerializer, NewsPostSerializer,
UserFullSerializer, UserRegisterSerializer,
)
from api.v1.schemas_views import (
APPEAL_SCHEMA, NEWS_SCHEMA, TOKEN_OBTAIN_SCHEMA,
TOKEN_REFRESH_SCHEMA, USERS_SCHEMA,
)
from info.models import Appeal, News
from info.models import Appeal, News, NewsComment
from urban_utopia_2024.app_data import APPEAL_STAGE_COMPLETED
from user.models import User

Expand Down Expand Up @@ -69,7 +70,7 @@ def create(self, request, *args, **kwargs):
permission_classes=(IsMunicipal,),
)
def post_answer(self, request, pk):
"""Позволяет давать ответ обращению"""
"""Оставить ответ обращению."""
appeal: Appeal = get_object_or_404(
Appeal,
id=pk,
Expand Down Expand Up @@ -102,7 +103,7 @@ def post_answer(self, request, pk):
permission_classes=(IsAuthenticated,),
)
def rate_answer(self, request, pk):
"""Позволяет ставить оценку обращению."""
"""Оставить оценку ответу обращения."""
appeal: Appeal = get_object_or_404(
Appeal, id=pk, user=self.request.user
)
Expand Down Expand Up @@ -143,7 +144,7 @@ class CustomTokenRefreshView(TokenRefreshView):
class NewsViewSet(ModelViewSet):
"""ViewSet для взаимодействия с моделью новостей."""

http_method_names = ('get',)
http_method_names = ('get', 'post',)
queryset = News.objects.select_related(
'category',
'address',
Expand All @@ -152,7 +153,54 @@ class NewsViewSet(ModelViewSet):
'picture',
'comment',
).all()
serializer_class = NewsSerializer

def get_permissions(self):
if self.action == 'add_comment':
self.permission_classes = [IsAuthenticated,]
elif self.request.method == 'POST':
self.permission_classes = [IsMunicipal,]
return super().get_permissions()

def get_serializer_class(self):
if self.request.method == 'POST':
return NewsPostSerializer
return NewsSerializer

def create(self, request, *args, **kwargs):
serializer: serializers = self.get_serializer(
data=request.data,
context={'municipal_id': request.user.id},
)
serializer.is_valid(raise_exception=True)
news_instance: News = serializer.save()
response_serializer: serializers = NewsSerializer(
instance=news_instance
)
return Response(
data=response_serializer.data,
status=status.HTTP_201_CREATED
)

@action(
methods=('post',),
detail=True,
url_name='add_comment',
permission_classes=(IsAuthenticated,),
)
def add_comment(self, request, pk):
"""Оставить комментарий к новости."""
news: News = get_object_or_404(News, id=pk)
serializer: serializers = NewsCommentSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
NewsComment.objects.create(
author=request.user,
news=news,
text=serializer.validated_data.get('text'),
)
return Response(
data={'comment': 'Ваш комментарий опубликован!'},
status=status.HTTP_201_CREATED,
)


@extend_schema_view(**USERS_SCHEMA)
Expand Down

0 comments on commit 76bb131

Please sign in to comment.