import datetime from django.utils import timezone as tz from django.utils.decorators import method_decorator from django.views.decorators.cache import cache_page from django.views.generic import ListView from rest_framework.generics import ListAPIView from ..models import Diffusion, Log from ..serializers import LogInfo, LogInfoSerializer from .base import BaseAPIView, BaseView from .mixins import AttachedToMixin, GetDateMixin __all__ = ("LogListMixin", "LogListView", "LogListAPIView") class LogListMixin(GetDateMixin): model = Log min_date = None max_date = None def get_date(self, param): date = super().get_date(param) if date is not None and not self.request.user.is_staff: return min(date, datetime.date.today()) return date def filter_qs(self, query): if self.min_date: query = query.after(self.min_date) if self.max_date: query = query.before(self.max_date) if not self.min_date and not self.max_date and self.date: return query.date(self.date) return query def get_queryset(self): # only get logs for tracks: log for diffusion will be retrieved # by the diffusions' queryset. query = super().get_queryset().on_air().filter(track__isnull=False).filter(date__lte=tz.now()) return self.filter_qs(query) def get_diffusions_queryset(self): query = Diffusion.objects.station(self.station).on_air().filter(start__lte=tz.now()).before() return self.filter_qs(query) def get_object_list(self, logs, full=False): """Return diffusions merged to the provided logs iterable. If `full`, sort items by date without merging. """ diffs = self.get_diffusions_queryset() if self.request.user.is_staff and full: return sorted(list(logs) + list(diffs), key=lambda obj: obj.start) return Log.merge_diffusions(logs, diffs) class LogListView(AttachedToMixin, BaseView, LogListMixin, ListView): """Return list of logs for the provided date (from `kwargs` or `request.GET`, defaults to today).""" redirect_date_url = "log-list" date_delta = tz.timedelta(days=7) def get_date(self, param): date = super().get_date(param) return datetime.date.today() if date is None else date def get(self, request, **kwargs): min_date = self.get_date("min_date") max_date = self.get_date("max_date") # ensure right values for min and max min_date, max_date = min(min_date, max_date), max(min_date, max_date) # limit logs list size using date delta if min_date and max_date: max_date = min(min_date + self.date_delta, max_date) elif min_date: max_date = min_date + self.date_delta elif max_date: min_date = max_date - self.date_delta self.min_date = min_date self.max_date = max_date return super().get(request, **kwargs) def get_context_data(self, **kwargs): today = datetime.date.today() # `super()...` must be called before updating kwargs, in order # to get `self.object_list` kwargs = super().get_context_data(**kwargs) kwargs.update( { "min_date": self.min_date or today, "max_date": self.max_date or today, "today": datetime.date.today(), "date": self.date, "dates": (today - datetime.timedelta(days=i) for i in range(0, 7)), "object_list": self.get_object_list(self.object_list), } ) return kwargs # Logs are accessible through API only with this list view class LogListAPIView(LogListMixin, BaseAPIView, ListAPIView): """Return logs list, including diffusions. By default return logs of the last 30 minutes. Available GET parameters: - "date": return logs for a specified date ( - "full": (staff user only) don't merge diffusion and logs """ serializer_class = LogInfoSerializer queryset = Log.objects.all() @method_decorator(cache_page(5)) def list(self, *args, **kwargs): return super().list(*args, **kwargs) def get_date(self, param): date = super().get_date(param) if date is None: self.min_date = tz.now() - tz.timedelta(minutes=30) return date def get_object_list(self, logs, full): return [LogInfo(obj) for obj in super().get_object_list(logs, full)] def get_serializer(self, queryset, *args, **kwargs): full = bool(self.request.GET.get("full")) return super().get_serializer(self.get_object_list(queryset, full), *args, **kwargs)