Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions .idea/csoc-2021-task5-Django-REST-Framework.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/inspectionProfiles/profiles_settings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions api/migrations/0003_todo_collaborators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 3.0.7 on 2021-08-02 19:01

from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('api', '0002_todo_creator'),
]

operations = [
migrations.AddField(
model_name='todo',
name='collaborators',
field=models.ManyToManyField(related_name='collaborators', to=settings.AUTH_USER_MODEL),
),
]
1 change: 1 addition & 0 deletions api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
class Todo(models.Model):
creator = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=255)
collaborators = models.ManyToManyField(User, related_name='collaborators')

def __str__(self):
return self.title
21 changes: 21 additions & 0 deletions api/serializers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.contrib.auth.models import User
from rest_framework import serializers
from .models import Todo

Expand All @@ -23,7 +24,27 @@ def save(self, **kwargs):
user = self.context['request'].user
title = data['title']
todo = Todo.objects.create(creator=user, title=title)
return {'id': todo.id, 'title': todo.title}

class Meta:
model = Todo
fields = ('id', 'title',)


class TodoListSerializer(serializers.ModelSerializer):
class Meta:
model = Todo
fields = ['id', 'title', 'creator']

class TodoEditSerializer(serializers.ModelSerializer):
class Meta:
model = Todo
fields = ['id', 'title']

class CollaboratorsSerializer(serializers.ModelSerializer):
class Meta:
model = Todo
fields = ['id', 'collaborator']
collaborator = serializers.CharField()


6 changes: 5 additions & 1 deletion api/urls.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from django.urls import path
from .views import TodoCreateView
from .views import TodoCreateView, TodoListView, TodoView, AddCollaboratorView, RemoveCollaboratorView

"""
TODO:
Expand All @@ -9,4 +9,8 @@

urlpatterns = [
path('todo/create/', TodoCreateView.as_view()),
path('todo/', TodoListView.as_view()),
path('todo/<int:pk>/', TodoView.as_view()),
path('todo/<int:pk>/add-collaborators', AddCollaboratorView.as_view()),
path('todo/<int:pk>/remove-collaborators', RemoveCollaboratorView.as_view()),
]
127 changes: 122 additions & 5 deletions api/views.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
from django.contrib.auth.models import User
from django.http import Http404
from rest_framework import generics
from rest_framework import permissions
from rest_framework import status
from rest_framework.generics import get_object_or_404
from rest_framework.permissions import IsAuthenticated, BasePermission
from rest_framework.response import Response
from .serializers import TodoCreateSerializer
from .models import Todo
from rest_framework.views import APIView

from .serializers import TodoCreateSerializer, TodoListSerializer, CollaboratorsSerializer, TodoEditSerializer
from .models import Todo

"""
TODO:
Expand All @@ -22,7 +27,7 @@ class TodoCreateView(generics.GenericAPIView):
Modify the below code (if required), so that this endpoint would
also return the serialized Todo data (id etc.), alongwith 200 status code.
"""
permission_classes = (permissions.IsAuthenticated, )
permission_classes = (permissions.IsAuthenticated,)
serializer_class = TodoCreateSerializer

def post(self, request):
Expand All @@ -31,5 +36,117 @@ def post(self, request):
"""
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(status=status.HTTP_200_OK)
s = serializer.save()
print(s, type(s))
return Response(s, status=status.HTTP_200_OK)


class TodoListView(generics.ListAPIView):
permission_classes = [permissions.IsAuthenticated, ]
serializer_class = TodoListSerializer

def get_queryset(self):
q = Todo.objects.all()
p = q.filter(creator=self.request.user)
q = q.filter(collaborators=self.request.user)
v = []
for i in q:
v.append(i)
for i in p:
if i not in v:
v.append(i)
return v


class Allowed(BasePermission):
def has_object_permission(self, request, view, obj):
t = Todo.objects.filter(id=obj.id)
if t:
if request.user in t[0].collaborators.all() or request.user == t[0].creator:
return True

return False


