diff --git a/.idea/dictionaries/vabene1111_PC.xml b/.idea/dictionaries/vabene1111_PC.xml index 7d60e459..13cb1b32 100644 --- a/.idea/dictionaries/vabene1111_PC.xml +++ b/.idea/dictionaries/vabene1111_PC.xml @@ -3,6 +3,7 @@ csrftoken gunicorn + ical traefik diff --git a/cookbook/templates/meal_plan.html b/cookbook/templates/meal_plan.html index b578376a..f1f8a3ad 100644 --- a/cookbook/templates/meal_plan.html +++ b/cookbook/templates/meal_plan.html @@ -175,7 +175,8 @@ {% trans 'Edit plan types' %}
{% trans 'Show help' %} + data-target="#id_plan_help_modal">{% trans 'Show help' %}
+ {% trans 'Week iCal export' %} @@ -621,6 +622,10 @@ } return url }, + getIcalUrl: function () { + return "{% url 'api_get_plan_ical' 12345 %}".replace(/12345/, this.week); + }, + addDayToShopping: function (day) { let date = moment(this.week).weekday(this.days.indexOf(day)).format('YYYY-MM-DD') diff --git a/cookbook/urls.py b/cookbook/urls.py index cf2b1a0e..99dc90b9 100644 --- a/cookbook/urls.py +++ b/cookbook/urls.py @@ -53,6 +53,7 @@ urlpatterns = [ path('api/get_recipe_file//', api.get_recipe_file, name='api_get_recipe_file'), path('api/sync_all/', api.sync_all, name='api_sync'), path('api/log_cooking//', api.log_cooking, name='api_log_cooking'), + path('api/plan-ical//', api.get_plan_ical, name='api_get_plan_ical'), path('dal/keyword/', dal.KeywordAutocomplete.as_view(), name='dal_keyword'), path('dal/ingredient/', dal.IngredientsAutocomplete.as_view(), name='dal_ingredient'), diff --git a/cookbook/views/api.py b/cookbook/views/api.py index 99bdfbeb..5d158aea 100644 --- a/cookbook/views/api.py +++ b/cookbook/views/api.py @@ -1,3 +1,4 @@ +import io import json import re @@ -9,6 +10,7 @@ from django.db.models import Q from django.http import HttpResponse, FileResponse from django.shortcuts import redirect from django.utils.translation import gettext as _ +from icalendar import Calendar, Event from rest_framework import viewsets, permissions from rest_framework.exceptions import APIException @@ -164,3 +166,27 @@ def log_cooking(request, recipe_id): return {'msg': 'updated successfully'} return {'error': 'recipe does not exist'} + + +@group_required('user') +def get_plan_ical(request, html_week): + queryset = MealPlan.objects.filter(Q(created_by=request.user) | Q(shared=request.user)).distinct().all() + + y, w = html_week.replace('-W', ' ').split() + queryset = queryset.filter(date__week=w, date__year=y) + + cal = Calendar() + + for p in queryset: + event = Event() + event['uid'] = p.id + event.add('dtstart', p.date) + event.add('dtend', p.date) + event['summary'] = f'{p.meal_type.name}: {p.get_label()}' + event['description'] = p.note + cal.add_component(event) + + response = FileResponse(io.BytesIO(cal.to_ical())) + response["Content-Disposition"] = f'attachment; filename=meal_plan_{html_week}.ics' + + return response diff --git a/requirements.txt b/requirements.txt index 600661af..e01177b2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -20,3 +20,4 @@ simplejson==3.17.0 six==1.15.0 webdavclient3==3.14.4 whitenoise==5.1.0 +icalendar==4.0.6 \ No newline at end of file