Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Workspace post api update #501

Merged
merged 2 commits into from
Nov 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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= 'basic_user@example.com', username='basic_user@example.com', first_name='Basic User', last_name='Test1')
self.user_for_contributor1 = User.objects.create_user(id=2, email= 'cont1@example.com', username='cont1@example.com', first_name='Contributor User 2', last_name='Test2')
self.user_for_contributor2 = User.objects.create_user(id=3, email= 'cont2@example.com', username='cont2@example.com', 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