jazzmin as a more beauty admin panel
0
app/aviary/__init__.py
Normal file
13
app/aviary/admin.py
Normal 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
|
@ -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
|
@ -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"),
|
||||
}
|
40
app/aviary/migrations/0001_initial.py
Normal 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",
|
||||
},
|
||||
),
|
||||
]
|
26
app/aviary/migrations/0002_alter_aviary_condition.py
Normal 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",
|
||||
),
|
||||
),
|
||||
]
|
26
app/aviary/migrations/0003_alter_aviary_condition.py
Normal 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",
|
||||
),
|
||||
),
|
||||
]
|
0
app/aviary/migrations/__init__.py
Normal file
21
app/aviary/models.py
Normal 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
|
60
app/aviary/templates/aviary/aviary_all.html
Normal 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 %}
|
42
app/aviary/templates/aviary/aviary_single.html
Normal 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
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
11
app/aviary/urls.py
Normal 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
|
@ -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
24
app/bird/admin.py
Normal 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
|
@ -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
|
@ -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"),
|
||||
}
|
156
app/bird/migrations/0001_initial.py
Normal 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",
|
||||
},
|
||||
),
|
||||
]
|
0
app/bird/migrations/__init__.py
Normal file
88
app/bird/models.py
Normal 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
|
107
app/bird/templates/bird/bird_all.html
Normal 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 %}
|
48
app/bird/templates/bird/bird_create.html
Normal 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 %}
|
25
app/bird/templates/bird/bird_delete.html
Normal 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 %}
|
13
app/bird/templates/bird/bird_help.html
Normal 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 %}
|
72
app/bird/templates/bird/bird_single.html
Normal 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
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
21
app/bird/urls.py
Normal 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
|
@ -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
16
app/core/asgi.py
Normal 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
|
@ -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
|
@ -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
|
@ -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
22
app/manage.py
Executable 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
|
@ -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
17
app/rescuer/admin.py
Normal 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
|
@ -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
|
@ -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"),
|
||||
}
|
46
app/rescuer/migrations/0001_initial.py
Normal 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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
0
app/rescuer/migrations/__init__.py
Normal file
20
app/rescuer/models.py
Normal 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
|
70
app/rescuer/templates/rescuer/rescuer_all.html
Normal 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 %}
|
52
app/rescuer/templates/rescuer/rescuer_create.html
Normal 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 %}
|
28
app/rescuer/templates/rescuer/rescuer_delete.html
Normal 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 %}
|
40
app/rescuer/templates/rescuer/rescuer_edit.html
Normal 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 %}
|
38
app/rescuer/templates/rescuer/rescuer_single.html
Normal 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
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
17
app/rescuer/urls.py
Normal 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
|
@ -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
3
app/sites/admin.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
6
app/sites/apps.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class SitesConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'sites'
|
0
app/sites/migrations/__init__.py
Normal file
3
app/sites/models.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.db import models
|
||||
|
||||
# Create your models here.
|
10
app/sites/templates/sites/index.html
Normal 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
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
9
app/sites/urls.py
Normal 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
|
@ -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
11
app/static/css/bootstrap.min.css
vendored
Normal file
48
app/static/css/style.css
Normal 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
BIN
app/static/img/WildvogelhilfeJena_Logo_1200x1200_V0.eps
Normal file
BIN
app/static/img/favicon.ico
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
app/static/img/favicon_small.ico
Normal file
After Width: | Height: | Size: 697 B |
BIN
app/static/img/logo.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
app/static/img/logo_medium.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
app/static/img/signal-2023-06-09-222100_004.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
app/static/img/signal-2023-06-09-222307_004.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
app/static/img/wvh.png
Normal file
After Width: | Height: | Size: 78 KiB |
2578
app/static/img/wvhLogo.svg
Normal file
After Width: | Height: | Size: 176 KiB |
BIN
app/static/img/wvhLogo12001200300x.png
Normal file
After Width: | Height: | Size: 310 KiB |
21
app/static/js/bird.js
Normal 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
17
app/static/js/find_circumstances.js
Normal 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()
|
||||
});
|
12
app/templates/account/account_inactive.html
Normal 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 %}
|
40
app/templates/account/base.html
Normal 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>
|
78
app/templates/account/email.html
Normal 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 %}
|
7
app/templates/account/email/base_message.txt
Normal 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 %}
|
|
@ -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 %}
|
|
@ -0,0 +1 @@
|
|||
{% include "account/email/email_confirmation_message.txt" %}
|
|
@ -0,0 +1 @@
|
|||
{% include "account/email/email_confirmation_subject.txt" %}
|
|
@ -0,0 +1,4 @@
|
|||
{% load i18n %}
|
||||
{% autoescape off %}
|
||||
{% blocktrans %}Please Confirm Your E-mail Address{% endblocktrans %}
|
||||
{% endautoescape %}
|
|
@ -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 %}
|
|
@ -0,0 +1,4 @@
|
|||
{% load i18n %}
|
||||
{% autoescape off %}
|
||||
{% blocktrans %}Password Reset E-mail{% endblocktrans %}
|
||||
{% endautoescape %}
|
12
app/templates/account/email/unknown_account_message.txt
Normal 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 %}
|
4
app/templates/account/email/unknown_account_subject.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
{% load i18n %}
|
||||
{% autoescape off %}
|
||||
{% blocktrans %}Password Reset E-mail{% endblocktrans %}
|
||||
{% endautoescape %}
|
32
app/templates/account/email_confirm.html
Normal 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 %}
|
48
app/templates/account/login.html
Normal 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 %}
|
22
app/templates/account/logout.html
Normal 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 %}
|
|
@ -0,0 +1,2 @@
|
|||
{% load i18n %}
|
||||
{% blocktrans %}You cannot remove your primary e-mail address ({{email}}).{% endblocktrans %}
|
|
@ -0,0 +1,2 @@
|
|||
{% load i18n %}
|
||||
{% blocktrans %}Confirmation e-mail sent to {{email}}.{% endblocktrans %}
|
2
app/templates/account/messages/email_confirmed.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
{% load i18n %}
|
||||
{% blocktrans %}You have confirmed {{email}}.{% endblocktrans %}
|
2
app/templates/account/messages/email_deleted.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
{% load i18n %}
|
||||
{% blocktrans %}Removed e-mail address {{email}}.{% endblocktrans %}
|
4
app/templates/account/messages/logged_in.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
{% load account %}
|
||||
{% load i18n %}
|
||||
{% user_display user as name %}
|
||||
{% blocktrans %}Successfully signed in as {{name}}.{% endblocktrans %}
|
2
app/templates/account/messages/logged_out.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
{% load i18n %}
|
||||
{% blocktrans %}You have signed out.{% endblocktrans %}
|
2
app/templates/account/messages/password_changed.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
{% load i18n %}
|
||||
{% blocktrans %}Password successfully changed.{% endblocktrans %}
|