Fakultas Ilmu Komputer UI

vacancies.py 13.4 KB
Newer Older
1
2
import requests
from django.conf import settings
3
from rest_framework import viewsets, status
4
from rest_framework.decorators import detail_route
5
from rest_framework.exceptions import ValidationError
6
from rest_framework.generics import get_object_or_404
Zamil Majdy's avatar
Zamil Majdy committed
7
from rest_framework.pagination import PageNumberPagination
8
from rest_framework.permissions import IsAuthenticated
9
from rest_framework.response import Response
Zamil Majdy's avatar
Zamil Majdy committed
10

11
from core.lib.mixins import MultiSerializerViewSetMixin
Zamil Majdy's avatar
Zamil Majdy committed
12
13
from core.lib.permissions import IsAdminOrStudent, IsAdminOrCompany, IsAdminOrVacancyOwner, AsAdminOrSupervisor, \
    VacancyApprovalPermission
14
from core.models import Student, Company
15
from core.models.vacancies import Vacancy, Application
16
from core.serializers.vacancies import VacancySerializer, ApplicationSerializer, ApplicationStatusSerializer, \
Zamil Majdy's avatar
Zamil Majdy committed
17
    PostVacancySerializer, VacancyVerifiedSerializer, SupervisorStudentApplicationSerializer
18
19


20
class VacancyViewSet(MultiSerializerViewSetMixin, viewsets.ModelViewSet):
21
    queryset = Vacancy.objects.all()
22
    serializer_class = VacancySerializer
23
24
25
    serializer_action_classes = {
        'create': PostVacancySerializer
    }
26
    permission_classes = [IsAdminOrCompany]
27
    pagination_class = PageNumberPagination
28

29
    def get_permissions(self):
30
        if self.action in ["retrieve", "list"]:
31
32
33
            return [IsAuthenticated()]
        return super(VacancyViewSet, self).get_permissions()

34
35
    def list(self, request, *args, **kwargs):
        vacancies = Vacancy.objects.all()
36
37
        verified = request.query_params['verified'] if 'verified' in request.query_params else "True"
        if verified.lower() in ("yes", "true", "t", "1"):
38
            vacancies = vacancies.filter(verified=True)
39
        if verified.lower() in {"no", "false", "f", "0"}:
Zamil Majdy's avatar
Zamil Majdy committed
40
            vacancies = vacancies.filter(verified=False)
41
42
43
        page = self.paginate_queryset(vacancies)
        if page is not None:
            return self.get_paginated_response(VacancySerializer(page, many=True, context={'request': request}).data)
44
45
        return Response(VacancySerializer(vacancies, many=True, context={'request': request}).data)

46
47
48
49
50
51
52
    @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)

Zamil Majdy's avatar
Zamil Majdy committed
53
54
    @detail_route(methods=['patch'], permission_classes=[VacancyApprovalPermission],
                  serializer_class=VacancyVerifiedSerializer)
55
56
57
58
59
60
    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)
Zamil Majdy's avatar
Zamil Majdy committed
61
        return Response({"error": "bad request"}, status=status.HTTP_400_BAD_REQUEST)
62

63

Zamil Majdy's avatar
Zamil Majdy committed
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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()
        print self.action
        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 {student_id}'s academic transcript
        ---
        """
        application = self.get_object()
        student = application.student
        if student.show_transcript:
            s = requests.Session()
            credentials = settings.API_CS_CREDENTIALS
            s.get('https://api.cs.ui.ac.id/api-auth/login/')
            csrf = s.cookies['csrftoken']
            resp = s.post('https://api.cs.ui.ac.id/api-auth/login/',
                          data={'username': credentials["user"], 'password': credentials["password"],
                                'csrfmiddlewaretoken': csrf})
            response = s.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/' + str(student.npm) + '/riwayat/')
            return Response({'name': student.full_name, 'transcript': response.json()}, status=status.HTTP_200_OK)
        else:
            return Response({'name': student.full_name, 'error': 'student does not allow transcript to be shown'},
                            status=status.HTTP_200_OK)

    def get_permissions(self):
        if self.action == "list":
            return [AsAdminOrSupervisor()]
        return super(ApplicationViewSet, self).get_permissions()


class StudentApplicationViewSet(viewsets.GenericViewSet):
123
    serializer_class = ApplicationSerializer
124
    permission_classes = [IsAdminOrStudent]
125
    pagination_class = PageNumberPagination
126

127
    def list(self, request, student_id):
128
        """
129
        Get list of a student {student_id}'s applied vacancies
130
131
        ---
        """
132
        student = get_object_or_404(Student.objects.all(), pk=student_id)
133
134
135
136
137
138
        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)
139
140

    def create(self, request, student_id):
141
142
143
144
145
        """
        Create a new application for student {student_id}
        ---
        parameters:
            - name: body
