jazzmin as a more beauty admin panel

This commit is contained in:
gw3000 2023-07-11 18:04:19 +02:00
parent 8ea5c87c9c
commit aca1c3c3fa
117 changed files with 4 additions and 0 deletions

0
app/aviary/__init__.py Normal file
View file

13
app/aviary/admin.py Normal file
View file

@ -0,0 +1,13 @@
from django.contrib import admin
from .models import Aviary
@admin.register(Aviary)
class AviaryAdmin(admin.ModelAdmin):
list_display = [
"description",
"condition",
"last_ward_round",
]
list_filter = ("description", "condition", "last_ward_round")

8
app/aviary/apps.py Normal file
View file

@ -0,0 +1,8 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class AviaryConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "aviary"
verbose_name = _("Volieren")

27
app/aviary/forms.py Normal file
View file

@ -0,0 +1,27 @@
from datetime import date
from django import forms
from django.utils.translation import gettext_lazy as _
from .models import Aviary
class DateInput(forms.DateInput):
input_type = "date"
class AviaryEditForm(forms.ModelForm):
class Meta:
widgets = {
"last_ward_round": DateInput(format="%Y-%m-%d", attrs={"value": date.today})
}
model = Aviary
fields = [
"description",
"condition",
"last_ward_round",
]
labels = {
"description": _("Bezeichnung"),
"condition": _("Zustand"),
"last_ward_round": _("Letzte Inspektion"),
}

View file

@ -0,0 +1,40 @@
# Generated by Django 4.2.2 on 2023-07-04 16:19
from django.db import migrations, models
import uuid
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name="Aviary",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
(
"description",
models.CharField(
max_length=256, unique=True, verbose_name="Beschreibung"
),
),
("condition", models.CharField(max_length=256, verbose_name="Zustand")),
("last_ward_round", models.DateField(verbose_name="letzte Visite")),
],
options={
"verbose_name": "Voliere",
"verbose_name_plural": "Volieren",
},
),
]

View file

@ -0,0 +1,26 @@
# Generated by Django 4.2.2 on 2023-07-08 20:30
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("aviary", "0001_initial"),
]
operations = [
migrations.AlterField(
model_name="aviary",
name="condition",
field=models.CharField(
choices=[
("Offen", "Offen"),
("Geschlossen", "Geschlossen"),
("Gesperrt", "Geshlossem"),
],
max_length=256,
verbose_name="Zustand",
),
),
]

View file

@ -0,0 +1,26 @@
# Generated by Django 4.2.2 on 2023-07-09 20:22
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("aviary", "0002_alter_aviary_condition"),
]
operations = [
migrations.AlterField(
model_name="aviary",
name="condition",
field=models.CharField(
choices=[
("Offen", "Offen"),
("Geschlossen", "Geschlossen"),
("Gesperrt", "Gesperrt"),
],
max_length=256,
verbose_name="Zustand",
),
),
]

View file

21
app/aviary/models.py Normal file
View file

@ -0,0 +1,21 @@
from uuid import uuid4
from django.db import models
from django.utils.translation import gettext_lazy as _
CHOICE_AVIARY = [("Offen","Offen"), ("Geschlossen", "Geschlossen"), ("Gesperrt", "Gesperrt")]
class Aviary(models.Model):
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
description = models.CharField(
max_length=256, verbose_name=_("Beschreibung"), unique=True
)
condition = models.CharField(max_length=256, choices=CHOICE_AVIARY, verbose_name=_("Zustand"))
last_ward_round = models.DateField(verbose_name=_("letzte Visite"))
class Meta:
verbose_name = _("Voliere")
verbose_name_plural = _("Volieren")
def __str__(self):
return self.description

View file

@ -0,0 +1,60 @@
{% extends "base.html" %}
{% load static %}
{% block header %}
<!-- Datatable CSS -->
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.4/css/dataTables.bootstrap5.min.css" />
<link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.2.9/css/responsive.bootstrap5.min.css">
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<!-- Datatable jQuery -->
<script src="https://cdn.datatables.net/1.11.3/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.11.3/js/dataTables.bootstrap5.min.js"></script>
<script src="https://cdn.datatables.net/responsive/2.2.9/js/dataTables.responsive.min.js"></script>
<script src="https://cdn.datatables.net/responsive/2.2.9/js/responsive.bootstrap5.min.js"></script>
<script>
$(document).ready(function () {
$('#t__aviary_all').DataTable({
language: {
url: 'https://cdn.datatables.net/plug-ins/1.11.3/i18n/de_de.json',
},
paging: false,
info: false,
responsive: true,
columnDefs: [
{ responsivePriority: 1, targets: 0 },
]
})
})
</script>
{% endblock header %}
{% block content %}
<h3>Übersicht aller Volieren</h3>
<p>
Die Übersicht aller Volieren.
</p>
<table class="table table-striped table-hover display responsive nowrap" width="100%" id="t__aviary_all">
<thead>
<tr>
<th>Bezeichnung</th>
<th>Zustand</th>
<th>letzte Visite</th>
</tr>
</thead>
<tbody>
{% for aviary in aviaries %}
<tr>
<td>
<a href="{% url 'aviary_single' aviary.id %}">{{ aviary.description }}</a>
</td>
<td>{{ aviary.condition }}</td>
<td>{{ aviary.last_ward_round }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock content %}

View file

@ -0,0 +1,42 @@
{% extends "base.html" %}
{% load static %}
{% load crispy_forms_tags %}
{% block content %}
<h3>Voliere <strong>{{ aviary.description }}</strong> bearbeiten </h3>
<div class="row">
<div class="col-lg-5 mb-3">
<form method="post" enctype="multipart/form-data">
<fieldset>
{% csrf_token %}
{{form|crispy}}
<button class="btn btn-success" type="abbort">Abbrechen</button>
<button class="btn btn-primary" type="submit">Speichern</button>
</fieldset>
</form>
</div>
<div class="col-lg-5">
<h4>
Zustand
</h4>
<p>
Lorem ipsum dolor sit, amet consectetur adipisicing elit.
Reiciendis, hic enim pariatur, exercitationem, repellat quasi sit
temporibus dicta voluptate in voluptates. Alias deserunt sint
suscipit explicabo et. Perferendis, dolor praesentium.
</p>
<h4>
Letzte Inspektion
</h4>
<p>
Lorem ipsum dolor sit, amet consectetur adipisicing elit.
Reiciendis, hic enim pariatur, exercitationem, repellat quasi sit
temporibus dicta voluptate in voluptates. Alias deserunt sint
suscipit explicabo et. Perferendis, dolor praesentium.
</p>
</div>
</div>
<script src="{% static 'js/bird.js' %}"></script
{% endblock content %}

3
app/aviary/tests.py Normal file
View file

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

11
app/aviary/urls.py Normal file
View file

@ -0,0 +1,11 @@
from django.urls import path
from .views import (
aviary_all,
aviary_single
)
urlpatterns = [
path("all/", aviary_all, name="aviary_all"),
path("<id>", aviary_single, name="aviary_single"),
]

25
app/aviary/views.py Normal file
View file

