feat: Add instance health check, allow clean locations for rescue orgs

This commit is contained in:
moanos [he/him] 2024-09-28 23:45:59 +02:00
parent 6f68d0cb51
commit cabb7f7181
6 changed files with 97 additions and 21 deletions

View File

@ -1,5 +1,6 @@
from django.core.management import BaseCommand from django.core.management import BaseCommand
from fellchensammlung.models import AdoptionNotice, Location from fellchensammlung.models import AdoptionNotice, Location
from fellchensammlung.tools.geo import clean_locations
class Command(BaseCommand): class Command(BaseCommand):
@ -14,19 +15,4 @@ class Command(BaseCommand):
) )
def handle(self, *args, **options): def handle(self, *args, **options):
adoption_notices_without_location = AdoptionNotice.objects.filter(location__isnull=True) clean_locations(quiet=False)
num_of_all = AdoptionNotice.objects.count()
num_without_location = adoption_notices_without_location.count()
print(f"From {num_of_all} there are {num_without_location} adoption notices without location "
f"({num_without_location/num_of_all*100:.2f}%)")
for adoption_notice in adoption_notices_without_location:
print(f"Searching {adoption_notice.location_string} in Nominatim")
location = Location.get_location_from_string(adoption_notice.location_string)
if location:
adoption_notice.location = location
adoption_notice.save()
adoption_notices_without_location_new = AdoptionNotice.objects.filter(location__isnull=True)
num_without_location_new = adoption_notices_without_location_new.count()
num_new = num_without_location - num_without_location_new
print(f"Added {num_new} new locations")

View File

@ -0,0 +1,15 @@
{% extends "fellchensammlung/base_generic.html" %}
{% load i18n %}
{% block content %}
<div class="card">
<h1>{% translate "Instanz-Check" %}</h1>
<p>{% translate "Nicht-lokalisierte Vermittlungen" %}: {{ number_not_geocoded_adoption_notices }}/{{ number_of_adoption_notices }}</p>
<p>{% translate "Nicht-lokalisierte Tierschutzorganisationen" %}: {{ number_not_geocoded_rescue_orgs }}/{{ number_of_rescue_orgs }}</p>
</div>
<form class="notification-card-mark-read" method="POST">
{% csrf_token %}
<input type="hidden" name="action" value="clean_locations">
<button class="btn2" type="submit" id="submit"><i class="fa-solid fa-broom"></i> {% translate "Erneut lokalisieren" %}</button>
</form>
{% endblock %}

View File

@ -0,0 +1,44 @@
from fellchensammlung.models import AdoptionNotice, Location, RescueOrganization
def clean_locations(quiet=True):
# ADOPTION NOTICES
adoption_notices_without_location = AdoptionNotice.objects.filter(location__isnull=True)
num_of_all = AdoptionNotice.objects.count()
num_without_location = adoption_notices_without_location.count()
if not quiet:
print(f"From {num_of_all} there are {num_without_location} adoption notices without location "
f"({num_without_location/num_of_all*100:.2f}%)")
for adoption_notice in adoption_notices_without_location:
if not quiet:
print(f"Searching {adoption_notice.location_string} in Nominatim")
location = Location.get_location_from_string(adoption_notice.location_string)
if location:
adoption_notice.location = location
adoption_notice.save()
adoption_notices_without_location_new = AdoptionNotice.objects.filter(location__isnull=True)
num_without_location_new = adoption_notices_without_location_new.count()
num_new = num_without_location - num_without_location_new
if not quiet:
print(f"Added {num_new} new locations")
# RESCUE ORGANIZATIONS
rescue_orgs_without_location = RescueOrganization.objects.filter(location__isnull=True)
num_of_all = RescueOrganization.objects.count()
num_without_location = rescue_orgs_without_location.count()
if not quiet:
print(f"From {num_of_all} there are {num_without_location} adoption notices without location "
f"({num_without_location/num_of_all*100:.2f}%)")
for rescue_org in rescue_orgs_without_location:
if not quiet:
print(f"Searching {rescue_org.location_string} in Nominatim")
location = Location.get_location_from_string(rescue_org.location_string)
if location:
rescue_org.location = location
rescue_org.save()
rescue_orgs_without_location_new = RescueOrganization.objects.filter(location__isnull=True)
num_without_location_new = rescue_orgs_without_location_new.count()
num_new = num_without_location - num_without_location_new
if not quiet:
print(f"Added {num_new} new locations")