class TodoView(generics.RetrieveUpdateDestroyAPIView):
permission_classes = [IsAuthenticated, Allowed, ]
queryset = Todo.objects.all()
serializer_class = TodoEditSerializer

def get_object(self):
q = Todo.objects.all()
queryset1 = q.filter(creator=self.request.user)
queryset2 = q.filter(collaborators=self.request.user)
queryset = queryset2 | queryset1

# Perform the lookup filtering.
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field

filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
obj = get_object_or_404(queryset, **filter_kwargs)

# May raise a permission denied
self.check_object_permissions(self.request, obj)

return obj


class AddCollaboratorView(generics.GenericAPIView):
permission_classes = [IsAuthenticated, ]
serializer_class = CollaboratorsSerializer
queryset = Todo.objects.all()

def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
todo_id = self.kwargs.get('pk')
user = User.objects.filter(username=request.data['collaborator'])
if len(user) == 0:
return Response({'Response': 'Invalid Username.'}, status=status.HTTP_400_BAD_REQUEST)

todo = Todo.objects.filter(pk=todo_id)
if len(todo) == 0:
return Response({'Response': 'Invalid Id.'}, status=status.HTTP_400_BAD_REQUEST)

if todo[0].creator != self.request.user:
return Response({'Response': 'Only Creator can add collaborator.'}, status=status.HTTP_400_BAD_REQUEST)

v = []
for i in todo[0].collaborators.all():
v.append(i.id)
if user[0].id in v:
return Response({'Response': 'User already in collaborator list'}, status=status.HTTP_400_BAD_REQUEST)

v.append(user[0].id)
todo[0].collaborators.set(v)
todo[0].save()
return Response({'Response': 'Success'}, status=status.HTTP_200_OK)


class RemoveCollaboratorView(generics.GenericAPIView):
permission_classes = [IsAuthenticated, ]
serializer_class = CollaboratorsSerializer
queryset = Todo.objects.all()

def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
todo_id = self.kwargs.get('pk')
user = User.objects.filter(username=request.data['collaborator'])
if len(user) == 0:
return Response({'Response': 'Invalid Username.'}, status=status.HTTP_400_BAD_REQUEST)

todo = Todo.objects.filter(pk=todo_id)
if len(todo) == 0:
return Response({'Response': 'Invalid Id.'}, status=status.HTTP_400_BAD_REQUEST)

if todo[0].creator != self.request.user:
return Response({'Response': 'Only Creator can remove collaborator.'}, status=status.HTTP_400_BAD_REQUEST)
v = []
for i in todo[0].collaborators.all():
v.append(i.id)
if user[0].id not in v:
return Response({'Response': 'User not present in collaborator list'}, status=status.HTTP_400_BAD_REQUEST)

v.remove(user[0].id)
todo[0].collaborators.set(v)
todo[0].save()
return Response({'Response': 'Success'},status=status.HTTP_200_OK)
30 changes: 23 additions & 7 deletions authentication/serializers.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,39 @@
from rest_framework import serializers
from django.contrib.auth import authenticate
from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token


class TokenSerializer(serializers.Serializer):
token = serializers.CharField(max_length=500)


class LoginSerializer(serializers.Serializer):
# TODO: Implement login functionality
pass
username = serializers.CharField()
password = serializers.CharField()

def validate(self, data):
user = authenticate(**data)
if user and user.is_authenticated:
return user
raise serializers.ValidationError("Incorrect.")

class RegisterSerializer(serializers.Serializer):
# TODO: Implement register functionality
pass

class RegisterSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('first_name', 'username', 'email', 'password')
extra_kwargs = {'password': {'write_only': True}}

def create(self, validated_data):
print(validated_data, len(validated_data))
user = User.objects.create_user(first_name=validated_data['first_name'], username=str(validated_data['username']), email=str(validated_data['email']), password=str(validated_data['password']))

return user


class UserSerializer(serializers.ModelSerializer):
# TODO: Implement the functionality to display user details
pass
class Meta:
model = User
fields = ['id', 'first_name', 'username', 'email']

Loading