Skip to content
This repository has been archived by the owner on Jun 16, 2021. It is now read-only.

Task 3 submission #12

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
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
7 changes: 6 additions & 1 deletion api/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
# Generated by Django 3.0.5 on 2020-04-21 08:58
# Generated by Django 3.0.6 on 2020-05-19 06:06

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


class Migration(migrations.Migration):

initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
Expand All @@ -16,6 +19,8 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=255)),
('collaborators', models.ManyToManyField(related_name='collaborators', to=settings.AUTH_USER_MODEL)),
('creator', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='creator', to=settings.AUTH_USER_MODEL)),
],
),
]
7 changes: 4 additions & 3 deletions api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@


class Todo(models.Model):
creator = models.ForeignKey(User, on_delete=models.CASCADE)
creator = models.ForeignKey(User, on_delete=models.CASCADE, related_name='creator')
title = models.CharField(max_length=255)

collaborators = models.ManyToManyField(User, related_name='collaborators')
def __str__(self):
return self.title
return self.title

57 changes: 55 additions & 2 deletions api/serializers.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from rest_framework import serializers
from .models import Todo


from rest_framework.exceptions import ValidationError
from django.contrib.auth.models import User
"""
TODO:
Create the appropriate Serializer class(es) for implementing
Expand All @@ -27,3 +27,56 @@ def save(self, **kwargs):
class Meta:
model = Todo
fields = ('id', 'title',)

class TodoSerializer(serializers.ModelSerializer):
collaborators = serializers.StringRelatedField(many=True, read_only=True)
creator = serializers.StringRelatedField()
class Meta:
model = Todo
fields = '__all__'
read_only_fields = ['id','creator']

class TodoCollaboratorSerializer(serializers.ModelSerializer):
collaborators = serializers.StringRelatedField(many=True)
class Meta:
model = Todo
fields = '__all__'
read_only_fields = ['id', 'creator', 'title', ]

def is_valid(self, raise_exception=True):
try:
usernames = self.initial_data['usernames']
except:
raise ValidationError({"usernames": "field required"})
if not isinstance(usernames, list):
raise ValidationError({"usernames": "array required"})
if not hasattr(self,'_validated_data'):
self._validated_data = {}

self.store_users(usernames)

self._errors = {}
return True

def store_users(self, usernames):
self._validated_data['collaborators'] = []
for name in usernames:
try:
user = User.objects.get(username = name)
except :
raise ValidationError({'details':"user does not exist"})
if self.context['request'].user != user:
self._validated_data['collaborators'].append(user)

def update(self, instance, validated_data):
for user in validated_data['collaborators']:
if self.context['add']:
instance.collaborators.add(user)
else:
try:
instance.collaborators.remove(user)
except:
pass
instance.save()
return instance

8 changes: 6 additions & 2 deletions 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, TodoView, TodoListView, TodoAddCollaboratorView, TodoRemoveCollaboratorView

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

urlpatterns = [
path('todo/', TodoListView.as_view()),
path('todo/create/', TodoCreateView.as_view()),
]
path('todo/<int:pk>/', TodoView.as_view()),
path('todo/<int:pk>/add-collaborators/',TodoAddCollaboratorView.as_view()),
path('todo/<int:pk>/remove-collaborators/',TodoRemoveCollaboratorView.as_view()),
]
65 changes: 61 additions & 4 deletions api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@
from rest_framework import permissions
from rest_framework import status
from rest_framework.response import Response
from .serializers import TodoCreateSerializer
from .serializers import TodoCreateSerializer, TodoSerializer, TodoCollaboratorSerializer
from .models import Todo

class IsOwnerOrCollaborator(permissions.BasePermission):
def has_object_permission(self, request, View, obj):
return request.user == obj.creator or obj.collaborators == request.user

class IsOwner(permissions.BasePermission):
def has_object_permission(self, request, View, obj):
return request.user == obj.creator

"""
TODO:
Expand All @@ -30,6 +37,56 @@ def post(self, request):
Creates a Todo entry for the logged in user.
"""
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(status=status.HTTP_200_OK)
if serializer.is_valid():
serializer.save()
return Response(status=status.HTTP_200_OK)
else :
return Response(status=serializer.errors)

class TodoView(generics.RetrieveUpdateDestroyAPIView):

permission_classes = (permissions.IsAuthenticated, IsOwnerOrCollaborator)
serializer_class = TodoSerializer
queryset = Todo.objects.all()

class TodoListView(generics.GenericAPIView):
permission_classes = (permissions.IsAuthenticated, )
def get(self, request, *args, **kwargs):
ownerqueryset = Todo.objects.filter(creator=request.user)
collabqueryset = Todo.objects.filter(collaborators=request.user)
ownerserializer = TodoSerializer(ownerqueryset, many=True)
collabserializer = TodoSerializer(collabqueryset, many=True)
return Response({
'owner':ownerserializer.data,
'collaborator':collabserializer.data,
})


'''
for adding or removing collaborators
request (PUT or PATCH) format

{
"usernames": <Array of usernames to be added or removed>
}
'''

class TodoAddCollaboratorView(generics.UpdateAPIView):
permission_classes = [permissions.IsAuthenticated, IsOwner]
serializer_class = TodoCollaboratorSerializer
queryset = Todo.objects.all()
def get_serializer_context(self):
context = super().get_serializer_context()
context['add'] = True
return context


class TodoRemoveCollaboratorView(generics.UpdateAPIView):
permission_classes = [permissions.IsAuthenticated, IsOwner]
serializer_class = TodoCollaboratorSerializer
queryset = Todo.objects.all()
def get_serializer_context(self):
context = super().get_serializer_context()
context['add'] = False
return context

24 changes: 21 additions & 3 deletions authentication/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,30 @@ class LoginSerializer(serializers.Serializer):
pass


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

class Meta:
model = User
fields = ('first_name', 'last_name', 'email', 'username', 'password')
extra_kwargs = {
'password':{'write_only':True},
}
def create(self, validated_data):
user = User(
email = validated_data['email'],
username = validated_data['username'],
first_name = validated_data['first_name'],
)
user.set_password(validated_data['password'])
user.save()
return user


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

3 changes: 2 additions & 1 deletion authentication/urls.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from django.urls import path
from .views import LoginView, RegisterView, UserProfileView
from rest_framework.authtoken.views import obtain_auth_token

urlpatterns = [
path('login/', LoginView.as_view()),
path('login/', obtain_auth_token),
path('register/', RegisterView.as_view()),
path('profile/', UserProfileView.as_view()),
]
23 changes: 19 additions & 4 deletions authentication/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from rest_framework.authtoken.models import Token
from .serializers import (
LoginSerializer, RegisterSerializer, UserSerializer, TokenSerializer)

from django.contrib.auth.models import User

def create_auth_token(user):
"""
Expand All @@ -30,13 +30,28 @@ class RegisterView(generics.GenericAPIView):
Implement register functionality, registering the user by
taking his details, and returning the Token.
"""
pass
def post(self, request, *args, **kwargs):
request.data['first_name'] = request.data['name']
serializer = RegisterSerializer(data = request.data)
if (serializer.is_valid()):
user = serializer.save()
token = create_auth_token(user).key
res = {'token':token}
return Response(status=200, data=res)
else :
return Response(status=400, data=serializer.errors)


class UserProfileView(generics.RetrieveAPIView):
class UserProfileView(generics.ListAPIView):
"""
TODO:
Implement the functionality to retrieve the details
of the logged in user.
"""
pass
permission_classes = [permissions.IsAuthenticated]
serializer_class = UserSerializer
queryset = User.objects.all()

def get_queryset(self):
return self.queryset.filter(id = self.request.user.id)