diff --git a/backend/tasks/api.py b/backend/tasks/api.py index 4736582..5352f9a 100644 --- a/backend/tasks/api.py +++ b/backend/tasks/api.py @@ -7,8 +7,8 @@ from rest_framework.response import Response from rest_framework.permissions import IsAuthenticated from tasks.utils import get_service -from tasks.models import Task -from tasks.serializers import TaskUpdateSerializer +from tasks.models import Todo, RecurrenceTask +from tasks.serializers import TodoUpdateSerializer, RecurrenceTaskUpdateSerializer class GoogleCalendarEventViewset(viewsets.ViewSet): @@ -17,28 +17,30 @@ class GoogleCalendarEventViewset(viewsets.ViewSet): def __init__(self, *args, **kwargs): super().__init__() self.current_time = datetime.now(tz=timezone.utc).isoformat() - self.event_fields = 'items(id,summary,description,created,updated,start,end)' + self.event_fields = 'items(id,summary,description,created,recurringEventId,updated,start,end)' def _validate_serializer(self, serializer): if serializer.is_valid(): serializer.save() - return Response("Task Sync Successfully", status=200) + return Response("Validate Successfully", status=200) return Response(serializer.errors, status=400) def post(self, request): service = get_service(request) events = service.events().list(calendarId='primary', fields=self.event_fields).execute() for event in events.get('items', []): + if event.get('recurringEventId'): + continue try: - task = Task.objects.get(google_calendar_id=event['id']) - serializer = TaskUpdateSerializer(instance=task, data=event) + task = Todo.objects.get(google_calendar_id=event['id']) + serializer = TodoUpdateSerializer(instance=task, data=event) return self._validate_serializer(serializer) - except Task.DoesNotExist: - serializer = TaskUpdateSerializer(data=event, user=request.user) + except Todo.DoesNotExist: + serializer = TodoUpdateSerializer(data=event, user=request.user) return self._validate_serializer(serializer) def list(self, request, days=7): - max_time = (datetime.now(tz=timezone.utc) + timedelta(days=3)).isoformat() + max_time = (datetime.now(tz=timezone.utc) + timedelta(days=days)).isoformat() service = get_service(request) events = [] @@ -49,11 +51,11 @@ class GoogleCalendarEventViewset(viewsets.ViewSet): calendarId='primary', timeMin=self.current_time, timeMax=max_time, - maxResults=20, + maxResults=200, singleEvents=True, orderBy='startTime', pageToken=next_page_token, - fields='items(id,summary,description,created,updated,start,end)', + fields='items(id,summary,description,created,recurringEventId,updated,start,end)', ) page_results = query.execute() diff --git a/backend/tasks/apps.py b/backend/tasks/apps.py index 3ff3ab3..0d81307 100644 --- a/backend/tasks/apps.py +++ b/backend/tasks/apps.py @@ -4,3 +4,6 @@ from django.apps import AppConfig class TasksConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'tasks' + + def ready(self): + import tasks.signals \ No newline at end of file diff --git a/backend/tasks/migrations/0010_todo_alter_subtask_parent_task_delete_task.py b/backend/tasks/migrations/0010_todo_alter_subtask_parent_task_delete_task.py new file mode 100644 index 0000000..2e6b65d --- /dev/null +++ b/backend/tasks/migrations/0010_todo_alter_subtask_parent_task_delete_task.py @@ -0,0 +1,47 @@ +# Generated by Django 4.2.6 on 2023-11-06 15:01 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('tasks', '0009_alter_task_options_task_importance_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='Todo', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.TextField()), + ('notes', models.TextField(default='')), + ('importance', models.PositiveSmallIntegerField(choices=[(1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5')], default=1)), + ('difficulty', models.PositiveSmallIntegerField(choices=[(1, 'Easy'), (2, 'Normal'), (3, 'Hard'), (4, 'Very Hard'), (5, 'Devil')], default=1)), + ('challenge', models.BooleanField(default=False)), + ('fromSystem', models.BooleanField(default=False)), + ('creation_date', models.DateTimeField(auto_now_add=True)), + ('last_update', models.DateTimeField(auto_now=True)), + ('google_calendar_id', models.CharField(blank=True, max_length=255, null=True)), + ('start_event', models.DateTimeField(null=True)), + ('end_event', models.DateTimeField(null=True)), + ('priority', models.PositiveSmallIntegerField(choices=[(1, 'Important & Urgent'), (2, 'Important & Not Urgent'), (3, 'Not Important & Urgent'), (4, 'Not Important & Not Urgent')], default=4)), + ('tags', models.ManyToManyField(blank=True, to='tasks.tag')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'abstract': False, + }, + ), + migrations.AlterField( + model_name='subtask', + name='parent_task', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tasks.todo'), + ), + migrations.DeleteModel( + name='Task', + ), + ] diff --git a/backend/tasks/migrations/0011_recurrencetask.py b/backend/tasks/migrations/0011_recurrencetask.py new file mode 100644 index 0000000..cc7225a --- /dev/null +++ b/backend/tasks/migrations/0011_recurrencetask.py @@ -0,0 +1,39 @@ +# Generated by Django 4.2.6 on 2023-11-06 16:14 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('tasks', '0010_todo_alter_subtask_parent_task_delete_task'), + ] + + operations = [ + migrations.CreateModel( + name='RecurrenceTask', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.TextField()), + ('notes', models.TextField(default='')), + ('importance', models.PositiveSmallIntegerField(choices=[(1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5')], default=1)), + ('difficulty', models.PositiveSmallIntegerField(choices=[(1, 'Easy'), (2, 'Normal'), (3, 'Hard'), (4, 'Very Hard'), (5, 'Devil')], default=1)), + ('challenge', models.BooleanField(default=False)), + ('fromSystem', models.BooleanField(default=False)), + ('creation_date', models.DateTimeField(auto_now_add=True)), + ('last_update', models.DateTimeField(auto_now=True)), + ('google_calendar_id', models.CharField(blank=True, max_length=255, null=True)), + ('start_event', models.DateTimeField(null=True)), + ('end_event', models.DateTimeField(null=True)), + ('recurrence_rule', models.TextField()), + ('tags', models.ManyToManyField(blank=True, to='tasks.tag')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/backend/tasks/models.py b/backend/tasks/models.py index 7677acb..5da815e 100644 --- a/backend/tasks/models.py +++ b/backend/tasks/models.py @@ -1,9 +1,5 @@ -from datetime import datetime - from django.db import models from django.conf import settings -from django.core import validators -from django.utils import timezone class Tag(models.Model): """ @@ -16,21 +12,16 @@ class Tag(models.Model): class Task(models.Model): """ - Represents a task, such as Habit, Daily, Todo, or Reward. - - :param type: The type of the tasks + Represents a Abstract of task, such as Habit, Daily, Todo, or Reward. + + :param user: The user who owns the task. :param title: Title of the task. :param notes: Optional additional notes for the task. :param tags: Associated tags for the task. :param completed: A boolean field indicating whether the task is completed. - :param exp: The experience values user will get from the task. - :param priority: The priority of the task (1, 2, .., 4), using Eisenhower Matrix Idea. :param importance: The importance of the task (range: 1 to 5) :param difficulty: The difficulty of the task (range: 1 to 5). - :param attribute: The attribute linked to the task - :param user: The user who owns the task. :param challenge: Associated challenge (optional). - :param reminders: A Many-to-Many relationship with Reminder. :param fromSystem: A boolean field indicating if the task is from System. :param creation_date: Creation date of the task. :param last_update: Last updated date of the task. @@ -38,87 +29,49 @@ class Task(models.Model): :param start_event: Start event of the task. :param end_event: End event(Due Date) of the task. """ - TASK_TYPES = [ - ('daily', 'Daily'), - ('habit', 'Habit'), - ('todo', 'Todo'), - ('Long Term Goal', 'Long Term Goal'), - ] + class Difficulty(models.IntegerChoices): + EASY = 1, 'Easy' + NORMAL = 2, 'Normal' + HARD = 3, 'Hard' + VERY_HARD = 4, 'Very Hard' + DEVIL = 5, 'Devil' - DIFFICULTY_CHOICES = [ - (1, 'Easy'), - (2, 'Normal'), - (3, 'Hard'), - (4, 'Very Hard'), - (5, 'Devil'), - ] - - ATTRIBUTE = [ - ('str', 'Strength'), - ('int', 'Intelligence'), - ('end', 'Endurance'), - ('per', 'Perception'), - ('luck', 'Luck'), - ] - - EISENHOWER_MATRIX = [ - (1, 'Important & Urgent'), - (2, 'Important & Not Urgent'), - (3, 'Not Important & Urgent'), - (4, 'Not Important & Not Urgent'), - ] - - type = models.CharField(max_length=15, choices=TASK_TYPES, default='habit') + user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) title = models.TextField() notes = models.TextField(default='') tags = models.ManyToManyField(Tag, blank=True) - completed = models.BooleanField(default=False) - exp = models.FloatField(default=0) - priority = models.PositiveSmallIntegerField(choices=EISENHOWER_MATRIX, default=4) importance = models.PositiveSmallIntegerField(choices=[(i, str(i)) for i in range(1, 6)], default=1) - difficulty = models.PositiveSmallIntegerField(choices=DIFFICULTY_CHOICES, default=1) - attribute = models.CharField(max_length=15, choices=ATTRIBUTE, default='str') - user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) + difficulty = models.PositiveSmallIntegerField(choices=Difficulty.choices, default=Difficulty.EASY) challenge = models.BooleanField(default=False) fromSystem = models.BooleanField(default=False) creation_date = models.DateTimeField(auto_now_add=True) last_update = models.DateTimeField(auto_now=True) - google_calendar_id = models.CharField(blank=True, null=True, max_length=255) + google_calendar_id = models.CharField(max_length=255, null=True, blank=True) start_event = models.DateTimeField(null=True) end_event = models.DateTimeField(null=True) - def calculate_eisenhower_matrix_category(self): - """ - Classify the task into one of the four categories in the Eisenhower Matrix. - - :return: The category of the task (1, 2, 3, or 4). - """ - if self.end_event: - time_until_due = (self.end_event - datetime.now(timezone.utc)).days - else: - time_until_due = float('inf') - - urgency_threshold = 3 - importance_threshold = 3 - - if time_until_due <= urgency_threshold and self.importance >= importance_threshold: - return 1 - elif time_until_due > urgency_threshold and self.importance >= importance_threshold: - return 2 - elif time_until_due <= urgency_threshold and self.importance < importance_threshold: - return 3 - else: - return 4 - - def save(self, *args, **kwargs): - self.priority = self.calculate_eisenhower_matrix_category() - super(Task, self).save(*args, **kwargs) - class Meta: - verbose_name = 'Task' - verbose_name_plural = 'Tasks' + abstract = True +class Todo(Task): + + class EisenhowerMatrix(models.IntegerChoices): + IMPORTANT_URGENT = 1, 'Important & Urgent' + IMPORTANT_NOT_URGENT = 2, 'Important & Not Urgent' + NOT_IMPORTANT_URGENT = 3, 'Not Important & Urgent' + NOT_IMPORTANT_NOT_URGENT = 4, 'Not Important & Not Urgent' + + priority = models.PositiveSmallIntegerField(choices=EisenhowerMatrix.choices, default=EisenhowerMatrix.NOT_IMPORTANT_NOT_URGENT) + + def __str__(self): + return self.title + +class RecurrenceTask(Task): + recurrence_rule = models.TextField() + + def __str__(self) -> str: + return f"{self.title} ({self.recurrence_rule})" class Subtask(models.Model): """ @@ -127,9 +80,9 @@ class Subtask(models.Model): :param completed: A boolean field indicating whether the subtask is completed. :param parent_task: The parent task of the subtask. """ + parent_task = models.ForeignKey(Todo, on_delete=models.CASCADE) description = models.TextField() completed = models.BooleanField(default=False) - parent_task = models.ForeignKey(Task, on_delete=models.CASCADE) class UserNotification(models.Model): diff --git a/backend/tasks/serializers.py b/backend/tasks/serializers.py index 494920f..ed02300 100644 --- a/backend/tasks/serializers.py +++ b/backend/tasks/serializers.py @@ -1,6 +1,6 @@ from rest_framework import serializers from django.utils.dateparse import parse_datetime -from .models import Task +from .models import Todo, RecurrenceTask class GoogleCalendarEventSerializer(serializers.Serializer): @@ -10,7 +10,7 @@ class GoogleCalendarEventSerializer(serializers.Serializer): description = serializers.CharField(required=False) -class TaskUpdateSerializer(serializers.ModelSerializer): +class TodoUpdateSerializer(serializers.ModelSerializer): id = serializers.CharField(source="google_calendar_id") summary = serializers.CharField(source="title") description = serializers.CharField(source="notes", required=False) @@ -21,15 +21,41 @@ class TaskUpdateSerializer(serializers.ModelSerializer): class Meta: - model = Task + model = Todo fields = ('id', 'summary', 'description', 'created', 'updated', 'start_datetime', 'end_datetime') def __init__(self, *args, **kwargs): self.user = kwargs.pop('user', None) - super(TaskUpdateSerializer, self).__init__(*args, **kwargs) + super(TodoUpdateSerializer, self).__init__(*args, **kwargs) def create(self, validated_data): validated_data['user'] = self.user - task = Task.objects.create(**validated_data) + task = Todo.objects.create(**validated_data) + + return task + + +class RecurrenceTaskUpdateSerializer(serializers.ModelSerializer): + id = serializers.CharField(source="google_calendar_id") + summary = serializers.CharField(source="title") + description = serializers.CharField(source="notes", required=False) + created = serializers.DateTimeField(source="creation_date") + updated = serializers.DateTimeField(source="last_update") + recurrence = serializers.DateTimeField(source="recurrence_rule") + start_datetime = serializers.DateTimeField(source="start_event", required=False) + end_datetime = serializers.DateTimeField(source="end_event", required=False) + + + class Meta: + model = RecurrenceTask + fields = ('id', 'summary', 'description', 'created', 'updated', 'recurrence', 'start_datetime', 'end_datetime') + + def __init__(self, *args, **kwargs): + self.user = kwargs.pop('user', None) + super(RecurrenceTaskUpdateSerializer, self).__init__(*args, **kwargs) + + def create(self, validated_data): + validated_data['user'] = self.user + task = RecurrenceTask.objects.create(**validated_data) return task \ No newline at end of file diff --git a/backend/tasks/signals.py b/backend/tasks/signals.py new file mode 100644 index 0000000..af17e57 --- /dev/null +++ b/backend/tasks/signals.py @@ -0,0 +1,25 @@ +from django.db.models.signals import pre_save +from django.dispatch import receiver +from django.utils import timezone + +from tasks.models import Todo + + +@receiver(pre_save, sender=Todo) +def update_priority(sender, instance, **kwargs): + if instance.end_event: + time_until_due = (instance.end_event - timezone.now()).days + else: + time_until_due = float('inf') + + urgency_threshold = 3 + importance_threshold = 3 + + if time_until_due <= urgency_threshold and instance.importance >= importance_threshold: + instance.priority = Todo.EisenhowerMatrix.IMPORTANT_URGENT + elif time_until_due > urgency_threshold and instance.importance >= importance_threshold: + instance.priority = Todo.EisenhowerMatrix.IMPORTANT_NOT_URGENT + elif time_until_due <= urgency_threshold and instance.importance < importance_threshold: + instance.priority = Todo.EisenhowerMatrix.NOT_IMPORTANT_URGENT + else: + instance.priority = Todo.EisenhowerMatrix.NOT_IMPORTANT_NOT_URGENT \ No newline at end of file diff --git a/backend/tasks/tasks/serializers.py b/backend/tasks/tasks/serializers.py index 7876263..85f0281 100644 --- a/backend/tasks/tasks/serializers.py +++ b/backend/tasks/tasks/serializers.py @@ -1,21 +1,21 @@ from rest_framework import serializers -from ..models import Task +from ..models import Todo class TaskCreateSerializer(serializers.ModelSerializer): class Meta: - model = Task + model = Todo # fields = '__all__' exclude = ('tags',) def create(self, validated_data): # Create a new task with validated data - return Task.objects.create(**validated_data) + return Todo.objects.create(**validated_data) class TaskGeneralSerializer(serializers.ModelSerializer): class Meta: - model = Task + model = Todo fields = '__all__' def create(self, validated_data): # Create a new task with validated data - return Task.objects.create(**validated_data) \ No newline at end of file + return Todo.objects.create(**validated_data) \ No newline at end of file diff --git a/backend/tasks/tasks/views.py b/backend/tasks/tasks/views.py index 0f75ced..4077315 100644 --- a/backend/tasks/tasks/views.py +++ b/backend/tasks/tasks/views.py @@ -2,11 +2,11 @@ from rest_framework import status from rest_framework.response import Response from rest_framework.generics import CreateAPIView, RetrieveAPIView, RetrieveUpdateAPIView, DestroyAPIView from rest_framework.permissions import IsAuthenticated -from ..models import Task +from ..models import Todo from .serializers import TaskCreateSerializer, TaskGeneralSerializer class TaskCreateView(CreateAPIView): - queryset = Task.objects.all() + queryset = Todo.objects.all() serializer_class = TaskCreateSerializer permission_classes = [IsAuthenticated] @@ -21,17 +21,17 @@ class TaskCreateView(CreateAPIView): class TaskRetrieveView(RetrieveAPIView): - queryset = Task.objects.all() + queryset = Todo.objects.all() serializer_class = TaskGeneralSerializer permission_classes = [IsAuthenticated] class TaskUpdateView(RetrieveUpdateAPIView): - queryset = Task.objects.all() + queryset = Todo.objects.all() serializer_class = TaskGeneralSerializer permission_classes = [IsAuthenticated] class TaskDeleteView(DestroyAPIView): - queryset = Task.objects.all() + queryset = Todo.objects.all() permission_classes = [IsAuthenticated] \ No newline at end of file diff --git a/backend/tasks/tests/test_deserializer.py b/backend/tasks/tests/test_deserializer.py index aa07480..306185c 100644 --- a/backend/tasks/tests/test_deserializer.py +++ b/backend/tasks/tests/test_deserializer.py @@ -5,8 +5,8 @@ from django.test import TestCase from django.utils import timezone from tasks.tests.utils import create_test_user, login_user -from tasks.serializers import TaskUpdateSerializer -from tasks.models import Task +from tasks.serializers import TodoUpdateSerializer +from tasks.models import Todo class TaskUpdateSerializerTest(TestCase): def setUp(self): @@ -25,14 +25,14 @@ class TaskUpdateSerializerTest(TestCase): 'end_datetie': self.end_time, } - serializer = TaskUpdateSerializer(data=data, user=self.user) + serializer = TodoUpdateSerializer(data=data, user=self.user) self.assertTrue(serializer.is_valid()) serializer.is_valid() task = serializer.save() - self.assertIsInstance(task, Task) + self.assertIsInstance(task, Todo) def test_serializer_update(self): - task = Task.objects.create(title='Original Task', notes='Original description', user=self.user) + task = Todo.objects.create(title='Original Task', notes='Original description', user=self.user) data = { 'id': '32141cwaNcapufh8jq2conw', @@ -44,7 +44,7 @@ class TaskUpdateSerializerTest(TestCase): 'end_datetie': self.end_time, } - serializer = TaskUpdateSerializer(instance=task, data=data) + serializer = TodoUpdateSerializer(instance=task, data=data) self.assertTrue(serializer.is_valid()) updated_task = serializer.save() diff --git a/backend/tasks/tests/test_task_eisenhower.py b/backend/tasks/tests/test_task_eisenhower.py deleted file mode 100644 index b8b3c22..0000000 --- a/backend/tasks/tests/test_task_eisenhower.py +++ /dev/null @@ -1,38 +0,0 @@ -from datetime import datetime, timedelta, timezone - -from django.test import TestCase - -from tasks.models import Task -from tasks.tests.utils import create_test_user - -class TaskModelTest(TestCase): - def setUp(self): - self.user = create_test_user() - - def test_eisenhower_matrix_category(self): - task = Task(importance=2, end_event=None, user=self.user) - task.save() - - # 'Not Important & Not Urgent' category (category 4) - self.assertEqual(task.calculate_eisenhower_matrix_category(), 4) - - due_date = datetime.now(timezone.utc) + timedelta(days=1) - task = Task(importance=4, end_event=due_date, user=self.user) - task.save() - - # 'Important & Urgent' category (category 1) - self.assertEqual(task.calculate_eisenhower_matrix_category(), 1) - - due_date = datetime.now(timezone.utc) + timedelta(days=10) - task = Task(importance=3, end_event=due_date, user=self.user) - task.save() - - # 'Important & Not Urgent' category (category 2) - self.assertEqual(task.calculate_eisenhower_matrix_category(), 2) - - due_date = datetime.now(timezone.utc) + timedelta(days=4) - task = Task(importance=1, end_event=due_date, user=self.user) - task.save() - - # 'Not Important & Urgent' category (category 3) - self.assertEqual(task.calculate_eisenhower_matrix_category(), 3) \ No newline at end of file diff --git a/backend/tasks/tests/test_task_creation.py b/backend/tasks/tests/test_todo_creation.py similarity index 82% rename from backend/tasks/tests/test_task_creation.py rename to backend/tasks/tests/test_todo_creation.py index af7986f..0852fbe 100644 --- a/backend/tasks/tests/test_task_creation.py +++ b/backend/tasks/tests/test_todo_creation.py @@ -5,9 +5,9 @@ from rest_framework import status from rest_framework.test import APITestCase from tasks.tests.utils import create_test_user, login_user -from ..models import Task +from ..models import Todo -class TaskCreateViewTests(APITestCase): +class TodoCreateViewTests(APITestCase): def setUp(self): self.user = create_test_user() @@ -16,7 +16,7 @@ class TaskCreateViewTests(APITestCase): self.due_date = datetime.now() + timedelta(days=5) - def test_create_valid_task(self): + def test_create_valid_todo(self): """ Test creating a valid task using the API. """ @@ -32,10 +32,10 @@ class TaskCreateViewTests(APITestCase): } response = self.client.post(self.url, data, format='json') self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual(Task.objects.count(), 1) - self.assertEqual(Task.objects.get().title, 'Test Task') + self.assertEqual(Todo.objects.count(), 1) + self.assertEqual(Todo.objects.get().title, 'Test Task') - def test_create_invalid_task(self): + def test_create_invalid_todo(self): """ Test creating an invalid task using the API. """ @@ -45,7 +45,7 @@ class TaskCreateViewTests(APITestCase): response = self.client.post(self.url, data, format='json') self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual(Task.objects.count(), 0) # No task should be created + self.assertEqual(Todo.objects.count(), 0) # No task should be created def test_missing_required_fields(self): """ @@ -58,7 +58,7 @@ class TaskCreateViewTests(APITestCase): response = self.client.post(self.url, data, format='json') self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual(Task.objects.count(), 0) # No task should be created + self.assertEqual(Todo.objects.count(), 0) # No task should be created def test_invalid_user_id(self): """ @@ -76,4 +76,4 @@ class TaskCreateViewTests(APITestCase): response = self.client.post(self.url, data, format='json') self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual(Task.objects.count(), 0) # No task should be created + self.assertEqual(Todo.objects.count(), 0) # No task should be created diff --git a/backend/tasks/tests/test_todo_eisenhower.py b/backend/tasks/tests/test_todo_eisenhower.py new file mode 100644 index 0000000..41ee078 --- /dev/null +++ b/backend/tasks/tests/test_todo_eisenhower.py @@ -0,0 +1,36 @@ +from datetime import datetime, timedelta, timezone +from django.test import TestCase +from tasks.models import Todo +from tasks.tests.utils import create_test_user + +class TodoPriorityTest(TestCase): + def setUp(self): + self.user = create_test_user() + + def test_priority_calculation(self): + # Important = 2, Till Due = none + todo = Todo(importance=2, end_event=None, user=self.user) + todo.save() + # 'Not Important & Not Urgent' + self.assertEqual(todo.priority, Todo.EisenhowerMatrix.NOT_IMPORTANT_NOT_URGENT) + + due_date = datetime.now(timezone.utc) + timedelta(days=1) + # Important = 4, Till Due = 1 + todo = Todo(importance=4, end_event=due_date, user=self.user) + todo.save() + # 'Important & Urgent' + self.assertEqual(todo.priority, Todo.EisenhowerMatrix.IMPORTANT_URGENT) + + due_date = datetime.now(timezone.utc) + timedelta(days=10) + # Important = 3, Till Due = 10 + todo = Todo(importance=3, end_event=due_date, user=self.user) + todo.save() + # 'Important & Not Urgent' + self.assertEqual(todo.priority, Todo.EisenhowerMatrix.IMPORTANT_NOT_URGENT) + + due_date = datetime.now(timezone.utc) + timedelta(days=2) + # Important = 1, Till Due = 2 + todo = Todo(importance=1, end_event=due_date, user=self.user) + todo.save() + # 'Not Important & Urgent' + self.assertEqual(todo.priority, Todo.EisenhowerMatrix.NOT_IMPORTANT_URGENT) diff --git a/backend/tasks/tests/utils.py b/backend/tasks/tests/utils.py index f33b828..b1bef0b 100644 --- a/backend/tasks/tests/utils.py +++ b/backend/tasks/tests/utils.py @@ -1,7 +1,7 @@ from rest_framework.test import APIClient from users.models import CustomUser -from ..models import Task +from ..models import Todo def create_test_user(email="testusertestuser@example.com", username="testusertestuser", @@ -61,4 +61,4 @@ def create_test_task(user, **kwargs): task_attributes = {**defaults, **kwargs} - return Task.objects.create(user=user, **task_attributes) \ No newline at end of file + return Todo.objects.create(user=user, **task_attributes) \ No newline at end of file