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
20 changes: 20 additions & 0 deletions api/migrations/0003_todo_collabs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 3.0.7 on 2021-08-03 07:03

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='collabs',
field=models.ManyToManyField(related_name='collaborators', to=settings.AUTH_USER_MODEL),
),
]
2 changes: 1 addition & 1 deletion api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
class Todo(models.Model):
creator = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=255)

collabs = models.ManyToManyField(User,related_name='collaborators')
def __str__(self):
return self.title
61 changes: 60 additions & 1 deletion 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,65 @@ def save(self, **kwargs):
user = self.context['request'].user
title = data['title']
todo = Todo.objects.create(creator=user, title=title)

data['id'] = todo.id

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

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

class TodoAddCollabSerializer(serializers.Serializer):
username = serializers.CharField()
def validate(self, attrs):
username = attrs.get('username')
todo = self.context.get('todo')

if username == todo.creator.username:
raise serializers.ValidationError({
'Creator': 'Cannot add creator of todo as a collaborator'
})

if username not in [i.username for i in User.objects.all()]:
raise serializers.ValidationError({
'username': 'Such a user does not exist'
})

if username in [i.username for i in todo.collabs.all()]:
raise serializers.ValidationError({
'username': 'User is already a collaborator to this todo'
})
return attrs

def save(self,todo):
newCollab = User.objects.get(username=self.validated_data.get('username'))
self.context.get('todo').collabs.add(newCollab)

class TodoRemoveCollabSerializer(serializers.Serializer):
username = serializers.CharField()
def validate(self, attrs):
username = attrs.get('username')
todo = self.context.get('todo')

if username == todo.creator.username:
raise serializers.ValidationError({
'Creator': 'Given user is creator of this todo'
})

if username not in [i.username for i in User.objects.all()]:
raise serializers.ValidationError({
'username': 'Such a user does not exist'
})

if username not in [i.username for i in todo.collabs.all()]:
raise serializers.ValidationError({
'username': 'User is not a collaborator to this todo'
})
return attrs

def save(self,todo):
newCollab = User.objects.get(username=self.validated_data.get('username'))
self.context.get('todo').collabs.remove(newCollab)
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,TodoDetail,TodoAddCollabs,TodoRemoveCollabs)

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

urlpatterns = [
path('todo/create/', TodoCreateView.as_view()),
path('todo/',TodoListView.as_view()),
path('todo/<int:id>/', TodoDetail.as_view()),
path('todo/<int:id>/add-collaborators/',TodoAddCollabs.as_view()),
path('todo/<int:id>/remove-collaborators/',TodoRemoveCollabs.as_view()),
]
119 changes: 114 additions & 5 deletions api/views.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from rest_framework import generics
from rest_framework import permissions
from rest_framework import status
from django.db.models import Q
from rest_framework import (generics, permissions, status)
from django.http import Http404
from rest_framework.response import Response
from .serializers import TodoCreateSerializer
from rest_framework.views import APIView
from .serializers import (TodoCreateSerializer, TodoSerializer,TodoAddCollabSerializer,TodoRemoveCollabSerializer)
from .models import Todo


Expand Down Expand Up @@ -32,4 +33,112 @@ 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)
return Response(serializer.data,status=status.HTTP_200_OK)

class TodoListView(generics.GenericAPIView):
permission_classes = (permissions.IsAuthenticated, )
serializer_class = TodoSerializer

# PRINTING ALL TODO IN WHICH AUTHENTICATED USER IS CREATOR OR CONTRIBUTOR
def get(self,request):
todos = Todo.objects.filter(Q(creator=request.user) | Q(collabs=request.user))
serializer = self.get_serializer(todos,many=True)
return Response(serializer.data)

class TodoDetail(APIView):
permission_classes = (permissions.IsAuthenticated, )
def get_todo(self, id):
try:
return Todo.objects.get(id=id)
except Todo.DoesNotExist:
raise Http404

def check_user(self,todo):
if todo.creator == self.request.user:
return 1
if self.request.user in todo.collabs.all():
return 1
return 0

def get(self, request, id):
todo = self.get_todo(id)
if self.check_user(todo)==0:
return Response(status=401)
serializer = TodoSerializer(todo)
return Response(serializer.data)

