diff --git a/bookwyrm/templates/settings/dashboard/dashboard.html b/bookwyrm/templates/settings/dashboard/dashboard.html index cec3e89ac..46d552fb1 100644 --- a/bookwyrm/templates/settings/dashboard/dashboard.html +++ b/bookwyrm/templates/settings/dashboard/dashboard.html @@ -37,6 +37,17 @@
+ {% if email_config_error %} +
+ + {% blocktrans trimmed %} + Your outgoing email address, {{ email_sender }}, may be misconfigured. + {% endblocktrans %} + {% trans "Check the EMAIL_SENDER_NAME and EMAIL_SENDER_DOMAIN in your .env." %} + +
+ {% endif %} + {% if reports %}
diff --git a/bookwyrm/views/admin/dashboard.py b/bookwyrm/views/admin/dashboard.py index b06b6ba00..df34fe5bf 100644 --- a/bookwyrm/views/admin/dashboard.py +++ b/bookwyrm/views/admin/dashboard.py @@ -1,5 +1,7 @@ """ instance overview """ from datetime import timedelta +import re + from dateutil.parser import parse from packaging import version @@ -13,6 +15,7 @@ from django.views import View from bookwyrm import models, settings from bookwyrm.connectors.abstract_connector import get_data from bookwyrm.connectors.connector_manager import ConnectorException +from bookwyrm.utils import regex # pylint: disable= no-self-use @@ -26,90 +29,18 @@ class Dashboard(View): def get(self, request): """list of users""" - interval = int(request.GET.get("days", 1)) - now = timezone.now() - start = request.GET.get("start") - if start: - start = timezone.make_aware(parse(start)) - else: - start = now - timedelta(days=6 * interval) + data = get_charts_and_stats(request) - end = request.GET.get("end") - end = timezone.make_aware(parse(end)) if end else now - start = start.replace(hour=0, minute=0, second=0) + # Make sure email looks properly configured + email_config_error = re.findall( + r"[\s\@]", settings.EMAIL_SENDER_DOMAIN + ) or not re.match(regex.DOMAIN, settings.EMAIL_SENDER_DOMAIN) - user_queryset = models.User.objects.filter(local=True) - user_chart = Chart( - queryset=user_queryset, - queries={ - "total": lambda q, s, e: q.filter( - Q(is_active=True) | Q(deactivation_date__gt=e), - created_date__lte=e, - ).count(), - "active": lambda q, s, e: q.filter( - Q(is_active=True) | Q(deactivation_date__gt=e), - created_date__lte=e, - ) - .filter( - last_active_date__gt=e - timedelta(days=31), - ) - .count(), - }, - ) - - status_queryset = models.Status.objects.filter(user__local=True, deleted=False) - status_chart = Chart( - queryset=status_queryset, - queries={ - "total": lambda q, s, e: q.filter( - created_date__gt=s, - created_date__lte=e, - ).count() - }, - ) - - register_chart = Chart( - queryset=user_queryset, - queries={ - "total": lambda q, s, e: q.filter( - created_date__gt=s, - created_date__lte=e, - ).count() - }, - ) - - works_chart = Chart( - queryset=models.Work.objects, - queries={ - "total": lambda q, s, e: q.filter( - created_date__gt=s, - created_date__lte=e, - ).count() - }, - ) - - data = { - "start": start.strftime("%Y-%m-%d"), - "end": end.strftime("%Y-%m-%d"), - "interval": interval, - "users": user_queryset.filter(is_active=True).count(), - "active_users": user_queryset.filter( - is_active=True, last_active_date__gte=now - timedelta(days=31) - ).count(), - "statuses": status_queryset.count(), - "works": models.Work.objects.count(), - "reports": models.Report.objects.filter(resolved=False).count(), - "pending_domains": models.LinkDomain.objects.filter( - status="pending" - ).count(), - "invite_requests": models.InviteRequest.objects.filter( - ignored=False, invite__isnull=True - ).count(), - "user_stats": user_chart.get_chart(start, end, interval), - "status_stats": status_chart.get_chart(start, end, interval), - "register_stats": register_chart.get_chart(start, end, interval), - "works_stats": works_chart.get_chart(start, end, interval), - } + data["email_config_error"] = email_config_error + # pylint: disable=line-too-long + data[ + "email_sender" + ] = f"{settings.EMAIL_SENDER_NAME}@{settings.EMAIL_SENDER_DOMAIN}" # check version try: @@ -126,6 +57,91 @@ class Dashboard(View): return TemplateResponse(request, "settings/dashboard/dashboard.html", data) +def get_charts_and_stats(request): + """Defines the dashbaord charts""" + interval = int(request.GET.get("days", 1)) + now = timezone.now() + start = request.GET.get("start") + if start: + start = timezone.make_aware(parse(start)) + else: + start = now - timedelta(days=6 * interval) + + end = request.GET.get("end") + end = timezone.make_aware(parse(end)) if end else now + start = start.replace(hour=0, minute=0, second=0) + + user_queryset = models.User.objects.filter(local=True) + user_chart = Chart( + queryset=user_queryset, + queries={ + "total": lambda q, s, e: q.filter( + Q(is_active=True) | Q(deactivation_date__gt=e), + created_date__lte=e, + ).count(), + "active": lambda q, s, e: q.filter( + Q(is_active=True) | Q(deactivation_date__gt=e), + created_date__lte=e, + ) + .filter( + last_active_date__gt=e - timedelta(days=31), + ) + .count(), + }, + ) + + status_queryset = models.Status.objects.filter(user__local=True, deleted=False) + status_chart = Chart( + queryset=status_queryset, + queries={ + "total": lambda q, s, e: q.filter( + created_date__gt=s, + created_date__lte=e, + ).count() + }, + ) + + register_chart = Chart( + queryset=user_queryset, + queries={ + "total": lambda q, s, e: q.filter( + created_date__gt=s, + created_date__lte=e, + ).count() + }, + ) + + works_chart = Chart( + queryset=models.Work.objects, + queries={ + "total": lambda q, s, e: q.filter( + created_date__gt=s, + created_date__lte=e, + ).count() + }, + ) + return { + "start": start.strftime("%Y-%m-%d"), + "end": end.strftime("%Y-%m-%d"), + "interval": interval, + "users": user_queryset.filter(is_active=True).count(), + "active_users": user_queryset.filter( + is_active=True, last_active_date__gte=now - timedelta(days=31) + ).count(), + "statuses": status_queryset.count(), + "works": models.Work.objects.count(), + "reports": models.Report.objects.filter(resolved=False).count(), + "pending_domains": models.LinkDomain.objects.filter(status="pending").count(), + "invite_requests": models.InviteRequest.objects.filter( + ignored=False, invite__isnull=True + ).count(), + "user_stats": user_chart.get_chart(start, end, interval), + "status_stats": status_chart.get_chart(start, end, interval), + "register_stats": register_chart.get_chart(start, end, interval), + "works_stats": works_chart.get_chart(start, end, interval), + } + + class Chart: """Data for a chart"""