feat: Add instance health check, allow clean locations for rescue orgs
This commit is contained in:
		@@ -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")
 | 
					 | 
				
			||||||
@@ -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 %}
 | 
				
			||||||
							
								
								
									
										44
									
								
								src/fellchensammlung/tools/admin.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/fellchensammlung/tools/admin.py
									
									
									
									
									
										Normal 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")
 | 
				
			||||||
@@ -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):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user