Skip to content

Commit

Permalink
Merge pull request #501 from bounswe/workspace-post-api-update
Browse files Browse the repository at this point in the history
  • Loading branch information
Simurgan authored Nov 26, 2023
2 parents 82c2dc4 + 16e97bd commit 7156442
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 5 deletions.
89 changes: 87 additions & 2 deletions project/backend/api/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,95 @@
from database.serializers import RegisterSerializer, UserSerializer
from database.models import *
import datetime

# Create your tests here for each class or API call.

class WorkspacePOSTAPITestCase(TestCase):
def setUp(self):
self.client = APIClient()

self.user_for_basic = User.objects.create_user(id=1, email= '[email protected]', username='[email protected]', first_name='Basic User', last_name='Test1')
self.user_for_contributor1 = User.objects.create_user(id=2, email= '[email protected]', username='[email protected]', first_name='Contributor User 2', last_name='Test2')
self.user_for_contributor2 = User.objects.create_user(id=3, email= '[email protected]', username='[email protected]', first_name='Contributor User 3', last_name='Test3')

self.basic_user = BasicUser.objects.create(user=self.user_for_basic, bio="I am a basic user")
self.contributor1 = Contributor.objects.create(user=self.user_for_contributor1, bio="I am the first contributor")
self.contributor2 = Contributor.objects.create(user=self.user_for_contributor2, bio="I am the second contributor")

self.basic_user_token = Token.objects.create(user=self.user_for_basic)
self.contributor1_token = Token.objects.create(user=self.user_for_contributor1)
self.contributor2_token = Token.objects.create(user=self.user_for_contributor2)

self.semantic_tag1 = SemanticTag.objects.create(wid="Q1", label="Semantic Tag 1")
self.semantic_tag2 = SemanticTag.objects.create(wid="Q2", label="Semantic Tag 2")

def tearDown(self):
User.objects.all().delete()
BasicUser.objects.all().delete()
Contributor.objects.all().delete()
Token.objects.all().delete()
Workspace.objects.all().delete()
SemanticTag.objects.all().delete()

print("All tests for the Workspace POST API are completed!")

def test_create_workspace(self):
# Testing the POST method for basic user tries to create workspace
self.client.credentials(HTTP_AUTHORIZATION=f"Token {self.basic_user_token.key}")
data = {
"workspace_title": "Basic User Workspace",
"semantic_tags": [self.semantic_tag1.pk]
}

response = self.client.post(reverse("workspace_post"), data, format="json")
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN, "Test failed: Basic user shouldnot be able to create a workspace")

# Testing the POST method for creating without title
self.client.credentials(HTTP_AUTHORIZATION=f"Token {self.contributor1_token.key}")

data = {
"semantic_tags": [self.semantic_tag1.pk]
}
response = self.client.post(reverse("workspace_post"), data, format="json")
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST, "Test failed: Workspace cannot be created without a title")

# Testing the POST method for creating without semantic tags
data = {
"workspace_title": "Contributor1 Workspace"
}
response = self.client.post(reverse("workspace_post"), data, format="json")
self.assertEqual(response.status_code, status.HTTP_201_CREATED, "Test failed: Workspace can be created without semantic tags")

workspaces = self.contributor1.workspaces.all()
self.assertEqual(workspaces.count(), 1, "Test failed: Workspace could not be created")

# Testing the POST method for updating workspace
if workspaces.count() > 0:
workspace = workspaces[0]

data = {
"workspace_id": workspace.workspace_id,
"workspace_title": "Contributor1 Workspace Updated",
"semantic_tags": [self.semantic_tag2.pk]
}
response = self.client.post(reverse("workspace_post"), data, format="json")

workspace = Workspace.objects.get(workspace_id=workspace.workspace_id)
self.assertEqual(response.status_code, status.HTTP_201_CREATED, "Update failure")
self.assertEqual(workspace.semantic_tags.count(), 1, "Update failure for semantic tags count")
self.assertEqual(workspace.semantic_tags.all()[0].wid, self.semantic_tag2.wid, "Update failure for semantic tag")
self.assertEqual(workspace.workspace_title, "Contributor1 Workspace Updated", "Update failure for title")

# Try to update workspace of a different contributor
self.client.credentials(HTTP_AUTHORIZATION=f"Token {self.contributor2_token.key}")
data = {
"workspace_id": workspace.workspace_id,
"workspace_title": "Contributor2 Workspace Updated",
"semantic_tags": [self.semantic_tag1.pk]
}
response = self.client.post(reverse("workspace_post"), data, format="json")
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN, "Test failed: Contributor2 shouldnot be able to update Contributor1's workspace")


class SignUpAPIViewTestCase(TestCase):
def setUp(self):
Expand Down Expand Up @@ -458,7 +545,6 @@ def setUp(self):

def test_get_workspaces_of_user(self):
response = self.client.get(self.url, {'user_id': self.cont.id})
print(response)

