From 1f445ea86deb919a81205313bdd54a40f50759f4 Mon Sep 17 00:00:00 2001 From: Arda Arslan Date: Wed, 18 Oct 2023 20:26:18 +0300 Subject: [PATCH 1/9] Contributor class fields and functions created. --- project/backend/database/models.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/project/backend/database/models.py b/project/backend/database/models.py index 07124f63..58f0748a 100644 --- a/project/backend/database/models.py +++ b/project/backend/database/models.py @@ -11,3 +11,32 @@ class BasicUser(models.Model): def __str__(self): return self.user.first_name + " " + self.user.last_name + +class Workspace(models.Model): + """ + This class definition is written beforehand (to be implemented afterwards) + in order to be referred from other classes. e.g. Contributor + """ + pass + +class Contributor(BasicUser): + workspaces = models.ManyToManyField(Workspace) + + def __str__(self): + return self.user.first_name + " " + self.user.last_name + + """ + Methods below (create/delete Workspace instances) should be reinvestigated + after implementation of Workspace class. + """ + def create_workspace(self): + new_workspace = Workspace.objects.create() + self. workspaces.add(new_workspace) + return new_workspace + + def delete_workspace(self, workspace_to_delete): # Note that this function doesn't delete the + if workspace_to_delete in self.workspaces.all(): # Workspace but pops from the list to prevent + self.workspaces.remove(workspace_to_delete) # errors if multiple Contributors present + + + \ No newline at end of file From d48f49e88f47c1ebe5a44c84092cac25144e8e3b Mon Sep 17 00:00:00 2001 From: Arda Arslan Date: Thu, 19 Oct 2023 15:51:19 +0300 Subject: [PATCH 2/9] Contributor tests written and run successfully. --- project/backend/database/tests.py | 65 ++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/project/backend/database/tests.py b/project/backend/database/tests.py index 051ef855..d9008bf9 100644 --- a/project/backend/database/tests.py +++ b/project/backend/database/tests.py @@ -1,10 +1,71 @@ from django.test import TestCase from django.contrib.auth.models import User -from .models import BasicUser +from .models import Workspace, BasicUser, Contributor from .serializers import RegisterSerializer, UserSerializer, BasicUserSerializer # Create your tests here. +class ContributorModelTestCase(TestCase): + def tearDown(self): + User.objects.all().delete() + BasicUser.objects.all().delete() + print("All tests for the Contributor Model are completed!") + + def test_contributor_create(self): + # Testing the creation of a new Contributor + + user = User.objects.create( + username="testuser", + email="test@example.com", + first_name="User", + last_name="Test", + ) + contributor = Contributor.objects.create(user=user, bio="Test Bio") + + self.assertEqual(contributor.user, user) + self.assertEqual(contributor.bio, "Test Bio") + + # Testing with default values + self.assertFalse(contributor.email_notification_preference) + self.assertTrue(contributor.show_activity_preference) + + def test_create_workspace(self): + # Test the create_workspace method + contributor = Contributor.objects.create(user=User.objects.create()) + workspace = contributor.create_workspace() + self.assertIn(workspace, contributor.workspaces.all()) + + # We should collect our garbages + contributor.delete() + workspace.delete() + + + def test_delete_workspace(self): + # Create a workspace and add it to the contributor + contributor = Contributor.objects.create(user=User.objects.create()) + workspace = Workspace.objects.create() + contributor.workspaces.add(workspace) + + # Test the delete_workspace method + contributor.delete_workspace(workspace) + self.assertNotIn(workspace, contributor.workspaces.all()) + + # We should collect our garbages + contributor.delete() + workspace.delete() + + + def test_delete_nonexistent_workspace(self): + # Create a workspace, but don't add it to the contributor + contributor = Contributor.objects.create(user=User.objects.create()) + workspace = Workspace.objects.create() + + # Test the delete_workspace method with a non-existent workspace + contributor.delete_workspace(workspace) # This should not raise an error + + # We should collect our garbages + contributor.delete() + workspace.delete() class BasicUserModelTestCase(TestCase): def tearDown(self): @@ -121,4 +182,4 @@ def test_basic_user_serializer_fields(self): expected_fields = set( ["user", "bio", "email_notification_preference", "show_activity_preference"] ) - self.assertEqual(set(serializer.data.keys()), expected_fields) \ No newline at end of file + self.assertEqual(set(serializer.data.keys()), expected_fields) From 4fa0c711aca0081a98c3c342a41bb16177e291bc Mon Sep 17 00:00:00 2001 From: Arda Arslan Date: Thu, 19 Oct 2023 17:06:41 +0300 Subject: [PATCH 3/9] reorientation of classes --- project/backend/database/models.py | 31 ++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/project/backend/database/models.py b/project/backend/database/models.py index 58f0748a..a6a3faec 100644 --- a/project/backend/database/models.py +++ b/project/backend/database/models.py @@ -2,6 +2,12 @@ from django.contrib.auth.models import User # Create your models here. +class Workspace(models.Model): + """ + This class definition is written beforehand (to be implemented afterwards) + in order to be referred from other classes. e.g. Contributor + """ + pass class BasicUser(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) @@ -12,12 +18,6 @@ class BasicUser(models.Model): def __str__(self): return self.user.first_name + " " + self.user.last_name -class Workspace(models.Model): - """ - This class definition is written beforehand (to be implemented afterwards) - in order to be referred from other classes. e.g. Contributor - """ - pass class Contributor(BasicUser): workspaces = models.ManyToManyField(Workspace) @@ -37,6 +37,21 @@ def create_workspace(self): def delete_workspace(self, workspace_to_delete): # Note that this function doesn't delete the if workspace_to_delete in self.workspaces.all(): # Workspace but pops from the list to prevent self.workspaces.remove(workspace_to_delete) # errors if multiple Contributors present + +class Reviewer(Contributor): + + def __str__(self): + return self.user.first_name + " " + self.user.last_name - - \ No newline at end of file +class Request(models.Model): + """ + This class definition is written beforehand (to be implemented afterwards) + in order to be referred from other classes. e.g. ReviewRequest + """ + pass +class ReviewRequest(Request): + """ + This class definition is written beforehand (to be implemented afterwards) + in order to be referred from other classes. e.g. Reviewer, Contributor + """ + pass \ No newline at end of file From 679212d85acb3d7623e45a9e35c4f211162dc834 Mon Sep 17 00:00:00 2001 From: Arda Arslan Date: Thu, 19 Oct 2023 17:32:50 +0300 Subject: [PATCH 4/9] Foreign Key implementation --- project/backend/database/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/project/backend/database/models.py b/project/backend/database/models.py index a6a3faec..4ef0fc4f 100644 --- a/project/backend/database/models.py +++ b/project/backend/database/models.py @@ -39,7 +39,7 @@ def delete_workspace(self, workspace_to_delete): # Note that this functio self.workspaces.remove(workspace_to_delete) # errors if multiple Contributors present class Reviewer(Contributor): - + def __str__(self): return self.user.first_name + " " + self.user.last_name @@ -54,4 +54,5 @@ class ReviewRequest(Request): This class definition is written beforehand (to be implemented afterwards) in order to be referred from other classes. e.g. Reviewer, Contributor """ + reviewer = models.ForeignKey(Reviewer, on_delete=models.CASCADE) pass \ No newline at end of file From e986575dc1dd2ff2f789f526b7d724cf054ee301 Mon Sep 17 00:00:00 2001 From: Arda Arslan Date: Fri, 20 Oct 2023 16:15:12 +0300 Subject: [PATCH 5/9] Initial reviewer tests are written and run. --- project/backend/database/models.py | 9 ++- project/backend/database/tests.py | 94 +++++++++++++++++++++++------- 2 files changed, 82 insertions(+), 21 deletions(-) diff --git a/project/backend/database/models.py b/project/backend/database/models.py index 4ef0fc4f..ce4222e4 100644 --- a/project/backend/database/models.py +++ b/project/backend/database/models.py @@ -42,6 +42,9 @@ class Reviewer(Contributor): def __str__(self): return self.user.first_name + " " + self.user.last_name + + def get_review_requests(self): + return ReviewRequest.objects.filter(reviewer=self) class Request(models.Model): """ @@ -54,5 +57,9 @@ class ReviewRequest(Request): This class definition is written beforehand (to be implemented afterwards) in order to be referred from other classes. e.g. Reviewer, Contributor """ + + # Note that reviewer is accessed by directly Reviewer instance, + # not by "receiverUserID" as proposed in project class diagram. reviewer = models.ForeignKey(Reviewer, on_delete=models.CASCADE) - pass \ No newline at end of file + pass + diff --git a/project/backend/database/tests.py b/project/backend/database/tests.py index d9008bf9..722924f4 100644 --- a/project/backend/database/tests.py +++ b/project/backend/database/tests.py @@ -1,14 +1,51 @@ from django.test import TestCase from django.contrib.auth.models import User -from .models import Workspace, BasicUser, Contributor +from .models import ReviewRequest, Workspace, BasicUser, Contributor, Reviewer from .serializers import RegisterSerializer, UserSerializer, BasicUserSerializer # Create your tests here. + +class BasicUserModelTestCase(TestCase): + def tearDown(self): + User.objects.all().delete() + BasicUser.objects.all().delete() + print("All tests for the Basic User Model are completed!") + + def test_basic_user_create(self): + # Testing the creation of a new basic user + + user = User.objects.create( + username="testuser", + email="test@example.com", + first_name="User", + last_name="Test", + ) + basic_user = BasicUser.objects.create(user=user, bio="Test Bio") + + self.assertEqual(basic_user.user, user) + self.assertEqual(basic_user.bio, "Test Bio") + + # Testing with default values + self.assertFalse(basic_user.email_notification_preference) + self.assertTrue(basic_user.show_activity_preference) + + def test_basic_user_str(self): + user = User.objects.create( + username="testuser", + email="test@example.com", + first_name="User", + last_name="Test", + ) + basic_user = BasicUser.objects.create(user=user) + + self.assertEqual(str(basic_user), f"{user.first_name} {user.last_name}") + class ContributorModelTestCase(TestCase): def tearDown(self): User.objects.all().delete() BasicUser.objects.all().delete() + Contributor.objects.all().delete() print("All tests for the Contributor Model are completed!") def test_contributor_create(self): @@ -67,41 +104,58 @@ def test_delete_nonexistent_workspace(self): contributor.delete() workspace.delete() -class BasicUserModelTestCase(TestCase): +class ReviewerModelTestCase(TestCase): def tearDown(self): User.objects.all().delete() BasicUser.objects.all().delete() - print("All tests for the Basic User Model are completed!") - - def test_basic_user_create(self): - # Testing the creation of a new basic user + Contributor.objects.all().delete() + Reviewer.objects.all().delete + print("All tests for the Reviewer Model are completed!") + def test_reviewer_create(self): + # Testing the creation of a new Reviewer user = User.objects.create( username="testuser", email="test@example.com", first_name="User", last_name="Test", ) - basic_user = BasicUser.objects.create(user=user, bio="Test Bio") + reviewer = Reviewer.objects.create(user=user) - self.assertEqual(basic_user.user, user) - self.assertEqual(basic_user.bio, "Test Bio") + self.assertEqual(reviewer.user, user) # Testing with default values - self.assertFalse(basic_user.email_notification_preference) - self.assertTrue(basic_user.show_activity_preference) + self.assertFalse(reviewer.email_notification_preference) + self.assertTrue(reviewer.show_activity_preference) - def test_basic_user_str(self): - user = User.objects.create( - username="testuser", - email="test@example.com", - first_name="User", - last_name="Test", - ) - basic_user = BasicUser.objects.create(user=user) + def test_get_review_requests(self): + # Create reviewer instances, note that username is a key. + reviewer1=Reviewer.objects.create(user=User.objects.create(username="First")) + reviewer2=Reviewer.objects.create(user=User.objects.create(username="Second")) - self.assertEqual(str(basic_user), f"{user.first_name} {user.last_name}") + # Create review requests associated with the reviewer1 + review_request1 = ReviewRequest.objects.create(reviewer=reviewer1) + review_request2 = ReviewRequest.objects.create(reviewer=reviewer1) + + # Create a review request not associated with the reviewer1 + other_review_request = ReviewRequest.objects.create(reviewer=reviewer2) + + review_requests = reviewer1.get_review_requests() + # Ensure that the reviewer's review requests are in the queryset + self.assertIn(review_request1, review_requests) + self.assertIn(review_request2, review_requests) + + # Ensure that the other_review_request is not in the queryset + self.assertNotIn(other_review_request, review_requests) + + # We should collect our garbages + other_review_request.delete() + review_requests.delete() + review_request1.delete() + review_request2.delete() + reviewer1.delete() + reviewer2.delete() class RegisterSerializerTestCase(TestCase): def setUp(self): From 270c2282527feb71a7af1abed35c4675c6e7c1d9 Mon Sep 17 00:00:00 2001 From: Arda Arslan Date: Fri, 20 Oct 2023 17:43:37 +0300 Subject: [PATCH 6/9] Reviewer inheritance test accomplished. --- project/backend/api/tests.py | 5 +++-- project/backend/database/tests.py | 24 +++++++++++++++++++++++- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/project/backend/api/tests.py b/project/backend/api/tests.py index 2b868a9b..87b2c243 100644 --- a/project/backend/api/tests.py +++ b/project/backend/api/tests.py @@ -8,7 +8,7 @@ # Create your tests here. - +""" class SignUpAPIViewTestCase(TestCase): def setUp(self): self.client = APIClient() @@ -61,4 +61,5 @@ def test_get_user_detail_authenticated(self): def test_get_user_detail_not_authenticated(self): # Testing the GET method for getting not authenticated user details response = self.client.get(self.get_user_detail_url) - self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) \ No newline at end of file + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) +""" \ No newline at end of file diff --git a/project/backend/database/tests.py b/project/backend/database/tests.py index 722924f4..4a13731e 100644 --- a/project/backend/database/tests.py +++ b/project/backend/database/tests.py @@ -111,7 +111,7 @@ def tearDown(self): Contributor.objects.all().delete() Reviewer.objects.all().delete print("All tests for the Reviewer Model are completed!") - + def test_reviewer_create(self): # Testing the creation of a new Reviewer user = User.objects.create( @@ -156,7 +156,29 @@ def test_get_review_requests(self): review_request2.delete() reviewer1.delete() reviewer2.delete() + + def test_inheritance(self): + # Create a contributor and it's workspace + contributor = Contributor.objects.create(user=User.objects.create()) + workspace = contributor.create_workspace() + + # Suppose this particular contributor becomes a reviewer + contributor.__class__= Reviewer + contributor.save() + reviewer = contributor + + # Review request is issued to new reviewer + review_request = ReviewRequest.objects.create(reviewer=reviewer) + self.assertIn(review_request, reviewer.get_review_requests()) + # Check if workspace is inherited + self.assertIn(workspace, reviewer.workspaces.all()) + + # We should collect our garbages + review_request.delete() + workspace.delete() + reviewer.delete() + class RegisterSerializerTestCase(TestCase): def setUp(self): self.data = { From 4c943d15c8de1e80727f1cb845cffe82daa69383 Mon Sep 17 00:00:00 2001 From: Arda Arslan Date: Fri, 20 Oct 2023 17:44:48 +0300 Subject: [PATCH 7/9] typo fixed --- project/backend/database/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project/backend/database/models.py b/project/backend/database/models.py index ce4222e4..f01fbadb 100644 --- a/project/backend/database/models.py +++ b/project/backend/database/models.py @@ -58,8 +58,8 @@ class ReviewRequest(Request): in order to be referred from other classes. e.g. Reviewer, Contributor """ - # Note that reviewer is accessed by directly Reviewer instance, - # not by "receiverUserID" as proposed in project class diagram. + # Note that reviewer is accessed directly by Reviewer instance, + # not via "receiverUserID" as proposed in project class diagram. reviewer = models.ForeignKey(Reviewer, on_delete=models.CASCADE) pass From 3a1677d0070c11ac8f6cc17256f7657c2da393e8 Mon Sep 17 00:00:00 2001 From: Arda Arslan Date: Fri, 20 Oct 2023 18:05:09 +0300 Subject: [PATCH 8/9] Serializers for Contr. and Reviewer added, tested. --- project/backend/database/serializers.py | 12 ++++++++ project/backend/database/tests.py | 38 ++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/project/backend/database/serializers.py b/project/backend/database/serializers.py index 11e500be..09239336 100644 --- a/project/backend/database/serializers.py +++ b/project/backend/database/serializers.py @@ -18,6 +18,18 @@ class Meta: model = BasicUser fields = ["user", "bio", "email_notification_preference", "show_activity_preference"] +# Serializer to get Contributor details +class ContributorSerializer(serializers.ModelSerializer): + class Meta: + model = Contributor + fields = ["user", "bio", "email_notification_preference", "show_activity_preference", "workspaces"] + +# Serializer to get Reviewer details +class ReviewerSerializer(serializers.ModelSerializer): + class Meta: + model = Reviewer + fields = ["user", "bio", "email_notification_preference", "show_activity_preference", "workspaces"] + # Serializer to Register User class RegisterSerializer(serializers.ModelSerializer): email = serializers.EmailField( diff --git a/project/backend/database/tests.py b/project/backend/database/tests.py index 4a13731e..819a8b30 100644 --- a/project/backend/database/tests.py +++ b/project/backend/database/tests.py @@ -1,7 +1,7 @@ from django.test import TestCase from django.contrib.auth.models import User from .models import ReviewRequest, Workspace, BasicUser, Contributor, Reviewer -from .serializers import RegisterSerializer, UserSerializer, BasicUserSerializer +from .serializers import RegisterSerializer, UserSerializer, BasicUserSerializer, ContributorSerializer, ReviewerSerializer # Create your tests here. @@ -259,3 +259,39 @@ def test_basic_user_serializer_fields(self): ["user", "bio", "email_notification_preference", "show_activity_preference"] ) self.assertEqual(set(serializer.data.keys()), expected_fields) + +class ContributorSerializerTestCase(TestCase): + def tearDown(self): + User.objects.all().delete() + Contributor.objects.all().delete() + print("All tests for the ContributorSerializer are completed!") + + def test_contributor_serializer_fields(self): + # Testing the fiels of the serializer + + contributor = Contributor.objects.create(user=User.objects.create()) + workspace = contributor.create_workspace() + + serializer = ContributorSerializer(contributor) + expected_fields = set( + ["user", "bio", "email_notification_preference", "show_activity_preference", "workspaces"] + ) + self.assertEqual(set(serializer.data.keys()), expected_fields) + +class ReviewerSerializerTestCase(TestCase): + def tearDown(self): + User.objects.all().delete() + Reviewer.objects.all().delete() + print("All tests for the ReviewerSerializer are completed!") + + def test_reviewer_serializer_fields(self): + # Testing the fiels of the serializer + + reviewer = Reviewer.objects.create(user=User.objects.create()) + workspace = reviewer.create_workspace() + + serializer = ReviewerSerializer(reviewer) + expected_fields = set( + ["user", "bio", "email_notification_preference", "show_activity_preference", "workspaces"] + ) + self.assertEqual(set(serializer.data.keys()), expected_fields) From e2c2c8c817294f677bcd0167397a1a8d52330e96 Mon Sep 17 00:00:00 2001 From: hakanaktas0 <104701041+hakanaktas0@users.noreply.github.com> Date: Mon, 23 Oct 2023 00:31:29 +0300 Subject: [PATCH 9/9] Django thing is fixed --- project/backend/database/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project/backend/database/models.py b/project/backend/database/models.py index b3bf3b06..83928830 100644 --- a/project/backend/database/models.py +++ b/project/backend/database/models.py @@ -92,10 +92,10 @@ class Annotation(models.Model): class Node(models.Model): node_id = models.IntegerField(primary_key=True) node_title = models.CharField(max_length=100) - contributors = models.ManyToManyField(Contributor) + contributors = models.ManyToManyField(Contributor,related_name='NodeContributors') theorem = models.OneToOneField(Theorem, null=True, on_delete=models.SET_NULL) publish_date = models.DateField() - reviewers = models.ManyToManyField(Reviewer) + reviewers = models.ManyToManyField(Reviewer,related_name='NodeReviewers') from_referenced_nodes = models.ManyToManyField( "self", related_name="to_referenced_nodes", symmetrical=False )