import requests from django.contrib.auth import authenticate, login from django.contrib.auth.models import User from django.shortcuts import get_object_or_404 from rest_framework import viewsets, status from rest_framework.decorators import list_route, detail_route from rest_framework.exceptions import PermissionDenied from rest_framework.parsers import FormParser,MultiPartParser from rest_framework.permissions import AllowAny from rest_framework.permissions import IsAdminUser, IsAuthenticated from rest_framework.response import Response from core.lib.permissions import IsAdminOrStudent, IsAdminOrSelfOrReadOnly, IsAdminOrCompany, IsAdminOrSupervisor, \ IsAdminOrSupervisorOrCompanyOrSelf from core.models.accounts import Student, Company, Supervisor from core.serializers.accounts import BasicUserSerializer, UserSerializer, StudentSerializer, CompanySerializer, \ SupervisorSerializer, RegisterSerializer, StudentUpdateSerializer, CompanyUpdateSerializer from kape import settings class UserViewSet(viewsets.ModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer permission_classes = [IsAdminUser] @list_route(methods=['get'], permission_classes=[IsAuthenticated]) def me(self, request): """ Get current user's details """ user = self.request.user serializer = BasicUserSerializer(user, context={"request": request}) return Response(serializer.data) def get_permissions(self): if self.action == "update" or self.action == "partial_update": return [IsAdminOrSelfOrReadOnly(), IsAuthenticated()] if self.action == "create": return [AllowAny()] return super(UserViewSet, self).get_permissions() class StudentViewSet(viewsets.ModelViewSet): queryset = Student.objects.all() serializer_class = StudentSerializer permission_classes = [IsAdminUser] def get_permissions(self): if self.action == "update" or self.action == "partial_update": return [IsAdminOrSelfOrReadOnly(), IsAdminOrStudent()] if self.action == "list": return [IsAuthenticated(), IsAdminOrSupervisor()] if self.action == "retrieve": return [IsAuthenticated(), IsAdminOrSupervisorOrCompanyOrSelf()] return super(StudentViewSet, self).get_permissions() @detail_route(methods=['patch'], permission_classes=[IsAdminOrStudent], serializer_class=StudentUpdateSerializer, parser_classes=(MultiPartParser, FormParser,)) def profile(self, request, pk=None): """ Update student {student_id}'s profile information --- """ user = self.get_object() serializer = self.serializer_class(user, 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=[IsAdminOrStudent]) def transcript(self, request, pk): """ Get student {student_id}'s academic transcript --- """ student = get_object_or_404(Student.objects.all(), pk=pk) if hasattr(request.user, 'student') and request.user.student.pk != student.pk: raise PermissionDenied("You are not allowed to see other student's transcript") 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) class CompanyViewSet(viewsets.ModelViewSet): queryset = Company.objects.all() serializer_class = CompanySerializer permission_classes = [IsAdminOrSelfOrReadOnly, IsAdminOrCompany] filter_fields = ('status',) @detail_route(methods=['patch'], permission_classes=[IsAdminOrCompany], serializer_class=CompanyUpdateSerializer, parser_classes=(MultiPartParser, FormParser,)) def profile(self, request, pk=None): """ Update student {student_id}'s profile information --- """ user = self.get_object() serializer = self.serializer_class(user, 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) class SupervisorViewSet(viewsets.ModelViewSet): queryset = Supervisor.objects.all() serializer_class = SupervisorSerializer permission_classes = [IsAdminOrSelfOrReadOnly, IsAdminOrSupervisor] class LoginViewSet(viewsets.GenericViewSet): permission_classes = (AllowAny, ) serializer_class = UserSerializer queryset = User.objects.all() def create(self, request): """ Authentication for user by means of logging in --- parameters: - name: body description: JSON object containing three strings: username, password and login-type. login-type should be either 'sso-ui' or 'company'. required: true type: string paramType: body """ username = request.data.get('username') password = request.data.get('password') login_type = request.data.get('login-type') if username is None or password is None or login_type is None: return Response(status=status.HTTP_400_BAD_REQUEST) if login_type == "sso-ui": r = requests.post('https://api.cs.ui.ac.id/authentication/ldap/v2/', json={"username": username, "password": password}) resp = r.json() if resp.get('state') != 0: # create user name = resp.get('nama').split(" ") first_name = name[0] name.pop(0) last_name = " ".join(name) user, created = User.objects.get_or_create( username=username, defaults={ 'email' : username + "@ui.ac.id", 'first_name' : first_name, 'last_name' : last_name } ) user.set_password(password) user.save() login(request, user) if created: if resp.get('nama_role') == "mahasiswa": student_detail = requests.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/{}/'.format(resp.get("kodeidentitas"))) resp_student_detail = student_detail.json() student = Student.objects.create( user=user, npm=resp.get("kodeidentitas"), birth_place=resp_student_detail.get('kota_lahir'), birth_date=resp_student_detail.get('tgl_lahir'), major=resp_student_detail.get('program')[0].get('nm_org'), batch=resp_student_detail.get('program')[0].get('angkatan') ) student.save() else: supervisor = Supervisor.objects.create( user=user, nip=resp.get("kodeidentitas") ) supervisor.save() serializer = UserSerializer(user, context={'request': request}) return Response(serializer.data, status=status.HTTP_201_CREATED) serializer = UserSerializer(user, context={'request': request}) return Response(serializer.data, status=status.HTTP_200_OK) else: return Response(status=status.HTTP_401_UNAUTHORIZED) elif login_type == "company": user = authenticate(username = username, password = password) if user is not None: login(request, user) serializer = UserSerializer(user, context={'request': request}) return Response(serializer.data, status=status.HTTP_200_OK) else: return Response(status=status.HTTP_401_UNAUTHORIZED) else: return Response(status=status.HTTP_400_BAD_REQUEST) class CompanyRegisterViewSet(viewsets.GenericViewSet): permission_classes = (AllowAny,) serializer_class = RegisterSerializer queryset = Company.objects.all() parser_classes = (MultiPartParser, FormParser,) def create(self, request): """ Create a new company user --- parameters: - name: username description: username of the new account required: true type: string - name: password description: password of the new account required: true type: string - name: email description: email address of the new account required: true type: string - name: name description: the new company's name required: true type: string - name: description description: description of the new company required: true type: string - name: logo description: logo of the new company required: false type: image - name: address description: address of the new account required: false type: string """ data = {} for attr in ['password', 'email', 'name', 'description', 'logo', 'address']: data[attr] = request.data.get(attr) if data[attr] is None: return Response({'error': attr+' is required'}, status=status.HTTP_400_BAD_REQUEST) user, created = User.objects.get_or_create( username=data['email'], email=data['email'], first_name=data['name'], last_name="" ) if created: user.set_password(data['password']) company = Company.objects.create( user=user, description=data['description'], logo=data['logo'], address=data['address'] ) user.save() company.save() serializer = self.serializer_class(user, context={'request': request}) login(request, user) return Response(serializer.data, status=status.HTTP_201_CREATED) else: return Response({'error': 'Company with email '+data['email']+' already exist'}, status=status.HTTP_409_CONFLICT)