Compare commits

..

No commits in common. "8de5f162eb46a7737a779abfad635acd8458d24a" and "3eb7dbe9843dfa6fecf653477d59464e8e557936" have entirely different histories.

7 changed files with 32 additions and 116 deletions

View File

@ -1,7 +1,7 @@
from django import forms from django import forms
from .models import AdoptionNotice, Animal, Image, ReportAdoptionNotice, ReportComment, ModerationAction, User, Species, \ from .models import AdoptionNotice, Animal, Image, ReportAdoptionNotice, ReportComment, ModerationAction, User, Species, \
Comment, SexChoicesWithAll Comment
from django_registration.forms import RegistrationForm from django_registration.forms import RegistrationForm
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit, Layout, Fieldset, HTML, Row, Column, Field, Hidden from crispy_forms.layout import Submit, Layout, Fieldset, HTML, Row, Column, Field, Hidden
@ -66,8 +66,7 @@ class AdoptionNoticeForm(forms.ModelForm):
class AdoptionNoticeFormWithDateWidget(AdoptionNoticeForm): class AdoptionNoticeFormWithDateWidget(AdoptionNoticeForm):
class Meta: class Meta:
model = AdoptionNotice model = AdoptionNotice
fields = ['name', "group_only", "further_information", "description", "searching_since", "location_string", fields = ['name', "group_only", "further_information", "description", "searching_since", "location_string", "organization"]
"organization"]
widgets = { widgets = {
'searching_since': DateInput(), 'searching_since': DateInput(),
} }
@ -186,7 +185,5 @@ def _get_distances():
class AdoptionNoticeSearchForm(forms.Form): class AdoptionNoticeSearchForm(forms.Form):
location = forms.CharField(max_length=20, label=_("Stadt"), required=False) location = forms.CharField(max_length=20, label=_("Stadt"))
max_distance = forms.ChoiceField(choices=_get_distances, label=_("Max. Distanz")) max_distance = forms.ChoiceField(choices=_get_distances, label=_("Max. Distanz"))
sex = forms.ChoiceField(choices=SexChoicesWithAll, label=_("Geschlecht"), required=False,
initial=SexChoicesWithAll.ALL)

View File

