@ -33,6 +33,9 @@ class LogQuerySet(models.QuerySet):
 | 
			
		||||
    def after(self, date):
 | 
			
		||||
        return self.filter(date__gte=date) if isinstance(date, tz.datetime) else self.filter(date__date__gte=date)
 | 
			
		||||
 | 
			
		||||
    def before(self, date):
 | 
			
		||||
        return self.filter(date__lte=date) if isinstance(date, tz.datetime) else self.filter(date__date__lte=date)
 | 
			
		||||
 | 
			
		||||
    def on_air(self):
 | 
			
		||||
        return self.filter(type=Log.TYPE_ON_AIR)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -6,15 +6,20 @@
 | 
			
		||||
{% block content-container %}
 | 
			
		||||
<div class="container">
 | 
			
		||||
 | 
			
		||||
{# TODO: date subtitle #}
 | 
			
		||||
{% comment %}
 | 
			
		||||
<nav class="navbar" role="menu">
 | 
			
		||||
    {% with "admin:tools-stats" as url_name %}
 | 
			
		||||
    {% include "aircox/widgets/dates_menu.html" %}
 | 
			
		||||
    {% endwith %}
 | 
			
		||||
</nav>
 | 
			
		||||
{% endcomment %}
 | 
			
		||||
 | 
			
		||||
<form method="GET" class="box mt-3 mb-3">
 | 
			
		||||
    <h3 class="title is-3">{% translate "Filter by date" %}</h3>
 | 
			
		||||
    <div class="flex-row gap-3" style="align-items: flex-end">
 | 
			
		||||
        <div class="field mb-0">
 | 
			
		||||
            <label class="label">{% translate "from" %}</label>
 | 
			
		||||
            <input type="date" class="input" name="min_date" value="{{ min_date|date:"Y-m-d" }}"/>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="field mb-0">
 | 
			
		||||
            <label class="label">{% translate "... to" %}</label>
 | 
			
		||||
            <input type="date" class="input" name="max_date" value="{{ max_date|date:"Y-m-d" }}"/>
 | 
			
		||||
        </div>
 | 
			
		||||
        <button class="button">{% translate "Apply" %}</button>
 | 
			
		||||
    </div>
 | 
			
		||||
</form>
 | 
			
		||||
<a-statistics class="column">
 | 
			
		||||
<template v-slot="{counts}">
 | 
			
		||||
    <table class="table is-hoverable is-fullwidth">
 | 
			
		||||
@ -26,7 +31,14 @@
 | 
			
		||||
            </tr>
 | 
			
		||||
        </thead>
 | 
			
		||||
        <tbody>
 | 
			
		||||
        {% for object in object_list %}
 | 
			
		||||
        {% regroup object_list by date.date as by_date %}
 | 
			
		||||
        {% for date, objects in by_date %}
 | 
			
		||||
            <tr>
 | 
			
		||||
                <th colspan="3">
 | 
			
		||||
                    {{ date|date:"l - d F Y" }}
 | 
			
		||||
                </th>
 | 
			
		||||
            </tr>
 | 
			
		||||
            {% for object in objects %}
 | 
			
		||||
            {% with object|is_diffusion as is_diff %}
 | 
			
		||||
            {% if is_diff %}
 | 
			
		||||
            <tr class="bg-main">
 | 
			
		||||
@ -70,6 +82,8 @@
 | 
			
		||||
 | 
			
		||||
            {% endwith %}
 | 
			
		||||
            {% endfor %}
 | 
			
		||||
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
        </tbody>
 | 
			
		||||
        <tfoot>
 | 
			
		||||
            <tr>
 | 
			
		||||
 | 
			
		||||
@ -42,7 +42,7 @@ class DashboardView(DashboardBaseView, TemplateView):
 | 
			
		||||
class StatisticsView(DashboardBaseView, LogListView):
 | 
			
		||||
    template_name = "aircox/dashboard/statistics.html"
 | 
			
		||||
    date = None
 | 
			
		||||
    redirect_date_url = "dashboard-statistics"
 | 
			
		||||
    # redirect_date_url = "dashboard-statistics"
 | 
			
		||||
 | 
			
		||||
    # TOOD: test_func & perms check
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,35 +17,32 @@ __all__ = ("LogListMixin", "LogListView", "LogListAPIView")
 | 
			
		||||
class LogListMixin(GetDateMixin):
 | 
			
		||||
    model = Log
 | 
			
		||||
    min_date = None
 | 
			
		||||
    max_date = None
 | 
			
		||||
 | 
			
		||||
    def get_date(self):
 | 
			
		||||
        date = super().get_date()
 | 
			
		||||
    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.
 | 
			
		||||
        qs = super().get_queryset().on_air().filter(track__isnull=False).filter(date__lte=tz.now())
 | 
			
		||||
        return (
 | 
			
		||||
            qs.date(self.date)
 | 
			
		||||
            if self.date is not None
 | 
			
		||||
            else qs.after(self.min_date)
 | 
			
		||||
            if self.min_date is not None
 | 
			
		||||
            else qs
 | 
			
		||||
        )
 | 
			
		||||
        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):
 | 
			
		||||
        qs = Diffusion.objects.station(self.station).on_air().filter(start__lte=tz.now()).before()
 | 
			
		||||
 | 
			
		||||
        return (
 | 
			
		||||
            qs.date(self.date)
 | 
			
		||||
            if self.date is not None
 | 
			
		||||
            else qs.after(self.min_date)
 | 
			
		||||
            if self.min_date is not None
 | 
			
		||||
            else qs
 | 
			
		||||
        )
 | 
			
		||||
        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.
 | 
			
		||||
