Skip to content

Commit

Permalink
Upcoming tasks support
Browse files Browse the repository at this point in the history
  • Loading branch information
matiasvallejosdev committed Feb 8, 2024
1 parent 7354b98 commit 23f65d4
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 37 deletions.
1 change: 0 additions & 1 deletion app/auth_api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ class GoogleLoginView(SocialLoginView): # Authorization Code grant
class ConnectionView(APIView):
permission_classes = (permissions.IsAuthenticated,)

# noinspection PyMethodMayBeStatic
def post(self, request, *args, **kwargs):
return Response({
"message": "Connection successfully!"
Expand Down
1 change: 1 addition & 0 deletions app/todo_api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class Meta:
"task_uuid",
"title",
"completed",
"due_date",
"task_list",
)
read_only_fields = (
Expand Down
62 changes: 50 additions & 12 deletions app/todo_api/tests/test_task_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

TASKS_URL = reverse("todo_api:tasks-list")
TASKS_COUNT_URL = reverse("todo_api:tasks-count")
TASKS_UPCOMING_URL = reverse("todo_api:tasks-upcoming")


def create_user(email="user@example.com", password="userexample123"):
Expand Down Expand Up @@ -84,6 +85,28 @@ def test_retrieve_tasks_failure_list_not_found(self):
res = self.client.get(TASKS_URL, {"list": "list-not-found"})
self.assertEqual(res.status_code, status.HTTP_404_NOT_FOUND)

def test_retrieve_upcoming_task(self):
"""Test retrieving upcoming tasks using due_date"""
create_task(
user=self.user, due_date=timezone.now() + timezone.timedelta(days=1)
)
create_task(
user=self.user, due_date=timezone.now() + timezone.timedelta(days=2)
)
create_task(
user=self.user, due_date=timezone.now() + timezone.timedelta(days=3)
)
create_task(user=self.user)

res = self.client.get(TASKS_UPCOMING_URL, {})

tasks = Task.objects.filter(due_date__isnull=False).order_by("due_date")
serializer = TaskSerializer(tasks, many=True)

self.assertEqual(res.status_code, status.HTTP_200_OK)
self.assertEqual(len(res.data), 3)
self.assertEqual(res.data, serializer.data)

def test_retrieve_tasks_limited_to_user(self):
"""Test retrieve list of tasks limited to user"""
user_two = create_user(email="email@test.com", password="userexample123")
Expand Down Expand Up @@ -218,6 +241,16 @@ def test_partial_update_task(self):
self.assertEqual(task.title, payload["title"])
self.assertEqual(task.completed, payload["completed"])

def test_partial_update_date(self):
"""Test partial update task due_date"""
task = create_task(user=self.user)
payload = {"due_date": timezone.now()}
url = task_detail_url_pk(task.task_uuid)
self.client.patch(url, payload)

task.refresh_from_db()
self.assertEqual(task.due_date, payload["due_date"])

def test_fully_update_task(self):
"""Test updating a task with put"""
list_task = create_list(user=self.user)
Expand Down Expand Up @@ -283,18 +316,23 @@ def test_retrieve_count_tasks_by_list(self):
self.assertEqual(res.data["total"], 3)
self.assertEqual(res.data["completed"], 2)
self.assertEqual(res.data["uncompleted"], 1)

def test_retrieve_upcoming_task(self):
"""Test retrieving upcoming tasks using due_date"""
create_task(
user=self.user, due_date=timezone.now() + timezone.timedelta(days=1)
)
create_task(
user=self.user, due_date=timezone.now() + timezone.timedelta(days=2)
)
create_task(
user=self.user, due_date=timezone.now() + timezone.timedelta(days=3)
)

def test_retrieve_count_upcoming_tasks(self):
"""Test retrieving count of upcoming tasks"""
list = create_list(user=self.user, name="inbox")

create_task(user=self.user, due_date=timezone.now(), task_list=list)
create_task(user=self.user, due_date=timezone.now(), task_list=list)
create_task(user=self.user)

params = {"list": "upcoming"}

res = self.client.get(TASKS_COUNT_URL, params)
self.assertEqual(res.status_code, status.HTTP_200_OK)

self.assertEqual(res.data["total"], 2)
self.assertEqual(res.data["completed"], 0)
self.assertEqual(res.data["uncompleted"], 2)

def test_retrieve_count_error_task_not_found(self):
"""Test 404 not found list cannot count tasks"""
Expand Down
4 changes: 2 additions & 2 deletions app/todo_api/tests/test_task_list_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def test_retrieve_unique_inbox_for_each_account(self):
self.assertTrue(exists)
self.assertNotEqual(list_inbox.list_uuid, list[0].list_uuid)

def test_fully_update_task_list(self):
def test_partial_update_task_list(self):
"""Test partial update list with patch"""
list = create_task_list(user=self.user)
payload = {"name": "New name"}
Expand All @@ -126,7 +126,7 @@ def test_fully_update_task_list(self):
self.assertEqual(res.status_code, status.HTTP_200_OK)
list.refresh_from_db()
self.assertEqual(list.name, payload["name"])

def test_update_unauthorized_failure(self):
new_user = get_user_model().objects.create_user(
email="user@new.com", password="usernew123"
Expand Down
1 change: 1 addition & 0 deletions app/todo_api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@
urlpatterns = [
path('', include(router.urls)),
path('tasks/count/', TaskViewSet.as_view({'GET': 'count'}), name='tasks-count'),
path('tasks/upcoming/', TaskViewSet.as_view({'GET': 'upcoming'}), name='tasks-upcoming'),
path('lists/find-by-name/', TaskListViewSet.as_view({'GET': 'find-by-name'}), name='lists-find-by-name'),
]
66 changes: 44 additions & 22 deletions app/todo_api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Views for todo_api endpoints
"""
from django.shortcuts import get_object_or_404
from django.utils import timezone
from rest_framework import permissions, viewsets, status
from .models import Task, TaskList
from .serializers import (
Expand Down Expand Up @@ -91,34 +92,55 @@ def count_tasks(self, queryset, *args, **kwargs):
If the list is not found, it will return a 404 error.
"""
task_list = self.request.query_params.get("list", None)
if task_list and task_list != "inbox":
try:
task_list = unquote(task_list) # Decode the URL-encoded string
task_list = str(task_list).lower().replace(" ", "-")
list_uuid = uuid.UUID(task_list)
exists = get_object_or_404(TaskList, list_uuid=list_uuid)
if not exists:
if task_list == "upcoming":
# Count upcoming tasks
tasks = Task.objects.filter(due_date__isnull=False)
tasks_completed = tasks.filter(completed=True).count()
tasks_uncompleted = tasks.filter(completed=False).count()
data = {
"total": tasks.count(),
"completed": tasks_completed,
"uncompleted": tasks_uncompleted,
}
else:
# Count inbox tasks or listed tasks using UUID
if task_list and task_list != "inbox":
try:
task_list = unquote(task_list) # Decode the URL-encoded string
task_list = str(task_list).lower().replace(" ", "-")
list_uuid = uuid.UUID(task_list)
exists = get_object_or_404(TaskList, list_uuid=list_uuid)
if not exists:
return Response(
status=status.HTTP_404_NOT_FOUND,
body={"message": "List was not found. We can not count tasks."},
)
except ValueError:
# If the conversion fails, handle the error gracefully
return Response(
status=status.HTTP_404_NOT_FOUND,
body={"message": "List was not found. We can not count tasks."},
data={"message": "List was not found. We cannot count tasks."},
)
except ValueError:
# If the conversion fails, handle the error gracefully
return Response(
status=status.HTTP_404_NOT_FOUND,
data={"message": "List was not found. We cannot count tasks."},
)
tasks = self.get_queryset().count()
tasks_completed = self.get_queryset().filter(completed=True).count()
tasks_uncompleted = self.get_queryset().filter(completed=False).count()
data = {
"total": tasks,
"completed": tasks_completed,
"uncompleted": tasks_uncompleted,
}
tasks = self.get_queryset().count()
tasks_completed = self.get_queryset().filter(completed=True).count()
tasks_uncompleted = self.get_queryset().filter(completed=False).count()
data = {
"total": tasks,
"completed": tasks_completed,
"uncompleted": tasks_uncompleted,
}

serializer = TaskCountSerializer(data, many=False)
return Response(serializer.data, status=status.HTTP_200_OK)

@action(methods=["GET"], detail=False, url_path="upcoming")
def upcoming_tasks(self, request, *args, **kwargs):
"""
List all upcoming tasks scheduled ordered by date
"""
tasks = self.get_queryset().filter(due_date__isnull=False).order_by('due_date')
serializer = TaskSerializer(tasks, many=True)
return Response(serializer.data)

class TaskListViewSet(viewsets.ModelViewSet):
"""Class for viewset task lists"""
Expand Down

0 comments on commit 23f65d4

Please sign in to comment.