@ -0,0 +1,25 @@
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect
from .models import Aviary
from .forms import AviaryEditForm
@login_required(login_url="account_login")
def aviary_all(request):
aviaries = Aviary.objects.all()
context = {"aviaries": aviaries}
return render(request, "aviary/aviary_all.html", context)
@login_required(login_url="account_login")
def aviary_single(request, id):
aviary = Aviary.objects.get(id=id)
form = AviaryEditForm(request.POST or None, instance=aviary)
if request.method == "POST":
if form.is_valid():
form.save()
return redirect("aviary_all")
context = {"aviary": aviary, "form": form}
return render(request, "aviary/aviary_single.html", context)

0
app/bird/__init__.py Normal file
View file

24
app/bird/admin.py Normal file
View file

@ -0,0 +1,24 @@
from django.contrib import admin
from .models import Bird, FallenBird, BirdStatus, Circumstance
@admin.register(FallenBird)
class FallenBirdAdmin(admin.ModelAdmin):
list_display = ["bird", "date_found", "place", "created", "updated", "user"]
list_filter = ("bird", "created", "user")
@admin.register(Bird)
class BirdAdmin(admin.ModelAdmin):
list_display = ["name", "description"]
@admin.register(BirdStatus)
class BirdStatusAdmin(admin.ModelAdmin):
list_display = ["id", "description"]
@admin.register(Circumstance)
class CircumstanceAdmin(admin.ModelAdmin):
list_display = ["id", "description"]

8
app/bird/apps.py Normal file
View file

@ -0,0 +1,8 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class BirdConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "bird"
verbose_name = _("Vögel")

63
app/bird/forms.py Normal file
View file

@ -0,0 +1,63 @@
from datetime import date
from django import forms
from django.utils.translation import gettext_lazy as _
from .models import FallenBird
class DateInput(forms.DateInput):
input_type = "date"
class BirdAddForm(forms.ModelForm):
# find_circumstances_new = forms.CharField(
# widget=forms.HiddenInput(attrs={"class": "textinput form-control mb-3"})
# )
class Meta:
widgets = {
"date_found": DateInput(format="%Y-%m-%d", attrs={"value": date.today})
}
model = FallenBird
fields = [
"bird_identifier",
"bird",
"date_found",
"place",
"find_circumstances",
# "find_circumstances_new",
# "status",
]
labels = {
"bird_identifier": _("Kennung"),
"bird": _("Vogel"),
"date_found": _("Datum des Fundes"),
"place": _("Fundort"),
"find_circumstances": _("Fundumstände"),
# "find_circumstances_new": _("neuer Fundumstand"),
# "status": _("Status"),
}
class BirdEditForm(forms.ModelForm):
class Meta:
widgets = {"date_found": DateInput(format="%Y-%m-%d")}
model = FallenBird
fields = [
"bird_identifier",
"bird",
"date_found",
"place",
"status",
"aviary",
"find_circumstances",
]
labels = {
"bird": _("Vogel"),
"date_found": _("Datum des Fundes"),
"place": _("Fundort"),
"status": _("Status"),
"aviary": _("Voliere"),
"find_circumstances": _("Fundumstände"),
}

View file

@ -0,0 +1,156 @@
# Generated by Django 4.2.2 on 2023-07-10 19:16
import bird.models
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("aviary", "0003_alter_aviary_condition"),
("rescuer", "0001_initial"),
]
operations = [
migrations.CreateModel(
name="Bird",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("name", models.CharField(max_length=256, unique=True)),
(
"description",
models.CharField(max_length=4096, verbose_name="Hilfetext"),
),
],
options={
"verbose_name": "Vogel",
"verbose_name_plural": "Vögel",
},
),
migrations.CreateModel(
name="BirdStatus",
fields=[
("id", models.BigAutoField(primary_key=True, serialize=False)),
("description", models.CharField(max_length=256, unique=True)),
],
options={
"verbose_name": "Patientenstatus",
"verbose_name_plural": "Patientenstatus",
},
),
migrations.CreateModel(
name="Circumstance",
fields=[
("id", models.BigAutoField(primary_key=True, serialize=False)),
("description", models.CharField(max_length=256)),
],
options={
"verbose_name": "Fundumstand",
"verbose_name_plural": "Fundumstände",
},
),
migrations.CreateModel(
name="FallenBird",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
(
"bird_identifier",
models.CharField(max_length=256, verbose_name="Kennung"),
),
("date_found", models.DateField(verbose_name="Datum des Fundes")),
(
"place",
models.CharField(max_length=256, verbose_name="Ort des Fundes"),
),
(
"created",
models.DateTimeField(auto_now_add=True, verbose_name="angelegt am"),
),
(
"updated",
models.DateTimeField(auto_now=True, verbose_name="geändert am"),
),
("diagnostic_finding", models.CharField(max_length=256)),
(
"costs",
models.JSONField(
default=bird.models.costs_default, verbose_name="Costs"
),
),
(
"aviary",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="aviary.aviary",
),
),
(
"bird",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="bird.bird",
verbose_name="Patient",
),
),
(
"find_circumstances",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="bird.circumstance",
),
),
(
"rescuer",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="rescuer.rescuer",
),
),
(
"status",
models.ForeignKey(
default=1,
on_delete=django.db.models.deletion.CASCADE,
to="bird.birdstatus",
),
),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"verbose_name": "Patient",
"verbose_name_plural": "Patienten",
},
),
]

View file

88
app/bird/models.py Normal file
View file

@ -0,0 +1,88 @@
from datetime import date
from uuid import uuid4
from django.conf import settings
from django.db import models
from django.utils.translation import gettext_lazy as _
from aviary.models import Aviary
from rescuer.models import Rescuer
def costs_default():
return [{"date": date.today().strftime("%Y-%m-%d"), "cost_entry": "0.00"}]
class FallenBird(models.Model):
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
bird_identifier = models.CharField(max_length=256, verbose_name=_("Kennung"))
bird = models.ForeignKey(
"Bird", on_delete=models.CASCADE, verbose_name=_("Patient")
)
date_found = models.DateField(verbose_name=_("Datum des Fundes"))
place = models.CharField(max_length=256, verbose_name=_("Ort des Fundes"))
created = models.DateTimeField(auto_now_add=True, verbose_name=_("angelegt am"))
updated = models.DateTimeField(auto_now=True, verbose_name=_("geändert am"))
find_circumstances = models.ForeignKey("Circumstance", on_delete=models.CASCADE)
diagnostic_finding = models.CharField(max_length=256)
costs = models.JSONField("Costs", default=costs_default)
rescuer = models.ForeignKey(
Rescuer, on_delete=models.SET_NULL, blank=True, null=True
)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
status = models.ForeignKey("BirdStatus", on_delete=models.CASCADE, default=1)
aviary = models.ForeignKey(Aviary, on_delete=models.SET_NULL, blank=True, null=True)
class Meta:
verbose_name = _("Patient")
verbose_name_plural = _("Patienten")
def __str__(self):
return self.place
class Bird(models.Model):
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
name = models.CharField(max_length=256, unique=True)
description = models.CharField(max_length=4096, verbose_name=_("Hilfetext"))
class Meta:
verbose_name = _("Vogel")
verbose_name_plural = _("Vögel")
def __str__(self):
return self.name
class BirdStatus(models.Model):
id = models.BigAutoField(primary_key=True)
description = models.CharField(max_length=256, unique=True)
class Meta:
verbose_name = _("Patientenstatus")
verbose_name_plural = _("Patientenstatus")
def __str__(self):
return self.description
# CHOICE_FIND_CIRCUMSTANCES = [
# ("Neu", "Neu"),
# ("Scheibenschlag", "Scheibenschlag"),
# ("Angriff Hund/Katze", "Angriff Hund/Katze"),
# ("Entkräftet", "Entkräftet"),
# ("Verkehrsunfall", "Verkehrsunfall"),
# ("unbekannt", "unbekannt"),
# ]
class Circumstance(models.Model):
id = models.BigAutoField(primary_key=True)
description = models.CharField(max_length=256)
class Meta:
verbose_name = _("Fundumstand")
verbose_name_plural = _("Fundumstände")
def __str__(self) -> str:
return self.description