@ -55,7 +52,6 @@ class LogListMixin(GetDateMixin):
 | 
			
		||||
        diffs = self.get_diffusions_queryset()
 | 
			
		||||
        if self.request.user.is_staff and full:
 | 
			
		||||
            return sorted(list(logs) + list(diffs), key=lambda obj: obj.start)
 | 
			
		||||
        print(">>>>", len(logs), len(diffs), Log.merge_diffusions(logs, diffs))
 | 
			
		||||
        return Log.merge_diffusions(logs, diffs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -64,11 +60,31 @@ class LogListView(AttachedToMixin, BaseView, LogListMixin, ListView):
 | 
			
		||||
    `request.GET`, defaults to today)."""
 | 
			
		||||
 | 
			
		||||
    redirect_date_url = "log-list"
 | 
			
		||||
    date_delta = tz.timedelta(days=7)
 | 
			
		||||
 | 
			
		||||
    def get_date(self):
 | 
			
		||||
        date = super().get_date()
 | 
			
		||||
    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
 | 
			
		||||
@ -76,6 +92,9 @@ class LogListView(AttachedToMixin, BaseView, LogListMixin, ListView):
 | 
			
		||||
        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),
 | 
			
		||||
@ -101,8 +120,8 @@ class LogListAPIView(LogListMixin, BaseAPIView, ListAPIView):
 | 
			
		||||
    def list(self, *args, **kwargs):
 | 
			
		||||
        return super().list(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def get_date(self):
 | 
			
		||||
        date = super().get_date()
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
@ -12,9 +12,9 @@ class GetDateMixin:
 | 
			
		||||
    date = None
 | 
			
		||||
    redirect_date_url = None
 | 
			
		||||
 | 
			
		||||
    def get_date(self):
 | 
			
		||||
        date = self.request.GET.get("date")
 | 
			
		||||
        return str_to_date(date, "-") if date is not None else self.kwargs["date"] if "date" in self.kwargs else None
 | 
			
		||||
    def get_date(self, param):
 | 
			
		||||
        date = self.request.GET.get(param)
 | 
			
		||||
        return str_to_date(date, "-") if date else self.kwargs[param] if param in self.kwargs else None
 | 
			
		||||
 | 
			
		||||
    def get(self, *args, **kwargs):
 | 
			
		||||
        if self.redirect_date_url and self.request.GET.get("date"):
 | 
			
		||||
@ -23,7 +23,7 @@ class GetDateMixin:
 | 
			
		||||
                date=self.request.GET["date"].replace("-", "/"),
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        self.date = self.get_date()
 | 
			
		||||
        self.date = self.get_date("date")
 | 
			
		||||
        return super().get(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user