diff --git a/src/fellchensammlung/forms.py b/src/fellchensammlung/forms.py index ded4274..246fc03 100644 --- a/src/fellchensammlung/forms.py +++ b/src/fellchensammlung/forms.py @@ -40,6 +40,7 @@ class AdoptionNoticeForm(forms.ModelForm): 'name', 'group_only', 'searching_since', + 'location_string', 'description', 'further_information', ), @@ -47,7 +48,7 @@ class AdoptionNoticeForm(forms.ModelForm): class Meta: model = AdoptionNotice - fields = ['name', "group_only", "further_information", "description", "searching_since"] + fields = ['name', "group_only", "further_information", "description", "searching_since", "location_string"] class AnimalForm(forms.ModelForm): diff --git a/src/fellchensammlung/migrations/0007_remove_location_country_remove_location_description_and_more.py b/src/fellchensammlung/migrations/0007_remove_location_country_remove_location_description_and_more.py new file mode 100644 index 0000000..891e891 --- /dev/null +++ b/src/fellchensammlung/migrations/0007_remove_location_country_remove_location_description_and_more.py @@ -0,0 +1,81 @@ +# Generated by Django 5.0.6 on 2024-06-05 13:19 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("fellchensammlung", "0006_announcement_type"), + ] + + operations = [ + migrations.RemoveField( + model_name="location", + name="country", + ), + migrations.RemoveField( + model_name="location", + name="description", + ), + migrations.RemoveField( + model_name="location", + name="postcode", + ), + migrations.AddField( + model_name="adoptionnotice", + name="location", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="fellchensammlung.location", + ), + ), + migrations.AddField( + model_name="adoptionnotice", + name="location_string", + field=models.CharField( + default="72072", max_length=200, verbose_name="Ortsangabe" + ), + preserve_default=False, + ), + migrations.AddField( + model_name="location", + name="latitude", + field=models.FloatField(default=47), + preserve_default=False, + ), + migrations.AddField( + model_name="location", + name="longitude", + field=models.FloatField(default=9), + preserve_default=False, + ), + migrations.AddField( + model_name="location", + name="osm_id", + field=models.IntegerField(default=1), + preserve_default=False, + ), + migrations.AddField( + model_name="location", + name="place_id", + field=models.IntegerField(default=1), + preserve_default=False, + ), + migrations.AddField( + model_name="rescueorganization", + name="location_string", + field=models.CharField( + default="72072", max_length=200, verbose_name="Ort der Organisation" + ), + preserve_default=False, + ), + migrations.AlterField( + model_name="location", + name="name", + field=models.CharField(max_length=2000), + ), + ] diff --git a/src/fellchensammlung/models.py b/src/fellchensammlung/models.py index 71748d4..4d32797 100644 --- a/src/fellchensammlung/models.py +++ b/src/fellchensammlung/models.py @@ -66,19 +66,11 @@ class Location(models.Model): def __str__(self): return f"{self.name}" - GERMANY = "DE" - AUSTRIA = "AT" - SWITZERLAND = "CH" - COUNTRIES_CHOICES = { - GERMANY: "Germany", - AUSTRIA: "Austria", - SWITZERLAND: "Switzerland" - } - - name = models.CharField(max_length=200) - postcode = models.CharField(max_length=200) - country = models.CharField(max_length=20, choices=COUNTRIES_CHOICES) - description = models.TextField(null=True, blank=True, verbose_name=_('Beschreibung')) + place_id = models.IntegerField() + osm_id = models.IntegerField() + latitude = models.FloatField() + longitude = models.FloatField() + name = models.CharField(max_length=2000) class RescueOrganization(models.Model): @@ -87,6 +79,7 @@ class RescueOrganization(models.Model): name = models.CharField(max_length=200) trusted = models.BooleanField(default=False, verbose_name=_('Vertrauenswürdig')) + location_string = models.CharField(max_length=200, verbose_name=_("Ort der Organisation")) location = models.ForeignKey(Location, on_delete=models.PROTECT) instagram = models.URLField(null=True, blank=True, verbose_name=_('Instagram Profil')) facebook = models.URLField(null=True, blank=True, verbose_name=_('Facebook Profil')) @@ -112,6 +105,8 @@ class AdoptionNotice(models.Model): further_information = models.URLField(null=True, blank=True, verbose_name=_('Link zu mehr Informationen')) group_only = models.BooleanField(default=False, verbose_name=_('Ausschließlich Gruppenadoption')) photos = models.ManyToManyField(Image, blank=True) + location_string = models.CharField(max_length=200, verbose_name=_("Ortsangabe")) + location = models.ForeignKey(Location, blank=True, null=True, on_delete=models.SET_NULL,) @property def animals(self): diff --git a/src/fellchensammlung/tools/geo.py b/src/fellchensammlung/tools/geo.py index 5acce58..77c4d0a 100644 --- a/src/fellchensammlung/tools/geo.py +++ b/src/fellchensammlung/tools/geo.py @@ -1,6 +1,7 @@ import requests import json from notfellchen import __version__ as nf_version +from fellchensammlung.models import Location from math import radians, sqrt, sin, cos, atan2 @@ -21,13 +22,15 @@ def calculate_distance_between_coordinates(position1, position2): distance_lat = radians(latitude2 - latitude1) distance_long = radians(longitude2 - longitude1) - a = pow(sin(distance_lat / 2), 2) + cos(radians(latitude1)) * cos(radians(latitude2)) * pow(sin(distance_long / 2), 2) + a = pow(sin(distance_lat / 2), 2) + cos(radians(latitude1)) * cos(radians(latitude2)) * pow(sin(distance_long / 2), + 2) c = 2 * atan2(sqrt(a), sqrt(1 - a)) distance_in_km = earth_radius_km * c return distance_in_km + class ResponseMock: content = b'[{"place_id":138181499,"licence":"Data \xc2\xa9 OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright","osm_type":"relation","osm_id":1247237,"lat":"48.4949904","lon":"9.040330235970146","category":"boundary","type":"postal_code","place_rank":21, "importance":0.12006895017929346,"addresstype":"postcode","name":"72072","display_name":"72072, Derendingen, T\xc3\xbcbingen, Landkreis T\xc3\xbcbingen, Baden-W\xc3\xbcrttemberg, Deutschland", "boundingbox":["48.4949404","48.4950404","9.0402802","9.0403802"]}]' status_code = 200 @@ -43,21 +46,33 @@ class RequestMock: class GeoAPI: + api_url = "https://nominatim.openstreetmap.org/search" + headers = { + 'User-Agent': f"Notfellchen {nf_version}", + 'From': 'info@notfellchen.org' # This is another valid field + } + def __init__(self, debug=True): - self.api_url = "https://nominatim.openstreetmap.org/search" if debug: self.requests = RequestMock else: self.requests = requests def get_coordinates_from_postcode(self, postcode): - headers = { - 'User-Agent': f"Notfellchen {nf_version}", - 'From': 'info@notfellchen.org' # This is another valid field - } - result = self.requests.get(self.api_url, {"q": postcode, "format": "jsonv2"}, headers=headers).json()[0] + result = self.requests.get(self.api_url, {"q": postcode, "format": "jsonv2"}, headers=self.headers).json()[0] return result["lat"], result["lon"] + def get_location_from_string(self, location_string): + result = self.requests.get(self.api_url, {"q": location_string, "format": "jsonv2"}, headers=self.headers).json()[0] + location = Location.objects.create( + place_id=result["place_id"], + osm_id=result["osm_id"], + latitude=result["lat"], + longitude=result["lon"], + name=result["name"], + ) + return location + if __name__ == "__main__": geo = GeoAPI(debug=True) diff --git a/src/fellchensammlung/urls.py b/src/fellchensammlung/urls.py index 5c251f2..42a9b7d 100644 --- a/src/fellchensammlung/urls.py +++ b/src/fellchensammlung/urls.py @@ -27,7 +27,7 @@ urlpatterns = [ # ex: /search/ path("suchen/", views.search, name="search"), # ex: /vermitteln/ - path("vermitteln/", views.add_adoption, name="add-adoption"), + path("vermitteln/", views.add_adoption_notice, name="add-adoption"), path("ueber-uns/", views.about, name="about"), diff --git a/src/fellchensammlung/views.py b/src/fellchensammlung/views.py index 229ad9d..e1e4ad9 100644 --- a/src/fellchensammlung/views.py +++ b/src/fellchensammlung/views.py @@ -15,6 +15,7 @@ from fellchensammlung.models import AdoptionNotice, Text, Animal, Rule, Image, R Member from .forms import AdoptionNoticeForm, ImageForm, ReportAdoptionNoticeForm, CommentForm, ReportCommentForm, AnimalForm from .models import Language, Announcement +from .tools.geo import GeoAPI def index(request): @@ -93,12 +94,19 @@ def search(request): @login_required -def add_adoption(request): +def add_adoption_notice(request): if request.method == 'POST': form = AdoptionNoticeForm(request.POST, request.FILES, in_adoption_notice_creation_flow=True) if form.is_valid(): instance = form.save() + + """Search the location given in the location string and add it to the adoption notice""" + geo_api = GeoAPI(debug=True) + location = geo_api.get_location_from_string(instance.location_string) + instance.location = location + instance.save() + return redirect(reverse("adoption-notice-add-animal", args=[instance.pk])) else: form = AdoptionNoticeForm(in_adoption_notice_creation_flow=True)