View File

@ -1,11 +1,11 @@
import logging import logging
import requests import requests
import json import json
from math import radians, sqrt, sin, cos, atan2
from notfellchen import __version__ as nf_version from notfellchen import __version__ as nf_version
from notfellchen import settings from notfellchen import settings
from math import radians, sqrt, sin, cos, atan2
def calculate_distance_between_coordinates(position1, position2): def calculate_distance_between_coordinates(position1, position2):

View File

@ -59,6 +59,11 @@ urlpatterns = [
path('accounts/', include('django_registration.backends.activation.urls')), path('accounts/', include('django_registration.backends.activation.urls')),
path('accounts/', include('django.contrib.auth.urls')), path('accounts/', include('django.contrib.auth.urls')),
path('change-language', views.change_language, name="change-language") path('change-language', views.change_language, name="change-language"),
###########
## ADMIN ##
###########
path('instance-health-check', views.instance_health_check, name="instance-health-check")
] ]

View File

@ -6,20 +6,21 @@ from django.urls import reverse
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.utils import translation from django.utils import translation
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.contrib.auth.decorators import user_passes_test
from .mail import mail_admins_new_report from .mail import mail_admins_new_report
from notfellchen import settings from notfellchen import settings
from fellchensammlung import logger from fellchensammlung import logger
from .models import AdoptionNotice, Text, Animal, Rule, Image, Report, ModerationAction, \ from .models import AdoptionNotice, Text, Animal, Rule, Image, Report, ModerationAction, \
User, Location, AdoptionNoticeStatus, Subscriptions, CommentNotification, BaseNotification User, Location, AdoptionNoticeStatus, Subscriptions, CommentNotification, BaseNotification, RescueOrganization
from .forms import AdoptionNoticeForm, AdoptionNoticeFormWithDateWidget, ImageForm, ReportAdoptionNoticeForm, \ from .forms import AdoptionNoticeForm, AdoptionNoticeFormWithDateWidget, ImageForm, ReportAdoptionNoticeForm, \
CommentForm, ReportCommentForm, AnimalForm, \ CommentForm, ReportCommentForm, AnimalForm, \
AdoptionNoticeSearchForm, AnimalFormWithDateWidget AdoptionNoticeSearchForm, AnimalFormWithDateWidget
from .models import Language, Announcement from .models import Language, Announcement
from .tools.geo import GeoAPI from .tools.geo import GeoAPI
from .tools.metrics import gather_metrics_data from .tools.metrics import gather_metrics_data
from django.contrib.auth.decorators import user_passes_test from .tools.admin import clean_locations
def user_is_trust_level_or_above(user, trust_level=User.MODERATOR): def user_is_trust_level_or_above(user, trust_level=User.MODERATOR):
@ -411,3 +412,28 @@ def map(request):
def metrics(request): def metrics(request):
data = gather_metrics_data() data = gather_metrics_data()
return JsonResponse(data) return JsonResponse(data)
@login_required
def instance_health_check(request):
"""
Allows an administrator to check common problems of an instance
"""
if request.method == "POST":
action = request.POST.get("action")
if action == "clean_locations":
clean_locations(quiet=False)
number_of_adoption_notices = AdoptionNotice.objects.all().count()
number_not_geocoded_adoption_notices = AdoptionNotice.objects.filter(location__isnull=True).count()
number_of_rescue_orgs = RescueOrganization.objects.all().count()
number_not_geocoded_rescue_orgs = RescueOrganization.objects.filter(location__isnull=True).count()
context = {
"number_of_adoption_notices": number_of_adoption_notices,
"number_not_geocoded_adoption_notices": number_not_geocoded_adoption_notices,
"number_of_rescue_orgs": number_of_rescue_orgs,
"number_not_geocoded_rescue_orgs": number_not_geocoded_rescue_orgs
}
return render(request, 'fellchensammlung/instance-health-check.html', context=context)