View file

@ -0,0 +1,107 @@
{% extends "base.html" %}
{% load static %}
{% block header %}
<!-- Datatable CSS -->
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.4/css/dataTables.bootstrap5.min.css" />
<link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.2.9/css/responsive.bootstrap5.min.css">
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<!-- Datatable jQuery -->
<script src="https://cdn.datatables.net/1.11.3/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.11.3/js/dataTables.bootstrap5.min.js"></script>
<script src="https://cdn.datatables.net/responsive/2.2.9/js/dataTables.responsive.min.js"></script>
<script src="https://cdn.datatables.net/responsive/2.2.9/js/responsive.bootstrap5.min.js"></script>
<script>
$(document).ready(function () {
$('#t__bird_all').DataTable({
language: {
url: 'https://cdn.datatables.net/plug-ins/1.11.3/i18n/de_de.json',
},
paging: false,
info: false,
responsive: true,
columnDefs: [
{ responsivePriority: 1, targets: 0 },
]
})
})
</script>
{% endblock header %}
{% block content %}
<h3>Übersicht aller Patienten in Behandlung</h3>
<p>
Übersicht aller in Behandlung befindlichen oder behandelten Vögel.
</p>
<p>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addPatientModal">einen Patienten
anlegen
</button>
</p>
<table class="table table-striped table-hover display responsive nowrap" id="t__bird_all">
<thead>
<tr>
<th>Patienten Alias</th>
<th>Vogel</th>
<th>Finder</th>
<th>Fundort</th>
<th>gefunden am</th>
<th>Status</th>
<th>Voliere</th>
<th>Kosten</th>
</tr>
</thead>
<tbody>
{% for bird in birds %}
<tr>
<td><a href="{% url 'bird_single' bird.id %}">{{ bird.bird_identifier }}</a></td>
<td>{{ bird.bird }}</td>
<td>
<a href="{% url 'rescuer_single' bird.rescuer_id %}">{{ bird.rescuer }}</a>
</td>
<td>{{ bird.place }}</td>
<td>{{ bird.date_found }}</td>
<td>{{ bird.status }}</td>
<td>{{ bird.aviary|default_if_none:"" }}</td>
<td>{{ bird.costs }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="modal fade" id="addPatientModal" tabindex="-1" data-bs-backdrop="static"
aria-labelledby="addRescuerModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-primary">
<h5 class="modal-title text-white" id="addRescuerModalLabel">(neuen) Finder zuweisen</h5>
</div>
<form method="post">
{% csrf_token %}
<div class="modal-body">
<label for="rescuer" class="form-label mt-3">Wählen Sie einen <strong>bereits angelegten</strong>
Finder aus oder legen Sie einen <strong>neuen</strong> Finder an:</label>
<select id="rescuer" class="form-select" name="rescuer_id">
<option value="new_rescuer"><strong>neuen
Finder anlegen</strong></option>
{% for rescuer in rescuer_modal %}
<option value={{rescuer.id}}>
{{rescuer.first_name}} {{rescuer.last_name}},
{{rescuer.street}} {{rescuer.street_number}},
{{rescuer.city}}
</option>
{% endfor %}
</select>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-bs-dismiss="modal">Abbruch</button>
<button class="btn btn-primary" type="submit">Übernehmen und weiter</button>
</div>
</div>
</div>
</div>
</form>
{% endblock content %}

View file

@ -0,0 +1,48 @@
{% extends "base.html" %}
{% load static %}
{% load crispy_forms_tags %}
{% block content %}
<h3>Patient anlegen</h3>
<p>(Retter: {{rescuer.first_name}} {{rescuer.last_name}})</p>
<div class="row">
<div class="col-lg-8 mb-3">
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<a href="{% url 'bird_all' %}" class="btn btn-danger">Abbruch</a>
<button class="btn btn-primary" type="submit">Patient anlegen</button>
<div class="mt-3"><small>* Pflichtfeld</small></div>
</form>
</div>
<div class="col-lg-4">
<h4>eins</h4>
<p>
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Facilis illum
quos eveniet obcaecati, adipisci voluptate alias iste ipsa blanditiis
earum veritatis provident modi repellendus ut maxime iusto enim distinctio
voluptatum.
</p>
<h4>zwei</h4>
<p>
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Facilis illum
quos eveniet obcaecati, adipisci voluptate alias iste ipsa blanditiis
earum veritatis provident modi repellendus ut maxime iusto enim distinctio
voluptatum.
</p>
<h4>drei</h4>
<p>
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Facilis illum
quos eveniet obcaecati, adipisci voluptate alias iste ipsa blanditiis
earum veritatis provident modi repellendus ut maxime iusto enim distinctio
voluptatum.
</p>
</div>
</div>
<script src="{% static 'js/find_circumstances.js' %}"></script>
{% endblock content %}

View file

@ -0,0 +1,25 @@
{% extends 'base.html' %}
{% block content %}
<h3>Patient löschen</h3>
<div class="row mt-3">
<div class="col-lg-7">
<form method="post">
{% csrf_token %}
<div class="alert alert-dismissible alert-danger">
<h4 class="alert-heading">Warnung!</h4>
<p class="mb-0">Wollen Sie den Vogel <strong>{{bird.bird}}</strong>
Reg-Num.: <strong>{{bird.id}}</strong> löschen?</p>
</div>
</p>
<a href="{% url 'bird_all'%}" class="btn btn-secondary">Abbruch</a>
<button class="btn btn-danger" type="submit">Löschen</button>
</form>
</div>
<div class="col-lg-5">
<h5>Vogel löschen</h5>
<p>
Hinweis zum Löschen eines Vogels!
</p>
</div>
</div>
{% endblock content %}

View file

@ -0,0 +1,13 @@
{% extends "base.html" %}
{% load static %}
{% block content %}
<div class="row">
<div class="col-lg-8 mb-3">
<h3>Hilfesammlung</h3>
{% for bird in birds %}
<h4>{{ bird.name }}</h4>
<p>{{ bird.description }}</p>
{% endfor %}
</div>
</div>
{% endblock content %}

View file

@ -0,0 +1,72 @@
{% extends "base.html" %}
{% load static %}
{% load crispy_forms_tags %}
{% block content %}
<h3>Patient <strong>{{ bird.bird_identifier }}</strong> bearbeiten </h3>
<p>Finder des Patienten: <strong> <a href="{% url 'rescuer_single' bird.rescuer_id %}">{{ bird.rescuer }}</a></strong></p>
<div class="row">
<div class="col-lg-5 mb-3">
<form method="post" enctype="multipart/form-data">
<fieldset>
{% csrf_token %}
{{form|crispy}}
<button class="btn btn-success" type="abbort">Abbrechen</button>
<a href="{% url 'bird_delete' bird.id %}" class="btn btn-danger">Löschen</a>
<button class="btn btn-primary" type="submit">Speichern</button>
</fieldset>
</form>
</div>
<div class="col-lg-5">
<h4>
Kennung
</h4>
<p>
Lorem ipsum dolor sit, amet consectetur adipisicing elit.
Reiciendis, hic enim pariatur, exercitationem, repellat quasi sit
temporibus dicta voluptate in voluptates. Alias deserunt sint
suscipit explicabo et. Perferendis, dolor praesentium.
</p>
<h4>
Vogel
</h4>
<p>
Lorem ipsum dolor sit, amet consectetur adipisicing elit.
Reiciendis, hic enim pariatur, exercitationem, repellat quasi sit
temporibus dicta voluptate in voluptates. Alias deserunt sint
suscipit explicabo et. Perferendis, dolor praesentium.
</p>
<h4>
Fundort
</h4>
<p>
Lorem ipsum dolor sit, amet consectetur adipisicing elit.
Reiciendis, hic enim pariatur, exercitationem, repellat quasi sit
temporibus dicta voluptate in voluptates. Alias deserunt sint
suscipit explicabo et. Perferendis, dolor praesentium.
</p>
<h4>
Voliere
</h4>
<p>
Lorem ipsum dolor sit, amet consectetur adipisicing elit.
Reiciendis, hic enim pariatur, exercitationem, repellat quasi sit
temporibus dicta voluptate in voluptates. Alias deserunt sint
suscipit explicabo et. Perferendis, dolor praesentium.
</p>
<h4>
Kosten
</h4>
<p>
Lorem ipsum dolor sit, amet consectetur adipisicing elit.
Reiciendis, hic enim pariatur, exercitationem, repellat quasi sit
temporibus dicta voluptate in voluptates. Alias deserunt sint
suscipit explicabo et. Perferendis, dolor praesentium.
</p>
</div>
</div>
<script src="{% static 'js/bird.js' %}"></script>
{% endblock content %}

3
app/bird/tests.py Normal file
View file

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

21
app/bird/urls.py Normal file
View file

@ -0,0 +1,21 @@
from django.urls import path
from .views import (
bird_all,
bird_help,
bird_create,
bird_delete,
bird_recover,
bird_recover_all,
bird_single,
)
urlpatterns = [
path("all/", bird_all, name="bird_all"),
path("create/", bird_create, name="bird_create"),
path("delete/<id>", bird_delete, name="bird_delete"),
path("help/", bird_help, name="bird_help"),
path("recover/<id>", bird_recover, name="bird_recover"),
path("recover/all", bird_recover_all, name="bird_recover_all"),
path("<id>/", bird_single, name="bird_single"),
]

104
app/bird/views.py Normal file
View file

@ -0,0 +1,104 @@
import names
from django.contrib.auth.decorators import login_required
from django.shortcuts import HttpResponse, redirect, render
from rescuer.models import Rescuer
from .forms import BirdAddForm, BirdEditForm
from .models import FallenBird, Bird
@login_required(login_url="account_login")
def bird_create(request):
form = BirdAddForm(initial={"bird_identifier": names.get_first_name()})
# Rescuer for modal usage
rescuer_id = request.session.get("rescuer_id")
rescuer = Rescuer.objects.get(id=rescuer_id, user=request.user)
# Just show only related rescuers in select field of the form.
if request.method == "POST":
form = BirdAddForm(request.POST or None, request.FILES or None)
# circumstances = Circumstance.objects.all()
rescuer_id = request.session.get("rescuer_id")
rescuer = Rescuer.objects.get(id=rescuer_id, user=request.user)
if form.is_valid():
# if form.cleaned_data["find_circumstances_new"]:
# circumstance = form.cleaned_data["find_circumstances_new"]
# if Circumstance.objects.filter(description=circumstance).exists():
# print("is in circumstances")
fs = form.save(commit=False)
fs.user = request.user
fs.rescuer_id = rescuer_id
fs.save()
request.session["rescuer_id"] = None
return redirect("bird_all")
context = {"form": form, "rescuer": rescuer}
return render(request, "bird/bird_create.html", context)
@login_required(login_url="account_login")
def bird_help(request):
birds = Bird.objects.all()
context = {"birds": birds}
return render(request, "bird/bird_help.html", context)
@login_required(login_url="account_login")
def bird_all(request):
birds = FallenBird.objects.all()
# Sum all costs per bird from json
for bird in birds:
costs_per_bird = float()
for item in bird.costs:
costs_per_bird += float(item["cost_entry"])
if costs_per_bird == 0.0:
costs_per_bird = ""
bird.costs = costs_per_bird
rescuer_modal = Rescuer.objects.all()
context = {"birds": birds, "rescuer_modal": rescuer_modal}
# Post came from the modal form.
if request.method == "POST":
rescuer_id = request._post["rescuer_id"]
if rescuer_id != "new_rescuer":
request.session["rescuer_id"] = rescuer_id
return redirect("bird_create")
else:
return redirect("rescuer_create")
return render(request, "bird/bird_all.html", context)
@login_required(login_url="account_login")
def bird_recover_all(request):
return HttpResponse("Show all recovered Birds")
@login_required(login_url="account_login")
def bird_single(request, id):
bird = FallenBird.objects.get(id=id)
form = BirdEditForm(request.POST or None, request.FILES or None, instance=bird)
if request.method == "POST":
if form.is_valid():
fs = form.save(commit=False)
if fs.status.description != "In Auswilderung":
fs.aviary = None
fs.save()
return redirect("bird_all")
context = {"form": form, "bird": bird}
return render(request, "bird/bird_single.html", context)
@login_required(login_url="account_login")
def bird_delete(request, id):
bird = FallenBird.objects.get(id=id)
if request.method == "POST":
bird.delete()
return redirect("bird_all")
context = {"bird": bird}
return render(request, "bird/bird_delete.html", context)
@login_required(login_url="account_login")
def bird_recover(request, id):
return HttpResponse(f"Show recover with ID {id}")

0
app/core/__init__.py Normal file
View file

16
app/core/asgi.py Normal file
View file

@ -0,0 +1,16 @@
"""
ASGI config for core project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings')
application = get_asgi_application()

183
app/core/settings.py Normal file
View file

@ -0,0 +1,183 @@
"""
Django settings for core project.
Generated by 'django-admin startproject' using Django 4.2.2.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/
"""
import os
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = ")g-j2v+*dvjtnz)q-3+*y7*lq$el$im8p^wr@2v$g^u99quq50"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
# -----------------------------------
# All auth
# -----------------------------------
"allauth",
"allauth.account",
"allauth.socialaccount",
# -----------------------------------
# Crispy forms, modals and bootstrap5
# -----------------------------------
"bootstrap_modal_forms",
"crispy_bootstrap5",
"crispy_forms",
# -----------------------------------
# Jazzmin
# -----------------------------------
"jazzmin",
# -----------------------------------
# My Apps
# -----------------------------------
"aviary",
"bird",
"rescuer",
"sites",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "core.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [os.path.join(BASE_DIR, "templates")],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
AUTHENTICATION_BACKENDS = [
# Needed to login by username in Django admin, regardless of `allauth`
"django.contrib.auth.backends.ModelBackend",
# Allauth specific authentication methods, such as login by e-mail
"allauth.account.auth_backends.AuthenticationBackend",
]
WSGI_APPLICATION = "core.wsgi.application"
# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME":
"django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME":
"django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME":
"django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME":
"django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/
LANGUAGE_CODE = "de-de"
TIME_ZONE = "Europe/Berlin"
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/
STATIC_URL = "static/"
STATICFILES_DIRS = [BASE_DIR / "static"]
# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
# Crispy forms
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
CRISPY_TEMPLATE_PACK = "bootstrap5"
# Allauth
SITE_ID = 1
ACCOUNT_AUTHENTICATION_METHOD = "username_email"
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
ACCOUNT_LOGIN_ATTEMPTS_LIMIT = 5
ACCOUNT_LOGIN_ATTEMPTS_TIMEOUT = 86400 # 1 day in seconds
ACCOUNT_LOGIN_ON_EMAIL_CONFIRMATION = True
ACCOUNT_LOGOUT_REDIRECT_URL = "/"
ACCOUNT_LOGOUT_ON_GET = True
ACCOUNT_SESSION_REMEMBER = True
ACCOUNT_USERNAME_BLACKLIST = ["admin", "god"]
ACCOUNT_USERNAME_MIN_LENGTH = 3
ACCOUNT_UNIQUE_EMAIL = True
LOGIN_REDIRECT_URL = "/bird/all"
# Email
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"

31
app/core/urls.py Normal file
View file

@ -0,0 +1,31 @@
"""
URL configuration for core project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
# Dynamic sites
path("bird/", include("bird.urls")),
path("rescuer/", include("rescuer.urls")),
path("aviary/", include("aviary.urls")),
# Admin
path("admin/", admin.site.urls),
# Allauth
path("accounts/", include("allauth.urls")),
# Static sites
path("", include("sites.urls")),
]