@ -1,18 +0,0 @@
# Generated by Django 5.1.1 on 2024-11-21 19:34
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('fellchensammlung', '0023_user_email_notifications'),
]
operations = [
migrations.AlterField(
model_name='animal',
name='sex',
field=models.CharField(choices=[('M_N', 'neutered male'), ('M', 'male'), ('F_N', 'neutered female'), ('F', 'female'), ('I', 'intersex')], max_length=20),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 5.1.1 on 2024-11-21 19:41
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('fellchensammlung', '0024_alter_animal_sex'),
]
operations = [
migrations.AlterField(
model_name='animal',
name='sex',
field=models.CharField(choices=[('F', 'Weiblich'), ('M', 'Männlich'), ('M_N', 'Männlich, kastriert'), ('F_N', 'Weiblich Kastriert'), ('I', 'Intersex')], max_length=20),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 5.1.1 on 2024-11-21 21:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('fellchensammlung', '0025_alter_animal_sex'),
]
operations = [
migrations.AlterField(
model_name='animal',
name='sex',
field=models.CharField(choices=[('F', 'Weiblich'), ('M', 'Männlich'), ('M_N', 'Männlich, kastriert'), ('F_N', 'Weiblich, kastriert'), ('I', 'Intergeschlechtlich')], max_length=20),
),
]

View File

@ -240,18 +240,15 @@ class AdoptionNotice(models.Model):
def sexes(self): def sexes(self):
sexes = set() sexes = set()
for animal in self.animals: for animal in self.animals:
sexes.add(animal.sex) sexes.update(animal.sex)
return sexes return sexes
def sex_code(self): def sex_code(self):
# Treat Intersex as mixed in order to increase their visibility
if len(self.sexes) > 1: if len(self.sexes) > 1:
return "mixed" return "mixed"
elif self.sexes.pop() == Animal.MALE:
sex = self.sexes.pop()
if sex == SexChoices.MALE:
return "male" return "male"
elif sex == SexChoices.FEMALE: elif self.sexes.pop() == Animal.FEMALE:
return "female" return "female"
else: else:
return "mixed" return "mixed"
@ -351,26 +348,18 @@ class AdoptionNotice(models.Model):
def set_closed(self): def set_closed(self):
self.last_checked = timezone.now() self.last_checked = timezone.now()
self.adoptionnoticestatus.set_closed() self.adoptionnoticestatus.set_closed()
self.save()
def set_active(self): def set_active(self):
self.last_checked = timezone.now() self.last_checked = timezone.now()
if not hasattr(self, 'adoptionnoticestatus'): if not hasattr(self, 'adoptionnoticestatus'):
AdoptionNoticeStatus.create_other(self) AdoptionNoticeStatus.create_other(self)
self.adoptionnoticestatus.set_active() self.adoptionnoticestatus.set_active()
self.save()
def set_unchecked(self): def set_unchecked(self):
self.last_checked = timezone.now() self.last_checked = timezone.now()
if not hasattr(self, 'adoptionnoticestatus'): if not hasattr(self, 'adoptionnoticestatus'):
AdoptionNoticeStatus.create_other(self) AdoptionNoticeStatus.create_other(self)
self.adoptionnoticestatus.set_unchecked() self.adoptionnoticestatus.set_unchecked()
self.save()
for subscription in self.get_subscriptions():
notification_title = _("Vermittlung deaktiviert:") + f" {self}"
text = _("Die folgende Vermittlung wurde deaktiviert: ") + f"{self.name}, {self.get_absolute_url()}"
BaseNotification.objects.create(user=subscription.owner, text=text, title=notification_title)
class AdoptionNoticeStatus(models.Model): class AdoptionNoticeStatus(models.Model):
@ -468,33 +457,24 @@ class AdoptionNoticeStatus(models.Model):
self.save() self.save()
class SexChoices(models.TextChoices):
FEMALE = "F", _("Weiblich")
MALE = "M", _("Männlich")
MALE_NEUTERED = "M_N", _("Männlich, kastriert")
FEMALE_NEUTERED = "F_N", _("Weiblich, kastriert")
INTER = "I", _("Intergeschlechtlich")
class SexChoicesWithAll(models.TextChoices):
FEMALE = "F", _("Weiblich")
MALE = "M", _("Männlich")
MALE_NEUTERED = "M_N", _("Männlich, kastriert")
FEMALE_NEUTERED = "F_N", _("Weiblich Kastriert")
INTER = "I", _("Intergeschlechtlich")
ALL = "A", _("Alle")
class Animal(models.Model): class Animal(models.Model):
MALE_NEUTERED = "M_N"
MALE = "M"
FEMALE_NEUTERED = "F_N"
FEMALE = "F"
SEX_CHOICES = {
MALE_NEUTERED: "neutered male",
MALE: "male",
FEMALE_NEUTERED: "neutered female",
FEMALE: "female",
}
date_of_birth = models.DateField(verbose_name=_('Geburtsdatum')) date_of_birth = models.DateField(verbose_name=_('Geburtsdatum'))
name = models.CharField(max_length=200) name = models.CharField(max_length=200)
description = models.TextField(null=True, blank=True, verbose_name=_('Beschreibung')) description = models.TextField(null=True, blank=True, verbose_name=_('Beschreibung'))
species = models.ForeignKey(Species, on_delete=models.PROTECT) species = models.ForeignKey(Species, on_delete=models.PROTECT)
photos = models.ManyToManyField(Image, blank=True) photos = models.ManyToManyField(Image, blank=True)
sex = models.CharField( sex = models.CharField(max_length=20, choices=SEX_CHOICES, )
max_length=20,
choices=SexChoices.choices,
)
adoption_notice = models.ForeignKey(AdoptionNotice, on_delete=models.CASCADE) adoption_notice = models.ForeignKey(AdoptionNotice, on_delete=models.CASCADE)
owner = models.ForeignKey(User, on_delete=models.CASCADE) owner = models.ForeignKey(User, on_delete=models.CASCADE)
updated_at = models.DateTimeField(auto_now=True) updated_at = models.DateTimeField(auto_now=True)

View File

@ -16,7 +16,7 @@ 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, RescueOrganization, \ User, Location, AdoptionNoticeStatus, Subscriptions, CommentNotification, BaseNotification, RescueOrganization, \
Species, Log, Timestamp, TrustLevel, SexChoicesWithAll Species, Log, Timestamp, TrustLevel
from .forms import AdoptionNoticeForm, AdoptionNoticeFormWithDateWidget, ImageForm, ReportAdoptionNoticeForm, \ from .forms import AdoptionNoticeForm, AdoptionNoticeFormWithDateWidget, ImageForm, ReportAdoptionNoticeForm, \
CommentForm, ReportCommentForm, AnimalForm, \ CommentForm, ReportCommentForm, AnimalForm, \
AdoptionNoticeSearchForm, AnimalFormWithDateWidget, AdoptionNoticeFormWithDateWidgetAutoAnimal AdoptionNoticeSearchForm, AnimalFormWithDateWidget, AdoptionNoticeFormWithDateWidgetAutoAnimal
@ -169,20 +169,11 @@ def animal_detail(request, animal_id):
def search(request): def search(request):
place_not_found = None place_not_found = None
if request.method == 'POST':
latest_adoption_list = AdoptionNotice.objects.order_by("-created_at") latest_adoption_list = AdoptionNotice.objects.order_by("-created_at")
active_adoptions = [adoption for adoption in latest_adoption_list if adoption.is_active] active_adoptions = [adoption for adoption in latest_adoption_list if adoption.is_active]
if request.method == 'POST':
sex = request.POST.get("sex")
if sex != SexChoicesWithAll.ALL:
active_adoptions = [adoption for adoption in active_adoptions if sex in adoption.sexes]
search_form = AdoptionNoticeSearchForm(request.POST) search_form = AdoptionNoticeSearchForm(request.POST)
search_form.is_valid()
if search_form.cleaned_data["location"] == "":
adoption_notices_in_distance = active_adoptions
place_not_found = False
else:
max_distance = int(request.POST.get('max_distance')) max_distance = int(request.POST.get('max_distance'))
if max_distance == "": if max_distance == "":
max_distance = None max_distance = None
@ -197,6 +188,8 @@ def search(request):
context = {"adoption_notices": adoption_notices_in_distance, "search_form": search_form, context = {"adoption_notices": adoption_notices_in_distance, "search_form": search_form,
"place_not_found": place_not_found} "place_not_found": place_not_found}
else: else:
latest_adoption_list = AdoptionNotice.objects.order_by("-created_at")
active_adoptions = [adoption for adoption in latest_adoption_list if adoption.is_active]
search_form = AdoptionNoticeSearchForm() search_form = AdoptionNoticeSearchForm()
context = {"adoption_notices": active_adoptions, "search_form": search_form} context = {"adoption_notices": active_adoptions, "search_form": search_form}
return render(request, 'fellchensammlung/search.html', context=context) return render(request, 'fellchensammlung/search.html', context=context)

View File

@ -120,7 +120,7 @@ class SearchTest(TestCase):
self.assertNotContains(response, "TestAdoption2") self.assertNotContains(response, "TestAdoption2")
def test_plz_search(self): def test_plz_search(self):
response = self.client.post(reverse('search'), {"max_distance": 100, "location": "Berlin", "sex": "A"}) response = self.client.post(reverse('search'), {"max_distance": 100, "location": "Berlin"})
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertContains(response, "TestAdoption1") self.assertContains(response, "TestAdoption1")
self.assertNotContains(response, "TestAdoption3") self.assertNotContains(response, "TestAdoption3")