self.assertEqual(response.status_code, 200)
self.assertEqual(response.json()['workspaces'][0]['workspace_id'],self.workspace.workspace_id)
Expand All @@ -478,7 +564,6 @@ def setUp(self):

def test_get_workspace_from_id(self):
response = self.client.get(self.url, {'workspace_id': self.workspace.workspace_id})
print(response)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json()['workspace_id'],self.workspace.workspace_id)
self.assertEqual(response.json()['workspace_id'], self.workspace.workspace_id)
Expand Down
1 change: 1 addition & 0 deletions project/backend/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
path('add_entry/',add_entry,name='add_entry'),
path('get_random_node_id/',get_random_node_id,name='get_random_node_id'),
path('create_workspace/',create_workspace,name='create_workspace'),
path('workspace_post/', WorkspacePostAPIView.as_view(), name='workspace_post'),
path('add_reference/',add_reference,name='add_reference'),
path('finalize_workspace/',finalize_workspace,name='finalize_workspace'),
path('delete_contributor/',delete_contributor,name='delete_contributor'),
Expand Down
26 changes: 25 additions & 1 deletion project/backend/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from rest_framework.views import APIView
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.permissions import IsAuthenticated, AllowAny, BasePermission
from database.serializers import *
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.models import User
Expand Down Expand Up @@ -72,6 +72,30 @@ def get(self, request):
serializer = NodeSerializer(node)
return Response(serializer.data)

class IsContributorAndWorkspace(BasePermission):
def has_permission(self, request, view):
workspace_id = request.data.get('workspace_id')
if not request.user.is_authenticated:
return False
if not Contributor.objects.filter(pk=request.user.basicuser.pk).exists():
return False
if workspace_id is not None:
return request.user.basicuser.contributor.workspaces.filter(workspace_id=workspace_id).exists()
return True

class WorkspacePostAPIView(APIView):
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated, IsContributorAndWorkspace)

def post(self, request):
serializer = WorkspaceSerializer(data=request.data, context={'request': request})
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=201)
return Response(
serializer.errors, status=400
)

def search(request):
search = request.GET.get("query")
search_type = request.GET.get("type")
Expand Down
5 changes: 3 additions & 2 deletions project/backend/database/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def existing_search_results(cls, keyword):
return existings

def __str__(self):
return self.label + " - " + self.wid
return str(self.pk) + " " + self.label + " - " + self.wid

class Entry(models.Model):
entry_id = models.AutoField(primary_key=True)
Expand All @@ -72,6 +72,7 @@ def set_as_theorem(self):
self.is_theorem_entry = True
def set_entry_content(self,cont):
self.content = cont

# Create your models here.
class Workspace(models.Model): #Node and Review Requests may be added later
workspace_id = models.AutoField(primary_key=True)
Expand Down Expand Up @@ -112,7 +113,7 @@ def __str__(self):


class Contributor(BasicUser):
workspaces = models.ManyToManyField(Workspace)
workspaces = models.ManyToManyField(Workspace, blank=True)

def __str__(self):
return self.user.first_name + " " + self.user.last_name
Expand Down
61 changes: 61 additions & 0 deletions project/backend/database/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,67 @@

from .models import *

class WorkspaceSerializer(serializers.ModelSerializer):
semantic_tags = serializers.PrimaryKeyRelatedField(many=True, queryset=SemanticTag.objects.all(), required=False)
workspace_id = serializers.IntegerField(required=False)
workspace_title = serializers.CharField(required=False)

class Meta:
model = Workspace
fields = [
'workspace_id',
'workspace_title',
'semantic_tags'
]

def validate(self, data):
workspace_id = data.get('workspace_id')
workspace_title = data.get('workspace_title')
tags = data.get('semantic_tags')

if workspace_id is None and workspace_title is None:
raise serializers.ValidationError("Both workspace_id and workspace_title cannot be empty.")

if tags is None and workspace_title is None:
raise serializers.ValidationError("Both workspace_title and semantic_tags cannot be empty.")

return data

def create(self, validated_data):
workspace_id = validated_data.get('workspace_id', None)
title = validated_data.get('workspace_title', None)

if workspace_id is not None:
workspace = Workspace.objects.get(workspace_id=workspace_id)
created = False
else:
workspace = Workspace.objects.create(workspace_title=title)
created = True

if created:
self.context['request'].user.basicuser.contributor.workspaces.add(workspace)
tags = validated_data.get('semantic_tags', None)
if tags is not None:
workspace.semantic_tags.add(*tags)

else:
if title:
workspace.workspace_title = title
workspace.save()

tags = validated_data.get('semantic_tags', None)
if tags is not None:
for tag in workspace.semantic_tags.all():
if tag not in tags:
workspace.semantic_tags.remove(tag)

for tag in tags:
if tag not in workspace.semantic_tags.all():
workspace.semantic_tags.add(tag)

return workspace


# Serializer to change password
class ChangePasswordSerializer(serializers.ModelSerializer):
old_password = serializers.CharField(write_only=True, required=True)
Expand Down

0 comments on commit 7156442

Please sign in to comment.