diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS new file mode 100644 index 0000000000000000000000000000000000000000..a69023229f36573edb56148d0e187d8e397ce110 --- /dev/null +++ b/.gitlab/CODEOWNERS @@ -0,0 +1,4 @@ +# Code owners file + +## Changes to these file(s) require approval from the teaching team +sonar-project.properties @addianto @hafiyyan94 \ No newline at end of file diff --git a/README.md b/README.md index 3020546098563953b463aa84d24bb2958f22f589..3734ba0a5f9c94947bcea0145748b6214280794a 100755 --- a/README.md +++ b/README.md @@ -2,6 +2,13 @@ > Internship matchmaking platform for students and companies. +[](https://gitlab.cs.ui.ac.id/pmpl/class-project/kape/commits/master) +[](https://gitlab.cs.ui.ac.id/pmpl/class-project/kape/commits/master) + +[](https://pmpl.cs.ui.ac.id/sonarqube/dashboard?id=id.ac.ui.cs.foss%3Akape) +[](https://pmpl.cs.ui.ac.id/sonarqube/dashboard?id=id.ac.ui.cs.foss%3Akape) +[](https://pmpl.cs.ui.ac.id/sonarqube/dashboard?id=id.ac.ui.cs.foss%3Akape) + ## Table of Contents - [Install](#install) diff --git a/core/admin.py b/core/admin.py index f30ded64324bcdff514ec1de0fd65d3ef0ff4e7c..b54eadf892ec46490d97dc3debac5ce39cd2748f 100755 --- a/core/admin.py +++ b/core/admin.py @@ -1,11 +1,11 @@ from django.contrib import admin from core.models.accounts import Company, Supervisor, Student +from core.models.feedbacks import Feedback from core.models.vacancies import Vacancy admin.site.register(Company) admin.site.register(Student) admin.site.register(Supervisor) admin.site.register(Vacancy) - - +admin.site.register(Feedback) diff --git a/core/migrations/0014_feedback.py b/core/migrations/0014_feedback.py new file mode 100644 index 0000000000000000000000000000000000000000..e8183198862766fdf15316cfcb43e4719a36cc12 --- /dev/null +++ b/core/migrations/0014_feedback.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2019-10-03 13:39 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0013_auto_20170602_1130'), + ] + + operations = [ + migrations.CreateModel( + name='Feedback', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(auto_now_add=True)), + ('title', models.CharField(blank=True, default=b'', max_length=100)), + ('content', models.TextField()), + ], + options={ + 'ordering': ['created'], + }, + ), + ] diff --git a/core/models/feedbacks.py b/core/models/feedbacks.py new file mode 100644 index 0000000000000000000000000000000000000000..c473ae82716b8c4a19526757c0bd09ab9a2c4363 --- /dev/null +++ b/core/models/feedbacks.py @@ -0,0 +1,10 @@ +from django.db import models + + +class Feedback(models.Model): + created = models.DateTimeField(auto_now_add=True) + title = models.CharField(max_length=100, blank=True, default='') + content = models.TextField() + + class Meta: + ordering = ['created'] diff --git a/core/serializers/feedbacks.py b/core/serializers/feedbacks.py new file mode 100644 index 0000000000000000000000000000000000000000..2558730792530d18a2199e96b4cba2d53f7ea0ee --- /dev/null +++ b/core/serializers/feedbacks.py @@ -0,0 +1,9 @@ +from rest_framework import serializers + +from core.models.feedbacks import Feedback + + +class FeedbackSerializer(serializers.ModelSerializer): + class Meta: + model = Feedback + fields = ['id', 'title', 'content'] diff --git a/core/tests/__init__.py b/core/tests/__init__.py index 76d673e4b0147d067a601ad568adbcc76c97c056..e8d87c6482286bd702d604fd44d22315c9d42b2c 100755 --- a/core/tests/__init__.py +++ b/core/tests/__init__.py @@ -1,3 +1,4 @@ # __init__.py from core.tests.test_accounts import LoginTests, RegisterTests from core.tests.test_vacancies import ApplicationTests, BookmarkApplicationTests, CompanyListsTests +from core.tests.test_feedbacks import FeedbacksTests diff --git a/core/tests/test_accounts.py b/core/tests/test_accounts.py index 35458deb5cb4174f6856ffcdfd95439d6ba6e3a6..25281a7cc774e3a409d4eebb22cabca899f6d795 100644 --- a/core/tests/test_accounts.py +++ b/core/tests/test_accounts.py @@ -8,6 +8,7 @@ from core.models.accounts import Company, Supervisor, Student class LoginTests(APITestCase): @requests_mock.Mocker() def test_succesful_student_login_relogin(self, m): + m.get('https://akun.cs.ui.ac.id/oauth/token/verify/?client_id=X3zNkFmepkdA47ASNMDZRX3Z9gqSU1Lwywu5WepG', json={"username": 'dummy.mahasiswa', "role": 'mahasiswa', "identity_number": '1234567890'}, status_code=200) m.post('https://api.cs.ui.ac.id/authentication/ldap/v2/', json={ "username": "dummy.mahasiswa", "nama": "Dummy Mahasiswa", @@ -16,7 +17,7 @@ class LoginTests(APITestCase): "kodeidentitas": "1234567890", "nama_role": "mahasiswa" }, status_code=200) - m.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/1234567890/', json={ + m.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/1234567890?client_id=X3zNkFmepkdA47ASNMDZRX3Z9gqSU1Lwywu5WepG', json={ "kota_lahir": "kota_kota", "tgl_lahir": "2017-12-31", "program": [{ @@ -35,6 +36,7 @@ class LoginTests(APITestCase): @requests_mock.Mocker() def test_successful_supervisor_login_relogin(self, m): + m.get('https://akun.cs.ui.ac.id/oauth/token/verify/?client_id=X3zNkFmepkdA47ASNMDZRX3Z9gqSU1Lwywu5WepG', json={"username": 'dummy.mahasiswa', "role": 'mahasiswa', "identity_number": '1234567890'}, status_code=200) m.post('https://api.cs.ui.ac.id/authentication/ldap/v2/', json={ "username": "dummy.dosen", "nama": "Dummy Dosen", @@ -106,6 +108,7 @@ class ProfileUpdateTests(APITestCase): @requests_mock.Mocker() def test_student_profile_update(self, m): + m.get('https://akun.cs.ui.ac.id/oauth/token/verify/?client_id=X3zNkFmepkdA47ASNMDZRX3Z9gqSU1Lwywu5WepG', json={"username": 'dummy.mahasiswa', "role": 'mahasiswa', "identity_number": '1234567890'}, status_code=200) m.post('https://api.cs.ui.ac.id/authentication/ldap/v2/', json={ "username": "dummy.mahasiswa", "nama": "Dummy Mahasiswa", @@ -114,7 +117,7 @@ class ProfileUpdateTests(APITestCase): "kodeidentitas": "1234567890", "nama_role": "mahasiswa" }, status_code=200) - m.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/1234567890/', json={ + m.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/1234567890?client_id=X3zNkFmepkdA47ASNMDZRX3Z9gqSU1Lwywu5WepG', json={ "kota_lahir": "kota_kota", "tgl_lahir": "2017-12-31", "program": [{ diff --git a/core/tests/test_feedbacks.py b/core/tests/test_feedbacks.py new file mode 100644 index 0000000000000000000000000000000000000000..f45dba9d7380edf778b6653af3812d00a84ff133 --- /dev/null +++ b/core/tests/test_feedbacks.py @@ -0,0 +1,258 @@ +import requests_mock +from rest_framework import status +from rest_framework.test import APITestCase + +from core.models.feedbacks import Feedback + + +class FeedbacksTests(APITestCase): + def login(self, m): + # Login + m.get('https://akun.cs.ui.ac.id/oauth/token/verify/?client_id=X3zNkFmepkdA47ASNMDZRX3Z9gqSU1Lwywu5WepG', + json={"username": 'dummy.mahasiswa', "role": 'mahasiswa', "identity_number": '1234567890'}, + status_code=200) + m.post('https://api.cs.ui.ac.id/authentication/ldap/v2/', json={ + "username": "dummy.mahasiswa", + "nama": "Dummy Mahasiswa", + "state": 1, + "kode_org": "01.00.12.01:mahasiswa", + "kodeidentitas": "1234567890", + "nama_role": "mahasiswa" + }, status_code=200) + m.get( + 'https://api.cs.ui.ac.id/siakngcs/mahasiswa/1234567890?client_id=X3zNkFmepkdA47ASNMDZRX3Z9gqSU1Lwywu5WepG', + json={ + "kota_lahir": "kota_kota", + "tgl_lahir": "2017-12-31", + "program": [{ + "nm_org": "Ilmu Informasi", + "angkatan": "2017" + }] + }, status_code=200) + login_url = '/api/login/' + self.client.post(login_url, {'username': 'dummy.mahasiswa', 'password': 'lalala', 'login-type': 'sso-ui'}, + format='json') + + @requests_mock.Mocker() + def test_feedback_list_with_more_than_10_feedback_and_with_page_number(self, m): + self.login(m) + + # test_feedback_list_with_more_than_10_feedback_and_with_page_number + for i in range(15): + Feedback.objects.create(content="a feedback", title="a title") + + feedbacks_url = '/api/feedbacks/' + feedbacks_url_page_1 = '/api/feedbacks/?page=1' + feedbacks_url_page_2 = '/api/feedbacks/?page=2' + + response1 = self.client.get(feedbacks_url_page_1) + self.assertEqual(response1.status_code, status.HTTP_200_OK) + self.assertEqual(response1.data['count'], 15) + self.assertIn(feedbacks_url_page_2, response1.data['next']) + self.assertEqual(response1.data['previous'], None) + self.assertEqual(len(response1.data['results']), 10) + + response2 = self.client.get(feedbacks_url_page_2) + self.assertEqual(response2.status_code, status.HTTP_200_OK) + self.assertEqual(response2.data['count'], 15) + self.assertIn(feedbacks_url, response2.data['previous']) + self.assertEqual(response2.data['next'], None) + self.assertEqual(len(response2.data['results']), 5) + + @requests_mock.Mocker() + def test_feedback_list_with_more_than_10_feedback_and_without_page_number(self, m): + self.login(m) + + # test_feedback_list_with_more_than_10_feedback_and_without_page_number + for i in range(15): + Feedback.objects.create(content="a feedback", title="a title") + + feedbacks_url = '/api/feedbacks/' + feedbacks_url_page_2 = '/api/feedbacks/?page=2' + + response1 = self.client.get(feedbacks_url) + self.assertEqual(response1.status_code, status.HTTP_200_OK) + self.assertEqual(response1.data['count'], 15) + self.assertIn(feedbacks_url_page_2, response1.data['next']) + self.assertEqual(response1.data['previous'], None) + self.assertEqual(len(response1.data['results']), 10) + + response2 = self.client.get(feedbacks_url_page_2) + self.assertEqual(response2.status_code, status.HTTP_200_OK) + self.assertEqual(response2.data['count'], 15) + self.assertIn(feedbacks_url, response2.data['previous']) + self.assertEqual(response2.data['next'], None) + self.assertEqual(len(response2.data['results']), 5) + + @requests_mock.Mocker() + def test_feedback_list_with_less_than_or_equals_10_feedbacks_and_with_zero_feedback_and_without_page_number(self, + m): + self.login(m) + + # test_feedback_list_with_more_than_10_feedback_and_without_page_number + feedbacks_url = '/api/feedbacks/' + + response1 = self.client.get(feedbacks_url) + self.assertEqual(response1.status_code, status.HTTP_200_OK) + self.assertEqual(response1.data['count'], 0) + self.assertEqual(response1.data['next'], None) + self.assertEqual(response1.data['previous'], None) + self.assertEqual(len(response1.data['results']), 0) + + @requests_mock.Mocker() + def test_feedback_list_with_less_than_or_equals_10_feedbacks_and_with_more_than_zero_feedback_and_with_page_number( + self, m): + self.login(m) + + # test_feedback_list_with_less_than_10_feedbacks_and_with_more_than_zero_feedback_and_with_page_number + for i in range(5): + Feedback.objects.create(content="a feedback", title="a title") + + feedbacks_url_page_1 = '/api/feedbacks/?page=1' + + response1 = self.client.get(feedbacks_url_page_1) + self.assertEqual(response1.status_code, status.HTTP_200_OK) + self.assertEqual(response1.data['count'], 5) + self.assertEqual(response1.data['previous'], None) + self.assertEqual(response1.data['next'], None) + self.assertEqual(len(response1.data['results']), 5) + + @requests_mock.Mocker() + def test_feedback_list_with_less_than_or_equals_10_feedbacks_and_with_more_than_zero_feedback_and_without_page_number( + self, + m): + self.login(m) + + # test_feedback_list_with_less_than_10_feedbacks_and_with_more_than_zero_feedback_and_without_page_number + for i in range(5): + Feedback.objects.create(content="a feedback", title="a title") + + feedbacks_url = '/api/feedbacks/' + + response1 = self.client.get(feedbacks_url) + self.assertEqual(response1.status_code, status.HTTP_200_OK) + self.assertEqual(response1.data['count'], 5) + self.assertEqual(response1.data['previous'], None) + self.assertEqual(response1.data['next'], None) + self.assertEqual(len(response1.data['results']), 5) + + @requests_mock.Mocker() + def test_feedback_list_with_less_than_or_equals_10_feedbacks_and_with_zero_feedback_and_with_page_number(self, m): + self.login(m) + + # test_feedback_list_with_less_than_10_feedbacks_and_with_zero_feedback_and_with_page_number + feedbacks_url = '/api/feedbacks/?page=1' + + response1 = self.client.get(feedbacks_url) + self.assertEqual(response1.status_code, status.HTTP_200_OK) + self.assertEqual(response1.data['count'], 0) + self.assertEqual(response1.data['next'], None) + self.assertEqual(response1.data['previous'], None) + self.assertEqual(len(response1.data['results']), 0) + + @requests_mock.Mocker() + def test_feedbacks_create_with_title_and_content(self, m): + self.login(m) + + # test_feedbacks_create_with_title_and_content + feedbacks_url = '/api/feedbacks/' + response = self.client.post(feedbacks_url, + {"content": "a content", "title": "a title"}) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data["title"], "a title") + self.assertEqual(response.data["content"], "a content") + + @requests_mock.Mocker() + def test_feedbacks_create_without_title_and_with_content(self, m): + self.login(m) + + # test_feedbacks_create_without_title_and_with_content + feedbacks_url = '/api/feedbacks/' + response = self.client.post(feedbacks_url, + {"content": "a content"}) + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.data['detail'], "Please send a json object that have title and content property") + + @requests_mock.Mocker() + def test_feedbacks_create_without_content_and_with_title(self, m): + self.login(m) + + # test_feedbacks_create_without_content_and_with_title + feedbacks_url = '/api/feedbacks/' + response = self.client.post(feedbacks_url, + {"title": "a title"}) + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.data['detail'], "Please send a json object that have title and content property") + + @requests_mock.Mocker() + def test_feedbacks_create_without_content_and_without_title(self, m): + self.login(m) + + # test_feedbacks_create_without_content_and_without_title + feedbacks_url = '/api/feedbacks/' + response = self.client.post(feedbacks_url, + {}) + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.data['detail'], "Please send a json object that have title and content property") + + @requests_mock.Mocker() + def test_feedbacks_delete_with_exist_data_and_with_data_id(self, m): + self.login(m) + + # test_feedbacks_delete_with_exist_data_and_with_data_id + + new_feedback = Feedback(title="a title", content="a content") + new_feedback.save() + feedback_id = new_feedback.id + + feedbacks_url = '/api/feedbacks/' + str(feedback_id) + '/' + response = self.client.delete(feedbacks_url) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data["detail"], "Feedback with id {} was removed".format(feedback_id)) + + @requests_mock.Mocker() + def test_feedbacks_delete_with_exist_data_and_with_data_id(self, m): + self.login(m) + + # test_feedbacks_delete_with_exist_data_and_with_data_id + + new_feedback = Feedback(title="a title", content="a content") + new_feedback.save() + feedback_id = new_feedback.id + + feedbacks_url = '/api/feedbacks/' + str(feedback_id) + '/' + response = self.client.delete(feedbacks_url) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.data["detail"], "Feedback with id {} was removed".format(feedback_id)) + + @requests_mock.Mocker() + def test_feedbacks_delete_with_not_exist_data_and_with_data_id(self, m): + self.login(m) + + # test_feedbacks_delete_with_not_exist_data_and_with_data_id + new_feedback = Feedback(title="a title", content="a content") + new_feedback.save() + feedback_id = new_feedback.id + new_feedback.delete() + + feedbacks_url = '/api/feedbacks/' + str(feedback_id) + '/' + response = self.client.delete(feedbacks_url) + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.data["detail"], "Feedback with id {} doesn't exist".format(feedback_id)) + + @requests_mock.Mocker() + def test_feedbacks_delete_without_data_id(self, m): + self.login(m) + + # test_feedbacks_delete_without_data_id + feedbacks_url = '/api/feedbacks/' + response = self.client.delete(feedbacks_url) + + self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED) diff --git a/core/tests/test_vacancies.py b/core/tests/test_vacancies.py index 78cdc5a2a71e0fcf48249f1a28df4277fb5221d7..1667ac14aaed6ec90c9f50562ea9c96ea363b47d 100644 --- a/core/tests/test_vacancies.py +++ b/core/tests/test_vacancies.py @@ -12,6 +12,7 @@ from core.models.vacancies import Vacancy, Application class ApplicationTests(APITestCase): @requests_mock.Mocker() def test_application_list(self, m): + m.get('https://akun.cs.ui.ac.id/oauth/token/verify/?client_id=X3zNkFmepkdA47ASNMDZRX3Z9gqSU1Lwywu5WepG', json={"username": 'dummy.mahasiswa', "role": 'mahasiswa', "identity_number": '1234567890'}, status_code=200) m.post('https://api.cs.ui.ac.id/authentication/ldap/v2/', json={ "username": "dummy.mahasiswa", "nama": "Dummy Mahasiswa", @@ -20,7 +21,7 @@ class ApplicationTests(APITestCase): "kodeidentitas": "1234567890", "nama_role": "mahasiswa" }, status_code=200) - m.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/1234567890/', json={ + m.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/1234567890?client_id=X3zNkFmepkdA47ASNMDZRX3Z9gqSU1Lwywu5WepG', json={ "kota_lahir": "kota_kota", "tgl_lahir": "2017-12-31", "program": [{ @@ -42,6 +43,7 @@ class ApplicationTests(APITestCase): @requests_mock.Mocker() def test_application_create_and_delete(self, m): + m.get('https://akun.cs.ui.ac.id/oauth/token/verify/?client_id=X3zNkFmepkdA47ASNMDZRX3Z9gqSU1Lwywu5WepG', json={"username": 'dummy.mahasiswa', "role": 'mahasiswa', "identity_number": '1234567890'}, status_code=200) m.post('https://api.cs.ui.ac.id/authentication/ldap/v2/', json={ "username": "dummy.mahasiswa", "nama": "Dummy Mahasiswa", @@ -50,7 +52,7 @@ class ApplicationTests(APITestCase): "kodeidentitas": "1234567890", "nama_role": "mahasiswa" }, status_code=200) - m.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/1234567890/', json={ + m.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/1234567890?client_id=X3zNkFmepkdA47ASNMDZRX3Z9gqSU1Lwywu5WepG', json={ "kota_lahir": "kota_kota", "tgl_lahir": "2017-12-31", "program": [{ @@ -84,6 +86,7 @@ class ApplicationTests(APITestCase): class BookmarkApplicationTests(APITestCase): @requests_mock.Mocker() def test_application_list(self, m): + m.get('https://akun.cs.ui.ac.id/oauth/token/verify/?client_id=X3zNkFmepkdA47ASNMDZRX3Z9gqSU1Lwywu5WepG', json={"username": 'dummy.mahasiswa', "role": 'mahasiswa', "identity_number": '1234567890'}, status_code=200) m.post('https://api.cs.ui.ac.id/authentication/ldap/v2/', json={ "username": "dummy.mahasiswa", "nama": "Dummy Mahasiswa", @@ -92,7 +95,7 @@ class BookmarkApplicationTests(APITestCase): "kodeidentitas": "1234567890", "nama_role": "mahasiswa" }, status_code=200) - m.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/1234567890/', json={ + m.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/1234567890?client_id=X3zNkFmepkdA47ASNMDZRX3Z9gqSU1Lwywu5WepG', json={ "kota_lahir": "kota_kota", "tgl_lahir": "2017-12-31", "program": [{ @@ -114,6 +117,7 @@ class BookmarkApplicationTests(APITestCase): @requests_mock.Mocker() def test_application_create_and_delete(self, m): + m.get('https://akun.cs.ui.ac.id/oauth/token/verify/?client_id=X3zNkFmepkdA47ASNMDZRX3Z9gqSU1Lwywu5WepG', json={"username": 'dummy.mahasiswa', "role": 'mahasiswa', "identity_number": '1234567890'}, status_code=200) m.post('https://api.cs.ui.ac.id/authentication/ldap/v2/', json={ "username": "dummy.mahasiswa", "nama": "Dummy Mahasiswa", @@ -122,7 +126,7 @@ class BookmarkApplicationTests(APITestCase): "kodeidentitas": "1234567890", "nama_role": "mahasiswa" }, status_code=200) - m.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/1234567890/', json={ + m.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/1234567890?client_id=X3zNkFmepkdA47ASNMDZRX3Z9gqSU1Lwywu5WepG', json={ "kota_lahir": "kota_kota", "tgl_lahir": "2017-12-31", "program": [{ diff --git a/core/views/accounts.py b/core/views/accounts.py index 0b74350fbc0a57c6d6d6a22562cfd647bc7f99a9..9ea10d861229a65fbb8bef2ac4ff23f8803f9539 100644 --- a/core/views/accounts.py +++ b/core/views/accounts.py @@ -9,6 +9,7 @@ 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 .sso_login import get_access_token, verify_user, get_riwayat_user, get_summary_user from core.lib.permissions import IsAdminOrStudent, IsAdminOrSelfOrReadOnly, IsAdminOrCompany, IsAdminOrSupervisor, \ IsAdminOrSupervisorOrCompanyOrSelf @@ -81,14 +82,9 @@ class StudentViewSet(viewsets.ModelViewSet): 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/') + access_token = get_access_token(credentials["user"], credentials["password"]) + ver_user = verify_user(access_token) + response = get_riwayat_user(access_token, ver_user['identity_number']) 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'}, @@ -146,7 +142,7 @@ class LoginViewSet(viewsets.GenericViewSet): 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}) + data={"username": username, "password": password}) resp = r.json() if resp.get('state') != 0: # create user @@ -167,8 +163,9 @@ class LoginViewSet(viewsets.GenericViewSet): 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() + access_token = get_access_token(username, password) + ver_user = verify_user(access_token) + resp_student_detail = get_summary_user(access_token, ver_user['identity_number']) student = Student.objects.create( user=user, npm=resp.get("kodeidentitas"), diff --git a/core/views/feedbacks.py b/core/views/feedbacks.py new file mode 100644 index 0000000000000000000000000000000000000000..42464b653148dcaf8b00bf235553342390dc53fa --- /dev/null +++ b/core/views/feedbacks.py @@ -0,0 +1,63 @@ +from rest_framework import viewsets, status +from rest_framework.response import Response + +from core.lib.permissions import IsAdminOrStudent +from core.models.feedbacks import Feedback +from core.serializers.feedbacks import FeedbackSerializer + + +class FeedbackViewSet(viewsets.GenericViewSet): + """ + This viewset automatically provides `list`, `create`, `retrieve`, + `update` and `destroy` feedback actions. + + Additionally we also provide an extra `highlight` action. + """ + queryset = Feedback.objects.all() + serializer_class = FeedbackSerializer + permission_classes = [IsAdminOrStudent] + + def list(self, request): + """ + Get list of feedbacks + --- + """ + feedbacks = Feedback.objects.all() + page = self.paginate_queryset(feedbacks) + serialized_page_data = FeedbackSerializer(page, many=True, context={'request': request}).data + print (serialized_page_data) + return self.get_paginated_response(serialized_page_data) + + def create(self, request): + """ + Create a feedback + --- + """ + if 'title' in request.data and 'content' in request.data: + new_feedback = Feedback(title=request.data['title'], content=request.data['content']) + new_feedback.save() + serialized_new_feedback = FeedbackSerializer(new_feedback, context={'request': request}) + serialized_new_feedback_data = serialized_new_feedback.data + print(serialized_new_feedback_data) + return Response(serialized_new_feedback_data) + else: + message = {"detail": "Please send a json object that have title and content property"} + print(message) + return Response(message, status=status.HTTP_400_BAD_REQUEST) + + def destroy(self, request, pk): + """ + Remove feedback {id} + --- + """ + if Feedback.objects.filter(id=pk).count() != 0: + print (request.data) + delete_feedback = Feedback.objects.get(id=pk) + delete_feedback.delete() + message = {"detail": "Feedback with id {} was removed".format(pk)} + print(message) + return Response(message, status=status.HTTP_200_OK) + else: + message = {"detail": "Feedback with id {} doesn't exist".format(pk)} + print(message) + return Response(message, status=status.HTTP_400_BAD_REQUEST) diff --git a/core/views/sso_login.py b/core/views/sso_login.py new file mode 100644 index 0000000000000000000000000000000000000000..669bf2be7327b5e268015c8b4e303734ee64cd47 --- /dev/null +++ b/core/views/sso_login.py @@ -0,0 +1,48 @@ +import requests + +API_MAHASISWA = "https://api.cs.ui.ac.id/siakngcs/mahasiswa/" +API_RIWAYAT_MAHASISWA = API_MAHASISWA+'{npm}/riwayat/' +API_VERIFY_USER = "https://akun.cs.ui.ac.id/oauth/token/verify/" +def get_access_token(username, password): + try: + url = "https://akun.cs.ui.ac.id/oauth/token/" + + payload = "username=" + username + "&password=" + password + "&grant_type=password" + headers = { + 'authorization': "Basic WDN6TmtGbWVwa2RBNDdBU05NRFpSWDNaOWdxU1UxTHd5d3U1V2VwRzpCRVFXQW43RDl6a2k3NEZ0bkNpWVhIRk50Ymg3eXlNWmFuNnlvMU1uaUdSVWNGWnhkQnBobUU5TUxuVHZiTTEzM1dsUnBwTHJoTXBkYktqTjBxcU9OaHlTNGl2Z0doczB0OVhlQ3M0Ym1JeUJLMldwbnZYTXE4VU5yTEFEMDNZeA==", + 'cache-control': "no-cache", + 'content-type': "application/x-www-form-urlencoded" + } + response = requests.request("POST", url, data=payload, headers=headers) + + return response.json()["access_token"] + except Exception as e: + return None + # raise Exception("username atau password sso salah, input : [{}, {}]".format(username, password,)) + +def get_client_id(): + client_id = 'X3zNkFmepkdA47ASNMDZRX3Z9gqSU1Lwywu5WepG' + return client_id + +def verify_user(access_token): + print ("#get identity number") + parameters = {"access_token": access_token, "client_id": get_client_id()} + response = requests.get(API_VERIFY_USER, params=parameters) + print ("response => ", response.json()) + return response.json() + +def get_summary_user(access_token, npm): + print ("#get summary user => ", npm) + parameters = {"access_token": access_token, "client_id": get_client_id()} + response = requests.get(API_MAHASISWA+str(npm), params=parameters) + print ("response => ", response.text) + print ("response => ", response.json()) + return response.json() + +def get_riwayat_user(access_token, npm): + print ("#get riwayat user => ", npm) + parameters = {"access_token": access_token, "client_id": get_client_id()} + response = requests.get(API_RIWAYAT_MAHASISWA.format(npm=npm), params=parameters) + print ("response => ", response.text) + print ("response => ", response.json()) + return response.json() diff --git a/kape/urls.py b/kape/urls.py index 21a1d46bafe92dfd1c3fbfee2bc1545dff38d28d..5ae9c0787fc03f3f61d7fe4abe83f9f62a6736b1 100755 --- a/kape/urls.py +++ b/kape/urls.py @@ -26,6 +26,7 @@ from core.views.accounts import StudentViewSet, CompanyViewSet, SupervisorViewSe CompanyRegisterViewSet from core.views.vacancies import VacancyViewSet, BookmarkedVacancyByStudentViewSet, StudentApplicationViewSet, \ CompanyApplicationViewSet, CompanyVacanciesViewSet, ApplicationViewSet +from core.views.feedbacks import FeedbackViewSet schema_view = get_swagger_view() router = routers.DefaultRouter() @@ -37,6 +38,7 @@ router.register(r'login', LoginViewSet) router.register(r'register', CompanyRegisterViewSet) router.register(r'vacancies', VacancyViewSet) router.register(r'applications', ApplicationViewSet) +router.register(r'feedbacks', FeedbackViewSet) # router.register(r'students/(?P<student_id>\d+)/profile', StudentProfileViewSet) router.register(r'students/(?P<student_id>\d+)/bookmarked-vacancies', BookmarkedVacancyByStudentViewSet, base_name='bookmarked-vacancy-list') diff --git a/sonar-project.properties b/sonar-project.properties index 48a6c493c8cf0d1ead4cb49babe175535621ae67..c3db74cddc82e00230c7f6527111959ce3a27b3d 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -7,6 +7,7 @@ sonar.projectKey=id.ac.ui.cs.foss:kape sonar.exclusions=/.devcontainer/,/.gitlab/,*.config.js,/.tmp/, sonar.scm.provider=git +sonar.projectVersion=1.0.0 ## Authentication ### sonar.login=[pass token via CLI/CI]