16
app/core/wsgi.py Normal file
View file

@ -0,0 +1,16 @@
"""
WSGI config for core project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings')
application = get_wsgi_application()

1
app/fixtures/data.json Normal file

File diff suppressed because one or more lines are too long

22
app/manage.py Executable file
View file

@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

7
app/requirements.txt Normal file
View file

@ -0,0 +1,7 @@
Django>=4.2
django-allauth>=0.50
django-bootstrap-datepicker-plus>=4.0
django-bootstrap-modal-forms>=2
django-crispy-forms>=1
crispy-bootstrap5>=0.6
names>=0.3.0

0
app/rescuer/__init__.py Normal file
View file

17
app/rescuer/admin.py Normal file
View file

@ -0,0 +1,17 @@
from django.contrib import admin
from django.contrib import admin
from .models import Rescuer
@admin.register(Rescuer)
class CustomerAdmin(admin.ModelAdmin):
list_display = [
"last_name",
"first_name",
"street",
"street_number",
"city",
"phone",
"user",
]

10
app/rescuer/apps.py Normal file
View file

@ -0,0 +1,10 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class RescuerConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "rescuer"
verbose_name = _("Finder")

31
app/rescuer/forms.py Normal file
View file

@ -0,0 +1,31 @@
from django import forms
from django.utils.translation import gettext_lazy as _
from .models import Rescuer
class DateInput(forms.DateInput):
input_type = "date"
class RescuerForm(forms.ModelForm):
class Meta:
model = Rescuer
fields = [
"first_name",
"last_name",
"street",
"street_number",
"zip_code",
"city",
"phone",
]
labels = {
"first_name": _("Vorname"),
"last_name": _("Nachname"),
"street": _("Straße"),
"street_number": _("Hausnummer"),
"zip_code": _("Postleitzahl"),
"city": _("Stadt"),
"phone": _("Telefon"),
}

View file

@ -0,0 +1,46 @@
# Generated by Django 4.2.2 on 2023-07-08 20:30
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name="Rescuer",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("first_name", models.CharField(max_length=200)),
("last_name", models.CharField(max_length=200)),
("street", models.CharField(max_length=200)),
("street_number", models.CharField(max_length=20)),
("city", models.CharField(max_length=200)),
("zip_code", models.CharField(max_length=200)),
("phone", models.CharField(max_length=200)),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
),
]

View file

20
app/rescuer/models.py Normal file
View file

@ -0,0 +1,20 @@
from datetime import date
from uuid import uuid4
from django.conf import settings
from django.db import models
class Rescuer(models.Model):
id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
street = models.CharField(max_length=200)
street_number = models.CharField(max_length=20)
city = models.CharField(max_length=200)
zip_code = models.CharField(max_length=200)
phone = models.CharField(max_length=200)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
def __str__(self) -> str:
return self.first_name + " " + self.last_name

View file

@ -0,0 +1,70 @@
{% extends "base.html" %}
{% load static %}
{% block header %}
<!-- Datatable CSS -->
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.4/css/dataTables.bootstrap5.min.css"/>
<link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.2.9/css/responsive.bootstrap5.min.css">
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<!-- Datatable jQuery -->
<script src="https://cdn.datatables.net/1.11.3/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.11.3/js/dataTables.bootstrap5.min.js"></script>
<script src="https://cdn.datatables.net/responsive/2.2.9/js/dataTables.responsive.min.js"></script>
<script src="https://cdn.datatables.net/responsive/2.2.9/js/responsive.bootstrap5.min.js"></script>
<script>
$(document).ready(function () {
$('#t__rescuer_all').DataTable({
language: {
url: 'https://cdn.datatables.net/plug-ins/1.11.3/i18n/de_de.json',
},
paging: false,
info: false,
responsive: true,
columnDefs: [
{ responsivePriority: 1, targets: 0 },
]
})
})
</script>
{% endblock header %}
{% block content %}
<h3>Übersicht aller Finder</h3>
<p>
Die Übersicht aller aktiven Finder.
</p>
<p>
<a href="{% url 'rescuer_create' %}" class="btn btn-primary">Einen neuen Finder anlegen</a>
</p>
<table class="table table-striped table-hover display responsive nowrap" width="100%" id="t__rescuer_all">
<thead>
<tr>
<th>Name</th>
<th>Vorname</th>
<th>Straße</th>
<th>PLZ</th>
<th>Ort</th>
<th>Phone</th>
</tr>
</thead>
<tbody>
{% for rescuer in rescuers %}
<tr>
<td>
<a href="{% url 'rescuer_single' rescuer.id %}">{{ rescuer.last_name }}</a>
</td>
<td>{{ rescuer.first_name }}</td>
<td>{{ rescuer.street }} {{ rescuer.street_number }}</td>
<td>{{ rescuer.zip_code }}</td>
<td>{{ rescuer.city }}</td>
<td>{{ rescuer.phone }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock content %}

View file

@ -0,0 +1,52 @@
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<h4>Einen neuen Finder anlegen</h4>
<div class="row">
<div class="col-lg-6">
<form method="post" class="form-horizontal">
{% csrf_token %}
<div class="row">
<div class="col-md-12 col-lg-6">{{ form.first_name|as_crispy_field }}</div>
<div class="col-md-12 col-lg-6">{{ form.last_name|as_crispy_field }}</div>
<div class="col-md-12 col-lg-8">{{ form.street|as_crispy_field }}</div>
<div class="col-md-12 col-lg-4">{{ form.street_number|as_crispy_field }}</div>
<div class="col-md-12 col-lg-8">{{ form.city|as_crispy_field }}</div>
<div class="col-md-12 col-lg-4">{{ form.zip_code|as_crispy_field }}</div>
<div class="col-md-12 col-lg-6">{{ form.phone|as_crispy_field }}</div>
</div>
<a href="{% url 'bird_all' %}" class="btn btn-danger">Abbruch</a>
<button class="btn btn-primary" type="submit">Speichern</button>
</form>
<div class="mt-3"><small>* Pflichtfeld</small></div>
</div>
<div class="col-lg-4">
<br />
<h4>eins</h4>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error nobis
necessitatibus distinctio pariatur vero sequi eum excepturi assumenda quam
maxime doloremque eligendi perspiciatis id aliquid, voluptate blanditiis
consequatur enim deleniti.
</p>
<h4>zwei</h4>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error nobis
necessitatibus distinctio pariatur vero sequi eum excepturi assumenda quam
maxime doloremque eligendi perspiciatis id aliquid, voluptate blanditiis
consequatur enim deleniti.
</p>
<h4>drei</h4>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error nobis
necessitatibus distinctio pariatur vero sequi eum excepturi assumenda quam
maxime doloremque eligendi perspiciatis id aliquid, voluptate blanditiis
consequatur enim deleniti.
</p>
</div>
</div>
{% endblock content %}

View file

@ -0,0 +1,28 @@
{% extends 'base.html' %}
{% block content %}
<h1>Finder löschen</h1>
<div class="row mt-3">
<div class="col-lg-7">
<form method="post">
{% csrf_token %}
<div class="alert alert-dismissible alert-danger">
<h4 class="alert-heading">Warnung!</h4>
<p class="mb-0">Wollen Sie den Finder <strong>{{rescuer.first_name}} {{rescuer.last_name}}</strong> löschen?</p>
</div>
</p>
<a href="{% url 'rescuer_all'%}" class="btn btn-secondary">Abbruch</a>
<button class="btn btn-danger" type="submit">Löschen</button>
</form>
</div>
<div class="col-lg-5">
<h5>Finder löschen</h5>
<p>
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Voluptates
ducimus inventore quia, quae quam reiciendis eligendi explicabo non
deleniti aliquid, modi dignissimos ullam ipsa incidunt vel similique fuga?
Suscipit, dolores?
</p>
</div>
</div>
{% endblock content %}

View file

@ -0,0 +1,40 @@
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="row">
<div class="col-lg-7">
<h3>Adressänderung des Finders</h3>
<form method="post" class="form-horizontal">
<fieldset>
{% csrf_token %}
<div class="row">
<div class="col-6">{{ form.first_name|as_crispy_field }}</div>
<div class="col-6">{{ form.last_name|as_crispy_field }}</div>
<div class="col-6">{{ form.phone|as_crispy_field }}</div>
<div class="col-8">{{ form.street|as_crispy_field }}</div>
<div class="col-4">{{ form.street_number|as_crispy_field }}</div>
<div class="col-8">{{ form.city|as_crispy_field }}</div>
<div class="col-4">{{ form.zip_code|as_crispy_field }}</div>
</div>
<a href="{% url 'rescuer_all' %}" class="btn btn-secondary">Abbruch</a>
<button class="btn btn-primary" type="submit">Speichern</button>
</fieldset>
</form>
</div>
<div class="col-lg-5">
<h4>Eins</h4>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Provident rem voluptates, facere voluptatum laudantium
voluptate possimus porro. Ab veritatis impedit esse architecto sit dolores, tempore officia! Nemo magni voluptate
officiis?</p>
<h4>Zwei</h4>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Provident rem voluptates, facere voluptatum laudantium
voluptate possimus porro. Ab veritatis impedit esse architecto sit dolores, tempore officia! Nemo magni voluptate
officiis?</p>
<h4>Drei</h4>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Provident rem voluptates, facere voluptatum laudantium
voluptate possimus porro. Ab veritatis impedit esse architecto sit dolores, tempore officia! Nemo magni voluptate
officiis?</p>
</div>
</div>
{% endblock content %}

View file

@ -0,0 +1,38 @@
{% extends 'base.html' %}
{% block content %}
<div class="row">
<div class="col-lg-6">
<h3>Stammdaten des Finders</h3>
<div class="card bg-light mb-3" style="max-width: 30rem;">
<div class="card-header">Adressdaten</div>
<div class="card-body">
<h4 class="card-title">{{rescuer.first_name}} {{rescuer.last_name}}</h4>
<p class="card-text">
{{rescuer.city}} {{rescuer.street}}<br>
{{rescuer.zip_code}}<br>
{{rescuer.phone}}<br>
</p>
</div>
</div>
<a href="{% url 'rescuer_all' %}" class="btn btn-success">zurück zur Übersicht</a>
<a href="{% url 'rescuer_delete' rescuer.id %}" class="btn btn-danger">Löschen</a>
<a href="{% url 'rescuer_edit' rescuer.id %}" class="btn btn-primary">Bearbeiten</a>
</div>
<div class="col-lg-6">
<h4>eins</h4>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Officia tempore voluptatibus voluptatum possimus in
iusto exercitationem perspiciatis eaque harum, nihil, praesentium debitis nisi unde eligendi, qui sapiente
odit expedita aut.</p>
<h4>zwei</h4>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Officia tempore voluptatibus voluptatum possimus in
iusto exercitationem perspiciatis eaque harum, nihil, praesentium debitis nisi unde eligendi, qui sapiente
odit expedita aut.</p>
</div>
</div>
{% endblock content %}

3
app/rescuer/tests.py Normal file
View file

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

17
app/rescuer/urls.py Normal file
View file

@ -0,0 +1,17 @@
from django.urls import path
from .views import (
rescuer_all,
rescuer_create,
rescuer_single,
rescuer_delete,
rescuer_edit,
)
urlpatterns = [
path("all", rescuer_all, name="rescuer_all"),
path("create", rescuer_create, name="rescuer_create"),
path("edit/<id>", rescuer_edit, name="rescuer_edit"),
path("delete/<id>", rescuer_delete, name="rescuer_delete"),
path("<id>", rescuer_single, name="rescuer_single"),
]

61
app/rescuer/views.py Normal file
View file

@ -0,0 +1,61 @@
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect
from .forms import RescuerForm
from .models import Rescuer
@login_required(login_url="account_login")
def rescuer_all(request):
rescuers = Rescuer.objects.all()
context = {"rescuers": rescuers}
return render(request, "rescuer/rescuer_all.html", context)
@login_required(login_url="account_login")
def rescuer_single(request, id):
rescuer = Rescuer.objects.get(id=id)
context = {"rescuer": rescuer}
return render(request, "rescuer/rescuer_single.html", context)
@login_required(login_url="account_login")
def rescuer_create(request):
form = RescuerForm()
if request.method == "POST":
form = RescuerForm(request.POST or None)
if form.is_valid():
fs = form.save(commit=False)
fs.user = request.user
fs.save()
# set customer id in session cookie
# (uuid has to be cast to a string)
rescuer_id = str(fs.pk)
request.session["rescuer_id"] = rescuer_id
return redirect("bird_create")
context = {"form": form}
return render(request, "rescuer/rescuer_create.html", context)
@login_required(login_url="account_login")
def rescuer_delete(request, id):
rescuer = Rescuer.objects.get(id=id)
if request.method == "POST":
rescuer.delete()
return redirect("rescuer_all")
context = {"rescuer": rescuer}
return render(request, "rescuer/rescuer_delete.html", context)
@login_required(login_url="account_login")
def rescuer_edit(request, id):
rescuer = Rescuer.objects.get(id=id)
form = RescuerForm(request.POST or None, instance=rescuer)
if request.method == "POST":
if form.is_valid():
form.save()
return redirect("rescuer_all")
context = {"form": form}
return render(request, "rescuer/rescuer_edit.html", context)

0
app/sites/__init__.py Normal file
View file

3
app/sites/admin.py Normal file
View file

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

6
app/sites/apps.py Normal file
View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class SitesConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'sites'

View file

3
app/sites/models.py Normal file
View file

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

View file

@ -0,0 +1,10 @@
{% extends 'base.html' %}
{% block content %}
<div class="row" style="text-align: center;">
<div>
<h1 style="margin-bottom: 5px;">FallenBirdy</h1>
<img src="../../../static/img/wvhLogo12001200300x.png" alt="Logo Wildvogelhilfe Jena" class="logowvh">
<a href="{% url 'account_login' %}" id="loginMain">Einloggen</a>
</div>
</div>
{% endblock content %}

3
app/sites/tests.py Normal file
View file

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

9
app/sites/urls.py Normal file
View file

@ -0,0 +1,9 @@
from .views import index, privacy, impress
from django.urls import path
urlpatterns = [
path("", index, name="index"),
path("privacy/", privacy, name="privacy"),
path("impress/", impress, name="impress"),
]

13
app/sites/views.py Normal file
View file

@ -0,0 +1,13 @@
from django.shortcuts import redirect, render
def index(request):
return render(request, "sites/index.html")
def privacy(request):
return render(request, "sites/privacy.html")
def impress(request):
return render(request, "sites/impress.html")

0
app/static/css/.gitkeep Normal file
View file

11
app/static/css/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

48
app/static/css/style.css Normal file
View file

@ -0,0 +1,48 @@
h1 {
margin-bottom: 2rem;
color: #0068b4;
font-weight: bold;
}
.logowvh {
display: block;
margin-left: auto;
margin-right: auto;
max-height: 15rem;
aspect-ratio: 1/1;
margin-top: 2rem;
margin-bottom: 2rem;
}
#loginMain{
color: #0068b4;
font-weight: bold;
font-size: 1.5rem;
text-decoration: none;
}
.rounded-pill {
margin-left: 5px;
}
.footer {
font-size: small;
}
#wfvmainsquare{
width: 100px;
height: 100px;
background-color: #0068b4;
rotate: 70deg;
margin: 3%;
border: 3px solid #b1b2b3;
}
.wfvwhitesquare{
width: 20%;
height: 50%;
background-color: white;
position: absolute;
margin-left: 15%;
}

0
app/static/img/.gitkeep Normal file
View file

BIN
app/static/img/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 697 B

BIN
app/static/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
app/static/img/wvh.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

2578
app/static/img/wvhLogo.svg Normal file

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

21
app/static/js/bird.js Normal file
View file

@ -0,0 +1,21 @@
function showHideAviary() {
let statusField = document.getElementById("id_status");
let aviaryField = document.getElementById("div_id_aviary");
let statusText = statusField.options[statusField.selectedIndex].text;
if (statusText == 'In Auswilderung') {
aviaryField.hidden = false
} else {
aviaryField.hidden = true
}
}
// Load function on windows load.
(showHideAviary)();
// Load function on change.
document.getElementById("id_status").addEventListener("change", (event) => {
showHideAviary()
});

7
app/static/js/bootstrap.bundle.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,17 @@
function showHideFindCircumstancesNew() {
let circField = document.getElementById("id_find_circumstances");
let circFieldNew = document.getElementById("id_find_circumstances_new");
let circText = circField.options[circField.selectedIndex].text;
if (circText == 'Neu') {
circFieldNew.type = "show"
} else {
circFieldNew.type = "hidden"
}
}
(showHideFindCircumstancesNew)();
document.getElementById("id_find_circumstances").addEventListener("change", (event) => {
showHideFindCircumstancesNew()
});

View file

@ -0,0 +1,12 @@
{% extends "base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block head_title %}{% trans "Account Inactive" %}{% endblock %}
{% block content %}
<h1>{% trans "Account Inactive" %}</h1>
<p>{% trans "This account is inactive." %}</p>
{% endblock %}

View file

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html>
<head>
<title>{% block head_title %}{% endblock %}</title>
{% block extra_head %}
{% endblock %}
</head>
<body>
{% block body %}
{% if messages %}
<div>
<strong>Messages:</strong>
<ul>
{% for message in messages %}
<li>{{message}}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<div>
<strong>Menu:</strong>
<ul>
{% if user.is_authenticated %}
<li><a href="{% url 'account_email' %}">Change E-mail</a></li>
<li><a href="{% url 'account_logout' %}">Sign Out</a></li>
{% else %}
<li><a href="{% url 'account_login' %}">Sign In</a></li>
<li><a href="{% url 'account_signup' %}">Sign Up</a></li>
{% endif %}
</ul>
</div>
{% block content %}
{% endblock %}
{% endblock %}
{% block extra_body %}
{% endblock %}
</body>
</html>

View file

@ -0,0 +1,78 @@
{% extends "base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block head_title %}{% trans "E-mail Addresses" %}{% endblock %}
{% block content %}
<div class="row">
<div class="col-lg-7">
<h1>{% trans "E-mail Addresses" %}</h1>
{% if user.emailaddress_set.all %}
<p>{% trans 'The following e-mail addresses are associated with your account:' %}</p>
<form action="{% url 'account_email' %}" class="email_list" method="post">
{% csrf_token %}
<fieldset class="blockLabels">
{% for emailaddress in user.emailaddress_set.all %}
<div class="ctrlHolder">
<label for="email_radio_{{forloop.counter}}" class="{% if emailaddress.primary %}primary_email{%endif%}">
<input id="email_radio_{{forloop.counter}}" type="radio" name="email" {% if emailaddress.primary or user.emailaddress_set.count == 1 %} checked="checked" {%endif %} value="{{emailaddress.email}}" />
{{ emailaddress.email }}
{% if emailaddress.verified %}
<span class="verified">{% trans "Verified" %}</span>
{% else %}
<span class="unverified">{% trans "Unverified" %}</span>
{% endif %}
{% if emailaddress.primary %}<span class="primary">{% trans "Primary" %}</span>{% endif %}
</label>
</div>
{% endfor %}
<div class="buttonHolder">
<button class="btn btn-primary secondaryAction" type="submit" name="action_primary">{% trans 'Make Primary' %}</button>
<button class="btn btn-success secondaryAction" type="submit" name="action_send">{% trans 'Re-send Verification' %}</button>
<button class="btn btn-danger primaryAction" type="submit" name="action_remove">{% trans 'Remove' %}</button>
</div>
</fieldset>
</form>
{% else %}
<p><strong>{% trans 'Warning:'%}</strong> {% trans "You currently do not have any e-mail address set up. You should
really add an e-mail address so you can receive notifications, reset your password, etc." %}</p>
{% endif %}
<br>
{% if can_add_email %}
<h2>{% trans "Add E-mail Address" %}</h2>
<form method="post" action="{% url 'account_email' %}" class="add_email">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-primary" name="action_add" type="submit">{% trans "Add E-mail" %}</button>
</form>
{% endif %}
</div>
</div>
{% endblock %}
{% block extra_body %}
<script type="text/javascript">
(function () {
var message = "{% trans 'Do you really want to remove the selected e-mail address?' %}";
var actions = document.getElementsByName('action_remove');
if (actions.length) {
actions[0].addEventListener("click", function (e) {
if (!confirm(message)) {
e.preventDefault();
}
});
}
})();
</script>
{% endblock %}

View file

@ -0,0 +1,7 @@
{% load i18n %}{% autoescape off %}{% blocktrans with site_name=current_site.name %}Hello from {{ site_name }}!{% endblocktrans %}
{% block content %}{% endblock %}
{% blocktrans with site_name=current_site.name site_domain=current_site.domain %}Thank you for using {{ site_name }}!
{{ site_domain }}{% endblocktrans %}
{% endautoescape %}

View file

@ -0,0 +1,7 @@
{% extends "account/email/base_message.txt" %}
{% load account %}
{% load i18n %}
{% block content %}{% autoescape off %}{% user_display user as user_display %}{% blocktrans with site_name=current_site.name site_domain=current_site.domain %}You're receiving this e-mail because user {{ user_display }} has given your e-mail address to register an account on {{ site_domain }}.
To confirm this is correct, go to {{ activate_url }}{% endblocktrans %}{% endautoescape %}{% endblock %}

View file

@ -0,0 +1 @@
{% include "account/email/email_confirmation_message.txt" %}

View file

@ -0,0 +1 @@
{% include "account/email/email_confirmation_subject.txt" %}

View file

@ -0,0 +1,4 @@
{% load i18n %}
{% autoescape off %}
{% blocktrans %}Please Confirm Your E-mail Address{% endblocktrans %}
{% endautoescape %}

View file

@ -0,0 +1,9 @@
{% extends "account/email/base_message.txt" %}
{% load i18n %}
{% block content %}{% autoescape off %}{% blocktrans %}You're receiving this e-mail because you or someone else has requested a password for your user account.
It can be safely ignored if you did not request a password reset. Click the link below to reset your password.{% endblocktrans %}
{{ password_reset_url }}{% if username %}
{% blocktrans %}In case you forgot, your username is {{ username }}.{% endblocktrans %}{% endif %}{% endautoescape %}{% endblock %}

View file

@ -0,0 +1,4 @@
{% load i18n %}
{% autoescape off %}
{% blocktrans %}Password Reset E-mail{% endblocktrans %}
{% endautoescape %}

View file

@ -0,0 +1,12 @@
{% extends "account/email/base_message.txt" %}
{% load i18n %}
{% block content %}{% autoescape off %}{% blocktrans %}You are receiving this e-mail because you or someone else has requested a
password for your user account. However, we do not have any record of a user
with email {{ email }} in our database.
This mail can be safely ignored if you did not request a password reset.
If it was you, you can sign up for an account using the link below.{% endblocktrans %}
{{ signup_url }}{% endautoescape %}{% endblock %}

View file

@ -0,0 +1,4 @@
{% load i18n %}
{% autoescape off %}
{% blocktrans %}Password Reset E-mail{% endblocktrans %}
{% endautoescape %}

View file

@ -0,0 +1,32 @@
{% extends "base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% load account %}
{% block head_title %}{% trans "Confirm E-mail Address" %}{% endblock %}
{% block content %}
<h1>{% trans "Confirm E-mail Address" %}</h1>
{% if confirmation %}
{% user_display confirmation.email_address.user as user_display %}
<p>{% blocktrans with confirmation.email_address.email as email %}Please confirm that <a href="mailto:{{ email }}">{{ email }}</a> is an e-mail address for user {{ user_display }}.{% endblocktrans %}</p>
<form method="post" action="{% url 'account_confirm_email' confirmation.key %}">
{% csrf_token %}
<button class="btn btn-primary" type="submit">{% trans 'Confirm' %}</button>
</form>
{% else %}
{% url 'account_email' as email_url %}
<p>{% blocktrans %}This e-mail confirmation link expired or is invalid. Please <a href="{{ email_url }}">issue a new e-mail confirmation request</a>.{% endblocktrans %}</p>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,48 @@
{% extends "base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% load account socialaccount %}
{% block head_title %}{% trans "Sign In" %}{% endblock %}
{% block content %}
<div class="row">
<div class="col-lg-5">
<h1>{% trans "Sign In" %}</h1>
{% get_providers as socialaccount_providers %}
{% comment %}
{% if socialaccount_providers %}
<p>{% blocktrans with site.name as site_name %}Please sign in with one
of your existing third party accounts. Or, <a href="{{ signup_url }}">sign up</a>
for a {{ site_name }} account and sign in below:{% endblocktrans %}</p>
<div class="socialaccount_ballot">
<ul class="socialaccount_providers">
{% include "socialaccount/snippets/provider_list.html" with process="login" %}
</ul>
<div class="login-or">{% trans 'or' %}</div>
</div>
{% include "socialaccount/snippets/login_extra.html" %}
{% else %}
<p>{% blocktrans %}If you have not created an account yet, then please
<a href="{{ signup_url }}">sign up</a> first.{% endblocktrans %}</p>
{% endif %} {% endcomment %}
<form class="login" method="POST" action="{% url 'account_login' %}">
{% csrf_token %}
{{ form|crispy }}
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<a class="btn btn-danger" href="{% url 'account_reset_password' %}">{% trans "Forgot Password?" %}</a>
<button class="btn btn-primary" type="submit">{% trans "Sign In" %}</button>
</form>
</div>
{% endblock %}

View file

@ -0,0 +1,22 @@
{% extends "base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block head_title %}{% trans "Sign Out" %}{% endblock %}
{% block content %}
<h1>{% trans "Sign Out" %}</h1>
<p>{% trans 'Are you sure you want to sign out?' %}</p>
<form method="post" action="{% url 'account_logout' %}">
{% csrf_token %}
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}"/>
{% endif %}
<button type="submit">{% trans 'Sign Out' %}</button>
</form>
{% endblock %}

View file

@ -0,0 +1,2 @@
{% load i18n %}
{% blocktrans %}You cannot remove your primary e-mail address ({{email}}).{% endblocktrans %}

View file

@ -0,0 +1,2 @@
{% load i18n %}
{% blocktrans %}Confirmation e-mail sent to {{email}}.{% endblocktrans %}

View file

@ -0,0 +1,2 @@
{% load i18n %}
{% blocktrans %}You have confirmed {{email}}.{% endblocktrans %}

View file

@ -0,0 +1,2 @@
{% load i18n %}
{% blocktrans %}Removed e-mail address {{email}}.{% endblocktrans %}

View file

@ -0,0 +1,4 @@
{% load account %}
{% load i18n %}
{% user_display user as name %}
{% blocktrans %}Successfully signed in as {{name}}.{% endblocktrans %}

View file

@ -0,0 +1,2 @@
{% load i18n %}
{% blocktrans %}You have signed out.{% endblocktrans %}

View file

@ -0,0 +1,2 @@
{% load i18n %}
{% blocktrans %}Password successfully changed.{% endblocktrans %}

Some files were not shown because too many files have changed in this diff Show more