mirror of
https://github.com/TurTaskProject/TurTaskWeb.git
synced 2025-12-19 05:54:07 +01:00
Merge pull request #10 from TurTaskProject/feature-tasks-api
Merge Tasks Tags Reminders API
This commit is contained in:
commit
dc83c7b79c
@ -47,6 +47,8 @@ INSTALLED_APPS = [
|
|||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
|
|
||||||
|
'tasks',
|
||||||
|
|
||||||
'users',
|
'users',
|
||||||
'rest_framework',
|
'rest_framework',
|
||||||
'corsheaders',
|
'corsheaders',
|
||||||
|
|||||||
@ -20,5 +20,6 @@ from django.urls import path, include
|
|||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
path('api/', include('users.urls')),
|
path('api/', include('users.urls')),
|
||||||
|
path('api/', include('tasks.urls')),
|
||||||
path('accounts/', include('allauth.urls')),
|
path('accounts/', include('allauth.urls')),
|
||||||
]
|
]
|
||||||
0
backend/tasks/__init__.py
Normal file
0
backend/tasks/__init__.py
Normal file
3
backend/tasks/admin.py
Normal file
3
backend/tasks/admin.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
6
backend/tasks/apps.py
Normal file
6
backend/tasks/apps.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class TasksConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'tasks'
|
||||||
83
backend/tasks/migrations/0001_initial.py
Normal file
83
backend/tasks/migrations/0001_initial.py
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# Generated by Django 4.2.6 on 2023-10-28 15:50
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
import django.core.validators
|
||||||
|
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 = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Reminder',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('startDate', models.DateField(blank=True, null=True)),
|
||||||
|
('time', models.DateTimeField()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Tag',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=255)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='UserNotification',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('type', models.CharField(choices=[('LEVEL_UP', 'Level Up'), ('DEATH', 'Death')], max_length=255)),
|
||||||
|
('data', models.JSONField(default=dict)),
|
||||||
|
('seen', models.BooleanField(default=False)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Transaction',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('currency', models.CharField(choices=[('gold', 'Gold')], max_length=12)),
|
||||||
|
('transaction_type', models.CharField(choices=[('buy_gold', 'Buy Gold'), ('spend', 'Spend'), ('debug', 'Debug'), ('force_update_gold', 'Force Update Gold')], max_length=24)),
|
||||||
|
('description', models.TextField(blank=True)),
|
||||||
|
('amount', models.FloatField(default=0)),
|
||||||
|
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Task',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('type', models.CharField(choices=[('daily', 'Daily'), ('habit', 'Habit'), ('todo', 'Todo'), ('Long Term Goal', 'Long Term Goal')], default='habit', max_length=15)),
|
||||||
|
('title', models.TextField()),
|
||||||
|
('notes', models.TextField(default='')),
|
||||||
|
('completed', models.BooleanField(default=False)),
|
||||||
|
('exp', models.FloatField(default=0)),
|
||||||
|
('priority', models.FloatField(default=1, validators=[django.core.validators.MinValueValidator(0.1), django.core.validators.MaxValueValidator(2)])),
|
||||||
|
('difficulty', models.PositiveSmallIntegerField(choices=[(1, 'Easy'), (2, 'Normal'), (3, 'Hard'), (4, 'Very Hard'), (5, 'Devil')], unique=True)),
|
||||||
|
('attribute', models.CharField(choices=[('str', 'Strength'), ('int', 'Intelligence'), ('end', 'Endurance'), ('per', 'Perception'), ('luck', 'Luck')], default='str', max_length=15)),
|
||||||
|
('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)),
|
||||||
|
('reminders', models.ManyToManyField(to='tasks.reminder')),
|
||||||
|
('tags', models.ManyToManyField(to='tasks.tag')),
|
||||||
|
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Subtask',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('description', models.TextField()),
|
||||||
|
('completed', models.BooleanField(default=False)),
|
||||||
|
('parent_task', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tasks.task')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 4.2.6 on 2023-10-29 11:17
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('tasks', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='task',
|
||||||
|
name='reminders',
|
||||||
|
field=models.ManyToManyField(blank=True, to='tasks.reminder'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='task',
|
||||||
|
name='tags',
|
||||||
|
field=models.ManyToManyField(blank=True, to='tasks.tag'),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
backend/tasks/migrations/0003_alter_task_difficulty.py
Normal file
18
backend/tasks/migrations/0003_alter_task_difficulty.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.2.6 on 2023-10-29 12:05
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('tasks', '0002_alter_task_reminders_alter_task_tags'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='task',
|
||||||
|
name='difficulty',
|
||||||
|
field=models.PositiveSmallIntegerField(choices=[(1, 'Easy'), (2, 'Normal'), (3, 'Hard'), (4, 'Very Hard'), (5, 'Devil')]),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 4.2.6 on 2023-10-29 12:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('tasks', '0003_alter_task_difficulty'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='reminder',
|
||||||
|
old_name='time',
|
||||||
|
new_name='alertTime',
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='reminder',
|
||||||
|
name='startDate',
|
||||||
|
field=models.DateField(auto_now_add=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
0
backend/tasks/migrations/__init__.py
Normal file
0
backend/tasks/migrations/__init__.py
Normal file
12
backend/tasks/misc/serializers.py
Normal file
12
backend/tasks/misc/serializers.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
from rest_framework import serializers
|
||||||
|
from ..models import Reminder, Tag
|
||||||
|
|
||||||
|
class ReminderSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Reminder
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
class TagSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Tag
|
||||||
|
fields = '__all__'
|
||||||
11
backend/tasks/misc/views.py
Normal file
11
backend/tasks/misc/views.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
from rest_framework import viewsets
|
||||||
|
from ..models import Reminder, Tag
|
||||||
|
from .serializers import ReminderSerializer, TagSerializer
|
||||||
|
|
||||||
|
class ReminderViewSet(viewsets.ModelViewSet):
|
||||||
|
queryset = Reminder.objects.all()
|
||||||
|
serializer_class = ReminderSerializer
|
||||||
|
|
||||||
|
class TagViewSet(viewsets.ModelViewSet):
|
||||||
|
queryset = Tag.objects.all()
|
||||||
|
serializer_class = TagSerializer
|
||||||
157
backend/tasks/models.py
Normal file
157
backend/tasks/models.py
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
from django.db import models
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core import validators
|
||||||
|
|
||||||
|
|
||||||
|
class Reminder(models.Model):
|
||||||
|
"""
|
||||||
|
Represents a reminder associated with a task.
|
||||||
|
Fields:
|
||||||
|
- startDate: The optional date for which the reminder is set.
|
||||||
|
- time: The time at which the reminder is triggered.
|
||||||
|
"""
|
||||||
|
startDate = models.DateField(auto_now_add=True, null=True, blank=True)
|
||||||
|
alertTime = models.DateTimeField(null=False, blank=False)
|
||||||
|
|
||||||
|
class Tag(models.Model):
|
||||||
|
"""
|
||||||
|
Represents a tag that can be associated with tasks.
|
||||||
|
Fields:
|
||||||
|
- name: The unique name of the tag.
|
||||||
|
"""
|
||||||
|
name = models.CharField(max_length=255)
|
||||||
|
|
||||||
|
class Task(models.Model):
|
||||||
|
"""
|
||||||
|
Represents a task, such as Habit, Daily, Todo, or Reward.
|
||||||
|
Fields:
|
||||||
|
- type: The type of the tasks
|
||||||
|
- title: Title of the task.
|
||||||
|
- notes: Optional additional notes for the task.
|
||||||
|
- tags: Associated tags for the task.
|
||||||
|
- completed: A boolean field indicating whether the task is completed.
|
||||||
|
- exp: The experience values user will get from the task.
|
||||||
|
- priority: The priority of the task (range: 0.1 to 2).
|
||||||
|
- difficulty: The difficulty of the task (range: 1 to 5).
|
||||||
|
- attribute: The attribute linked to the task
|
||||||
|
- user: The user who owns the task.
|
||||||
|
- challenge: Associated challenge (optional).
|
||||||
|
- reminders: A Many-to-Many relationship with Reminder.
|
||||||
|
- fromSystem: A boolean field indicating if the task is from System.
|
||||||
|
- creation_date: Creation date of the task.
|
||||||
|
- last_update: Last updated date of the task.
|
||||||
|
"""
|
||||||
|
TASK_TYPES = [
|
||||||
|
('daily', 'Daily'),
|
||||||
|
('habit', 'Habit'),
|
||||||
|
('todo', 'Todo'),
|
||||||
|
('Long Term Goal', 'Long Term Goal'),
|
||||||
|
]
|
||||||
|
|
||||||
|
DIFFICULTY_CHOICES = [
|
||||||
|
(1, 'Easy'),
|
||||||
|
(2, 'Normal'),
|
||||||
|
(3, 'Hard'),
|
||||||
|
(4, 'Very Hard'),
|
||||||
|
(5, 'Devil'),
|
||||||
|
]
|
||||||
|
|
||||||
|
type = models.CharField(max_length=15, choices=TASK_TYPES, default='habit')
|
||||||
|
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.FloatField(default=1, validators=[
|
||||||
|
validators.MinValueValidator(0.1),
|
||||||
|
validators.MaxValueValidator(2),
|
||||||
|
])
|
||||||
|
difficulty = models.PositiveSmallIntegerField(choices=DIFFICULTY_CHOICES)
|
||||||
|
attribute = models.CharField(max_length=15, choices=[
|
||||||
|
('str', 'Strength'),
|
||||||
|
('int', 'Intelligence'),
|
||||||
|
('end', 'Endurance'),
|
||||||
|
('per', 'Perception'),
|
||||||
|
('luck', 'Luck'),
|
||||||
|
], default='str')
|
||||||
|
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
|
||||||
|
challenge = models.BooleanField(default=False)
|
||||||
|
reminders = models.ManyToManyField(Reminder, blank=True)
|
||||||
|
fromSystem = models.BooleanField(default=False)
|
||||||
|
creation_date = models.DateTimeField(auto_now_add=True)
|
||||||
|
last_update = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
|
|
||||||
|
class Subtask(models.Model):
|
||||||
|
"""
|
||||||
|
Represents a subtask associated with a task.
|
||||||
|
- description: Description of the subtask.
|
||||||
|
- completed: A boolean field indicating whether the subtask is completed.
|
||||||
|
- parent_task: The parent task of the subtask.
|
||||||
|
"""
|
||||||
|
description = models.TextField()
|
||||||
|
completed = models.BooleanField(default=False)
|
||||||
|
parent_task = models.ForeignKey(Task, on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
|
||||||
|
class UserNotification(models.Model):
|
||||||
|
"""
|
||||||
|
Represents a user notification.
|
||||||
|
Fields:
|
||||||
|
- type: The type of the notification (e.g., 'NEW_CHAT_MESSAGE').
|
||||||
|
- data: JSON data associated with the notification.
|
||||||
|
- seen: A boolean field indicating whether the notification has been seen.
|
||||||
|
"""
|
||||||
|
NOTIFICATION_TYPES = (
|
||||||
|
('LEVEL_UP', 'Level Up'),
|
||||||
|
('DEATH', 'Death'),
|
||||||
|
)
|
||||||
|
|
||||||
|
type = models.CharField(max_length=255, choices=[type for type in NOTIFICATION_TYPES])
|
||||||
|
data = models.JSONField(default=dict)
|
||||||
|
seen = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def clean_notification(notifications):
|
||||||
|
"""
|
||||||
|
Cleanup function for removing corrupt notification data:
|
||||||
|
- Removes notifications with null or missing id or type.
|
||||||
|
"""
|
||||||
|
if not notifications:
|
||||||
|
return notifications
|
||||||
|
|
||||||
|
filtered_notifications = []
|
||||||
|
|
||||||
|
for notification in notifications:
|
||||||
|
if notification.id is None or notification.type is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
return filtered_notifications
|
||||||
|
|
||||||
|
|
||||||
|
class Transaction(models.Model):
|
||||||
|
"""
|
||||||
|
Represents a transaction involving currencies in the system.
|
||||||
|
Fields:
|
||||||
|
- currency: The type of currency used in the transaction
|
||||||
|
- transactionType: The type of the transaction
|
||||||
|
- description: Additional text.
|
||||||
|
- amount: The transaction amount.
|
||||||
|
- user: The user involved in the transaction.
|
||||||
|
"""
|
||||||
|
CURRENCIES = (('gold', 'Gold'),)
|
||||||
|
TRANSACTION_TYPES = (
|
||||||
|
('buy_gold', 'Buy Gold'),
|
||||||
|
('spend', 'Spend'),
|
||||||
|
('debug', 'Debug'),
|
||||||
|
('force_update_gold', 'Force Update Gold'),
|
||||||
|
)
|
||||||
|
|
||||||
|
currency = models.CharField(max_length=12, choices=CURRENCIES)
|
||||||
|
transaction_type = models.CharField(max_length=24, choices=TRANSACTION_TYPES)
|
||||||
|
description = models.TextField(blank=True)
|
||||||
|
amount = models.FloatField(default=0)
|
||||||
|
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"Transaction ({self.id})"
|
||||||
21
backend/tasks/tasks/serializers.py
Normal file
21
backend/tasks/tasks/serializers.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
from rest_framework import serializers
|
||||||
|
from ..models import Task
|
||||||
|
|
||||||
|
class TaskCreateSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Task
|
||||||
|
# fields = '__all__'
|
||||||
|
exclude = ('tags', 'reminders')
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
# Create a new task with validated data
|
||||||
|
return Task.objects.create(**validated_data)
|
||||||
|
|
||||||
|
class TaskGeneralSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Task
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
# Create a new task with validated data
|
||||||
|
return Task.objects.create(**validated_data)
|
||||||
37
backend/tasks/tasks/views.py
Normal file
37
backend/tasks/tasks/views.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
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 .serializers import TaskCreateSerializer, TaskGeneralSerializer
|
||||||
|
|
||||||
|
class TaskCreateView(CreateAPIView):
|
||||||
|
queryset = Task.objects.all()
|
||||||
|
serializer_class = TaskCreateSerializer
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
def create(self, request, *args, **kwargs):
|
||||||
|
serializer = self.get_serializer(data=request.data)
|
||||||
|
|
||||||
|
if serializer.is_valid():
|
||||||
|
self.perform_create(serializer)
|
||||||
|
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||||
|
|
||||||
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
|
class TaskRetrieveView(RetrieveAPIView):
|
||||||
|
queryset = Task.objects.all()
|
||||||
|
serializer_class = TaskGeneralSerializer
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
|
||||||
|
class TaskUpdateView(RetrieveUpdateAPIView):
|
||||||
|
queryset = Task.objects.all()
|
||||||
|
serializer_class = TaskGeneralSerializer
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
|
||||||
|
class TaskDeleteView(DestroyAPIView):
|
||||||
|
queryset = Task.objects.all()
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
0
backend/tasks/tests/__init__.py
Normal file
0
backend/tasks/tests/__init__.py
Normal file
73
backend/tasks/tests/test_task_creation.py
Normal file
73
backend/tasks/tests/test_task_creation.py
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
from django.urls import reverse
|
||||||
|
from rest_framework import status
|
||||||
|
from rest_framework.test import APITestCase
|
||||||
|
|
||||||
|
from .utils import create_test_user, login_user
|
||||||
|
from ..models import Task
|
||||||
|
|
||||||
|
class TaskCreateViewTests(APITestCase):
|
||||||
|
def setUp(self):
|
||||||
|
|
||||||
|
self.user = create_test_user()
|
||||||
|
self.client = login_user(self.user)
|
||||||
|
self.url = reverse("add-task")
|
||||||
|
|
||||||
|
def test_create_valid_task(self):
|
||||||
|
"""
|
||||||
|
Test creating a valid task using the API.
|
||||||
|
"""
|
||||||
|
data = {
|
||||||
|
'title': 'Test Task',
|
||||||
|
'type': 'habit',
|
||||||
|
'exp': 10,
|
||||||
|
'attribute': 'str',
|
||||||
|
'priority': 1.5,
|
||||||
|
'difficulty': 1,
|
||||||
|
'user': self.user.id,
|
||||||
|
}
|
||||||
|
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')
|
||||||
|
|
||||||
|
def test_create_invalid_task(self):
|
||||||
|
"""
|
||||||
|
Test creating an invalid task using the API.
|
||||||
|
"""
|
||||||
|
data = {
|
||||||
|
'type': 'invalid', # Invalid task type
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
def test_missing_required_fields(self):
|
||||||
|
"""
|
||||||
|
Test creating a task with missing required fields using the API.
|
||||||
|
"""
|
||||||
|
data = {
|
||||||
|
'title': 'Incomplete Task',
|
||||||
|
'type': 'habit',
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
def test_invalid_user_id(self):
|
||||||
|
"""
|
||||||
|
Test creating a task with an invalid user ID using the API.
|
||||||
|
"""
|
||||||
|
data = {
|
||||||
|
'title': 'Test Task',
|
||||||
|
'type': 'habit',
|
||||||
|
'exp': 10,
|
||||||
|
'priority': 1.5,
|
||||||
|
'difficulty': 1,
|
||||||
|
'user': 999, # Invalid user ID
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
66
backend/tasks/tests/utils.py
Normal file
66
backend/tasks/tests/utils.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
from rest_framework.test import APIClient
|
||||||
|
|
||||||
|
from users.models import CustomUser
|
||||||
|
from ..models import Task
|
||||||
|
|
||||||
|
|
||||||
|
def create_test_user(email="testusertestuser@example.com", username="testusertestuser",
|
||||||
|
first_name="Test", password="testpassword",):
|
||||||
|
"""create predifined user for testing"""
|
||||||
|
return CustomUser.objects.create_user(
|
||||||
|
email=email,
|
||||||
|
username=username,
|
||||||
|
first_name=first_name,
|
||||||
|
password=password,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def login_user(user):
|
||||||
|
"""Login a user to API client."""
|
||||||
|
|
||||||
|
client = APIClient()
|
||||||
|
client.force_authenticate(user=user)
|
||||||
|
return client
|
||||||
|
|
||||||
|
|
||||||
|
def create_task_json(user, **kwargs):
|
||||||
|
"""Create task JSON data to use with the API."""
|
||||||
|
defaults = {
|
||||||
|
"title": "Test Task",
|
||||||
|
"type": "habit",
|
||||||
|
"notes": "This is a test task created via the API.",
|
||||||
|
"exp": 10,
|
||||||
|
"priority": 1.5,
|
||||||
|
"difficulty": 1,
|
||||||
|
"attribute": "str",
|
||||||
|
"challenge": False,
|
||||||
|
"reminders": False,
|
||||||
|
"fromSystem": False,
|
||||||
|
"creation_date": None,
|
||||||
|
"last_update": None,
|
||||||
|
}
|
||||||
|
|
||||||
|
task_attributes = {**defaults, **kwargs}
|
||||||
|
task_attributes["user"] = user
|
||||||
|
|
||||||
|
return task_attributes
|
||||||
|
|
||||||
|
|
||||||
|
def create_test_task(user, **kwargs):
|
||||||
|
"""Create a test task and associate it with the given user."""
|
||||||
|
defaults = {
|
||||||
|
'title': "Test Task",
|
||||||
|
'task_type': 'habit',
|
||||||
|
'notes': "This is a test task created via the API.",
|
||||||
|
'exp': 10,
|
||||||
|
'priority': 1.5,
|
||||||
|
'difficulty': 1,
|
||||||
|
'attribute': 'str',
|
||||||
|
'challenge': False,
|
||||||
|
'reminders': False,
|
||||||
|
'fromSystem': False,
|
||||||
|
}
|
||||||
|
|
||||||
|
task_attributes = {**defaults, **kwargs}
|
||||||
|
|
||||||
|
return Task.objects.create(user=user, **task_attributes)
|
||||||
16
backend/tasks/urls.py
Normal file
16
backend/tasks/urls.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
from django.urls import path, include
|
||||||
|
from rest_framework.routers import DefaultRouter
|
||||||
|
from .tasks.views import TaskCreateView, TaskRetrieveView, TaskUpdateView, TaskDeleteView
|
||||||
|
from .misc.views import TagViewSet, ReminderViewSet
|
||||||
|
|
||||||
|
router = DefaultRouter()
|
||||||
|
router.register(r'reminders', ReminderViewSet)
|
||||||
|
router.register(r'tags', TagViewSet)
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('', include(router.urls)),
|
||||||
|
path('tasks/create/', TaskCreateView.as_view(), name="add-task"),
|
||||||
|
path('tasks/<int:pk>/', TaskRetrieveView.as_view(), name='retrieve-task'),
|
||||||
|
path('tasks/<int:pk>/update/', TaskUpdateView.as_view(), name='update-task'),
|
||||||
|
path('tasks/<int:pk>/delete/', TaskDeleteView.as_view(), name='delete-task'),
|
||||||
|
]
|
||||||
@ -26,3 +26,17 @@ class CustomUser(AbstractBaseUser, PermissionsMixin):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
# String representation of the user
|
# String representation of the user
|
||||||
return self.username
|
return self.username
|
||||||
|
|
||||||
|
|
||||||
|
# class UserStats(models.Model):
|
||||||
|
# """
|
||||||
|
# Represents User Profiles and Attributes.
|
||||||
|
# Fields:
|
||||||
|
# - health: health points of the user.
|
||||||
|
# - gold: gold points of the user.
|
||||||
|
# - experience: experience points of the user.
|
||||||
|
# """
|
||||||
|
# user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
|
||||||
|
# health = models.IntegerField(default=100)
|
||||||
|
# gold = models.IntegerField(default=0)
|
||||||
|
# experience = models.FloatField(default=0)
|
||||||
Loading…
Reference in New Issue
Block a user