mirror of
https://github.com/TurTaskProject/TurTaskWeb.git
synced 2025-12-18 21:44:07 +01:00
Add RRule parser from 2 tasks and save Recurrence Tasks
This commit is contained in:
parent
b47e83e5cf
commit
d2f75c4fc1
@ -6,46 +6,22 @@ from rest_framework import viewsets
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
from tasks.utils import get_service
|
||||
from tasks.utils import get_service, generate_recurrence_rule
|
||||
from tasks.models import Todo, RecurrenceTask
|
||||
from tasks.serializers import TodoUpdateSerializer, RecurrenceTaskUpdateSerializer
|
||||
|
||||
|
||||
class GoogleCalendarEventViewset(viewsets.ViewSet):
|
||||
"""Viewset for list or save Google Calendar Events."""
|
||||
permission_classes = (IsAuthenticated,)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__()
|
||||
self.current_time = datetime.now(tz=timezone.utc).isoformat()
|
||||
self.event_fields = 'items(id,summary,description,created,recurringEventId,updated,start,end)'
|
||||
self.current_time = (datetime.now(tz=timezone.utc) + timedelta(days=-7)).isoformat()
|
||||
self.max_time = (datetime.now(tz=timezone.utc) + timedelta(days=7)).isoformat()
|
||||
self.event_fields = 'items(id,summary,description,created,recurringEventId,updated,start,end,originalStartTime)'
|
||||
|
||||
def _validate_serializer(self, serializer):
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
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
|
||||
event['start_datetime'] = event.get('start').get('dateTime')
|
||||
event['end_datetime'] = event.get('end').get('dateTime')
|
||||
event.pop('start')
|
||||
event.pop('end')
|
||||
try:
|
||||
task = Todo.objects.get(google_calendar_id=event['id'])
|
||||
serializer = TodoUpdateSerializer(instance=task, data=event)
|
||||
return self._validate_serializer(serializer)
|
||||
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=days)).isoformat()
|
||||
|
||||
def _get_google_events(self, request):
|
||||
"""Get all events from Google Calendar. """
|
||||
service = get_service(request)
|
||||
events = []
|
||||
next_page_token = None
|
||||
@ -54,21 +30,77 @@ class GoogleCalendarEventViewset(viewsets.ViewSet):
|
||||
query = service.events().list(
|
||||
calendarId='primary',
|
||||
timeMin=self.current_time,
|
||||
timeMax=max_time,
|
||||
timeMax=self.max_time,
|
||||
maxResults=200,
|
||||
singleEvents=True,
|
||||
orderBy='startTime',
|
||||
pageToken=next_page_token,
|
||||
fields='items(id,summary,description,created,recurringEventId,updated,start,end)',
|
||||
fields=self.event_fields,
|
||||
)
|
||||
|
||||
page_results = query.execute()
|
||||
page_events = page_results.get('items', [])
|
||||
|
||||
|
||||
events.extend(page_events)
|
||||
next_page_token = page_results.get('nextPageToken')
|
||||
|
||||
if next_page_token is None:
|
||||
break
|
||||
|
||||
return Response(events, status=200)
|
||||
return events
|
||||
|
||||
def _validate_serializer(self, serializer):
|
||||
"""Validate serializer and return response."""
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
return Response("Validate Successfully", status=200)
|
||||
return Response(serializer.errors, status=400)
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
"""Create a new Google Calendar Event."""
|
||||
events = self._get_google_events(request)
|
||||
|
||||
responses = []
|
||||
recurrence_task_ids = []
|
||||
for event in events:
|
||||
start_datetime = event.get('start', {}).get('dateTime')
|
||||
end_datetime = event.get('end', {}).get('dateTime')
|
||||
|
||||
event['start_datetime'] = start_datetime
|
||||
event['end_datetime'] = end_datetime
|
||||
event.pop('start')
|
||||
event.pop('end')
|
||||
|
||||
if (event.get('recurringEventId') in recurrence_task_ids):
|
||||
continue
|
||||
|
||||
if (event.get('recurringEventId') is not None):
|
||||
originalStartTime = event.get('originalStartTime', {}).get('dateTime')
|
||||
rrule_text = generate_recurrence_rule(event['start_datetime'], event['end_datetime'], originalStartTime)
|
||||
event['recurrence'] = rrule_text
|
||||
event.pop('originalStartTime')
|
||||
recurrence_task_ids.append(event['recurringEventId'])
|
||||
|
||||
try:
|
||||
task = RecurrenceTask.objects.get(google_calendar_id=event['id'])
|
||||
serializer = RecurrenceTaskUpdateSerializer(instance=task, data=event)
|
||||
except RecurrenceTask.DoesNotExist:
|
||||
serializer = RecurrenceTaskUpdateSerializer(data=event, user=request.user)
|
||||
|
||||
responses.append(self._validate_serializer(serializer))
|
||||
continue
|
||||
|
||||
try:
|
||||
task = Todo.objects.get(google_calendar_id=event['id'])
|
||||
serializer = TodoUpdateSerializer(instance=task, data=event)
|
||||
except Todo.DoesNotExist:
|
||||
serializer = TodoUpdateSerializer(data=event, user=request.user)
|
||||
|
||||
responses.append(self._validate_serializer(serializer))
|
||||
|
||||
return responses[0] if responses else Response("No events to process", status=200)
|
||||
|
||||
def list(self, request):
|
||||
"""List all Google Calendar Events."""
|
||||
return Response(self._get_google_events(request), status=200)
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.6 on 2023-11-14 15:17
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('tasks', '0012_habit'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='recurrencetask',
|
||||
name='recurrence_rule',
|
||||
field=models.CharField(),
|
||||
),
|
||||
]
|
||||
@ -68,7 +68,7 @@ class Todo(Task):
|
||||
return self.title
|
||||
|
||||
class RecurrenceTask(Task):
|
||||
recurrence_rule = models.TextField()
|
||||
recurrence_rule = models.CharField()
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.title} ({self.recurrence_rule})"
|
||||
|
||||
@ -41,7 +41,7 @@ class RecurrenceTaskUpdateSerializer(serializers.ModelSerializer):
|
||||
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")
|
||||
recurrence = serializers.CharField(source="recurrence_rule")
|
||||
start_datetime = serializers.DateTimeField(source="start_event", required=False)
|
||||
end_datetime = serializers.DateTimeField(source="end_event", required=False)
|
||||
|
||||
|
||||
@ -14,6 +14,10 @@ class TodoViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = TaskSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = Todo.objects.filter(user=self.request.user)
|
||||
return queryset
|
||||
|
||||
def get_serializer_class(self):
|
||||
# Can't add ManytoMany at creation time (Tags)
|
||||
if self.action == 'create':
|
||||
|
||||
@ -1,8 +1,55 @@
|
||||
from dateutil import rrule
|
||||
from datetime import datetime
|
||||
|
||||
from googleapiclient.discovery import build
|
||||
|
||||
from authentications.access_token_cache import get_credential_from_cache_token
|
||||
|
||||
|
||||
def get_service(request):
|
||||
"""
|
||||
Get a service that communicates to a Google API.
|
||||
|
||||
:param request: Http request object
|
||||
:return: A Resource object with methods for interacting with the calendar service
|
||||
"""
|
||||
credentials = get_credential_from_cache_token(request.user.id)
|
||||
return build('calendar', 'v3', credentials=credentials)
|
||||
return build('calendar', 'v3', credentials=credentials)
|
||||
|
||||
def _determine_frequency(time_difference):
|
||||
if time_difference.days >= 365:
|
||||
return rrule.YEARLY
|
||||
elif time_difference.days >= 30:
|
||||
return rrule.MONTHLY
|
||||
elif time_difference.days >= 7:
|
||||
return rrule.WEEKLY
|
||||
elif time_difference.days >= 1:
|
||||
return rrule.DAILY
|
||||
elif time_difference.seconds >= 3600:
|
||||
return rrule.HOURLY
|
||||
elif time_difference.seconds >= 60:
|
||||
return rrule.MINUTELY
|
||||
else:
|
||||
return rrule.SECONDLY
|
||||
|
||||
def generate_recurrence_rule(datetime1: str, datetime2: str, original_start_time: str) -> str:
|
||||
"""
|
||||
Generate recurrence rule from
|
||||
difference between two datetime string.
|
||||
|
||||
:param task1: A task object
|
||||
:param task2: A task object
|
||||
:return: A recurrence rule string according to ICAL format
|
||||
"""
|
||||
start_time1 = datetime.fromisoformat(datetime1)
|
||||
start_time2 = datetime.fromisoformat(datetime2)
|
||||
|
||||
time_difference = start_time2 - start_time1
|
||||
|
||||
recurrence_rule = rrule.rrule(
|
||||
freq=_determine_frequency(time_difference),
|
||||
dtstart=datetime.fromisoformat(original_start_time),
|
||||
interval=time_difference.days if time_difference.days > 0 else 1,
|
||||
)
|
||||
|
||||
return str(recurrence_rule)
|
||||
@ -14,4 +14,5 @@ google_auth_oauthlib>=1.1
|
||||
google-auth-httplib2>=0.1
|
||||
django-storages[s3]>=1.14
|
||||
Pillow>=10.1
|
||||
drf-spectacular>=0.26
|
||||
drf-spectacular>=0.26
|
||||
python-dateutil>=2.8
|
||||
Loading…
Reference in New Issue
Block a user