import requests from django.conf import settings from rest_framework import viewsets, status from rest_framework.decorators import detail_route from rest_framework.exceptions import ValidationError from rest_framework.generics import get_object_or_404 from rest_framework.pagination import PageNumberPagination from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from core.lib.mixins import MultiSerializerViewSetMixin from core.lib.permissions import IsAdminOrStudent, IsAdminOrCompany, IsAdminOrVacancyOwner, AsAdminOrSupervisor, \ VacancyApprovalPermission from core.models import Student, Company from core.models.vacancies import Vacancy, Application from core.serializers.vacancies import VacancySerializer, ApplicationSerializer, ApplicationStatusSerializer, \ PostVacancySerializer, VacancyVerifiedSerializer, SupervisorStudentApplicationSerializer from core.views.accounts import StudentViewSet class VacancyViewSet(MultiSerializerViewSetMixin, viewsets.ModelViewSet): queryset = Vacancy.objects.all() serializer_class = VacancySerializer serializer_action_classes = { 'create': PostVacancySerializer } permission_classes = [IsAdminOrCompany] pagination_class = PageNumberPagination def get_permissions(self): if self.action in ["retrieve", "list"]: return [IsAuthenticated()] return super(VacancyViewSet, self).get_permissions() def list(self, request, *args, **kwargs): vacancies = Vacancy.objects.all() verified = request.query_params['verified'] if 'verified' in request.query_params else "True" if verified.lower() in ("yes", "true", "t", "1"): vacancies = vacancies.filter(verified=True) if verified.lower() in {"no", "false", "f", "0"}: vacancies = vacancies.filter(verified=False) page = self.paginate_queryset(vacancies) if page is not None: return self.get_paginated_response(VacancySerializer(page, many=True, context={'request': request}).data) return Response(VacancySerializer(vacancies, many=True, context={'request': request}).data) @detail_route(permission_classes=[IsAdminOrCompany]) def count(self, request, pk=None): vacancy = self.get_object() count = Application.objects.filter(vacancy=vacancy).count() count_new = Application.objects.filter(vacancy=vacancy, status=Application.NEW).count() return Response({"count": count, "count_new": count_new}, status=status.HTTP_200_OK) @detail_route(methods=['patch'], permission_classes=[VacancyApprovalPermission], serializer_class=VacancyVerifiedSerializer) def verify(self, request, pk=None): vacancy = self.get_object() serializer = self.get_serializer_class()(vacancy, data=request.data, partial=True) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_200_OK) return Response({"error": "bad request"}, status=status.HTTP_400_BAD_REQUEST) class ApplicationViewSet(MultiSerializerViewSetMixin, viewsets.GenericViewSet): queryset = Application.objects.all() serializer_class = ApplicationSerializer serializer_action_classes = { 'update': ApplicationStatusSerializer, 'partial_update': ApplicationStatusSerializer, 'list': SupervisorStudentApplicationSerializer } permission_classes = [IsAdminOrVacancyOwner] pagination_class = PageNumberPagination def list(self, request): applications = Application.objects.order_by('student') page = self.paginate_queryset(applications) serializer = self.get_serializer_class() if page is not None: return self.get_paginated_response( serializer(applications, many=True, context={'request': request}).data) return Response(serializer(applications, many=True, context={'request': request}).data) def partial_update(self, request, pk=None): application = self.get_object() serializer = self.get_serializer_class()(application, data=request.data, partial=True) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_202_ACCEPTED) else: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) @detail_route(methods=['get'], permission_classes=[IsAdminOrVacancyOwner]) def transcript(self, request, pk): """ Get student's academic transcript on application {application_id} --- """ application = self.get_object() return StudentViewSet.transcript(StudentViewSet(), request, application.student.pk) def get_permissions(self): if self.action == "list": return [AsAdminOrSupervisor()] return super(ApplicationViewSet, self).get_permissions() class StudentApplicationViewSet(viewsets.GenericViewSet): serializer_class = ApplicationSerializer permission_classes = [IsAdminOrStudent] pagination_class = PageNumberPagination def list(self, request, student_id): """ Get list of a student {student_id}'s applied vacancies --- """ student = get_object_or_404(Student.objects.all(), pk=student_id) vacancy_ids = Application.objects.filter(student=student).values('vacancy') vacancies = Vacancy.objects.filter(id__in=vacancy_ids) page = self.paginate_queryset(vacancies) if page is not None: return self.get_paginated_response(VacancySerializer(page, many=True, context={'request': request}).data) return Response(VacancySerializer(vacancies, many=True, context={'request': request}).data) def create(self, request, student_id): """ Create a new application for student {student_id} --- parameters: - name: body description: JSON object containing an integer 'vacancy_id' and a string 'cover_letter' required: true type: string paramType: body """ cover_letter = request.data.get('cover_letter') vacancy = get_object_or_404(Vacancy.objects.all(), pk=request.data.get('vacancy_id')) student = get_object_or_404(Student.objects.all(), pk=student_id) if Application.objects.filter(vacancy=vacancy, student=student).exists(): raise ValidationError("You have already applied for the vacancy") application = Application(vacancy=vacancy, student=student, cover_letter=cover_letter) application.save() return Response(ApplicationSerializer(application, context={'request': request}).data) def destroy(self, request, student_id, pk): """ Remove a application {id} for student {student_id} --- """ vacancy = get_object_or_404(Vacancy.objects.all(), pk=pk) student = get_object_or_404(Student.objects.all(), pk=student_id) application = get_object_or_404(Application.objects.all(), student=student, vacancy=vacancy) application.delete() return Response(ApplicationSerializer(application, context={'request': request}).data) class CompanyApplicationViewSet(viewsets.GenericViewSet): queryset = Application.objects.all() permission_classes = [IsAdminOrCompany] pagination_class = PageNumberPagination def list(self, request, company_id): """ Get list of company {company_id}'s applications --- """ company = get_object_or_404(Company.objects.all(), pk=company_id) if not request.user.is_superuser and request.user != company.user: return Response({"error": "forbidden"}, status=status.HTTP_403_FORBIDDEN) vacancies = Vacancy.objects.filter(company=company) applications = Application.objects.filter(vacancy__in=vacancies) if 'status' in request.query_params: applications = applications.filter(status=request.query_params['status']) page = self.paginate_queryset(applications) if page is not None: return self.get_paginated_response( ApplicationSerializer(page, many=True, context={'request': request}).data) return Response(ApplicationSerializer(applications, many=True, context={'request': request}).data) @detail_route(methods=["get"]) def by_vacancy(self, request, company_id, pk=None): """ Get list of company {company_id}'s applications by vacancy {id} --- """ if pk is None: return list(self, request, company_id) company = get_object_or_404(Company.objects.all().order_by('-updated'), pk=company_id) if not request.user.is_superuser and request.user != company.user: return Response({"error": "forbidden"}, status=status.HTTP_403_FORBIDDEN) vacancy = get_object_or_404(Vacancy.objects.all(), pk=pk) if vacancy.company != company: return Response({"error": "forbidden"}, status=status.HTTP_403_FORBIDDEN) applications = Application.objects.filter(vacancy=vacancy) st = request.query_params.get('status', None) if st is not None: try: st = int(st) if st < 0 or st > 4: return Response({"error": "status must be an integer between 0 and 4"}, status=status.HTTP_400_BAD_REQUEST) applications = applications.filter(status=st) except: return Response({"error": "status must be an integer between 0 and 4"}, \ status=status.HTTP_400_BAD_REQUEST) page = self.paginate_queryset(applications) if page is not None: return self.get_paginated_response( ApplicationSerializer(page, many=True, context={'request': request}).data) return Response(ApplicationSerializer(applications, many=True, context={'request': request}).data) class CompanyVacanciesViewSet(viewsets.GenericViewSet): queryset = Vacancy.objects.all() pagination_class = PageNumberPagination permission_classes = [IsAdminOrCompany] def list(self, request, company_id): """ Get list of company {company_id}'s vacancies --- """ company = get_object_or_404(Company.objects.all().order_by('-updated'), pk=company_id) if not request.user.is_superuser and request.user != company.user: return Response({"error": "forbidden"}, status=status.HTTP_403_FORBIDDEN) vacancies = Vacancy.objects.filter(company=company) page = self.paginate_queryset(vacancies) if page is not None: return self.get_paginated_response(VacancySerializer(page, many=True, context={'request': request}).data) return Response(VacancySerializer(vacancies, many=True, context={'request': request}).data) class BookmarkedVacancyByStudentViewSet(viewsets.GenericViewSet): serializer_class = VacancySerializer permission_classes = [IsAdminOrStudent] def list(self, request, student_id): """ Get list of a student {student_id}'s bookmarked vacancies --- """ student = get_object_or_404(Student.objects.all(), pk=student_id) vacancies = student.bookmarked_vacancies.all() page = self.paginate_queryset(vacancies) if page is not None: return self.get_paginated_response(VacancySerializer(page, many=True, context={'request': request}).data) return Response(VacancySerializer(vacancies, many=True, context={'request': request}).data) def create(self, request, student_id): """ Bookmarks a vacancy for student {student_id} --- parameters: - name: body description: JSON object containing only one string: vacancy_id required: true type: string paramType: body """ vacancy = get_object_or_404(Vacancy.objects.all(), pk=request.data['vacancy_id']) student = get_object_or_404(Student.objects.all(), pk=student_id) student.bookmarked_vacancies.add(vacancy) return Response( self.serializer_class(student.bookmarked_vacancies, many=True, context={'request': request}).data) def destroy(self, request, student_id, pk): """ Remove bookmark {id} for student {student_id} --- """ vacancy = get_object_or_404(Vacancy.objects.all(), pk=pk) student = get_object_or_404(Student.objects.all(), pk=student_id) student.bookmarked_vacancies.remove(vacancy) return Response( self.serializer_class(student.bookmarked_vacancies, many=True, context={'request': request}).data)