# -*- coding: utf-8 -*- from django.contrib import messages from django.contrib.messages.views import SuccessMessageMixin from django.forms import Form from django.http import HttpResponseRedirect from django.urls import reverse, reverse_lazy from django.utils import timezone from django.utils.translation import gettext as _ from django.views.generic.base import RedirectView, TemplateView from django.views.generic.detail import DetailView from django.views.generic.edit import CreateView, UpdateView, DeleteView, \ FormView from babybuddy.mixins import LoginRequiredMixin, PermissionRequiredMixin from babybuddy.views import BabyBuddyFilterView from core import forms, models, timeline def _prepare_timeline_context_data(context, date, child=None): date = timezone.datetime.strptime(date, '%Y-%m-%d') date = timezone.localtime(timezone.make_aware(date)) context['timeline_objects'] = timeline.get_objects(date, child) context['date'] = date context['date_previous'] = date - timezone.timedelta(days=1) if date.date() < timezone.localdate(): context['date_next'] = date + timezone.timedelta(days=1) pass class CoreAddView(PermissionRequiredMixin, SuccessMessageMixin, CreateView): def get_success_message(self, cleaned_data): cleaned_data['model'] = self.model._meta.verbose_name.title() if 'child' in cleaned_data: self.success_message = _('%(model)s entry for %(child)s added!') else: self.success_message = _('%(model)s entry added!') return self.success_message % cleaned_data def get_form_kwargs(self): """ Check for and add "child" and "timer" from request query parameters. - "child" may provide a slug for a Child instance. - "timer" may provided an ID for a Timer instance. These arguments are used in some add views to pre-fill initial data in the form fields. :return: Updated keyword arguments. """ kwargs = super(CoreAddView, self).get_form_kwargs() for parameter in ['child', 'timer']: value = self.request.GET.get(parameter, None) if value: kwargs.update({parameter: value}) return kwargs class CoreUpdateView(PermissionRequiredMixin, SuccessMessageMixin, UpdateView): def get_success_message(self, cleaned_data): cleaned_data['model'] = self.model._meta.verbose_name.title() if 'child' in cleaned_data: self.success_message = _('%(model)s entry for %(child)s updated.') else: self.success_message = _('%(model)s entry updated.') return self.success_message % cleaned_data class CoreDeleteView(PermissionRequiredMixin, DeleteView): """ SuccessMessageMixin is not compatible DeleteView. See: https://code.djangoproject.com/ticket/21936 """ def delete(self, request, *args, **kwargs): success_message = _('%(model)s entry deleted.') % { 'model': self.model._meta.verbose_name.title() } messages.success(request, success_message) return super(CoreDeleteView, self).delete(request, *args, **kwargs) class ChildList(PermissionRequiredMixin, BabyBuddyFilterView): model = models.Child template_name = 'core/child_list.html' permission_required = ('core.view_child',) paginate_by = 10 filterset_fields = ('first_name', 'last_name') class ChildAdd(CoreAddView): model = models.Child permission_required = ('core.add_child',) form_class = forms.ChildForm success_url = reverse_lazy('core:child-list') success_message = _('%(first_name)s %(last_name)s added!') class ChildDetail(PermissionRequiredMixin, DetailView): model = models.Child permission_required = ('core.view_child',) def get_context_data(self, **kwargs): context = super(ChildDetail, self).get_context_data(**kwargs) date = self.request.GET.get('date', str(timezone.localdate())) _prepare_timeline_context_data(context, date, self.object) return context class ChildUpdate(CoreUpdateView): model = models.Child permission_required = ('core.change_child',) form_class = forms.ChildForm success_url = reverse_lazy('core:child-list') class ChildDelete(CoreUpdateView): model = models.Child form_class = forms.ChildDeleteForm template_name = 'core/child_confirm_delete.html' permission_required = ('core.delete_child',) success_url = reverse_lazy('core:child-list') def get_success_message(self, cleaned_data): """ This class cannot use `CoreDeleteView` because of the confirmation step required so the success message must be overridden.""" success_message = _('%(model)s entry deleted.') % { 'model': self.model._meta.verbose_name.title() } return success_message % cleaned_data class DiaperChangeList(PermissionRequiredMixin, BabyBuddyFilterView): model = models.DiaperChange template_name = 'core/diaperchange_list.html' permission_required = ('core.view_diaperchange',) paginate_by = 10 filterset_fields = ('child', 'wet', 'solid', 'color') class DiaperChangeAdd(CoreAddView): model = models.DiaperChange permission_required = ('core.add_diaperchange',) form_class = forms.DiaperChangeForm success_url = reverse_lazy('core:diaperchange-list') class DiaperChangeUpdate(CoreUpdateView): model = models.DiaperChange permission_required = ('core.change_diaperchange',) form_class = forms.DiaperChangeForm success_url = reverse_lazy('core:diaperchange-list') class DiaperChangeDelete(CoreDeleteView): model = models.DiaperChange permission_required = ('core.delete_diaperchange',) success_url = reverse_lazy('core:diaperchange-list') class FeedingList(PermissionRequiredMixin, BabyBuddyFilterView): model = models.Feeding template_name = 'core/feeding_list.html' permission_required = ('core.view_feeding',) paginate_by = 10 filterset_fields = ('child', 'type', 'method') class FeedingAdd(CoreAddView): model = models.Feeding permission_required = ('core.add_feeding',) form_class = forms.FeedingForm success_url = reverse_lazy('core:feeding-list') class FeedingUpdate(CoreUpdateView): model = models.Feeding permission_required = ('core.change_feeding',) form_class = forms.FeedingForm success_url = reverse_lazy('core:feeding-list') class FeedingDelete(CoreDeleteView): model = models.Feeding permission_required = ('core.delete_feeding',) success_url = reverse_lazy('core:feeding-list') class NoteList(PermissionRequiredMixin, BabyBuddyFilterView): model = models.Note template_name = 'core/note_list.html' permission_required = ('core.view_note',) paginate_by = 10 filterset_fields = ('child',) class NoteAdd(CoreAddView): model = models.Note permission_required = ('core.add_note',) form_class = forms.NoteForm success_url = reverse_lazy('core:note-list') class NoteUpdate(CoreUpdateView): model = models.Note permission_required = ('core.change_note',) form_class = forms.NoteForm success_url = reverse_lazy('core:note-list') class NoteDelete(CoreDeleteView): model = models.Note permission_required = ('core.delete_note',) success_url = reverse_lazy('core:note-list') class SleepList(PermissionRequiredMixin, BabyBuddyFilterView): model = models.Sleep template_name = 'core/sleep_list.html' permission_required = ('core.view_sleep',) paginate_by = 10 filterset_fields = ('child',) class SleepAdd(CoreAddView): model = models.Sleep permission_required = ('core.add_sleep',) form_class = forms.SleepForm success_url = reverse_lazy('core:sleep-list') class SleepUpdate(CoreUpdateView): model = models.Sleep permission_required = ('core.change_sleep',) form_class = forms.SleepForm success_url = reverse_lazy('core:sleep-list') class SleepDelete(CoreDeleteView): model = models.Sleep permission_required = ('core.delete_sleep',) success_url = reverse_lazy('core:sleep-list') class TemperatureList(PermissionRequiredMixin, BabyBuddyFilterView): model = models.Temperature template_name = 'core/temperature_list.html' permission_required = ('core.view_temperature',) paginate_by = 10 filterset_fields = ('child',) class TemperatureAdd(CoreAddView): model = models.Temperature permission_required = ('core.add_temperature',) form_class = forms.TemperatureForm success_url = reverse_lazy('core:temperature-list') success_message = _('%(model)s reading added!') class TemperatureUpdate(CoreUpdateView): model = models.Temperature permission_required = ('core.change_temperature',) form_class = forms.TemperatureForm success_url = reverse_lazy('core:temperature-list') success_message = _('%(model)s reading for %(child)s updated.') class TemperatureDelete(CoreDeleteView): model = models.Temperature permission_required = ('core.delete_temperature',) success_url = reverse_lazy('core:temperature-list') class Timeline(LoginRequiredMixin, TemplateView): template_name = 'timeline/timeline.html' # Show the overall timeline or a child timeline if one Child instance. def get(self, request, *args, **kwargs): children = models.Child.objects.count() if children == 1: return HttpResponseRedirect( reverse( 'core:child', args={models.Child.objects.first().slug} ) ) return super(Timeline, self).get(request, *args, **kwargs) def get_context_data(self, **kwargs): context = super(Timeline, self).get_context_data(**kwargs) date = self.request.GET.get('date', str(timezone.localdate())) _prepare_timeline_context_data(context, date) return context class TimerList(PermissionRequiredMixin, BabyBuddyFilterView): model = models.Timer template_name = 'core/timer_list.html' permission_required = ('core.view_timer',) paginate_by = 10 filterset_fields = ('active', 'user') class TimerDetail(PermissionRequiredMixin, DetailView): model = models.Timer permission_required = ('core.view_timer',) class TimerAdd(PermissionRequiredMixin, CreateView): model = models.Timer permission_required = ('core.add_timer',) form_class = forms.TimerForm def get_form_kwargs(self): kwargs = super(TimerAdd, self).get_form_kwargs() kwargs.update({'user': self.request.user}) return kwargs def get_success_url(self): return reverse('core:timer-detail', kwargs={'pk': self.object.pk}) class TimerUpdate(CoreUpdateView): model = models.Timer permission_required = ('core.change_timer',) form_class = forms.TimerForm success_url = reverse_lazy('core:timer-list') def get_form_kwargs(self): kwargs = super(TimerUpdate, self).get_form_kwargs() kwargs.update({'user': self.request.user}) return kwargs def get_success_url(self): instance = self.get_object() return reverse('core:timer-detail', kwargs={'pk': instance.pk}) class TimerAddQuick(PermissionRequiredMixin, RedirectView): http_method_names = ['post'] permission_required = ('core.add_timer',) def post(self, request, *args, **kwargs): instance = models.Timer.objects.create(user=request.user) # Add child relationship if there is only Child instance. if models.Child.count() == 1: instance.child = models.Child.objects.first() instance.save() self.url = request.GET.get( 'next', reverse('core:timer-detail', args={instance.id})) return super(TimerAddQuick, self).get(request, *args, **kwargs) class TimerRestart(PermissionRequiredMixin, RedirectView): http_method_names = ['post'] permission_required = ('core.change_timer',) def post(self, request, *args, **kwargs): instance = models.Timer.objects.get(id=kwargs['pk']) instance.restart() messages.success(request, '{} restarted.'.format(instance)) return super(TimerRestart, self).get(request, *args, **kwargs) def get_redirect_url(self, *args, **kwargs): return reverse('core:timer-detail', kwargs={'pk': kwargs['pk']}) class TimerStop(PermissionRequiredMixin, SuccessMessageMixin, RedirectView): http_method_names = ['post'] permission_required = ('core.change_timer',) success_message = _('%(timer)s stopped.') def post(self, request, *args, **kwargs): instance = models.Timer.objects.get(id=kwargs['pk']) instance.stop() messages.success(request, '{} stopped.'.format(instance)) return super(TimerStop, self).get(request, *args, **kwargs) def get_redirect_url(self, *args, **kwargs): return reverse('core:timer-detail', kwargs={'pk': kwargs['pk']}) class TimerDelete(CoreDeleteView): model = models.Timer permission_required = ('core.delete_timer',) success_url = reverse_lazy('core:timer-list') class TimerDeleteInactive(PermissionRequiredMixin, SuccessMessageMixin, FormView): permission_required = ('core.delete_timer',) form_class = Form template_name = 'core/timer_confirm_delete_inactive.html' success_url = reverse_lazy('core:timer-list') success_message = _('All inactive timers deleted.') def get_context_data(self, **kwargs): kwargs = super().get_context_data(**kwargs) kwargs['timer_count'] = self.get_instances().count() return kwargs def get(self, request, *args, **kwargs): # Redirect back to list if there are no inactive timers. if self.get_instances().count() == 0: messages.warning(request, _('No inactive timers exist.')) return HttpResponseRedirect(self.success_url) return super().get(request, *args, **kwargs) def form_valid(self, form): self.get_instances().delete() return super().form_valid(form) @staticmethod def get_instances(): return models.Timer.objects.filter(active=False) class TummyTimeList(PermissionRequiredMixin, BabyBuddyFilterView): model = models.TummyTime template_name = 'core/tummytime_list.html' permission_required = ('core.view_tummytime',) paginate_by = 10 filterset_fields = ('child',) class TummyTimeAdd(CoreAddView): model = models.TummyTime permission_required = ('core.add_tummytime',) form_class = forms.TummyTimeForm success_url = reverse_lazy('core:tummytime-list') class TummyTimeUpdate(CoreUpdateView): model = models.TummyTime permission_required = ('core.change_tummytime',) form_class = forms.TummyTimeForm success_url = reverse_lazy('core:tummytime-list') class TummyTimeDelete(CoreDeleteView): model = models.TummyTime permission_required = ('core.delete_tummytime',) success_url = reverse_lazy('core:tummytime-list') class WeightList(PermissionRequiredMixin, BabyBuddyFilterView): model = models.Weight template_name = 'core/weight_list.html' permission_required = ('core.view_weight',) paginate_by = 10 filterset_fields = ('child',) class WeightAdd(CoreAddView): model = models.Weight permission_required = ('core.add_weight',) form_class = forms.WeightForm success_url = reverse_lazy('core:weight-list') class WeightUpdate(CoreUpdateView): model = models.Weight permission_required = ('core.change_weight',) form_class = forms.WeightForm success_url = reverse_lazy('core:weight-list') class WeightDelete(CoreDeleteView): model = models.Weight permission_required = ('core.delete_weight',) success_url = reverse_lazy('core:weight-list') class HeightList(PermissionRequiredMixin, BabyBuddyFilterView): model = models.Height template_name = 'core/height_list.html' permission_required = ('core.view_height',) paginate_by = 10 filterset_fields = ('child',) class HeightAdd(CoreAddView): model = models.Height permission_required = ('core.add_height',) form_class = forms.HeightForm success_url = reverse_lazy('core:height-list') class HeightUpdate(CoreUpdateView): model = models.Height permission_required = ('core.change_height',) form_class = forms.HeightForm success_url = reverse_lazy('core:height-list') class HeightDelete(CoreDeleteView): model = models.Height permission_required = ('core.delete_height',) success_url = reverse_lazy('core:height-list') class HeadCircumferenceList(PermissionRequiredMixin, BabyBuddyFilterView): model = models.HeadCircumference template_name = 'core/head_circumference_list.html' permission_required = ('core.view_head_circumference',) paginate_by = 10 filterset_fields = ('child',) class HeadCircumferenceAdd(CoreAddView): model = models.HeadCircumference template_name = 'core/head_circumference_form.html' permission_required = ('core.add_head_circumference',) form_class = forms.HeadCircumferenceForm success_url = reverse_lazy('core:head-circumference-list') class HeadCircumferenceUpdate(CoreUpdateView): model = models.HeadCircumference template_name = 'core/head_circumference_form.html' permission_required = ('core.change_head_circumference',) form_class = forms.HeadCircumferenceForm success_url = reverse_lazy('core:head-circumference-list') class HeadCircumferenceDelete(CoreDeleteView): model = models.HeadCircumference template_name = 'core/head_circumference_delete.html' permission_required = ('core.delete_head_circumference',) success_url = reverse_lazy('core:head-circumference-list') class BMIList(PermissionRequiredMixin, BabyBuddyFilterView): model = models.BMI template_name = 'core/bmi_list.html' permission_required = ('core.view_bmi',) paginate_by = 10 filterset_fields = ('child',) class BMIAdd(CoreAddView): model = models.BMI permission_required = ('core.add_bmi',) form_class = forms.BMIForm success_url = reverse_lazy('core:bmi-list') class BMIUpdate(CoreUpdateView): model = models.BMI permission_required = ('core.change_bmi',) form_class = forms.BMIForm success_url = reverse_lazy('core:bmi-list') class BMIDelete(CoreDeleteView): model = models.BMI permission_required = ('core.delete_bmi',) success_url = reverse_lazy('core:bmi-list')