146
              description: JSON object containing an integer 'vacancy_id' and a string 'cover_letter'
147
148
149
150
              required: true
              type: string
              paramType: body
        """
151
152
        cover_letter = request.data.get('cover_letter')
        vacancy = get_object_or_404(Vacancy.objects.all(), pk=request.data.get('vacancy_id'))
153
        student = get_object_or_404(Student.objects.all(), pk=student_id)
154
155
        if Application.objects.filter(vacancy=vacancy, student=student).exists():
            raise ValidationError("You have already applied for the vacancy")
156
157
158
        application = Application(vacancy=vacancy, student=student, cover_letter=cover_letter)
        application.save()
        return Response(ApplicationSerializer(application, context={'request': request}).data)
159
160

    def destroy(self, request, student_id, pk):
161
162
163
164
        """
        Remove a application {id} for student {student_id}
        ---
        """
165
166
        vacancy = get_object_or_404(Vacancy.objects.all(), pk=pk)
        student = get_object_or_404(Student.objects.all(), pk=student_id)
167
        application = get_object_or_404(Application.objects.all(), student=student, vacancy=vacancy)
168
        application.delete()
169
        return Response(ApplicationSerializer(application, context={'request': request}).data)
170

171

172
173
class CompanyApplicationViewSet(viewsets.GenericViewSet):
    queryset = Application.objects.all()
174
    permission_classes = [IsAdminOrCompany]
175
    pagination_class = PageNumberPagination
176
177
178
179
180
181
182

    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)
183
184
        if not request.user.is_superuser and request.user != company.user:
            return Response({"error": "forbidden"}, status=status.HTTP_403_FORBIDDEN)
185
186
187
188
        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'])
189
190
        page = self.paginate_queryset(applications)
        if page is not None:
Zamil Majdy's avatar
Zamil Majdy committed
191
192
            return self.get_paginated_response(
                ApplicationSerializer(page, many=True, context={'request': request}).data)
193
194
        return Response(ApplicationSerializer(applications, many=True, context={'request': request}).data)

195
196
    @detail_route(methods=["get"])
    def by_vacancy(self, request, company_id, pk=None):
Zamil Majdy's avatar
Zamil Majdy committed
197
198
199
200
        """
        Get list of company {company_id}'s applications by vacancy {id}
        ---
        """
201
202
203
204
205
206
207
208
209
        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)
210
211
212
213
214
215
216
217
218
219
220
        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)
221
222
223
224
225
226
        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)

227
228

class CompanyVacanciesViewSet(viewsets.GenericViewSet):
229
    queryset = Vacancy.objects.all()
230
    pagination_class = PageNumberPagination
231
    permission_classes = [IsAdminOrCompany]
232
233
234
235
236
237

    def list(self, request, company_id):
        """
        Get list of company {company_id}'s vacancies
        ---
        """
238
        company = get_object_or_404(Company.objects.all().order_by('-updated'), pk=company_id)
239
240
        if not request.user.is_superuser and request.user != company.user:
            return Response({"error": "forbidden"}, status=status.HTTP_403_FORBIDDEN)
241
        vacancies = Vacancy.objects.filter(company=company)
242
243
244
        page = self.paginate_queryset(vacancies)
        if page is not None:
            return self.get_paginated_response(VacancySerializer(page, many=True, context={'request': request}).data)
245
246
247
        return Response(VacancySerializer(vacancies, many=True, context={'request': request}).data)


248
249
250
251
252
class BookmarkedVacancyByStudentViewSet(viewsets.GenericViewSet):
    serializer_class = VacancySerializer
    permission_classes = [IsAdminOrStudent]

    def list(self, request, student_id):
253
254
255
256
        """
        Get list of a student {student_id}'s bookmarked vacancies
        ---
        """
257
        student = get_object_or_404(Student.objects.all(), pk=student_id)
258
259
260
261
262
        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)
263
264

    def create(self, request, student_id):
265
266
267
268
269
270
271
272
273
274
        """
        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
        """
275
276
277
        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)
Zamil Majdy's avatar
Zamil Majdy committed
278
279
        return Response(
            self.serializer_class(student.bookmarked_vacancies, many=True, context={'request': request}).data)
280
281

    def destroy(self, request, student_id, pk):
282
283
284
285
        """
        Remove bookmark {id} for student {student_id}
        ---
        """
286
287
288
        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)
Zamil Majdy's avatar
Zamil Majdy committed
289
290
        return Response(
            self.serializer_class(student.bookmarked_vacancies, many=True, context={'request': request}).data)