Skip to content

Commit

Permalink
App BEMAS: Betreiber:innen von Verursachern können sowohl Organisatio…
Browse files Browse the repository at this point in the history
…nen als auch Personen sein; Selects mit Autocompletion (#25)
  • Loading branch information
gdmhrogut authored Aug 31, 2023
1 parent b2081c3 commit fe9fec0
Show file tree
Hide file tree
Showing 17 changed files with 177 additions and 92 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ Für die App *BEMAS* kann optional ein Cronjob eingerichtet werden, der folgende

python manage.py deletepersons

Dieser Befehl führt dazu, dass alle Personen gelöscht werden, die nicht als Ansprechpartner:innen mit Organisationen verknüpft sind und die als Beschwerdeführer:innen nur noch mit Beschwerden verknüpft sind, die seit `BEMAS_STATUS_CHANGE_DEADLINE_DAYS` (siehe `secrets.template`) abgeschlossen sind.
Dieser Befehl führt dazu, dass alle Personen gelöscht werden, die nicht als Ansprechpartner:innen mit Organisationen verknüpft sind, nicht als Betreiber:innen mit Verursachern verknüpft sind und die als Beschwerdeführer:innen nur noch mit Beschwerden verknüpft sind, die seit `BEMAS_STATUS_CHANGE_DEADLINE_DAYS` (siehe `secrets.template`) abgeschlossen sind.

## Entwicklung

Expand Down
6 changes: 3 additions & 3 deletions bemas/management/commands/deletepersons.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.core.management.base import BaseCommand

from bemas.models import Complaint, Contact, Person
from bemas.models import Complaint, Contact, Originator, Person
from bemas.utils import get_orphaned_persons
from bemas.views.functions import create_log_entry

Expand All @@ -9,8 +9,8 @@ class Command(BaseCommand):

def handle(self, *args, **options):
# get persons to be deleted
# (i.e. persons not connected to contacts and active complaints)
persons_delete = get_orphaned_persons(Complaint, Contact, Person)
# (i.e. persons not connected to any contacts and any originators and any active complaints)
persons_delete = get_orphaned_persons(Complaint, Contact, Originator, Person)
num_deleted = 0
for person_delete in persons_delete:
object_pk, content = person_delete.pk, str(person_delete)
Expand Down
11 changes: 6 additions & 5 deletions bemas/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 4.2.4 on 2023-08-18 10:37
# Generated by Django 4.2.4 on 2023-08-31 10:24

import datenmanagement.models.fields
import datetime
Expand Down Expand Up @@ -72,7 +72,7 @@ class Migration(migrations.Migration):
('search_content', models.CharField(blank=True, editable=False, max_length=255, null=True)),
('name', models.CharField(max_length=255, unique=True, validators=[django.core.validators.RegexValidator(message='Texte dürfen keine Akute (´) enthalten. Stattdessen muss der typographisch korrekte Apostroph (’) verwendet werden.', regex='^(?!.*´).*$'), django.core.validators.RegexValidator(message='Texte dürfen keine doppelten Schreibmaschinensatz-Anführungszeichen (") enthalten. Stattdessen müssen die typographisch korrekten Anführungszeichen („“) verwendet werden.', regex='^(?!.*\\").*$'), django.core.validators.RegexValidator(message="Texte dürfen keine einfachen Schreibmaschinensatz-Anführungszeichen (') enthalten. Stattdessen muss der typographisch korrekte Apostroph(’) verwendet werden.", regex="^(?!.*\\').*$"), django.core.validators.RegexValidator(message='Texte dürfen keine doppelten Leerzeichen und/oder Zeilenumbrüche enthalten.', regex='^(?!.* ).*$'), django.core.validators.RegexValidator(message='Texte dürfen keine Gravis (`) enthalten. Stattdessen muss der typographisch korrekte Apostroph (’) verwendet werden.', regex='^(?!.*`).*$')], verbose_name='Name')),
('address_street', models.CharField(blank=True, max_length=255, null=True, validators=[django.core.validators.RegexValidator(message='Texte dürfen keine Akute (´) enthalten. Stattdessen muss der typographisch korrekte Apostroph (’) verwendet werden.', regex='^(?!.*´).*$'), django.core.validators.RegexValidator(message='Texte dürfen keine doppelten Schreibmaschinensatz-Anführungszeichen (") enthalten. Stattdessen müssen die typographisch korrekten Anführungszeichen („“) verwendet werden.', regex='^(?!.*\\").*$'), django.core.validators.RegexValidator(message="Texte dürfen keine einfachen Schreibmaschinensatz-Anführungszeichen (') enthalten. Stattdessen muss der typographisch korrekte Apostroph(’) verwendet werden.", regex="^(?!.*\\').*$"), django.core.validators.RegexValidator(message='Texte dürfen keine doppelten Leerzeichen und/oder Zeilenumbrüche enthalten.', regex='^(?!.* ).*$'), django.core.validators.RegexValidator(message='Texte dürfen keine Gravis (`) enthalten. Stattdessen muss der typographisch korrekte Apostroph (’) verwendet werden.', regex='^(?!.*`).*$')], verbose_name='Straße')),
('address_house_number', models.CharField(blank=True, max_length=4, null=True, validators=[django.core.validators.RegexValidator(message='Die <strong><em>Hausnummer</em></strong> muss eine Zahl zwischen 1 und 999 sein, optional gefolgt von einem Kleinbuchstaben.', regex='^[1-9][0-9]{0,2}[a-z]?$')], verbose_name='Hausnummer')),
('address_house_number', models.CharField(blank=True, max_length=4, null=True, validators=[django.core.validators.RegexValidator(message='Die <strong><em>Hausnummer</em></strong> muss eine Zahl zwischen 1 und 999 sein, optional direkt gefolgt von einem Kleinbuchstaben.', regex='^[1-9][0-9]{0,2}[a-z]?$')], verbose_name='Hausnummer')),
('address_postal_code', models.CharField(blank=True, max_length=5, null=True, validators=[django.core.validators.RegexValidator(message='Die <strong><em>Postleitzahl</em></strong> muss aus genau fünf Ziffern bestehen.', regex='^[0-9]{5}$')], verbose_name='Postleitzahl')),
('address_place', models.CharField(blank=True, max_length=255, null=True, validators=[django.core.validators.RegexValidator(message='Texte dürfen keine Akute (´) enthalten. Stattdessen muss der typographisch korrekte Apostroph (’) verwendet werden.', regex='^(?!.*´).*$'), django.core.validators.RegexValidator(message='Texte dürfen keine doppelten Schreibmaschinensatz-Anführungszeichen (") enthalten. Stattdessen müssen die typographisch korrekten Anführungszeichen („“) verwendet werden.', regex='^(?!.*\\").*$'), django.core.validators.RegexValidator(message="Texte dürfen keine einfachen Schreibmaschinensatz-Anführungszeichen (') enthalten. Stattdessen muss der typographisch korrekte Apostroph(’) verwendet werden.", regex="^(?!.*\\').*$"), django.core.validators.RegexValidator(message='Texte dürfen keine doppelten Leerzeichen und/oder Zeilenumbrüche enthalten.', regex='^(?!.* ).*$'), django.core.validators.RegexValidator(message='Texte dürfen keine Gravis (`) enthalten. Stattdessen muss der typographisch korrekte Apostroph (’) verwendet werden.', regex='^(?!.*`).*$')], verbose_name='Ort')),
('email_addresses', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, max_length=255, null=True, validators=[django.core.validators.EmailValidator(message='E-Mail-Adressen müssen syntaktisch korrekt sein und daher folgendes Format aufweisen (Beispiele): abc@def.xyz oder 1cba_mno.asff@xy.a23c.zy')], verbose_name='E-Mail-Adresse(n)'), blank=True, null=True, size=None, verbose_name='E-Mail-Adresse(n)')),
Expand All @@ -98,7 +98,7 @@ class Migration(migrations.Migration):
('first_name', models.CharField(blank=True, max_length=255, null=True, validators=[django.core.validators.RegexValidator(message='Texte dürfen keine Akute (´) enthalten. Stattdessen muss der typographisch korrekte Apostroph (’) verwendet werden.', regex='^(?!.*´).*$'), django.core.validators.RegexValidator(message='Texte dürfen keine doppelten Schreibmaschinensatz-Anführungszeichen (") enthalten. Stattdessen müssen die typographisch korrekten Anführungszeichen („“) verwendet werden.', regex='^(?!.*\\").*$'), django.core.validators.RegexValidator(message="Texte dürfen keine einfachen Schreibmaschinensatz-Anführungszeichen (') enthalten. Stattdessen muss der typographisch korrekte Apostroph(’) verwendet werden.", regex="^(?!.*\\').*$"), django.core.validators.RegexValidator(message='Texte dürfen keine doppelten Leerzeichen und/oder Zeilenumbrüche enthalten.', regex='^(?!.* ).*$'), django.core.validators.RegexValidator(message='Texte dürfen keine Gravis (`) enthalten. Stattdessen muss der typographisch korrekte Apostroph (’) verwendet werden.', regex='^(?!.*`).*$'), django.core.validators.RegexValidator(message='Im Text darf nach einem Bindestrich kein Leerzeichen stehen.', regex='^(?!.*- ).*$'), django.core.validators.RegexValidator(message='Im Text darf vor einem Bindestrich kein Leerzeichen stehen.', regex='^(?!.* -).*$')], verbose_name='Vorname')),
('last_name', models.CharField(max_length=255, validators=[django.core.validators.RegexValidator(message='Texte dürfen keine Akute (´) enthalten. Stattdessen muss der typographisch korrekte Apostroph (’) verwendet werden.', regex='^(?!.*´).*$'), django.core.validators.RegexValidator(message='Texte dürfen keine doppelten Schreibmaschinensatz-Anführungszeichen (") enthalten. Stattdessen müssen die typographisch korrekten Anführungszeichen („“) verwendet werden.', regex='^(?!.*\\").*$'), django.core.validators.RegexValidator(message="Texte dürfen keine einfachen Schreibmaschinensatz-Anführungszeichen (') enthalten. Stattdessen muss der typographisch korrekte Apostroph(’) verwendet werden.", regex="^(?!.*\\').*$"), django.core.validators.RegexValidator(message='Texte dürfen keine doppelten Leerzeichen und/oder Zeilenumbrüche enthalten.', regex='^(?!.* ).*$'), django.core.validators.RegexValidator(message='Texte dürfen keine Gravis (`) enthalten. Stattdessen muss der typographisch korrekte Apostroph (’) verwendet werden.', regex='^(?!.*`).*$'), django.core.validators.RegexValidator(message='Im Text darf nach einem Bindestrich kein Leerzeichen stehen.', regex='^(?!.*- ).*$'), django.core.validators.RegexValidator(message='Im Text darf vor einem Bindestrich kein Leerzeichen stehen.', regex='^(?!.* -).*$')], verbose_name='Nachname')),
('address_street', models.CharField(blank=True, max_length=255, null=True, validators=[django.core.validators.RegexValidator(message='Texte dürfen keine Akute (´) enthalten. Stattdessen muss der typographisch korrekte Apostroph (’) verwendet werden.', regex='^(?!.*´).*$'), django.core.validators.RegexValidator(message='Texte dürfen keine doppelten Schreibmaschinensatz-Anführungszeichen (") enthalten. Stattdessen müssen die typographisch korrekten Anführungszeichen („“) verwendet werden.', regex='^(?!.*\\").*$'), django.core.validators.RegexValidator(message="Texte dürfen keine einfachen Schreibmaschinensatz-Anführungszeichen (') enthalten. Stattdessen muss der typographisch korrekte Apostroph(’) verwendet werden.", regex="^(?!.*\\').*$"), django.core.validators.RegexValidator(message='Texte dürfen keine doppelten Leerzeichen und/oder Zeilenumbrüche enthalten.', regex='^(?!.* ).*$'), django.core.validators.RegexValidator(message='Texte dürfen keine Gravis (`) enthalten. Stattdessen muss der typographisch korrekte Apostroph (’) verwendet werden.', regex='^(?!.*`).*$')], verbose_name='Straße')),
('address_house_number', models.CharField(blank=True, max_length=4, null=True, validators=[django.core.validators.RegexValidator(message='Die <strong><em>Hausnummer</em></strong> muss eine Zahl zwischen 1 und 999 sein, optional gefolgt von einem Kleinbuchstaben.', regex='^[1-9][0-9]{0,2}[a-z]?$')], verbose_name='Hausnummer')),
('address_house_number', models.CharField(blank=True, max_length=4, null=True, validators=[django.core.validators.RegexValidator(message='Die <strong><em>Hausnummer</em></strong> muss eine Zahl zwischen 1 und 999 sein, optional direkt gefolgt von einem Kleinbuchstaben.', regex='^[1-9][0-9]{0,2}[a-z]?$')], verbose_name='Hausnummer')),
('address_postal_code', models.CharField(blank=True, max_length=5, null=True, validators=[django.core.validators.RegexValidator(message='Die <strong><em>Postleitzahl</em></strong> muss aus genau fünf Ziffern bestehen.', regex='^[0-9]{5}$')], verbose_name='Postleitzahl')),
('address_place', models.CharField(blank=True, max_length=255, null=True, validators=[django.core.validators.RegexValidator(message='Texte dürfen keine Akute (´) enthalten. Stattdessen muss der typographisch korrekte Apostroph (’) verwendet werden.', regex='^(?!.*´).*$'), django.core.validators.RegexValidator(message='Texte dürfen keine doppelten Schreibmaschinensatz-Anführungszeichen (") enthalten. Stattdessen müssen die typographisch korrekten Anführungszeichen („“) verwendet werden.', regex='^(?!.*\\").*$'), django.core.validators.RegexValidator(message="Texte dürfen keine einfachen Schreibmaschinensatz-Anführungszeichen (') enthalten. Stattdessen muss der typographisch korrekte Apostroph(’) verwendet werden.", regex="^(?!.*\\').*$"), django.core.validators.RegexValidator(message='Texte dürfen keine doppelten Leerzeichen und/oder Zeilenumbrüche enthalten.', regex='^(?!.* ).*$'), django.core.validators.RegexValidator(message='Texte dürfen keine Gravis (`) enthalten. Stattdessen muss der typographisch korrekte Apostroph (’) verwendet werden.', regex='^(?!.*`).*$')], verbose_name='Ort')),
('email_addresses', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, max_length=255, null=True, validators=[django.core.validators.EmailValidator(message='E-Mail-Adressen müssen syntaktisch korrekt sein und daher folgendes Format aufweisen (Beispiele): abc@def.xyz oder 1cba_mno.asff@xy.a23c.zy')], verbose_name='E-Mail-Adresse(n)'), blank=True, null=True, size=None, verbose_name='E-Mail-Adresse(n)')),
Expand Down Expand Up @@ -197,14 +197,15 @@ class Migration(migrations.Migration):
('emission_point', django.contrib.gis.db.models.fields.PointField(srid=4326, verbose_name='Emissionsort')),
('address', models.CharField(blank=True, max_length=255, null=True, verbose_name='Adresse')),
('dms_link', models.CharField(blank=True, max_length=16, null=True, validators=[django.core.validators.RegexValidator(message='Der <strong><em>d.3</em></strong>-Vorgang muss folgendes Format aufweisen (Beispiel): 552.6#04-004/008', regex='^[0-9]{3}\\.[0-9]#[0-9]{2}-[0-9]{3}\\/[0-9]{3}$')], verbose_name=' d.3')),
('operator', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='bemas.organization', verbose_name='Betreiberin')),
('operator_organization', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='bemas.organization', verbose_name='Organisation als Betreiberin')),
('operator_person', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='bemas.person', verbose_name='Person als Betreiber:in')),
('sector', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='bemas.sector', verbose_name='Branche')),
],
options={
'verbose_name': 'Verursacher',
'verbose_name_plural': 'Verursacher',
'db_table': 'originator',
'ordering': ['sector__title', 'operator__name', 'description'],
'ordering': ['sector__title', 'operator_organization__name', 'operator_person__last_name', 'description'],
'get_latest_by': 'updated_at',
'abstract': False,
},
Expand Down
37 changes: 30 additions & 7 deletions bemas/models/models_objectclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,10 +375,19 @@ class Originator(GeometryObjectclass):
verbose_name='Branche',
on_delete=PROTECT
)
operator = ForeignKey(
operator_organization = ForeignKey(
Organization,
verbose_name='Betreiberin',
on_delete=PROTECT
verbose_name='Organisation als Betreiberin',
on_delete=PROTECT,
blank=True,
null=True
)
operator_person = ForeignKey(
Person,
verbose_name='Person als Betreiber:in',
on_delete=PROTECT,
blank=True,
null=True
)
description = TextField(
'Beschreibung',
Expand Down Expand Up @@ -408,7 +417,12 @@ class Originator(GeometryObjectclass):

class Meta(GeometryObjectclass.Meta):
db_table = 'originator'
ordering = ['sector__title', 'operator__name', 'description']
ordering = [
'sector__title',
'operator_organization__name',
'operator_person__last_name',
'description'
]
verbose_name = 'Verursacher'
verbose_name_plural = 'Verursacher'

Expand All @@ -421,11 +435,20 @@ class BasemodelMeta(GeometryObjectclass.BasemodelMeta):
new = 'neuen'

def __str__(self):
return str(self.sector) + ' mit der Betreiberin ' + str(self.operator) + \
' (' + shorten_string(self.description) + ')'
operator = ''
if self.operator_organization:
operator = ' mit der Betreiberin ' + str(self.operator_organization)
elif self.operator_person:
operator = ' mit der/dem Betreiber:in ' + str(self.operator_person)
return str(self.sector) + operator + ' (' + shorten_string(self.description) + ')'

def sector_and_operator(self):
return str(self.sector) + ' (Betreiberin: ' + str(self.operator) + ')'
operator = ''
if self.operator_organization:
operator = ' (Betreiberin: ' + str(self.operator_organization) + ')'
elif self.operator_person:
operator = ' (Betreiber:in: ' + str(self.operator_person) + ')'
return str(self.sector) + operator

def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
# store search content in designated field
Expand Down
20 changes: 16 additions & 4 deletions bemas/templates/bemas/generic-objectclass-form.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
{% else %}
<link rel="stylesheet" type="text/css" href="{% static 'datenmanagement/css/form-desktop.css' %}">
{% endif %}
<link rel="stylesheet" type="text/css" href="{% static 'select2/select2.min.css' %}">
{% endblock %}

{% block scripts %}
Expand All @@ -33,6 +34,8 @@
<script type="module" src="{% static 'datenmanagement/js/leafletHelpers.js' %}"></script>
{% endif %}
<script src="{% static 'bemas/js/form.js' %}"></script>
<script src="{% static 'bemas/js/form.js' %}"></script>
<script src="{% static 'select2/select2.min.js' %}"></script>
{% endblock %}

{% block content %}
Expand Down Expand Up @@ -246,10 +249,19 @@ <h2><i class="fas fa-{{ objectclass_name|lower|get_icon }}"></i> <em>{{ objectcl
$(this).attr('title', sectorExamples[value]);
});

// handle multiple select fields
$('select[multiple]').each(function () {
addEmptyFieldButton($(this));
});
// handle certain select fields: convert them to autocomplete fields
$('select#id_organization').select2();
$('select#id_person').select2();
$('select#id_operator_organization').select2();
$('select#id_operator_person').select2();
$('select#id_originator').select2();
$('select#id_complainers_organizations').select2();
$('select#id_complainers_persons').select2();

// currently not needed due to conversion of multiple select fields to autocomplete fields
/* $('select[multiple]').each(function () {
// addEmptyFieldButton($(this));
}); */

// initialize address search (and make its results globally available)
window.results = $('div.results');
Expand Down
6 changes: 4 additions & 2 deletions bemas/templates/bemas/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
{% if not is_mobile %}
<div class="row g-4">
<div class="col-4">
<div class="alert alert-primary h-100 text-center d-flex align-items-center">
<a class="fs-1 stretched-link" href="{% url 'bemas:map' %}"><i class="fas fa-{{ 'map'|get_icon }}"></i><br>Immissions- und Emissionsorte</a>
<div class="alert alert-primary h-100 text-center">
<p class="mt-5 mb-0 fs-1">
<a href="{% url 'bemas:map' %}"><i class="fas fa-{{'map'|get_icon }}"></i><br>Immissions-<br>und Emissionsorte</a>
</p>
</div>
</div>
<div class="col-8">
Expand Down
Loading

0 comments on commit fe9fec0

Please sign in to comment.