def put(self, request, id):
todo = self.get_todo(id)
if self.check_user(todo)==0:
return Response(status=401)
serializer = TodoSerializer(todo, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

def patch(self, request, id):
todo = self.get_todo(id)
if self.check_user(todo)==0:
return Response(status=401)
serializer = TodoSerializer(todo, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

def delete(self, request, id):
todo = self.get_todo(id)
if self.check_user(todo)==0:
return Response(status=401)
todo.delete()
return Response(status=status.HTTP_204_NO_CONTENT)


class TodoAddCollabs(APIView):
permission_classes = (permissions.IsAuthenticated, )
def get_todo(self, id):
try:
return Todo.objects.get(id=id)
except Todo.DoesNotExist:
raise Http404

def check_user(self,todo):
if todo.creator == self.request.user:
return 1
return 0

def post(self,request,id):
todo = self.get_todo(id)
if self.check_user(todo)==0:
return Response(status=401)

serializer = TodoAddCollabSerializer(data = request.data, context={'todo':todo})
if serializer.is_valid():
serializer.save(todo)
return Response({'info': 'New Collaborator Added'})
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class TodoRemoveCollabs(APIView):
permission_classes = (permissions.IsAuthenticated, )
def get_todo(self, id):
try:
return Todo.objects.get(id=id)
except Todo.DoesNotExist:
raise Http404

def check_user(self,todo):
if todo.creator == self.request.user:
return 1
return 0

def post(self,request,id):
todo = self.get_todo(id)
if self.check_user(todo)==0:
return Response(status=401)

serializer = TodoRemoveCollabSerializer(data = request.data, context={'todo':todo})
if serializer.is_valid():
serializer.save(todo)
return Response({'info': 'Collaborator Removed'})
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
45 changes: 41 additions & 4 deletions authentication/serializers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from django.db.models import fields
from rest_framework import serializers
from django.contrib.auth import authenticate
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import User


Expand All @@ -9,15 +11,50 @@ class TokenSerializer(serializers.Serializer):

class LoginSerializer(serializers.Serializer):
# TODO: Implement login functionality
pass

username = serializers.CharField()
password = serializers.CharField(style={'input_type': 'password'},trim_whitespace=False)

def validate(self, attrs):
username = attrs.get('username')
password = attrs.get('password')

if username and password:
user = authenticate(request=self.context.get('request'),username=username, password=password)
if not user:
msg = _('Unable to log in with provided credentials.')
raise serializers.ValidationError(msg, code='authorization')
else:
msg = _('Must include "username" and "password".')
raise serializers.ValidationError(msg, code='authorization')

attrs['user'] = user
return attrs


class RegisterSerializer(serializers.Serializer):
# TODO: Implement register functionality
pass
first_name = serializers.CharField(max_length=100,required=True)
email = serializers.EmailField(required=True)
username = serializers.CharField(max_length=150,required=True)
password = serializers.CharField(
write_only=True,
required=True,
style={'input_type': 'password', 'placeholder': 'Password'}
)

def create(self, validated_data):
return User.objects.create(**validated_data)



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






43 changes: 34 additions & 9 deletions authentication/views.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from rest_framework import permissions
from rest_framework import generics
from rest_framework import status
from django.contrib.auth.models import User
from rest_framework import permissions, serializers, generics, status
from rest_framework.decorators import permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.authtoken.models import Token
from .serializers import (
LoginSerializer, RegisterSerializer, UserSerializer, TokenSerializer)


def create_auth_token(user):
"""
Returns the token required for authentication for a user.
Expand All @@ -21,7 +21,11 @@ class LoginView(generics.GenericAPIView):
Implement login functionality, taking username and password
as input, and returning the Token.
"""
pass
def post(self,request):
serializer = LoginSerializer(data = request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
return Response({ "token": str(create_auth_token(user)) }, status=200)


class RegisterView(generics.GenericAPIView):
Expand All @@ -30,13 +34,34 @@ class RegisterView(generics.GenericAPIView):
Implement register functionality, registering the user by
taking his details, and returning the Token.
"""
pass

def post(self,request):
serializer = RegisterSerializer(data={
'first_name':request.data['name'],
'email':request.data['email'],
'username':request.data['username'],
'password':request.data['password'],
})
if serializer.is_valid():
try:
newUser = serializer.save()
except :
return Response({'username': 'This username is already taken.'}, status=400)
return Response({ "token": str(create_auth_token(newUser)) }, status=201)
return Response(serializer.errors,status=400)

class UserProfileView(generics.RetrieveAPIView):
class UserProfileView(generics.GenericAPIView):
"""
TODO:
Implement the functionality to retrieve the details
of the logged in user.
"""
pass
permission_classes = (permissions.IsAuthenticated, )
def post(self,request):
user = User.objects.get(id=request.user.id)
serializer = UserSerializer(user)
return Response({
"id": serializer.data['id'],
"name": serializer.data['first_name'],
"email": serializer.data['email'],
"username": serializer.data['username']
})
4 changes: 2 additions & 2 deletions todo/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@
CORS_ORIGIN_ALLOW_ALL = True

REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
)
],
}

ROOT_URLCONF = 'todo.urls'
Expand Down