diff --git a/client/src/services/files.ts b/client/src/services/files.ts index cb00bd5c..aaf8e65e 100644 --- a/client/src/services/files.ts +++ b/client/src/services/files.ts @@ -71,7 +71,7 @@ export async function uploadCircleDocument( await uploadFile(startData, data.file); const response = await itPost(`/api/core/file/finish`, { - file_id: startData.id, + file_id: startData.file_id, }); const newDocument: CircleDocument = { diff --git a/server/config/settings/base.py b/server/config/settings/base.py index 91e34203..fdf9c92a 100644 --- a/server/config/settings/base.py +++ b/server/config/settings/base.py @@ -611,9 +611,6 @@ if APP_ENVIRONMENT == "development": FILE_UPLOAD_STORAGE = env("FILE_UPLOAD_STORAGE", default="local") # local | s3 if FILE_UPLOAD_STORAGE == "local": - MEDIA_ROOT_NAME = "media" - MEDIA_ROOT = os.path.join(SERVER_ROOT_DIR, MEDIA_ROOT_NAME) - MEDIA_URL = f"/{MEDIA_ROOT_NAME}/" FILE_MAX_SIZE = env.int("FILE_MAX_SIZE", default=5242880) if FILE_UPLOAD_STORAGE == "s3": diff --git a/server/vbv_lernwelt/course/tests/test_document_uploads.py b/server/vbv_lernwelt/course/tests/test_document_uploads.py new file mode 100644 index 00000000..4a1d462c --- /dev/null +++ b/server/vbv_lernwelt/course/tests/test_document_uploads.py @@ -0,0 +1,183 @@ +from rest_framework.test import APITestCase + +from vbv_lernwelt.core.create_default_users import create_default_users +from vbv_lernwelt.core.models import User +from vbv_lernwelt.course.consts import COURSE_TEST_ID +from vbv_lernwelt.course.creators.test_course import create_test_course +from vbv_lernwelt.course.models import CircleDocument, CourseSession, CourseSessionUser +from vbv_lernwelt.files.models import File +from vbv_lernwelt.learnpath.models import Circle, LearningSequence + + +class DocumentUploadApiTestCase(APITestCase): + def setUp(self) -> None: + create_default_users() + create_test_course() + + self.user = User.objects.get(username="student") + self.expert = User.objects.get( + username="patrizia.huggel@eiger-versicherungen.ch" + ) + + self.course_session = CourseSession.objects.create( + course_id=COURSE_TEST_ID, + title="Test Lehrgang Session", + ) + + csu = CourseSessionUser.objects.create( + course_session=self.course_session, + user=User.objects.get(username="patrizia.huggel@eiger-versicherungen.ch"), + role=CourseSessionUser.Role.EXPERT, + ) + csu.expert.add(Circle.objects.get(slug="test-lehrgang-lp-circle-basis")) + + self.test_data = { + "file_name": "test.pdf", + "file_type": "application/pdf", + "name": "Test", + "course_session": self.course_session.id, + } + + self.client.login( + username="patrizia.huggel@eiger-versicherungen.ch", password="myvbv1234" + ) + + def test_can_start_upload(self): + ls = LearningSequence.objects.get( + slug="test-lehrgang-lp-circle-basis-ls-starten" + ) + self.test_data["learning_sequence"] = ls.id + response = self.client.post(f"/api/core/document/start", self.test_data) + + self.assertEqual(response.status_code, 200) + self.assertNotEqual(response.data["url"], "") + self.assertEqual( + response.data["fields"]["Content-Type"], self.test_data["file_type"] + ) + self.assertEqual( + response.data["fields"]["Content-Disposition"], + f"attachment; filename={self.test_data['file_name']}", + ) + + file_id = response.data["file_id"] + file = File.objects.get(id=file_id) + + self.assertIsNone(file.upload_finished_at) + + def test_cannot_start_upload_in_other_circle(self): + ls = LearningSequence.objects.get( + slug="test-lehrgang-lp-circle-analyse-ls-beenden" + ) + self.test_data["learning_sequence"] = ls.id + response = self.client.post(f"/api/core/document/start", self.test_data) + + self.assertEqual(response.status_code, 401) + + def test_student_cannot_start_uploads(self): + self.client.login(username="student", password="test") + ls = LearningSequence.objects.get( + slug="test-lehrgang-lp-circle-basis-ls-starten" + ) + self.test_data["learning_sequence"] = ls.id + response = self.client.post(f"/api/core/document/start", self.test_data) + + self.assertEqual(response.status_code, 401) + + def test_expert_can_finish_own_upload(self): + ls = LearningSequence.objects.get( + slug="test-lehrgang-lp-circle-basis-ls-starten" + ) + self.test_data["learning_sequence"] = ls.id + response = self.client.post(f"/api/core/document/start", self.test_data) + + self.assertEqual(response.status_code, 200) + file_id = response.data["file_id"] + + response = self.client.post( + f"/api/core/file/finish", + { + "file_id": response.data["id"], + }, + ) + + self.assertEqual(response.status_code, 200) + self.assertNotEqual(response.data["url"], "") + + file = File.objects.get(id=file_id) + self.assertIsNotNone(file.upload_finished_at) + + def test_can_only_finish_own_files(self): + file = File( + original_file_name="test.pdf", + file_name="test.pdf", + file_type="application/pdf", + uploaded_by=self.user, + file=None, + ) + file.full_clean() + file.save() + + response = self.client.post(f"/api/core/file/finish/", {"file_id": file.id}) + + self.assertEqual(response.status_code, 401) + + def test_can_delete_document(self): + ls = LearningSequence.objects.get( + slug="test-lehrgang-lp-circle-basis-ls-starten" + ) + file = File( + original_file_name="test.pdf", + file_name="test.pdf", + file_type="application/pdf", + uploaded_by=self.expert, + file=None, + ) + file.full_clean() + file.save() + + document = CircleDocument.objects.create( + file=file, + name="Test", + learning_sequence=ls, + course_session=self.course_session, + ) + + response = self.client.delete(f"/api/core/document/{document.id}/") + self.assertEqual(response.status_code, 200) + + try: + CircleDocument.objects.get(id=document.id) + self.fail("Document was not deleted") + except CircleDocument.DoesNotExist: + pass + + file = File.objects.get(id=file.id) + self.assertIsNone(file.upload_finished_at) + + def test_student_cannot_delete_document(self): + ls = LearningSequence.objects.get( + slug="test-lehrgang-lp-circle-basis-ls-starten" + ) + file = File( + original_file_name="test.pdf", + file_name="test.pdf", + file_type="application/pdf", + uploaded_by=self.expert, + file=None, + ) + file.full_clean() + file.save() + + document = CircleDocument.objects.create( + file=file, + name="Test", + learning_sequence=ls, + course_session=self.course_session, + ) + + response = self.client.delete(f"/api/core/document/{document.id}/") + self.assertEqual(response.status_code, 403) + + +# expert cannot upload in other course +# expert cannot delete other upload diff --git a/server/vbv_lernwelt/course/views.py b/server/vbv_lernwelt/course/views.py index 33de3ca0..82775155 100644 --- a/server/vbv_lernwelt/course/views.py +++ b/server/vbv_lernwelt/course/views.py @@ -182,6 +182,7 @@ def document_upload_start(request): ) document.save() presigned_data["id"] = document.id + presigned_data["file_id"] = file.id return Response(data=presigned_data) diff --git a/trufflehog-allow.json b/trufflehog-allow.json index 0f80add6..c74e9e1d 100644 --- a/trufflehog-allow.json +++ b/trufflehog-allow.json @@ -7,5 +7,6 @@ "ignore hash 6": "A035C8C19219BA821ECEA86B64E628F8D684696D", "json base64 content": "regex:\"content\": \"", "img base64 content": "regex:data:image/png;base64,.*", - "sentry url": "https://2df6096a4fd94bd6b4802124d10e4b8d@o8544.ingest.sentry.io/4504157846372352" + "sentry url": "https://2df6096a4fd94bd6b4802124d10e4b8d@o8544.ingest.sentry.io/4504157846372352", + "git commit": "bdadf52b849bb5fa47854a3094f4da6fe9d54d02" }