diff --git a/apps/main/serializers/common.py b/apps/main/serializers/common.py index 4f7ad68f..fd3e32fe 100644 --- a/apps/main/serializers/common.py +++ b/apps/main/serializers/common.py @@ -1,11 +1,14 @@ """Main app serializers.""" +from typing import Union + from django.contrib.contenttypes.models import ContentType from rest_framework import serializers +from establishment.models import Employee from location.serializers import CountrySerializer from main import models -from establishment.models import Employee from tag.serializers import TagBackOfficeSerializer +from utils.exceptions import EmployeeNotFoundError from utils.serializers import ProjectModelSerializer, RecursiveFieldSerializer, TranslatedField @@ -207,6 +210,7 @@ class AwardBaseSerializer(serializers.ModelSerializer): """Award base serializer.""" title_translated = serializers.CharField(read_only=True, allow_null=True) + title = serializers.CharField(write_only=True, help_text='Title text') class Meta: model = models.Award @@ -215,45 +219,63 @@ class AwardBaseSerializer(serializers.ModelSerializer): 'title_translated', 'vintage_year', 'image_url', + 'title', ] + @property + def request(self): + """Return a request object""" + return self.context.get('request') + + @property + def context_kwargs(self) -> Union[dict, None]: + """Return a request kwargs.""" + if hasattr(self.request, 'parser_context'): + return self.request.parser_context.get('kwargs') + + def validate_title(self, value) -> dict: + """Construct title str to JSON that contains locale from request.""" + return {self.request.locale: value} + class AwardSerializer(AwardBaseSerializer): """Award serializer.""" - award_type = AwardTypeBaseSerializer(read_only=True) - class Meta: - model = models.Award + class Meta(AwardBaseSerializer.Meta): fields = AwardBaseSerializer.Meta.fields + ['award_type', ] class BackAwardSerializer(AwardBaseSerializer): """Award serializer.""" + award_type_display = AwardTypeBaseSerializer(read_only=True, + source='award_type') + award_type = serializers.PrimaryKeyRelatedField( + queryset=models.AwardType.objects.all(), + write_only=True, + required=True, + ) - award_type = AwardTypeBaseSerializer(read_only=True) - - class Meta: - model = models.Award + class Meta(AwardBaseSerializer.Meta): fields = AwardBaseSerializer.Meta.fields + [ 'award_type', + 'award_type_display', 'state', 'content_type', 'object_id', ] + def to_representation(self, instance): + data = super(BackAwardSerializer, self).to_representation(instance) + data['award_type'] = data.pop('award_type_display', None) + return data -class BackAwardEmployeeCreateSerializer(serializers.ModelSerializer): + +class BackAwardEmployeeCreateSerializer(AwardBaseSerializer): """Award, The Creator.""" - award_type = serializers.PrimaryKeyRelatedField(required=True, queryset=models.AwardType.objects.all()) - title = serializers.CharField(write_only=True) - def get_title(self, obj): - pass - - class Meta: - model = models.Award + class Meta(AwardBaseSerializer.Meta): fields = ( 'id', 'award_type', @@ -262,9 +284,15 @@ class BackAwardEmployeeCreateSerializer(serializers.ModelSerializer): ) def validate(self, attrs): - attrs['object_id'] = self.context.get('request').parser_context.get('kwargs')['employee_id'] + """An overridden validate method.""" + employee_id = self.context_kwargs.get('employee_id') + employee_qs = Employee.objects.filter(id=employee_id) + + if not employee_qs.exists(): + raise EmployeeNotFoundError() + + attrs['object_id'] = employee_id attrs['content_type'] = ContentType.objects.get_for_model(Employee) - attrs['title'] = {self.context.get('request').locale: attrs['title']} return attrs diff --git a/apps/main/urls/back.py b/apps/main/urls/back.py index 8b8f5102..8b1cd6e4 100644 --- a/apps/main/urls/back.py +++ b/apps/main/urls/back.py @@ -8,7 +8,8 @@ app_name = 'main' urlpatterns = [ path('awards/', views.AwardLstView.as_view(), name='awards-list-create'), path('awards//', views.AwardRUDView.as_view(), name='awards-rud'), - path('awards/create-and-bind//', views.AwardCreateAndBind.as_view(), name='award-employee-create'), + path('awards/create-and-bind//', views.AwardCreateAndBind.as_view(), + name='award-employee-create'), path('award-types/', views.AwardTypesListView.as_view(), name='awards-types-list'), path('content_type/', views.ContentTypeView.as_view(), name='content_type-list'), path('sites/', views.SiteListBackOfficeView.as_view(), name='site-list-create'), diff --git a/apps/main/views/back.py b/apps/main/views/back.py index 5584cf00..8f264ac6 100644 --- a/apps/main/views/back.py +++ b/apps/main/views/back.py @@ -17,7 +17,53 @@ from utils.methods import get_permission_classes class AwardLstView(generics.ListCreateAPIView): - """Award list create view.""" + """ + ## List of awards + ### *GET* + #### Description + Return paginated list of awards. + Available filters: + * establishment_id (`int`) - Filter by establishment identifier + * product_id (`int`) - Filter by product identifier + * employee_id (`int`) - Filter by employee identifier + * state (`enum`) - `0 (Waiting)`, `1 (Published)` + * award_type (`str`) - Filter by award type identifier + * vintage_year (`str`) - Filter by a vintage year + ##### Response + E.g.: + ``` + { + "count": 58, + "next": 2, + "previous": null, + "results": [ + { + "id": 1, + ... + } + ] + } + ``` + + ### *POST* + #### Description + Create a record in Award table. + ##### Request + Required: + * content_type (`int`) - identifier of content type entity + * object_id (`int`) - identifier of content object + * award_type (`int`) - identifier of award type + * title (`str`) - title of an award + Non required: + * vintage_year (str) - vintage year in a format - `yyyy` + ##### Response + ``` + { + "id": 1, + ... + } + ``` + """ queryset = Award.objects.all().with_base_related() serializer_class = serializers.BackAwardSerializer permission_classes = get_permission_classes() @@ -25,7 +71,35 @@ class AwardLstView(generics.ListCreateAPIView): class AwardCreateAndBind(generics.CreateAPIView): - """Award create and bind to employee by id""" + """ + ## Creating an Award for an Employee. + ### *POST* + #### Description + Creating an Award for an Employee and return in response + serialized Employee object. + ##### Response + E.g. + ``` + { + "id": 1, + ... + } + ``` + ##### Request + Required: + * award_type (`int`) - identifier of award type + * title (`str`) - title of an award + Non required: + * vintage_year (str) - vintage year in a format - `yyyy` + ##### Response + E.g. + ``` + { + "id": 1, + ... + } + ``` + """ queryset = Award.objects.all().with_base_related() serializer_class = serializers.BackAwardEmployeeCreateSerializer permission_classes = get_permission_classes() @@ -41,7 +115,52 @@ class AwardCreateAndBind(generics.CreateAPIView): class AwardRUDView(generics.RetrieveUpdateDestroyAPIView): - """Award RUD view.""" + """ + ## Retrieve/Update/Destroy Award view + ### *GET* + #### Description + Retrieving serialized object of an Award by an identifier + #### Response + E.g. + ``` + { + "id": 1, + ... + } + ``` + + ### *PATCH* + #### Description + Partially update Award object by identifier + ##### Request + Available: + * content_type (`int`) - identifier of content type entity + * object_id (`int`) - identifier of content object + * award_type (`int`) - identifier of award type + * title (`str`) - title of an award + * vintage_year (str) - vintage year in a format - `yyyy` + ##### Response + E.g. + ``` + { + "id": 1, + ... + } + ``` + + ### *DELETE* + #### Description + Delete an Award instance by award identifier + ##### Request + ``` + No request data + ``` + ##### Response + E.g. + ``` + No content + ``` + """ queryset = Award.objects.all().with_base_related() serializer_class = serializers.BackAwardSerializer permission_classes = get_permission_classes() diff --git a/apps/utils/exceptions.py b/apps/utils/exceptions.py index 03507ab0..3c88736b 100644 --- a/apps/utils/exceptions.py +++ b/apps/utils/exceptions.py @@ -32,6 +32,11 @@ class UserNotFoundError(AuthErrorMixin, ProjectBaseException): default_detail = _('User not found') +class EmployeeNotFoundError(ProjectBaseException): + """The exception should be thrown when the employee cannot get""" + default_detail = _('Employee not found') + + class EmailSendingError(exceptions.APIException): """The exception should be thrown when unable to send an email""" status_code = status.HTTP_400_BAD_REQUEST