Skip to content

Commit

Permalink
Add API views for task chunk series manipulation (closes #85)
Browse files Browse the repository at this point in the history
  • Loading branch information
wichmannpas committed Sep 6, 2018
1 parent be3e53c commit 83eae2c
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 6 deletions.
3 changes: 3 additions & 0 deletions task/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,14 @@ class Meta:
fields = (
'id',
'task',
'series',
'task_id',
'day',
'day_order',
'duration',
'finished',
)
series = serializers.PrimaryKeyRelatedField(read_only=True)
day = DayOrScheduleField()
day_order = serializers.IntegerField(max_value=32767, min_value=-32768, required=False)
task = TaskSerializer(read_only=True)
Expand Down Expand Up @@ -194,6 +196,7 @@ class TaskChunkSeriesSerializer(serializers.ModelSerializer):
class Meta:
model = TaskChunkSeries
fields = (
'id',
'task_id',
'duration',
'start',
Expand Down
107 changes: 107 additions & 0 deletions task/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3543,6 +3543,113 @@ def test_validation_update_change_end(self):
date(2010, 5, 1))


class TaskChunkSeriesViewSetTest(AuthenticatedApiTest):
def setUp(self):
super().setUp()

self.task = Task.objects.create(
user=self.user,
name='Testtask',
duration=Decimal(2))

@freeze_time('2010-05-03')
def test_create(self):
"""
Test the creation of a series, making sure that initial
task chunks are scheduled and returned.
"""
self.assertEqual(
TaskChunkSeries.objects.count(),
0)
self.assertEqual(
TaskChunk.objects.count(),
0)

resp = self.client.post('/task/chunk/series/', {
'task_id': self.task.pk,
'duration': '2',
'start': '2010-05-23',
'end': '2010-06-23',
'rule': 'interval',
'interval_days': 1,
})
self.assertEqual(
resp.status_code,
status.HTTP_201_CREATED)

self.assertSetEqual(
set(resp.data.keys()),
{'series', 'scheduled'})

self.assertEqual(
resp.data['series']['task_id'],
self.task.pk)
self.assertEqual(
Decimal(resp.data['series']['duration']),
Decimal(2))
self.assertEqual(
resp.data['series']['start'],
'2010-05-23')
self.assertEqual(
resp.data['series']['end'],
'2010-06-23')
self.assertEqual(
resp.data['series']['rule'],
'interval')
self.assertEqual(
resp.data['series']['interval_days'],
1)

self.assertEqual(
len(resp.data['scheduled']),
32)

self.assertEqual(
TaskChunkSeries.objects.count(),
1)
series = TaskChunkSeries.objects.first()
self.assertTrue(
series.completely_scheduled)

self.assertEqual(
TaskChunk.objects.count(),
32)

def test_partial_update(self):
"""
Test that it is not allowed to partially update a task chunk series.
"""
series = TaskChunkSeries.objects.create(
task=self.task,
start=date(2010, 2, 24),
rule='interval',
interval_days=7)

resp = self.client.patch('/task/chunk/series/{}/'.format(series.pk), {
'duration': '2.5',
})
self.assertEqual(
resp.status_code,
status.HTTP_405_METHOD_NOT_ALLOWED)

def test_no_getting_of_foreign(self):
foreign_user = get_user_model().objects.create(
username='foreign')
foreign_task = Task.objects.create(
user=foreign_user,
name='Testtask',
duration=Decimal(2))
series = TaskChunkSeries.objects.create(
task=foreign_task,
start=date(2010, 2, 24),
rule='interval',
interval_days=7)
resp = self.client.get('/task/chunk/series/{}/'.format(series.id))
self.assertEqual(
resp.status_code,
status.HTTP_404_NOT_FOUND)


class TaskChunkTest(TestCase):
def setUp(self):
self.user1 = get_user_model().objects.create(
Expand Down
6 changes: 5 additions & 1 deletion task/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@
'task',
views.TaskViewSet,
base_name='task')
router.register(
'chunk/series',
views.TaskChunkSeriesViewSet,
base_name='taskchunkseries')
router.register(
'chunk',
views.TaskChunkViewSet,
base_name='chunk')
base_name='taskchunk')
urlpatterns = router.urls
41 changes: 36 additions & 5 deletions task/views.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
from django.db import transaction
from django.db.models import F
from rest_framework import mixins, serializers, status, viewsets
from rest_framework.decorators import action
from rest_framework.exceptions import ParseError, ValidationError
from rest_framework.exceptions import MethodNotAllowed, ParseError, ValidationError
from rest_framework.generics import get_object_or_404
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from .filters import TaskChunkFilterBackend, TaskFilterBackend
from .models import TaskChunk
from .serializers import TaskSerializer, TaskChunkSerializer
from .models import TaskChunk, TaskChunkSeries
from .serializers import TaskSerializer, TaskChunkSerializer, TaskChunkSeriesSerializer


class TaskViewSet(viewsets.ModelViewSet):
Expand Down Expand Up @@ -36,6 +37,33 @@ def merge(self, request, pk: int, other_pk: int):
return Response(serializer.data)


class TaskChunkSeriesViewSet(viewsets.GenericViewSet, mixins.ListModelMixin,
mixins.RetrieveModelMixin, mixins.UpdateModelMixin):
permission_classes = IsAuthenticated,
serializer_class = TaskChunkSeriesSerializer

def get_queryset(self):
return TaskChunkSeries.objects.filter(task__user=self.request.user) \
.select_related('task')

@transaction.atomic
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
instance = serializer.save()

scheduled = instance.schedule()
scheduled_serializer = TaskChunkSerializer(scheduled, many=True)

return Response({
'series': serializer.data,
'scheduled': scheduled_serializer.data,
}, status=status.HTTP_201_CREATED)

def partial_update(self, request, *args, **kwargs):
raise MethodNotAllowed('PATCH')


class TaskChunkViewSet(viewsets.GenericViewSet, mixins.CreateModelMixin,
mixins.ListModelMixin, mixins.RetrieveModelMixin,
mixins.UpdateModelMixin):
Expand All @@ -45,8 +73,11 @@ class TaskChunkViewSet(viewsets.GenericViewSet, mixins.CreateModelMixin,

def get_queryset(self):
return TaskChunk.objects.filter(task__user=self.request.user) \
.select_related('task') \
.prefetch_related('task__chunks', 'task__labels')
.select_related(
'task',
'series',
'series__task'
).prefetch_related('task__chunks', 'task__labels')

def destroy(self, request, pk=None):
class ParameterSerializer(serializers.Serializer):
Expand Down

0 comments on commit 83eae2c

Please sign in to comment.