diff --git a/cookbook/admin.py b/cookbook/admin.py index 1207b9da..61966eb0 100644 --- a/cookbook/admin.py +++ b/cookbook/admin.py @@ -277,7 +277,7 @@ admin.site.register(RecipeBookEntry, RecipeBookEntryAdmin) class MealPlanAdmin(admin.ModelAdmin): - list_display = ('user', 'recipe', 'meal_type', 'date') + list_display = ('user', 'recipe', 'meal_type', 'from_date', 'to_date') @staticmethod def user(obj): diff --git a/cookbook/forms.py b/cookbook/forms.py index 12bbce44..e0ca965c 100644 --- a/cookbook/forms.py +++ b/cookbook/forms.py @@ -326,49 +326,6 @@ class ImportRecipeForm(forms.ModelForm): # TODO deprecate -class MealPlanForm(forms.ModelForm): - def __init__(self, *args, **kwargs): - space = kwargs.pop('space') - super().__init__(*args, **kwargs) - self.fields['recipe'].queryset = Recipe.objects.filter(space=space).all() - self.fields['meal_type'].queryset = MealType.objects.filter(space=space).all() - self.fields['shared'].queryset = User.objects.filter(userpreference__space=space).all() - - def clean(self): - cleaned_data = super(MealPlanForm, self).clean() - - if cleaned_data['title'] == '' and cleaned_data['recipe'] is None: - raise forms.ValidationError( - _('You must provide at least a recipe or a title.') - ) - - return cleaned_data - - class Meta: - model = MealPlan - fields = ( - 'recipe', 'title', 'meal_type', 'note', - 'servings', 'date', 'shared' - ) - - help_texts = { - 'shared': _('You can list default users to share recipes with in the settings.'), - 'note': _('You can use markdown to format this field. See the docs here') - - } - - widgets = { - 'recipe': SelectWidget, - 'date': DateWidget, - 'shared': MultiSelectWidget - } - field_classes = { - 'recipe': SafeModelChoiceField, - 'meal_type': SafeModelChoiceField, - 'shared': SafeModelMultipleChoiceField, - } - - class InviteLinkForm(forms.ModelForm): def __init__(self, *args, **kwargs): user = kwargs.pop('user') diff --git a/cookbook/migrations/0201_rename_date_mealplan_from_date_mealplan_to_date.py b/cookbook/migrations/0201_rename_date_mealplan_from_date_mealplan_to_date.py new file mode 100644 index 00000000..343d758e --- /dev/null +++ b/cookbook/migrations/0201_rename_date_mealplan_from_date_mealplan_to_date.py @@ -0,0 +1,36 @@ +# Generated by Django 4.1.10 on 2023-09-08 12:20 + +from django.db import migrations, models +from django.db.models import F +from django_scopes import scopes_disabled + + +def apply_migration(apps, schema_editor): + with scopes_disabled(): + MealPlan = apps.get_model('cookbook', 'MealPlan') + MealPlan.objects.update(to_date=F('from_date')) + + +class Migration(migrations.Migration): + dependencies = [ + ('cookbook', '0200_alter_propertytype_options_remove_keyword_icon_and_more'), + ] + + operations = [ + migrations.RenameField( + model_name='mealplan', + old_name='date', + new_name='from_date', + ), + migrations.AddField( + model_name='mealplan', + name='to_date', + field=models.DateField(blank=True, null=True), + ), + migrations.RunPython(apply_migration), + migrations.AlterField( + model_name='mealplan', + name='to_date', + field=models.DateField(), + ), + ] diff --git a/cookbook/models.py b/cookbook/models.py index 5651aa7b..893d099b 100644 --- a/cookbook/models.py +++ b/cookbook/models.py @@ -993,7 +993,8 @@ class MealPlan(ExportModelOperationsMixin('meal_plan'), models.Model, Permission shared = models.ManyToManyField(User, blank=True, related_name='plan_share') meal_type = models.ForeignKey(MealType, on_delete=models.CASCADE) note = models.TextField(blank=True) - date = models.DateField() + from_date = models.DateField() + to_date = models.DateField() space = models.ForeignKey(Space, on_delete=models.CASCADE) objects = ScopedManager(space='space') @@ -1007,7 +1008,7 @@ class MealPlan(ExportModelOperationsMixin('meal_plan'), models.Model, Permission return self.meal_type.name def __str__(self): - return f'{self.get_label()} - {self.date} - {self.meal_type.name}' + return f'{self.get_label()} - {self.from_date} - {self.meal_type.name}' class ShoppingListRecipe(ExportModelOperationsMixin('shopping_list_recipe'), models.Model, PermissionModelMixin): diff --git a/cookbook/serializer.py b/cookbook/serializer.py index 6dc269b6..63ded300 100644 --- a/cookbook/serializer.py +++ b/cookbook/serializer.py @@ -449,7 +449,7 @@ class KeywordSerializer(UniqueFieldsMixin, ExtendedRecipeMixin): class Meta: model = Keyword fields = ( - 'id', 'name', 'label', 'description', 'image', 'parent', 'numchild', 'numrecipe', 'created_at', + 'id', 'name', 'label', 'description', 'image', 'parent', 'numchild', 'numrecipe', 'created_at', 'updated_at', 'full_name') read_only_fields = ('id', 'label', 'numchild', 'parent', 'image') @@ -528,7 +528,7 @@ class PropertyTypeSerializer(OpenDataModelMixin, WritableNestedModelSerializer, class Meta: model = PropertyType - fields = ('id', 'name', 'unit', 'description', 'order', 'open_data_slug') + fields = ('id', 'name', 'unit', 'description', 'order', 'open_data_slug') class PropertySerializer(UniqueFieldsMixin, WritableNestedModelSerializer): @@ -995,7 +995,7 @@ class MealPlanSerializer(SpacedModelSerializer, WritableNestedModelSerializer): model = MealPlan fields = ( 'id', 'title', 'recipe', 'servings', 'note', 'note_markdown', - 'date', 'meal_type', 'created_by', 'shared', 'recipe_name', + 'from_date', 'to_date', 'meal_type', 'created_by', 'shared', 'recipe_name', 'meal_type_name', 'shopping' ) read_only_fields = ('created_by',) diff --git a/cookbook/urls.py b/cookbook/urls.py index 0308a395..987d3e46 100644 --- a/cookbook/urls.py +++ b/cookbook/urls.py @@ -166,7 +166,7 @@ urlpatterns = [ ] generic_models = ( - Recipe, RecipeImport, Storage, RecipeBook, MealPlan, SyncLog, Sync, + Recipe, RecipeImport, Storage, RecipeBook, SyncLog, Sync, Comment, RecipeBookEntry, ShoppingList, InviteLink, UserSpace, Space ) diff --git a/cookbook/views/api.py b/cookbook/views/api.py index 16a885a0..7332241e 100644 --- a/cookbook/views/api.py +++ b/cookbook/views/api.py @@ -662,11 +662,11 @@ class MealPlanViewSet(viewsets.ModelViewSet): from_date = self.request.query_params.get('from_date', None) if from_date is not None: - queryset = queryset.filter(date__gte=from_date) + queryset = queryset.filter(to_date__gte=from_date) to_date = self.request.query_params.get('to_date', None) if to_date is not None: - queryset = queryset.filter(date__lte=to_date) + queryset = queryset.filter(to_date__lte=to_date) return queryset @@ -1673,8 +1673,11 @@ def get_plan_ical(request, from_date, to_date): for p in queryset: event = Event() event['uid'] = p.id - event.add('dtstart', p.date) - event.add('dtend', p.date) + event.add('dtstart', p.from_date) + if p.to_date: + event.add('dtend', p.to_date) + else: + event.add('dtend', p.from_date) event['summary'] = f'{p.meal_type.name}: {p.get_label()}' event['description'] = p.note cal.add_component(event) diff --git a/cookbook/views/edit.py b/cookbook/views/edit.py index 50e87866..1bacc54a 100644 --- a/cookbook/views/edit.py +++ b/cookbook/views/edit.py @@ -8,7 +8,7 @@ from django.utils.translation import gettext as _ from django.views.generic import UpdateView from django.views.generic.edit import FormMixin -from cookbook.forms import CommentForm, ExternalRecipeForm, MealPlanForm, StorageForm, SyncForm +from cookbook.forms import CommentForm, ExternalRecipeForm, StorageForm, SyncForm from cookbook.helper.permission_helper import GroupRequiredMixin, OwnerRequiredMixin, group_required, above_space_limit from cookbook.models import (Comment, MealPlan, MealType, Recipe, RecipeImport, Storage, Sync, UserPreference) @@ -192,26 +192,6 @@ class ImportUpdate(GroupRequiredMixin, UpdateView): return context -class MealPlanUpdate(OwnerRequiredMixin, UpdateView, SpaceFormMixing): - template_name = "generic/edit_template.html" - model = MealPlan - form_class = MealPlanForm - - def get_success_url(self): - return reverse('view_plan_entry', kwargs={'pk': self.object.pk}) - - def get_form(self, form_class=None): - form = self.form_class(**self.get_form_kwargs()) - form.fields['meal_type'].queryset = MealType.objects \ - .filter(created_by=self.request.user).all() - return form - - def get_context_data(self, **kwargs): - context = super(MealPlanUpdate, self).get_context_data(**kwargs) - context['title'] = _("Meal-Plan") - return context - - class ExternalRecipeUpdate(GroupRequiredMixin, UpdateView, SpaceFormMixing): groups_required = ['user'] model = Recipe diff --git a/cookbook/views/new.py b/cookbook/views/new.py index 0bae4689..48dcf99d 100644 --- a/cookbook/views/new.py +++ b/cookbook/views/new.py @@ -12,7 +12,7 @@ from django.urls import reverse, reverse_lazy from django.utils.translation import gettext as _ from django.views.generic import CreateView -from cookbook.forms import ImportRecipeForm, InviteLinkForm, MealPlanForm, Storage, StorageForm +from cookbook.forms import ImportRecipeForm, InviteLinkForm, Storage, StorageForm from cookbook.helper.permission_helper import GroupRequiredMixin, group_required, above_space_limit from cookbook.models import (InviteLink, MealPlan, MealType, Recipe, RecipeBook, RecipeImport, ShareLink, Step, UserPreference, UserSpace) @@ -135,55 +135,3 @@ def create_new_external_recipe(request, import_id): return render(request, 'forms/edit_import_recipe.html', {'form': form}) -class MealPlanCreate(GroupRequiredMixin, CreateView, SpaceFormMixing): - groups_required = ['user'] - template_name = "generic/new_template.html" - model = MealPlan - form_class = MealPlanForm - success_url = reverse_lazy('view_plan') - - def get_form(self, form_class=None): - form = self.form_class(**self.get_form_kwargs()) - form.fields['meal_type'].queryset = MealType.objects.filter(created_by=self.request.user, - space=self.request.space).all() - return form - - def get_initial(self): - return dict( - meal_type=( - self.request.GET['meal'] - if 'meal' in self.request.GET - else None - ), - date=( - datetime.strptime(self.request.GET['date'], '%Y-%m-%d') - if 'date' in self.request.GET - else None - ), - shared=( - self.request.user.userpreference.plan_share.all() - if self.request.user.userpreference.plan_share - else None - ) - ) - - def form_valid(self, form): - obj = form.save(commit=False) - obj.created_by = self.request.user - obj.space = self.request.space - obj.save() - return HttpResponseRedirect(reverse('view_plan')) - - def get_context_data(self, **kwargs): - context = super(MealPlanCreate, self).get_context_data(**kwargs) - context['title'] = _("Meal-Plan") - - recipe = self.request.GET.get('recipe') - if recipe: - if re.match(r'^([0-9])+$', recipe): - if Recipe.objects.filter(pk=int(recipe), space=self.request.space).exists(): - context['default_recipe'] = Recipe.objects.get(pk=int(recipe), space=self.request.space) - - return context - - diff --git a/vue/src/apps/MealPlanView/MealPlanView.vue b/vue/src/apps/MealPlanView/MealPlanView.vue index 3587566f..6c49a117 100644 --- a/vue/src/apps/MealPlanView/MealPlanView.vue +++ b/vue/src/apps/MealPlanView/MealPlanView.vue @@ -1,7 +1,7 @@