Compare commits
29 Commits
964aeb97a7
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
| 151ce0d88e | |||
| e07e633651 | |||
| dd3b1fde9d | |||
| 2ffc9b4ba1 | |||
| 22eebd4586 | |||
| e589a048d3 | |||
| 392eb5a7a8 | |||
| 44fa4d4880 | |||
| 9b97cc4cb1 | |||
| 656a24ef02 | |||
| 74643db087 | |||
| 3a6fd3cee1 | |||
| 29e9d1bd8c | |||
| 3c5ca9ae00 | |||
| 3d1ad6112d | |||
| b843e67e9b | |||
| 4cab71e8fb | |||
| 969339a95f | |||
| e06efa1539 | |||
| 2fb6d2782f | |||
| f69eccd0e4 | |||
| e20e6d4b1d | |||
| 0352a60e28 | |||
| abeb14601a | |||
| f52225495d | |||
| 797b2c15f7 | |||
| e81618500b | |||
| f7a5da306c | |||
| 92a9b5c6c9 |
@@ -15,32 +15,44 @@ class DrawioDirective(SphinxDirective):
|
|||||||
.. drawio::
|
.. drawio::
|
||||||
example-diagram.drawio.html
|
example-diagram.drawio.html
|
||||||
example-diagram.drawio.png
|
example-diagram.drawio.png
|
||||||
|
:alt: Example of a Draw.io diagram
|
||||||
"""
|
"""
|
||||||
|
|
||||||
has_content = False
|
has_content = False
|
||||||
required_arguments = 2 # html and png
|
required_arguments = 2 # html and png
|
||||||
|
optional_arguments = 1
|
||||||
|
final_argument_whitespace = True # indicating if the final argument may contain whitespace
|
||||||
|
option_spec = {
|
||||||
|
"alt": str,
|
||||||
|
}
|
||||||
|
|
||||||
def run(self) -> list[nodes.Node]:
|
def run(self) -> list[nodes.Node]:
|
||||||
html_path = self.arguments[0]
|
|
||||||
png_path = self.arguments[1]
|
|
||||||
|
|
||||||
env = self.state.document.settings.env
|
env = self.state.document.settings.env
|
||||||
|
builder = env.app.builder
|
||||||
|
|
||||||
|
# Resolve paths relative to the document
|
||||||
docdir = Path(env.doc2path(env.docname)).parent
|
docdir = Path(env.doc2path(env.docname)).parent
|
||||||
html_rel = Path(self.arguments[0])
|
html_rel = Path(self.arguments[0])
|
||||||
png_rel = Path(self.arguments[1])
|
png_rel = Path(self.arguments[1])
|
||||||
|
|
||||||
html_path = (docdir / html_rel).resolve()
|
html_path = (docdir / html_rel).resolve()
|
||||||
png_path = (docdir / png_rel).resolve()
|
png_path = (docdir / png_rel).resolve()
|
||||||
|
|
||||||
|
alt_text = self.options.get("alt", "")
|
||||||
|
|
||||||
container = nodes.container()
|
container = nodes.container()
|
||||||
|
|
||||||
# HTML output -> raw HTML node
|
# HTML output -> raw HTML node
|
||||||
if self.builder.format == "html":
|
if builder.format == "html":
|
||||||
# Embed the HTML file contents directly
|
# Embed the HTML file contents directly
|
||||||
|
try:
|
||||||
|
html_content = html_path.read_text(encoding="utf-8")
|
||||||
|
except OSError as e:
|
||||||
|
msg = self.state_machine.reporter.error(f"Cannot read HTML file: {e}")
|
||||||
|
return [msg]
|
||||||
|
aria_attribute = f' aria-label="{alt_text}"' if alt_text else ""
|
||||||
raw_html_node = nodes.raw(
|
raw_html_node = nodes.raw(
|
||||||
"",
|
"",
|
||||||
f'<div class="drawio-diagram">{open(html_path, encoding="utf-8").read()}</div>',
|
f'<div class="drawio-diagram"{aria_attribute}>{html_content}</div>',
|
||||||
format="html",
|
format="html",
|
||||||
)
|
)
|
||||||
container += raw_html_node
|
container += raw_html_node
|
||||||
@@ -51,17 +63,12 @@ class DrawioDirective(SphinxDirective):
|
|||||||
|
|
||||||
return [container]
|
return [container]
|
||||||
|
|
||||||
@property
|
|
||||||
def builder(self):
|
|
||||||
# Helper to access the builder from the directive context
|
|
||||||
return self.state.document.settings.env.app.builder
|
|
||||||
|
|
||||||
|
|
||||||
def setup(app: Sphinx) -> ExtensionMetadata:
|
def setup(app: Sphinx) -> ExtensionMetadata:
|
||||||
app.add_directive("drawio", DrawioDirective)
|
app.add_directive("drawio", DrawioDirective)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"version": "0.1",
|
"version": "0.2",
|
||||||
"parallel_read_safe": True,
|
"parallel_read_safe": True,
|
||||||
"parallel_write_safe": True,
|
"parallel_write_safe": True,
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
docs/user/Vermittlung-Lifecycle.drawio.png
Normal file
BIN
docs/user/Vermittlung-Lifecycle.drawio.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 150 KiB |
11
docs/user/Vermittlung_Lifecycle.drawio.html
Normal file
11
docs/user/Vermittlung_Lifecycle.drawio.html
Normal file
File diff suppressed because one or more lines are too long
@@ -6,14 +6,27 @@ Jede Vermittlung kann abonniert werden. Dafür klickst du auf die Glocke neben d
|
|||||||
|
|
||||||
.. image:: abonnieren.png
|
.. image:: abonnieren.png
|
||||||
|
|
||||||
|
|
||||||
|
Einstellungen
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Du kannst E-Mail Benachrichtigungen in den Einstellungen deaktivieren.
|
||||||
|
|
||||||
|
.. image::
|
||||||
|
einstellungen-benachrichtigungen.png
|
||||||
|
:alt: Screenshot der Profileinstellungen in Notfellchen. Ein roter Pfeil zeigt auf einen Schalter "E-Mail Benachrichtigungen"
|
||||||
|
|
||||||
Auf der Website
|
Auf der Website
|
||||||
+++++++++++++++
|
+++++++++++++++
|
||||||
|
|
||||||
|
.. image::
|
||||||
|
screenshot-benachrichtigungen.png
|
||||||
|
:alt: Screenshot der Menüleiste von Notfellchen.org. Neben dem Symbol einer Glocke steht die Zahl 27.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
E-Mail
|
E-Mail
|
||||||
++++++
|
++++++
|
||||||
|
|
||||||
Mit während deiner :doc:`registrierung` gibst du eine E-Mail Addresse an.
|
Mit während deiner :doc:`registrierung` gibst du eine E-Mail Adresse an. An diese senden wir Benachrichtigungen, außer
|
||||||
|
du deaktiviert dies wie oben beschrieben.
|
||||||
Benachrichtigungen senden wir per Mail - du kannst das jederzeit in den Einstellungen deaktivieren.
|
|
||||||
BIN
docs/user/einstellungen-benachrichtigungen.png
Normal file
BIN
docs/user/einstellungen-benachrichtigungen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
58
docs/user/erste-schritte.rst
Normal file
58
docs/user/erste-schritte.rst
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
Erste Schritte
|
||||||
|
==============
|
||||||
|
|
||||||
|
Tiere zum Adoptieren suchen
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
Wenn du Tiere zum adoptieren suchst, brauchst du keinen Account. Du kannst bequem die `Suche <https://notfellchen.org/suchen/>`_ nutzen, um Tiere zur Adoption in deiner Nähe zu finden.
|
||||||
|
Wenn dich eine Vermittlung interessiert, kannst du folgendes tun
|
||||||
|
|
||||||
|
* die Vermittlung aufrufen um Details zu sehen
|
||||||
|
* den Link :guilabel:`Weitere Informationen` anklicken um auf der Tierheimwebsite mehr zu erfahren
|
||||||
|
* per Kommentar weitere Informationen erfragen oder hinzufügen
|
||||||
|
|
||||||
|
Wenn du die Tiere tatsächlich informieren willst, folge der Anleitung unter :guilabel:`Adoptionsprozess`.
|
||||||
|
Dieser kann sich je nach Tierschutzorganisation unterscheiden.
|
||||||
|
|
||||||
|
.. image::
|
||||||
|
screenshot-adoptionsprozess.png
|
||||||
|
:alt: Screenshot der Sektion "Adoptionsprozess" einer Vermittlungsanzeige. Der Prozess ist folgendermaßen: 1. Link zu "Weiteren Informationen" prüfen, 2. Organization kontaktieren, 3. Bei erfolgreicher Vermittlung: Vermittlung als geschlossen melden
|
||||||
|
|
||||||
|
Suchen abonnieren
|
||||||
|
+++++++++++++++++
|
||||||
|
|
||||||
|
Es kann sein, dass es in deiner Umgebung keine passenden Tiere für deine Suche gibt. Damit du nicht ständig wieder Suchen musst, gibt es die Funktion "Suche abonnieren".
|
||||||
|
Wenn du eine Suche abonnierst, wirst du für neue Vermittlungen, die den Kriterien der Suche entsprechen, benachrichtigt.
|
||||||
|
|
||||||
|
.. image::
|
||||||
|
screenshot-suche-abonnieren.png
|
||||||
|
:alt: Screenshot der Suchmaske auf Notfellchen.org . Ein roter Pfeil zeigt auf den Button "Suche abonnieren"
|
||||||
|
|
||||||
|
.. important::
|
||||||
|
|
||||||
|
Um Suchen zu abonnieren brauchst du einen Account. Wie du einen Account erstellst erfährst du hier: :doc:`registrierung`.
|
||||||
|
|
||||||
|
.. hint::
|
||||||
|
|
||||||
|
Mehr über Benachrichtigungen findest du hier: :doc:`benachrichtigungen`.
|
||||||
|
|
||||||
|
Vermittlungen hinzufügen
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Gehe zu `Vermittlung hinzufügen <https://notfellchen.org/vermitteln/>`_ um eine neue Vermittlung einzustellen.
|
||||||
|
Füge alle Informationen die du hast hinzu.
|
||||||
|
|
||||||
|
.. important::
|
||||||
|
|
||||||
|
Um Vermittlungen hinzuzufügen brauchst du einen Account.
|
||||||
|
Wie du einen Account erstellst erfährst du hier: :doc:`registrierung`.
|
||||||
|
|
||||||
|
|
||||||
|
.. important::
|
||||||
|
|
||||||
|
Vermittlungen die du einstellst müssen erst durch Moderator\*innen freigeschaltet werden. Das passiert normalerweise
|
||||||
|
innerhalb von 24 Stunden. Wenn deine Vermittlung dann noch nicht freigeschaltet ist, prüfe bitte dein E-Mail Postfach,
|
||||||
|
es könnte sein, dass die Moderator\*innen Rückfragen haben. Melde dich gerne unter info@notfellchen.org, wenn deine
|
||||||
|
Vermittlung nach 24 Stunden nicht freigeschaltet ist.
|
||||||
|
|
||||||
|
|
||||||
@@ -1,10 +1,15 @@
|
|||||||
******************
|
****************
|
||||||
User Dokumentation
|
Benutzerhandbuch
|
||||||
******************
|
****************
|
||||||
|
|
||||||
|
Im Benutzerhandbuch findest du Informationen zur Benutzung von `notfellchen.org <https://notfellchen.org>`_.
|
||||||
|
Solltest du darüber hinaus Fragen haben, komm gerne auf uns zu: info@notfellchen.org
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
:caption: Inhalt:
|
:caption: Inhalt:
|
||||||
|
|
||||||
|
erste-schritte.rst
|
||||||
registrierung.rst
|
registrierung.rst
|
||||||
vermittlungen.rst
|
vermittlungen.rst
|
||||||
moderationskonzept.rst
|
moderationskonzept.rst
|
||||||
|
|||||||
@@ -1,10 +1,19 @@
|
|||||||
Tiere in Vermittlung systematisch entdecken & eintragen
|
Tiere in Vermittlung systematisch entdecken & eintragen
|
||||||
=======================================================
|
=======================================================
|
||||||
|
|
||||||
Notfellchen hat eine Liste der meisten deutschen Tierheime und anderer Tierschutzorganisationen (550, Stand Oktober 2025).
|
Notfellchen hat eine Liste der meisten deutschen Tierheime und anderer Tierschutzorganisationen.
|
||||||
Die meisten dieser Organisationen (412, Stand Oktober 2025) nehmen Tiere auf die bei Notfellchen eingetragen werden können.
|
Die meisten dieser Organisationen nehmen Tiere auf die bei Notfellchen eingetragen werden können.
|
||||||
Es ist daher das Ziel, diese Organisationen alle zwei Wochen auf neue Tiere zu prüfen.
|
Es ist daher das Ziel, diese Organisationen alle zwei Wochen auf neue Tiere zu prüfen.
|
||||||
|
|
||||||
|
|
||||||
|
+-------------------------------------------------+---------+----------------------+
|
||||||
|
| Gruppe | Anzahl | Zuletzt aktualisiert |
|
||||||
|
+=================================================+=========+======================+
|
||||||
|
| Tierschutzorganisationen im Verzeichnis | 550 | Oktober 2025 |
|
||||||
|
+-------------------------------------------------+---------+----------------------+
|
||||||
|
| Tierschutzorganisationen in regelmäßigerPrüfung | 412 | Oktober 2025 |
|
||||||
|
+-------------------------------------------------+---------+----------------------+
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
|
|
||||||
Organisationen auf neue Tiere zu prüfen ist eine Funktion für Moderator\*innen. Falls du Lust hast mitzuhelfen,
|
Organisationen auf neue Tiere zu prüfen ist eine Funktion für Moderator\*innen. Falls du Lust hast mitzuhelfen,
|
||||||
|
|||||||
BIN
docs/user/screenshot-adoptionsprozess.png
Normal file
BIN
docs/user/screenshot-adoptionsprozess.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
BIN
docs/user/screenshot-benachrichtigungen.png
Normal file
BIN
docs/user/screenshot-benachrichtigungen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 205 KiB |
BIN
docs/user/screenshot-suche-abonnieren.png
Normal file
BIN
docs/user/screenshot-suche-abonnieren.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
BIN
docs/user/screenshot-suche.png
Normal file
BIN
docs/user/screenshot-suche.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
@@ -16,6 +16,12 @@ Ersteller*innen von Vermittlungen werden über neue Kommentare per Mail benachri
|
|||||||
|
|
||||||
Kommentare können, wie Vermittlungen, gemeldet werden.
|
Kommentare können, wie Vermittlungen, gemeldet werden.
|
||||||
|
|
||||||
|
.. drawio::
|
||||||
|
Vermittlung_Lifecycle.drawio.html
|
||||||
|
Vermittlung-Lifecycle.drawio.png
|
||||||
|
:alt: Diagramm das den Prozess der Vermittlungen zeigt.
|
||||||
|
|
||||||
|
|
||||||
Adoption Notice Status Choices
|
Adoption Notice Status Choices
|
||||||
++++++++++++++++++++++++++++++
|
++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ host=localhost
|
|||||||
[django]
|
[django]
|
||||||
secret=CHANGE-ME
|
secret=CHANGE-ME
|
||||||
debug=True
|
debug=True
|
||||||
|
internal_ips=["127.0.0.1"]
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
backend=sqlite3
|
backend=sqlite3
|
||||||
@@ -28,3 +29,6 @@ django_log_level=INFO
|
|||||||
api_url=https://photon.hyteck.de/api
|
api_url=https://photon.hyteck.de/api
|
||||||
api_format=photon
|
api_format=photon
|
||||||
|
|
||||||
|
[security]
|
||||||
|
totp_issuer="NF Localhost"
|
||||||
|
webauth_allow_insecure_origin=True
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ dependencies = [
|
|||||||
"celery[redis]",
|
"celery[redis]",
|
||||||
"drf-spectacular[sidecar]",
|
"drf-spectacular[sidecar]",
|
||||||
"django-widget-tweaks",
|
"django-widget-tweaks",
|
||||||
"django-super-deduper"
|
"django-super-deduper",
|
||||||
|
"django-allauth[mfa]",
|
||||||
]
|
]
|
||||||
|
|
||||||
dynamic = ["version", "readme"]
|
dynamic = ["version", "readme"]
|
||||||
@@ -48,6 +49,7 @@ develop = [
|
|||||||
"pytest",
|
"pytest",
|
||||||
"coverage",
|
"coverage",
|
||||||
"model_bakery",
|
"model_bakery",
|
||||||
|
"debug_toolbar",
|
||||||
]
|
]
|
||||||
docs = [
|
docs = [
|
||||||
"sphinx",
|
"sphinx",
|
||||||
|
|||||||
@@ -164,6 +164,13 @@ class SocialMediaPostAdmin(admin.ModelAdmin):
|
|||||||
list_filter = ("platform",)
|
list_filter = ("platform",)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Log)
|
||||||
|
class LogAdmin(admin.ModelAdmin):
|
||||||
|
ordering = ["-created_at"]
|
||||||
|
list_filter = ("action",)
|
||||||
|
list_display = ("action", "user", "created_at")
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Animal)
|
admin.site.register(Animal)
|
||||||
admin.site.register(Species)
|
admin.site.register(Species)
|
||||||
admin.site.register(Rule)
|
admin.site.register(Rule)
|
||||||
@@ -172,5 +179,4 @@ admin.site.register(ModerationAction)
|
|||||||
admin.site.register(Language)
|
admin.site.register(Language)
|
||||||
admin.site.register(Announcement)
|
admin.site.register(Announcement)
|
||||||
admin.site.register(Subscriptions)
|
admin.site.register(Subscriptions)
|
||||||
admin.site.register(Log)
|
|
||||||
admin.site.register(Timestamp)
|
admin.site.register(Timestamp)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
|
from django.forms.widgets import Textarea
|
||||||
|
|
||||||
from .models import AdoptionNotice, Animal, Image, ReportAdoptionNotice, ReportComment, ModerationAction, User, Species, \
|
from .models import AdoptionNotice, Animal, Image, ReportAdoptionNotice, ReportComment, ModerationAction, User, Species, \
|
||||||
Comment, SexChoicesWithAll, DistanceChoices, SpeciesSpecificURL, RescueOrganization
|
Comment, SexChoicesWithAll, DistanceChoices, SpeciesSpecificURL, RescueOrganization
|
||||||
@@ -9,6 +10,8 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
from notfellchen.settings import MEDIA_URL
|
from notfellchen.settings import MEDIA_URL
|
||||||
from crispy_forms.layout import Div
|
from crispy_forms.layout import Div
|
||||||
|
|
||||||
|
from .tools.model_helpers import reason_for_signup_label, reason_for_signup_help_text
|
||||||
|
|
||||||
|
|
||||||
def animal_validator(value: str):
|
def animal_validator(value: str):
|
||||||
value = value.lower()
|
value = value.lower()
|
||||||
@@ -57,6 +60,14 @@ class AnimalForm(forms.ModelForm):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateRescueOrgRegularCheckStatus(forms.ModelForm):
|
||||||
|
template_name = "fellchensammlung/forms/form_snippets.html"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = RescueOrganization
|
||||||
|
fields = ["regular_check_status"]
|
||||||
|
|
||||||
|
|
||||||
class ImageForm(forms.ModelForm):
|
class ImageForm(forms.ModelForm):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
if 'in_flow' in kwargs:
|
if 'in_flow' in kwargs:
|
||||||
@@ -129,6 +140,18 @@ class ModerationActionForm(forms.ModelForm):
|
|||||||
fields = ('action', 'public_comment', 'private_comment')
|
fields = ('action', 'public_comment', 'private_comment')
|
||||||
|
|
||||||
|
|
||||||
|
class AddedRegistrationForm(forms.Form):
|
||||||
|
reason_for_signup = forms.CharField(label=reason_for_signup_label,
|
||||||
|
help_text=reason_for_signup_help_text,
|
||||||
|
widget=Textarea)
|
||||||
|
captcha = forms.CharField(validators=[animal_validator], label=_("Nenne eine bekannte Tierart"), help_text=_(
|
||||||
|
"Bitte nenne hier eine bekannte Tierart (z.B. ein Tier das an der Leine geführt wird). Das Fragen wir dich um "
|
||||||
|
"sicherzustellen, dass du kein Roboter bist."))
|
||||||
|
|
||||||
|
def signup(self, request, user):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class CustomRegistrationForm(RegistrationForm):
|
class CustomRegistrationForm(RegistrationForm):
|
||||||
class Meta(RegistrationForm.Meta):
|
class Meta(RegistrationForm.Meta):
|
||||||
model = User
|
model = User
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.2.1 on 2025-10-20 08:43
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('fellchensammlung', '0068_alter_adoptionnotice_adoption_notice_status_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='rescueorganization',
|
||||||
|
name='regular_check_status',
|
||||||
|
field=models.CharField(choices=[('regular_check', 'Wird regelmäßig geprüft'), ('excluded_no_online_listing', 'Exkludiert: Tiere werden nicht online gelistet'), ('excluded_other_org', 'Exkludiert: Andere Organisation wird geprüft'), ('excluded_scope', 'Exkludiert: Organisation hat nie Notfellchen-relevanten Vermittlungen'), ('excluded_other', 'Exkludiert: Anderer Grund')], default='regular_check', help_text='Organisationen können, durch ändern dieser Einstellung, von der regelmäßigen Prüfung ausgeschlossen werden.', max_length=30, verbose_name='Status der regelmäßigen Prüfung'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -13,7 +13,8 @@ from notfellchen.settings import MEDIA_URL, base_url
|
|||||||
from .tools.geo import LocationProxy, Position
|
from .tools.geo import LocationProxy, Position
|
||||||
from .tools.misc import time_since_as_hr_string
|
from .tools.misc import time_since_as_hr_string
|
||||||
from .tools.model_helpers import NotificationTypeChoices, AdoptionNoticeStatusChoices, AdoptionProcess, \
|
from .tools.model_helpers import NotificationTypeChoices, AdoptionNoticeStatusChoices, AdoptionProcess, \
|
||||||
AdoptionNoticeStatusChoicesDescriptions
|
AdoptionNoticeStatusChoicesDescriptions, RegularCheckStatusChoices, reason_for_signup_label, \
|
||||||
|
reason_for_signup_help_text
|
||||||
from .tools.model_helpers import ndm as NotificationDisplayMapping
|
from .tools.model_helpers import ndm as NotificationDisplayMapping
|
||||||
|
|
||||||
|
|
||||||
@@ -172,6 +173,12 @@ class RescueOrganization(models.Model):
|
|||||||
exclude_from_check = models.BooleanField(default=False, verbose_name=_('Von Prüfung ausschließen'),
|
exclude_from_check = models.BooleanField(default=False, verbose_name=_('Von Prüfung ausschließen'),
|
||||||
help_text=_("Organisation von der manuellen Überprüfung ausschließen, "
|
help_text=_("Organisation von der manuellen Überprüfung ausschließen, "
|
||||||
"z.B. weil Tiere nicht online geführt werden"))
|
"z.B. weil Tiere nicht online geführt werden"))
|
||||||
|
regular_check_status = models.CharField(max_length=30, choices=RegularCheckStatusChoices.choices,
|
||||||
|
default=RegularCheckStatusChoices.REGULAR_CHECK,
|
||||||
|
verbose_name=_('Status der regelmäßigen Prüfung'),
|
||||||
|
help_text=_(
|
||||||
|
"Organisationen können, durch ändern dieser Einstellung, von der "
|
||||||
|
"regelmäßigen Prüfung ausgeschlossen werden."))
|
||||||
ongoing_communication = models.BooleanField(default=False, verbose_name=_('In aktiver Kommunikation'),
|
ongoing_communication = models.BooleanField(default=False, verbose_name=_('In aktiver Kommunikation'),
|
||||||
help_text=_(
|
help_text=_(
|
||||||
"Es findet gerade Kommunikation zwischen Notfellchen und der Organisation statt."))
|
"Es findet gerade Kommunikation zwischen Notfellchen und der Organisation statt."))
|
||||||
@@ -261,10 +268,6 @@ class RescueOrganization(models.Model):
|
|||||||
"""
|
"""
|
||||||
return self.instagram or self.facebook or self.website or self.phone_number or self.email or self.fediverse_profile
|
return self.instagram or self.facebook or self.website or self.phone_number or self.email or self.fediverse_profile
|
||||||
|
|
||||||
def set_exclusion_from_checks(self):
|
|
||||||
self.exclude_from_check = True
|
|
||||||
self.save()
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def child_organizations(self):
|
def child_organizations(self):
|
||||||
return RescueOrganization.objects.filter(parent_org=self)
|
return RescueOrganization.objects.filter(parent_org=self)
|
||||||
@@ -305,8 +308,7 @@ class User(AbstractUser):
|
|||||||
updated_at = models.DateTimeField(auto_now=True)
|
updated_at = models.DateTimeField(auto_now=True)
|
||||||
organization_affiliation = models.ForeignKey(RescueOrganization, on_delete=models.PROTECT, null=True, blank=True,
|
organization_affiliation = models.ForeignKey(RescueOrganization, on_delete=models.PROTECT, null=True, blank=True,
|
||||||
verbose_name=_('Organisation'))
|
verbose_name=_('Organisation'))
|
||||||
reason_for_signup = models.TextField(verbose_name=_("Grund für die Registrierung"), help_text=_(
|
reason_for_signup = models.TextField(verbose_name=reason_for_signup_label, help_text=reason_for_signup_help_text)
|
||||||
"Wir würden gerne wissen warum du dich registriertst, ob du dich z.B. Tiere eines bestimmten Tierheim einstellen willst 'nur mal gucken' willst. Beides ist toll! Wenn du für ein Tierheim/eine Pflegestelle arbeitest kontaktieren wir dich ggf. um dir erweiterte Rechte zu geben."))
|
|
||||||
email_notifications = models.BooleanField(verbose_name=_("Benachrichtigung per E-Mail"), default=True)
|
email_notifications = models.BooleanField(verbose_name=_("Benachrichtigung per E-Mail"), default=True)
|
||||||
REQUIRED_FIELDS = ["reason_for_signup", "email"]
|
REQUIRED_FIELDS = ["reason_for_signup", "email"]
|
||||||
|
|
||||||
@@ -417,9 +419,10 @@ class AdoptionNotice(models.Model):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def num_per_sex(self):
|
def num_per_sex(self):
|
||||||
|
print(f"{self.pk} x")
|
||||||
num_per_sex = dict()
|
num_per_sex = dict()
|
||||||
for sex in SexChoices:
|
for sex in SexChoices:
|
||||||
num_per_sex[sex] = self.animals.filter(sex=sex).count()
|
num_per_sex[sex] = len([animal for animal in self.animals if animal.sex == sex])
|
||||||
return num_per_sex
|
return num_per_sex
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -509,6 +512,7 @@ class AdoptionNotice(models.Model):
|
|||||||
photos.extend(animal.photos.all())
|
photos.extend(animal.photos.all())
|
||||||
if len(photos) > 0:
|
if len(photos) > 0:
|
||||||
return photos
|
return photos
|
||||||
|
return None
|
||||||
|
|
||||||
def get_photo(self):
|
def get_photo(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
12
src/fellchensammlung/templates/allauth/elements/badge.html
Normal file
12
src/fellchensammlung/templates/allauth/elements/badge.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{% load allauth %}
|
||||||
|
{% setvar variant %}
|
||||||
|
{% if "primary" in attrs.tags %}
|
||||||
|
is-success
|
||||||
|
{% elif "secondary" in attrs.tags %}
|
||||||
|
is-success is-light
|
||||||
|
{% endif %}
|
||||||
|
{% endsetvar %}
|
||||||
|
<span class="tag{% if variant %} {{ variant }}{% endif %}" {% if attrs.title %}title="{{ attrs.title }}"{% endif %}>
|
||||||
|
{% slot %}
|
||||||
|
{% endslot %}
|
||||||
|
</span>
|
||||||
15
src/fellchensammlung/templates/allauth/elements/button.html
Normal file
15
src/fellchensammlung/templates/allauth/elements/button.html
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{% load allauth %}
|
||||||
|
{% comment %} djlint:off {% endcomment %}
|
||||||
|
<div class="control">
|
||||||
|
<{% if attrs.href %}a href="{{ attrs.href }}"{% else %}button{% endif %}
|
||||||
|
class="button is-primary"
|
||||||
|
{% if attrs.form %}form="{{ attrs.form }}"{% endif %}
|
||||||
|
{% if attrs.id %}id="{{ attrs.id }}"{% endif %}
|
||||||
|
{% if attrs.name %}name="{{ attrs.name }}"{% endif %}
|
||||||
|
{% if attrs.value %}value="{{ attrs.value }}"{% endif %}
|
||||||
|
{% if attrs.type %}type="{{ attrs.type }}"{% endif %}
|
||||||
|
>
|
||||||
|
{% slot %}
|
||||||
|
{% endslot %}
|
||||||
|
</{% if attrs.href %}a{% else %}button{% endif %}>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{% load allauth %}
|
||||||
|
<div class="field is-grouped">
|
||||||
|
{% slot %}
|
||||||
|
{% endslot %}
|
||||||
|
</div>
|
||||||
50
src/fellchensammlung/templates/allauth/elements/field.html
Normal file
50
src/fellchensammlung/templates/allauth/elements/field.html
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{% load allauth %}
|
||||||
|
<div class="field">
|
||||||
|
|
||||||
|
{% if attrs.type == "textarea" %}
|
||||||
|
<label class="label" for="{{ attrs.id }}">
|
||||||
|
{% slot label %}
|
||||||
|
{% endslot %}
|
||||||
|
</label>
|
||||||
|
<textarea class="textarea"
|
||||||
|
{% if attrs.required %}required{% endif %}
|
||||||
|
{% if attrs.rows %}rows="{{ attrs.rows }}"{% endif %}
|
||||||
|
{% if attrs.disabled %}disabled{% endif %}
|
||||||
|
{% if attrs.readonly %}readonly{% endif %}
|
||||||
|
{% if attrs.checked %}checked{% endif %}
|
||||||
|
{% if attrs.name %}name="{{ attrs.name }}"{% endif %}
|
||||||
|
{% if attrs.id %}id="{{ attrs.id }}"{% endif %}
|
||||||
|
{% if attrs.placeholder %}placeholder="{{ attrs.placeholder }}"{% endif %}>{% slot value %}{% endslot %}</textarea>
|
||||||
|
{% else %}
|
||||||
|
{% if attrs.type != "checkbox" and attrs.type != "radio" %}
|
||||||
|
<label class="label" for="{{ attrs.id }}">
|
||||||
|
{% slot label %}
|
||||||
|
{% endslot %}
|
||||||
|
</label>
|
||||||
|
{% endif %}
|
||||||
|
<input {% if attrs.type != "checkbox" and attrs.type != "radio" %}class="input"{% endif %}
|
||||||
|
{% if attrs.required %}required{% endif %}
|
||||||
|
{% if attrs.disabled %}disabled{% endif %}
|
||||||
|
{% if attrs.readonly %}readonly{% endif %}
|
||||||
|
{% if attrs.checked %}checked{% endif %}
|
||||||
|
{% if attrs.name %}name="{{ attrs.name }}"{% endif %}
|
||||||
|
{% if attrs.id %}id="{{ attrs.id }}"{% endif %}
|
||||||
|
{% if attrs.placeholder %}placeholder="{{ attrs.placeholder }}"{% endif %}
|
||||||
|
{% if attrs.autocomplete %}autocomplete="{{ attrs.autocomplete }}"{% endif %}
|
||||||
|
{% if attrs.value is not None %}value="{{ attrs.value }}"{% endif %}
|
||||||
|
type="{{ attrs.type }}">
|
||||||
|
{% if attrs.type == "checkbox" or attrs.type == "radio" %}
|
||||||
|
<label for="{{ attrs.id }}">
|
||||||
|
{% slot label %}
|
||||||
|
{% endslot %}
|
||||||
|
</label>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if slots.help_text %}
|
||||||
|
<p class="help is-danger">
|
||||||
|
{% slot help_text %}
|
||||||
|
{% endslot %}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
<p class="help is-danger">{{ attrs.errors }}</p>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{{ attrs.form }}
|
||||||
12
src/fellchensammlung/templates/allauth/elements/form.html
Normal file
12
src/fellchensammlung/templates/allauth/elements/form.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{% load allauth %}
|
||||||
|
<div class="block">
|
||||||
|
<form method="{{ attrs.method }}"
|
||||||
|
{% if attrs.action %}action="{{ attrs.action }}"{% endif %}>
|
||||||
|
{% slot body %}
|
||||||
|
{% endslot %}
|
||||||
|
<div class="field is-grouped is-grouped-multiline">
|
||||||
|
{% slot actions %}
|
||||||
|
{% endslot %}
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
1
src/fellchensammlung/templates/allauth/elements/h1.html
Normal file
1
src/fellchensammlung/templates/allauth/elements/h1.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{% comment %} djlint:off {% endcomment %}{% load allauth %}<h1 class="title is-1">{% slot %}{% endslot %}</h1>
|
||||||
1
src/fellchensammlung/templates/allauth/elements/h2.html
Normal file
1
src/fellchensammlung/templates/allauth/elements/h2.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{% comment %} djlint:off {% endcomment %}{% load allauth %}<h2 class="title is-2">{% slot %}{% endslot %}</h2>
|
||||||
1
src/fellchensammlung/templates/allauth/elements/p.html
Normal file
1
src/fellchensammlung/templates/allauth/elements/p.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{% comment %} djlint:off {% endcomment %}{% load allauth %}<p class="content">{% slot %}{% endslot %}</p>
|
||||||
18
src/fellchensammlung/templates/allauth/elements/panel.html
Normal file
18
src/fellchensammlung/templates/allauth/elements/panel.html
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{% load allauth %}
|
||||||
|
<section class="block">
|
||||||
|
<h2 class="title is-2">
|
||||||
|
{% slot title %}
|
||||||
|
{% endslot %}
|
||||||
|
</h2>
|
||||||
|
{% slot body %}
|
||||||
|
{% endslot %}
|
||||||
|
{% if slots.actions %}
|
||||||
|
<div class="field is-grouped is-grouped-multiline">
|
||||||
|
{% for action in slots.actions %}
|
||||||
|
<div class="control">
|
||||||
|
{{ action }}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</section>
|
||||||
1
src/fellchensammlung/templates/allauth/layouts/base.html
Normal file
1
src/fellchensammlung/templates/allauth/layouts/base.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{% extends "fellchensammlung/base.html" %}
|
||||||
@@ -37,6 +37,26 @@
|
|||||||
{% block header %}
|
{% block header %}
|
||||||
{% include "fellchensammlung/header.html" %}
|
{% include "fellchensammlung/header.html" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
{% if profile %}
|
||||||
|
<div class="profile">
|
||||||
|
<table class="table is-bordered is-fullwidth is-hoverable is-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td>Timestamp</td>
|
||||||
|
<td>Status</td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for status in profile %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ status.0 }}</td>
|
||||||
|
<td>{{ status.1 }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
@@ -45,5 +65,8 @@
|
|||||||
{% block footer %}
|
{% block footer %}
|
||||||
{% include "fellchensammlung/footer.html" %}
|
{% include "fellchensammlung/footer.html" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extra_body %}
|
||||||
|
{% endblock extra_body %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -19,53 +19,10 @@
|
|||||||
<div class="columns">
|
<div class="columns">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<div class="card">
|
{% include "fellchensammlung/partials/rescue_orgs/partial-basic-info-card.html" %}
|
||||||
<div class="card-header">
|
|
||||||
<h1 class="card-header-title">{{ org.name }}</h1>
|
|
||||||
</div>
|
|
||||||
<div class="card-content">
|
|
||||||
<div class="block">
|
|
||||||
<b><i class="fa-solid fa-location-dot"></i></b>
|
|
||||||
{% if org.location %}
|
|
||||||
{{ org.location }}
|
|
||||||
{% else %}
|
|
||||||
{{ org.location_string }}
|
|
||||||
{% endif %}
|
|
||||||
{% if org.description %}
|
|
||||||
<div class="block content">
|
|
||||||
<p>{{ org.description | render_markdown }}</p>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% if org.specializations %}
|
|
||||||
<div class="block">
|
|
||||||
<h3 class="title is-5">{% translate 'Spezialisierung' %}</h3>
|
|
||||||
<div class="content">
|
|
||||||
<ul>
|
|
||||||
{% for specialization in org.specializations.all %}
|
|
||||||
<li>{{ specialization }}</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% if org.parent_org %}
|
|
||||||
<div class="block">
|
|
||||||
<h3 class="title is-5">{% translate 'Übergeordnete Organisation' %}</h3>
|
|
||||||
<p>
|
|
||||||
<span>
|
|
||||||
<i class="fa-solid fa-building fa-fw"
|
|
||||||
aria-label="{% trans 'Tierschutzorganisation' %}"></i>
|
|
||||||
<a href="{{ org.parent_org.get_absolute_url }}"> {{ org.parent_org }}</a>
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="block">
|
<div class="block">
|
||||||
{% include "fellchensammlung/partials/partial-rescue-organization-contact.html" %}
|
{% include "fellchensammlung/partials/rescue_orgs/partial-rescue-organization-contact.html" %}
|
||||||
</div>
|
</div>
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<a class="button is-warning is-fullwidth" href="{% url org_meta|admin_urlname:'change' org.pk %}">
|
<a class="button is-warning is-fullwidth" href="{% url org_meta|admin_urlname:'change' org.pk %}">
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
{% extends "fellchensammlung/base.html" %}
|
{% extends "fellchensammlung/base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
{% load account %}
|
||||||
|
|
||||||
{% block title %}<title>{{ user.get_full_name }}</title>{% endblock %}
|
{% block title %}<title>{% user_display user %}</title>{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
@@ -13,7 +14,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="level-right">
|
<div class="level-right">
|
||||||
<div class="level-item">
|
<div class="level-item">
|
||||||
<form class="" action="{% url 'logout' %}" method="post">
|
<form class="" action="{% url 'account_logout' %}" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<button class="button" type="submit">
|
<button class="button" type="submit">
|
||||||
<i aria-hidden="true" class="fas fa-sign-out fa-fw"></i> Logout
|
<i aria-hidden="true" class="fas fa-sign-out fa-fw"></i> Logout
|
||||||
@@ -25,69 +26,87 @@
|
|||||||
|
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<h2 class="title is-2">{% trans 'Profil verwalten' %}</h2>
|
<h2 class="title is-2">{% trans 'Profil verwalten' %}</h2>
|
||||||
<p><strong>{% translate "E-Mail" %}:</strong> {{ user.email }}</p>
|
<div class="block"><strong>{% translate "E-Mail" %}:</strong> {{ user.email }}</div>
|
||||||
<div class="">
|
|
||||||
<p>
|
|
||||||
<a class="button is-warning" href="{% url 'password_change' %}">{% translate "Change password" %}</a>
|
|
||||||
<a class="button is-info" href="{% url 'user-me-export' %}">{% translate "Daten exportieren" %}</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if user.id is request.user.id %}
|
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<h2 class="title is-2">{% trans 'Einstellungen' %}</h2>
|
<div class="field is-grouped is-grouped-multiline">
|
||||||
<form class="block" action="" method="POST">
|
<div class="control">
|
||||||
{% csrf_token %}
|
<a class="button is-warning"
|
||||||
{% if user.email_notifications %}
|
href="{% url 'account_change_password' %}">{% translate "Passwort ändern" %}</a>
|
||||||
<label class="toggle">
|
|
||||||
<input type="submit" class="toggle-checkbox checked" name="toggle_email_notifications">
|
|
||||||
<div class="toggle-switch round "></div>
|
|
||||||
<span class="slider-label">
|
|
||||||
{% translate 'E-Mail Benachrichtigungen' %}
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
{% else %}
|
|
||||||
<label class="toggle">
|
|
||||||
<input type="submit" class="toggle-checkbox" name="toggle_email_notifications">
|
|
||||||
<div class="toggle-switch round"></div>
|
|
||||||
<span class="slider-label">
|
|
||||||
{% translate 'E-Mail Benachrichtigungen' %}
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
{% endif %}
|
|
||||||
</form>
|
|
||||||
<details>
|
|
||||||
<summary><strong>{% trans 'Erweiterte Einstellungen' %}</strong></summary>
|
|
||||||
<div class="block">
|
|
||||||
{% if token %}
|
|
||||||
<form action="" method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
<p class="text-muted"><strong>{% translate "API token:" %}</strong> {{ token }}</p>
|
|
||||||
<input class="button is-danger" type="submit" name="delete_token"
|
|
||||||
value={% translate "Delete API token" %}>
|
|
||||||
</form>
|
|
||||||
{% else %}
|
|
||||||
<p>{% translate "Kein API-Token vorhanden." %}</p>
|
|
||||||
<form action="" method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input class="button is-primary" type="submit" name="create_token"
|
|
||||||
value={% translate "Create API token" %}>
|
|
||||||
</form>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</details>
|
<div class="control">
|
||||||
|
<a class="button is-warning"
|
||||||
|
href="{% url 'account_email' %}">
|
||||||
|
{% translate "E-Mail Adresse ändern" %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="control">
|
||||||
|
<a class="button is-warning"
|
||||||
|
href="{% url 'mfa_index' %}">
|
||||||
|
{% translate "2-Faktor Authentifizierung" %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="control">
|
||||||
|
<a class="button is-info" href="{% url 'user-me-export' %}">
|
||||||
|
{% translate "Daten exportieren" %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 class="title is-2">{% translate 'Benachrichtigungen' %}</h2>
|
{% if user.id is request.user.id %}
|
||||||
{% include "fellchensammlung/lists/list-notifications.html" %}
|
<div class="block">
|
||||||
|
<h2 class="title is-2">{% trans 'Einstellungen' %}</h2>
|
||||||
|
<form class="block" action="" method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
{% if user.email_notifications %}
|
||||||
|
<label class="toggle">
|
||||||
|
<input type="submit" class="toggle-checkbox checked" name="toggle_email_notifications">
|
||||||
|
<div class="toggle-switch round "></div>
|
||||||
|
<span class="slider-label">
|
||||||
|
{% translate 'E-Mail Benachrichtigungen' %}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
{% else %}
|
||||||
|
<label class="toggle">
|
||||||
|
<input type="submit" class="toggle-checkbox" name="toggle_email_notifications">
|
||||||
|
<div class="toggle-switch round"></div>
|
||||||
|
<span class="slider-label">
|
||||||
|
{% translate 'E-Mail Benachrichtigungen' %}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
{% endif %}
|
||||||
|
</form>
|
||||||
|
<details>
|
||||||
|
<summary><strong>{% trans 'Erweiterte Einstellungen' %}</strong></summary>
|
||||||
|
<div class="block">
|
||||||
|
{% if token %}
|
||||||
|
<form action="" method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
<p class="text-muted"><strong>{% translate "API token:" %}</strong> {{ token }}</p>
|
||||||
|
<input class="button is-danger" type="submit" name="delete_token"
|
||||||
|
value={% translate "Delete API token" %}>
|
||||||
|
</form>
|
||||||
|
{% else %}
|
||||||
|
<p>{% translate "Kein API-Token vorhanden." %}</p>
|
||||||
|
<form action="" method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input class="button is-primary" type="submit" name="create_token"
|
||||||
|
value={% translate "Create API token" %}>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
<h2 class="title is-2">{% translate 'Abonnierte Suchen' %}</h2>
|
</div>
|
||||||
{% include "fellchensammlung/lists/list-search-subscriptions.html" %}
|
|
||||||
|
|
||||||
<h2 class="title is-2">{% translate 'Meine Vermittlungen' %}</h2>
|
<h2 class="title is-2">{% translate 'Benachrichtigungen' %}</h2>
|
||||||
{% include "fellchensammlung/lists/list-adoption-notices.html" %}
|
{% include "fellchensammlung/lists/list-notifications.html" %}
|
||||||
|
|
||||||
{% endif %}
|
<h2 class="title is-2">{% translate 'Abonnierte Suchen' %}</h2>
|
||||||
|
{% include "fellchensammlung/lists/list-search-subscriptions.html" %}
|
||||||
|
|
||||||
|
<h2 class="title is-2">{% translate 'Meine Vermittlungen' %}</h2>
|
||||||
|
{% include "fellchensammlung/lists/list-adoption-notices.html" %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load custom_tags %}
|
{% load custom_tags %}
|
||||||
|
|
||||||
{% block title %}<title>{% translate "403 Forbidden" %}</title>{% endblock %}
|
{% block title %}<title>{% translate "404 Forbidden" %}</title>{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1 class="title is-1">404 Not Found</h1>
|
<h1 class="title is-1">404 Not Found</h1>
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
{% extends "fellchensammlung/base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load widget_tweaks %}
|
||||||
|
{% load admin_urls %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
<title>Organisation {{ org }} von regelmäßiger Prüfung ausschließen</title>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1 class="title is-1">Organisation {{ org }} von regelmäßiger Prüfung ausschließen</h1>
|
||||||
|
<div class="columns block">
|
||||||
|
<div class="column">
|
||||||
|
{% include "fellchensammlung/partials/rescue_orgs/partial-basic-info-card.html" %}
|
||||||
|
</div>
|
||||||
|
<div class="column">
|
||||||
|
{% include "fellchensammlung/partials/rescue_orgs/partial-rescue-organization-contact.html" %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="block">
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
|
|
||||||
|
<input class="button is-primary" type="submit" name="delete"
|
||||||
|
value="{% translate "Aktualisieren" %}">
|
||||||
|
<a class="button" href="{% url 'organization-check' %}">{% translate "Zurück" %}</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="block">
|
||||||
|
<a class="button is-warning is-fullwidth" href="{% url org_meta|admin_urlname:'change' org.pk %}">
|
||||||
|
<i class="fa-solid fa-tools fa-fw"></i> Admin interface
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
{{ field|add_class:"input" }}
|
{{ field|add_class:"input" }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="help">
|
<div class="help content">
|
||||||
{{ field.help_text }}
|
{{ field.help_text }}
|
||||||
</div>
|
</div>
|
||||||
<div class="help is-danger">
|
<div class="help is-danger">
|
||||||
|
|||||||
@@ -49,10 +49,10 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<div class="navbar-item">
|
<div class="navbar-item">
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<a class="button is-primary" href="{% url "django_registration_register" %}">
|
<a class="button is-primary" href="{% url "account_signup" %}">
|
||||||
<strong>{% translate "Registrieren" %}</strong>
|
<strong>{% translate "Registrieren" %}</strong>
|
||||||
</a>
|
</a>
|
||||||
<a class="button is-light" href="{% url "login" %}">
|
<a class="button is-light" href="{% url "account_login" %}">
|
||||||
<strong>{% translate "Login" %}</strong>
|
<strong>{% translate "Login" %}</strong>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
{% if rescue_organizations %}
|
{% if rescue_organizations %}
|
||||||
{% for rescue_organization in rescue_organizations %}
|
{% for rescue_organization in rescue_organizations %}
|
||||||
<div class="cell">
|
<div class="cell">
|
||||||
{% include "fellchensammlung/partials/partial-rescue-organization.html" %}
|
{% include "fellchensammlung/partials/rescue_orgs/partial-rescue-organization.html" %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
{% load custom_tags %}
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h1 class="card-header-title">{{ org.name }}</h1>
|
||||||
|
</div>
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="block">
|
||||||
|
<b><i class="fa-solid fa-location-dot"></i></b>
|
||||||
|
{% if org.location %}
|
||||||
|
{{ org.location }}
|
||||||
|
{% else %}
|
||||||
|
{{ org.location_string }}
|
||||||
|
{% endif %}
|
||||||
|
{% if org.description %}
|
||||||
|
<div class="block content">
|
||||||
|
<p>{{ org.description | render_markdown }}</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% if org.specializations %}
|
||||||
|
<div class="block">
|
||||||
|
<h3 class="title is-5">{% translate 'Spezialisierung' %}</h3>
|
||||||
|
<div class="content">
|
||||||
|
<ul>
|
||||||
|
{% for specialization in org.specializations.all %}
|
||||||
|
<li>{{ specialization }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if org.parent_org %}
|
||||||
|
<div class="block">
|
||||||
|
<h3 class="title is-5">{% translate 'Übergeordnete Organisation' %}</h3>
|
||||||
|
<p>
|
||||||
|
<span>
|
||||||
|
<i class="fa-solid fa-building fa-fw"
|
||||||
|
aria-label="{% trans 'Tierschutzorganisation' %}"></i>
|
||||||
|
<a href="{{ org.parent_org.get_absolute_url }}"> {{ org.parent_org }}</a>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -75,15 +75,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer-item is-danger">
|
<div class="card-footer-item is-danger">
|
||||||
<form method="post">
|
<a href="{% url 'rescue-organization-exclude' rescue_organization_id=rescue_org.pk %}">{% translate "Von Check exkludieren" %}</a>
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden"
|
|
||||||
name="rescue_organization_id"
|
|
||||||
value="{{ rescue_org.pk }}">
|
|
||||||
<input type="hidden" name="action" value="exclude">
|
|
||||||
<button class="" type="submit">{% translate "Von Check exkludieren" %}</button>
|
|
||||||
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,19 +1,20 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<div class="grid is-col-min-2">
|
<div class="grid is-col-min-2">
|
||||||
{% if adoption_notice.num_per_sex.F > 0 %}
|
{% with num_per_sex=adoption_notice.num_per_sex %}
|
||||||
<span class="cell icon-text tag is-medium">
|
{% if num_per_sex.F > 0 %}
|
||||||
<span class="has-text-weight-bold is-size-4">{{ adoption_notice.num_per_sex.F }} </span>
|
<span class="cell icon-text tag is-medium">
|
||||||
|
<span class="has-text-weight-bold is-size-4">{{ num_per_sex.F }}</span>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<img class="icon" src="{% static 'fellchensammlung/img/sexes/Female.png' %}"
|
<img class="icon" src="{% static 'fellchensammlung/img/sexes/Female.png' %}"
|
||||||
alt="{% translate 'weibliche Tiere' %}">
|
alt="{% translate 'weibliche Tiere' %}">
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if adoption_notice.num_per_sex.I > 0 %}
|
{% if num_per_sex.I > 0 %}
|
||||||
<span class="cell icon-text tag is-medium">
|
<span class="cell icon-text tag is-medium">
|
||||||
<span class="has-text-weight-bold is-size-4">{{ adoption_notice.num_per_sex.I }}</span>
|
<span class="has-text-weight-bold is-size-4">{{ num_per_sex.I }}</span>
|
||||||
|
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<img class="icon"
|
<img class="icon"
|
||||||
@@ -21,24 +22,25 @@
|
|||||||
alt="{% translate 'intersexuelle Tiere' %}">
|
alt="{% translate 'intersexuelle Tiere' %}">
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if adoption_notice.num_per_sex.M > 0 %}
|
{% if num_per_sex.M > 0 %}
|
||||||
<span class="cell icon-text tag is-medium">
|
<span class="cell icon-text tag is-medium">
|
||||||
<span class="has-text-weight-bold is-size-4">{{ adoption_notice.num_per_sex.M }}</span>
|
<span class="has-text-weight-bold is-size-4">{{ num_per_sex.M }}</span>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<img class="icon" src="{% static 'fellchensammlung/img/sexes/Male.png' %}"
|
<img class="icon" src="{% static 'fellchensammlung/img/sexes/Male.png' %}"
|
||||||
alt="{% translate 'männliche Tiere' %}">
|
alt="{% translate 'männliche Tiere' %}">
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if adoption_notice.num_per_sex.M_N > 0 %}
|
{% if num_per_sex.M_N > 0 %}
|
||||||
<span class="cell icon-text tag is-medium">
|
<span class="cell icon-text tag is-medium">
|
||||||
<span class="has-text-weight-bold is-size-4">{{ adoption_notice.num_per_sex.M_N }}</span>
|
<span class="has-text-weight-bold is-size-4">{{ num_per_sex.M_N }}</span>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<img class="icon"
|
<img class="icon"
|
||||||
src="{% static 'fellchensammlung/img/sexes/Male Neutered.png' %}"
|
src="{% static 'fellchensammlung/img/sexes/Male Neutered.png' %}"
|
||||||
alt="{% translate 'männlich, kastrierte Tiere' %}">
|
alt="{% translate 'männlich, kastrierte Tiere' %}">
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
</div>
|
</div>
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
<div class="grid is-col-min-15">
|
<div class="grid is-col-min-15">
|
||||||
{% for rescue_org in rescue_orgs_to_check %}
|
{% for rescue_org in rescue_orgs_to_check %}
|
||||||
<div class="cell">
|
<div class="cell">
|
||||||
{% include "fellchensammlung/partials/partial-check-rescue-org.html" %}
|
{% include "fellchensammlung/partials/rescue_orgs/partial-check-rescue-org.html" %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
<div class="grid is-col-min-15">
|
<div class="grid is-col-min-15">
|
||||||
{% for rescue_org in rescue_orgs_with_ongoing_communication %}
|
{% for rescue_org in rescue_orgs_with_ongoing_communication %}
|
||||||
<div class="cell">
|
<div class="cell">
|
||||||
{% include "fellchensammlung/partials/partial-check-rescue-org.html" %}
|
{% include "fellchensammlung/partials/rescue_orgs/partial-check-rescue-org.html" %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
@@ -62,7 +62,7 @@
|
|||||||
<div class="grid is-col-min-15">
|
<div class="grid is-col-min-15">
|
||||||
{% for rescue_org in rescue_orgs_last_checked %}
|
{% for rescue_org in rescue_orgs_last_checked %}
|
||||||
<div class="cell">
|
<div class="cell">
|
||||||
{% include "fellchensammlung/partials/partial-check-rescue-org.html" %}
|
{% include "fellchensammlung/partials/rescue_orgs/partial-check-rescue-org.html" %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -65,7 +65,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% if not subscribed_search %}
|
{% if not subscribed_search %}
|
||||||
<div class="block">{% translate 'Wenn du die Suche abbonierst, wirst du für neue Vermittlungen, die den Kriterien entsprechen, benachrichtigt.' %}</div>
|
<div class="block">{% translate 'Wenn du die Suche abonnierst, wirst du für neue Vermittlungen, die den Kriterien entsprechen, benachrichtigt.' %}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<button class="button is-primary is-fullwidth" type="submit" value="search" name="search">
|
<button class="button is-primary is-fullwidth" type="submit" value="search" name="search">
|
||||||
|
|||||||
43
src/fellchensammlung/templates/mfa/recovery_codes/index.html
Normal file
43
src/fellchensammlung/templates/mfa/recovery_codes/index.html
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
{% extends "mfa/recovery_codes/base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load allauth %}
|
||||||
|
{% block content %}
|
||||||
|
{% element h1 %}
|
||||||
|
{% translate "Recovery Codes" %}
|
||||||
|
{% endelement %}
|
||||||
|
{% element p %}
|
||||||
|
{% blocktranslate count unused_count=unused_codes|length %}There is {{ unused_count }} out of {{ total_count }}
|
||||||
|
recovery codes available.{% plural %}There are {{ unused_count }} out of {{ total_count }} recovery codes
|
||||||
|
available.{% endblocktranslate %}
|
||||||
|
{% endelement %}
|
||||||
|
<div class="block">
|
||||||
|
{% element field id="recovery_codes" type="textarea" disabled=True rows=unused_codes|length readonly=True %}
|
||||||
|
{% slot label %}
|
||||||
|
{% translate "Unused codes" %}
|
||||||
|
{% endslot %}
|
||||||
|
{% comment %} djlint:off {% endcomment %}
|
||||||
|
{% slot value %}{% for code in unused_codes %}{% if forloop.counter0 %}
|
||||||
|
{% endif %}{{ code }}{% endfor %}{% endslot %}
|
||||||
|
{% comment %} djlint:on {% endcomment %}
|
||||||
|
{% endelement %}
|
||||||
|
</div>
|
||||||
|
<div class="block">
|
||||||
|
<div class="field is-grouped is-grouped-multiline">
|
||||||
|
{% if unused_codes %}
|
||||||
|
{% url 'mfa_download_recovery_codes' as download_url %}
|
||||||
|
<div class="control">
|
||||||
|
{% element button href=download_url %}
|
||||||
|
{% translate "Download codes" %}
|
||||||
|
{% endelement %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% url 'mfa_generate_recovery_codes' as generate_url %}
|
||||||
|
|
||||||
|
<div class="control">
|
||||||
|
{% element button href=generate_url %}
|
||||||
|
{% translate "Generate new codes" %}
|
||||||
|
{% endelement %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
{% extends "mfa/webauthn/base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load static %}
|
||||||
|
{% load allauth %}
|
||||||
|
{% load humanize %}
|
||||||
|
{% block content %}
|
||||||
|
{% element h1 %}
|
||||||
|
{% trans "Security Keys" %}
|
||||||
|
{% endelement %}
|
||||||
|
{% if authenticators|length == 0 %}
|
||||||
|
{% element p %}
|
||||||
|
{% blocktranslate %}No security keys have been added.{% endblocktranslate %}
|
||||||
|
{% endelement %}
|
||||||
|
{% else %}
|
||||||
|
<article class="panel">
|
||||||
|
<p class="panel-heading">{% trans "Security Keys" %}</p>
|
||||||
|
{% for authenticator in authenticators %}
|
||||||
|
<div class="panel-block">
|
||||||
|
<div class="level" style="width: 100%;">
|
||||||
|
<div class="level-left">
|
||||||
|
<div class="level-item">
|
||||||
|
{% if authenticator.wrap.is_passwordless is True %}
|
||||||
|
{% element badge tags="mfa,key,primary" %}
|
||||||
|
{% translate "Passkey" %}
|
||||||
|
{% endelement %}
|
||||||
|
{% elif authenticator.wrap.is_passwordless is False %}
|
||||||
|
{% element badge tags="mfa,key,secondary" %}
|
||||||
|
{% translate "Security key" %}
|
||||||
|
{% endelement %}
|
||||||
|
{% else %}
|
||||||
|
{% element badge title=_("This key does not indicate whether it is a passkey.") tags="mfa,key,warning" %}
|
||||||
|
{% translate "Unspecified" %}
|
||||||
|
{% endelement %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="level-item">
|
||||||
|
<strong>
|
||||||
|
{{ authenticator }}
|
||||||
|
</strong>
|
||||||
|
</div>
|
||||||
|
<div class="level-item">
|
||||||
|
{% blocktranslate with created_at=authenticator.created_at|date:"SHORT_DATE_FORMAT" %}
|
||||||
|
Added
|
||||||
|
on {{ created_at }}{% endblocktranslate %}.
|
||||||
|
</div>
|
||||||
|
<div class="level-item">
|
||||||
|
{% if authenticator.last_used_at %}
|
||||||
|
{% blocktranslate with last_used=authenticator.last_used_at|naturaltime %}Last used
|
||||||
|
{{ last_used }}{% endblocktranslate %}
|
||||||
|
{% else %}
|
||||||
|
Not used.
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="level-right">
|
||||||
|
<div class="level-item">
|
||||||
|
{% url 'mfa_edit_webauthn' pk=authenticator.pk as edit_url %}
|
||||||
|
{% element button tags="mfa,authenticator,edit,tool" href=edit_url %}
|
||||||
|
{% translate "Edit" %}
|
||||||
|
{% endelement %}
|
||||||
|
</div>
|
||||||
|
<div class="level-item">
|
||||||
|
{% url 'mfa_remove_webauthn' pk=authenticator.pk as remove_url %}
|
||||||
|
{% element button tags="mfa,authenticator,danger,delete,tool" href=remove_url %}
|
||||||
|
{% translate "Remove" %}
|
||||||
|
{% endelement %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</article>
|
||||||
|
{% endif %}
|
||||||
|
{% url 'mfa_add_webauthn' as add_url %}
|
||||||
|
{% element button href=add_url %}
|
||||||
|
{% translate "Add" %}
|
||||||
|
{% endelement %}
|
||||||
|
{% endblock %}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import datetime as datetime
|
import datetime as datetime
|
||||||
import logging
|
import logging
|
||||||
|
import time
|
||||||
|
|
||||||
from django.utils.translation import ngettext
|
from django.utils.translation import ngettext
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
@@ -75,3 +76,20 @@ def is_404(url):
|
|||||||
return result.status_code == 404
|
return result.status_code == 404
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
logging.warning(f"Request to {url} failed: {e}")
|
logging.warning(f"Request to {url} failed: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
class RequestProfiler:
|
||||||
|
data = []
|
||||||
|
|
||||||
|
def add_status(self, status):
|
||||||
|
self.data.append((time.time(), status))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def as_relative(self):
|
||||||
|
first_ts = self.data[0][0]
|
||||||
|
return [(datum[0] - first_ts, datum[1]) for datum in self.data]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def as_relative_with_ms(self):
|
||||||
|
first_ts = self.data[0][0]
|
||||||
|
return [(f"{(datum[0] - first_ts)*1000:.4}ms", datum[1]) for datum in self.data]
|
||||||
|
|||||||
@@ -110,7 +110,8 @@ class AdoptionNoticeStatusChoicesDescriptions:
|
|||||||
_ansc.AwaitingAction.WAITING_FOR_REVIEW: _(
|
_ansc.AwaitingAction.WAITING_FOR_REVIEW: _(
|
||||||
"Deaktiviert bis Moderator*innen die Vermittlung prüfen können."),
|
"Deaktiviert bis Moderator*innen die Vermittlung prüfen können."),
|
||||||
_ansc.AwaitingAction.NEEDS_ADDITIONAL_INFO: _("Deaktiviert bis Informationen nachgetragen werden."),
|
_ansc.AwaitingAction.NEEDS_ADDITIONAL_INFO: _("Deaktiviert bis Informationen nachgetragen werden."),
|
||||||
_ansc.AwaitingAction.UNCHECKED: _("Vermittlung deaktiviert bis sie vom Team auf Aktualität geprüft wurde."),
|
_ansc.AwaitingAction.UNCHECKED: _(
|
||||||
|
"Vermittlung deaktiviert bis sie vom Team auf Aktualität geprüft wurde."),
|
||||||
|
|
||||||
_ansc.Disabled.AGAINST_RULES: _("Vermittlung deaktiviert da sie gegen die Regeln verstößt."),
|
_ansc.Disabled.AGAINST_RULES: _("Vermittlung deaktiviert da sie gegen die Regeln verstößt."),
|
||||||
_ansc.Disabled.OTHER: _("Vermittlung deaktiviert.")
|
_ansc.Disabled.OTHER: _("Vermittlung deaktiviert.")
|
||||||
@@ -125,3 +126,22 @@ class AdoptionNoticeProcessTemplates:
|
|||||||
_bp = "fellchensammlung/partials/adoption_process/" # Base path for ease
|
_bp = "fellchensammlung/partials/adoption_process/" # Base path for ease
|
||||||
mapping = {AdoptionProcess.CONTACT_PERSON_IN_AN: f"{_bp}contact_person_in_an.html",
|
mapping = {AdoptionProcess.CONTACT_PERSON_IN_AN: f"{_bp}contact_person_in_an.html",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class RegularCheckStatusChoices(models.TextChoices):
|
||||||
|
REGULAR_CHECK = "regular_check", _("Wird regelmäßig geprüft")
|
||||||
|
EXCLUDED_NO_ONLINE_LISTING = "excluded_no_online_listing", _("Exkludiert: Tiere werden nicht online gelistet")
|
||||||
|
EXCLUDED_OTHER_ORG = "excluded_other_org", _("Exkludiert: Andere Organisation wird geprüft")
|
||||||
|
EXCLUDED_SCOPE = "excluded_scope", _("Exkludiert: Organisation hat nie Notfellchen-relevanten Vermittlungen")
|
||||||
|
EXCLUDED_OTHER = "excluded_other", _("Exkludiert: Anderer Grund")
|
||||||
|
|
||||||
|
|
||||||
|
##########
|
||||||
|
## USER ##
|
||||||
|
##########
|
||||||
|
|
||||||
|
reason_for_signup_label = _("Grund für die Registrierung")
|
||||||
|
reason_for_signup_help_text = _(
|
||||||
|
"Wir würden gerne wissen warum du dich registrierst, ob du dich z.B. Tiere eines bestimmten Tierheim einstellen "
|
||||||
|
"willst 'nur mal gucken' willst. Beides ist toll! Wenn du für ein Tierheim/eine Pflegestelle arbeitest "
|
||||||
|
"kontaktieren wir dich ggf. um dir erweiterte Rechte zu geben.")
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ urlpatterns = [
|
|||||||
path("tierschutzorganisationen/", views.list_rescue_organizations, name="rescue-organizations"),
|
path("tierschutzorganisationen/", views.list_rescue_organizations, name="rescue-organizations"),
|
||||||
path("tierschutzorganisationen/<int:rescue_organization_id>/", views.detail_view_rescue_organization,
|
path("tierschutzorganisationen/<int:rescue_organization_id>/", views.detail_view_rescue_organization,
|
||||||
name="rescue-organization-detail"),
|
name="rescue-organization-detail"),
|
||||||
|
path("tierschutzorganisationen/<int:rescue_organization_id>/exkludieren", views.exclude_from_regular_check,
|
||||||
|
name="rescue-organization-exclude"),
|
||||||
|
path("tierschutzorganisationen/add-exclusion-reason", views.update_exclusion_reason,
|
||||||
|
name="rescue-organization-add-exclusion-reason"),
|
||||||
path("tierschutzorganisationen/spezialisierung/<slug:species_slug>", views.specialized_rescues,
|
path("tierschutzorganisationen/spezialisierung/<slug:species_slug>", views.specialized_rescues,
|
||||||
name="specialized-rescue-organizations"),
|
name="specialized-rescue-organizations"),
|
||||||
|
|
||||||
@@ -90,15 +94,6 @@ urlpatterns = [
|
|||||||
path("user/notifications/", views.my_notifications, name="user-notifications"),
|
path("user/notifications/", views.my_notifications, name="user-notifications"),
|
||||||
path('user/me/export/', views.export_own_profile, name='user-me-export'),
|
path('user/me/export/', views.export_own_profile, name='user-me-export'),
|
||||||
|
|
||||||
path('accounts/register/',
|
|
||||||
registration_views.HTMLMailRegistrationView.as_view(
|
|
||||||
form_class=CustomRegistrationForm,
|
|
||||||
email_body_template="fellchensammlung/mail/activation_email.html",
|
|
||||||
),
|
|
||||||
name='django_registration_register',
|
|
||||||
),
|
|
||||||
path('accounts/', include('django_registration.backends.activation.urls')),
|
|
||||||
path('accounts/', include('django.contrib.auth.urls')),
|
|
||||||
|
|
||||||
path('change-language', views.change_language, name="change-language"),
|
path('change-language', views.change_language, name="change-language"),
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import logging
|
import logging
|
||||||
from datetime import timedelta
|
|
||||||
|
|
||||||
from django.contrib.auth.views import redirect_to_login
|
from django.contrib.auth.views import redirect_to_login
|
||||||
from django.core.paginator import Paginator
|
from django.core.paginator import Paginator
|
||||||
@@ -25,7 +24,8 @@ from .models import AdoptionNotice, Text, Animal, Rule, Image, Report, Moderatio
|
|||||||
Species, Log, Timestamp, TrustLevel, SexChoicesWithAll, SearchSubscription, \
|
Species, Log, Timestamp, TrustLevel, SexChoicesWithAll, SearchSubscription, \
|
||||||
ImportantLocation, SpeciesSpecificURL, NotificationTypeChoices, SocialMediaPost
|
ImportantLocation, SpeciesSpecificURL, NotificationTypeChoices, SocialMediaPost
|
||||||
from .forms import AdoptionNoticeForm, ImageForm, ReportAdoptionNoticeForm, \
|
from .forms import AdoptionNoticeForm, ImageForm, ReportAdoptionNoticeForm, \
|
||||||
CommentForm, ReportCommentForm, AnimalForm, AdoptionNoticeFormAutoAnimal, SpeciesURLForm, RescueOrgInternalComment
|
CommentForm, ReportCommentForm, AnimalForm, AdoptionNoticeFormAutoAnimal, SpeciesURLForm, RescueOrgInternalComment, \
|
||||||
|
UpdateRescueOrgRegularCheckStatus
|
||||||
from .models import Language, Announcement
|
from .models import Language, Announcement
|
||||||
from .tools import i18n, img
|
from .tools import i18n, img
|
||||||
from .tools.fedi import post_an_to_fedi
|
from .tools.fedi import post_an_to_fedi
|
||||||
@@ -36,7 +36,8 @@ from .tools.admin import clean_locations, get_unchecked_adoption_notices, deacti
|
|||||||
from .tasks import post_adoption_notice_save
|
from .tasks import post_adoption_notice_save
|
||||||
from rest_framework.authtoken.models import Token
|
from rest_framework.authtoken.models import Token
|
||||||
|
|
||||||
from .tools.model_helpers import AdoptionNoticeStatusChoices, AdoptionNoticeProcessTemplates
|
from .tools.misc import RequestProfiler
|
||||||
|
from .tools.model_helpers import AdoptionNoticeStatusChoices, AdoptionNoticeProcessTemplates, RegularCheckStatusChoices
|
||||||
from .tools.search import AdoptionNoticeSearch, RescueOrgSearch
|
from .tools.search import AdoptionNoticeSearch, RescueOrgSearch
|
||||||
|
|
||||||
|
|
||||||
@@ -241,11 +242,17 @@ def search_important_locations(request, important_location_slug):
|
|||||||
|
|
||||||
|
|
||||||
def search(request, templatename="fellchensammlung/search.html"):
|
def search(request, templatename="fellchensammlung/search.html"):
|
||||||
|
search_profile = RequestProfiler()
|
||||||
|
search_profile.add_status("Start")
|
||||||
|
|
||||||
# A user just visiting the search site did not search, only upon completing the search form a user has really
|
# A user just visiting the search site did not search, only upon completing the search form a user has really
|
||||||
# searched. This will toggle the "subscribe" button
|
# searched. This will toggle the "subscribe" button
|
||||||
searched = False
|
searched = False
|
||||||
|
search_profile.add_status("Init Search")
|
||||||
search = AdoptionNoticeSearch()
|
search = AdoptionNoticeSearch()
|
||||||
|
search_profile.add_status("Search from request starting")
|
||||||
search.adoption_notice_search_from_request(request)
|
search.adoption_notice_search_from_request(request)
|
||||||
|
search_profile.add_status("Search from request finished")
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
searched = True
|
searched = True
|
||||||
if "subscribe_to_search" in request.POST:
|
if "subscribe_to_search" in request.POST:
|
||||||
@@ -265,10 +272,12 @@ def search(request, templatename="fellchensammlung/search.html"):
|
|||||||
subscribed_search = search.get_subscription_or_none(request.user)
|
subscribed_search = search.get_subscription_or_none(request.user)
|
||||||
else:
|
else:
|
||||||
subscribed_search = None
|
subscribed_search = None
|
||||||
|
search_profile.add_status("End of POST")
|
||||||
site_title = _("Suche")
|
site_title = _("Suche")
|
||||||
site_description = _("Ratten in Tierheimen und Rattenhilfen in der Nähe suchen.")
|
site_description = _("Ratten in Tierheimen und Rattenhilfen in der Nähe suchen.")
|
||||||
canonical_url = reverse("search")
|
canonical_url = reverse("search")
|
||||||
|
|
||||||
|
search_profile.add_status("Start of context")
|
||||||
context = {"adoption_notices": search.get_adoption_notices(),
|
context = {"adoption_notices": search.get_adoption_notices(),
|
||||||
"search_form": search.search_form,
|
"search_form": search.search_form,
|
||||||
"place_not_found": search.place_not_found,
|
"place_not_found": search.place_not_found,
|
||||||
@@ -285,6 +294,10 @@ def search(request, templatename="fellchensammlung/search.html"):
|
|||||||
"site_title": site_title,
|
"site_title": site_title,
|
||||||
"site_description": site_description,
|
"site_description": site_description,
|
||||||
"canonical_url": canonical_url}
|
"canonical_url": canonical_url}
|
||||||
|
search_profile.add_status("End of context")
|
||||||
|
if request.user.is_superuser:
|
||||||
|
context["profile"] = search_profile.as_relative_with_ms
|
||||||
|
search_profile.add_status("Finished - returing render")
|
||||||
return render(request, templatename, context=context)
|
return render(request, templatename, context=context)
|
||||||
|
|
||||||
|
|
||||||
@@ -577,12 +590,20 @@ def report_detail_success(request, report_id):
|
|||||||
|
|
||||||
|
|
||||||
def user_detail(request, user, token=None):
|
def user_detail(request, user, token=None):
|
||||||
|
user_detail_profile = RequestProfiler()
|
||||||
|
user_detail_profile.add_status("Start")
|
||||||
|
adoption_notices = AdoptionNotice.objects.filter(owner=user)
|
||||||
|
user_detail_profile.add_status("Finished fetching adoption notices")
|
||||||
context = {"user": user,
|
context = {"user": user,
|
||||||
"adoption_notices": AdoptionNotice.objects.filter(owner=user),
|
"adoption_notices": adoption_notices,
|
||||||
"notifications": Notification.objects.filter(user_to_notify=user, read=False),
|
"notifications": Notification.objects.filter(user_to_notify=user, read=False),
|
||||||
"search_subscriptions": SearchSubscription.objects.filter(owner=user), }
|
"search_subscriptions": SearchSubscription.objects.filter(owner=user), }
|
||||||
|
user_detail_profile.add_status("End of context")
|
||||||
if token is not None:
|
if token is not None:
|
||||||
context["token"] = token
|
context["token"] = token
|
||||||
|
user_detail_profile.add_status("Finished - returning to renderer")
|
||||||
|
if request.user.is_superuser:
|
||||||
|
context["profile"] = user_detail_profile.as_relative_with_ms
|
||||||
return render(request, 'fellchensammlung/details/detail-user.html', context=context)
|
return render(request, 'fellchensammlung/details/detail-user.html', context=context)
|
||||||
|
|
||||||
|
|
||||||
@@ -653,7 +674,7 @@ def my_notifications(request):
|
|||||||
context = {"notifications_unread": Notification.objects.filter(user_to_notify=request.user, read=False).order_by(
|
context = {"notifications_unread": Notification.objects.filter(user_to_notify=request.user, read=False).order_by(
|
||||||
"-created_at"),
|
"-created_at"),
|
||||||
"notifications_read_last": Notification.objects.filter(user_to_notify=request.user,
|
"notifications_read_last": Notification.objects.filter(user_to_notify=request.user,
|
||||||
read=True).order_by("-read_at")}
|
read=True).order_by("-read_at")[:10]}
|
||||||
return render(request, 'fellchensammlung/notifications.html', context=context)
|
return render(request, 'fellchensammlung/notifications.html', context=context)
|
||||||
|
|
||||||
|
|
||||||
@@ -845,8 +866,7 @@ def rescue_organization_check(request, context=None):
|
|||||||
action = request.POST.get("action")
|
action = request.POST.get("action")
|
||||||
if action == "checked":
|
if action == "checked":
|
||||||
rescue_org.set_checked()
|
rescue_org.set_checked()
|
||||||
elif action == "exclude":
|
Log.objects.create(user=request.user, action="rescue_organization_checked", )
|
||||||
rescue_org.set_exclusion_from_checks()
|
|
||||||
elif action == "set_species_url":
|
elif action == "set_species_url":
|
||||||
species_url_form = SpeciesURLForm(request.POST)
|
species_url_form = SpeciesURLForm(request.POST)
|
||||||
|
|
||||||
@@ -857,6 +877,7 @@ def rescue_organization_check(request, context=None):
|
|||||||
elif action == "update_internal_comment":
|
elif action == "update_internal_comment":
|
||||||
comment_form = RescueOrgInternalComment(request.POST, instance=rescue_org)
|
comment_form = RescueOrgInternalComment(request.POST, instance=rescue_org)
|
||||||
if comment_form.is_valid():
|
if comment_form.is_valid():
|
||||||
|
Log.objects.create(user=request.user, action="rescue_organization_added_internal_comment", )
|
||||||
comment_form.save()
|
comment_form.save()
|
||||||
|
|
||||||
rescue_orgs_to_check = RescueOrganization.objects.filter(exclude_from_check=False,
|
rescue_orgs_to_check = RescueOrganization.objects.filter(exclude_from_check=False,
|
||||||
@@ -896,6 +917,42 @@ def rescue_organization_check_dq(request):
|
|||||||
return rescue_organization_check(request, context)
|
return rescue_organization_check(request, context)
|
||||||
|
|
||||||
|
|
||||||
|
def exclude_from_regular_check(request, rescue_organization_id, source="organization-check"):
|
||||||
|
rescue_org = get_object_or_404(RescueOrganization, pk=rescue_organization_id)
|
||||||
|
if request.method == "POST":
|
||||||
|
form = UpdateRescueOrgRegularCheckStatus(request.POST, instance=rescue_org)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
to_be_excluded = form.cleaned_data["regular_check_status"] != RegularCheckStatusChoices.REGULAR_CHECK
|
||||||
|
rescue_org.exclude_from_check = to_be_excluded
|
||||||
|
rescue_org.save()
|
||||||
|
if to_be_excluded:
|
||||||
|
Log.objects.create(user=request.user,
|
||||||
|
action="rescue_organization_excluded_from_check",
|
||||||
|
text=f"New status: {form.cleaned_data["regular_check_status"]}")
|
||||||
|
|
||||||
|
return redirect(reverse(source))
|
||||||
|
else:
|
||||||
|
form = UpdateRescueOrgRegularCheckStatus(instance=rescue_org)
|
||||||
|
org_meta = rescue_org._meta
|
||||||
|
context = {"form": form, "org": rescue_org, "org_meta": org_meta}
|
||||||
|
return render(request, 'fellchensammlung/forms/form-exclude-org-from-check.html', context=context)
|
||||||
|
|
||||||
|
|
||||||
|
@user_passes_test(user_is_trust_level_or_above)
|
||||||
|
def update_exclusion_reason(request):
|
||||||
|
"""
|
||||||
|
This view will redirect to update a rescue org that not yet has an exclusion reason but is excluded
|
||||||
|
"""
|
||||||
|
orgs_to_check = RescueOrganization.objects.filter(exclude_from_check=True,
|
||||||
|
regular_check_status=RegularCheckStatusChoices.REGULAR_CHECK)
|
||||||
|
if orgs_to_check.count() > 0:
|
||||||
|
return exclude_from_regular_check(request, orgs_to_check[0].pk,
|
||||||
|
source="rescue-organization-add-exclusion-reason")
|
||||||
|
else:
|
||||||
|
return render(request, "fellchensammlung/errors/404.html", status=404)
|
||||||
|
|
||||||
|
|
||||||
@user_passes_test(user_is_trust_level_or_above)
|
@user_passes_test(user_is_trust_level_or_above)
|
||||||
def moderation_tools_overview(request):
|
def moderation_tools_overview(request):
|
||||||
context = None
|
context = None
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ https://docs.djangoproject.com/en/3.2/topics/settings/
|
|||||||
For the full list of settings and their values, see
|
For the full list of settings and their values, see
|
||||||
https://docs.djangoproject.com/en/3.2/ref/settings/
|
https://docs.djangoproject.com/en/3.2/ref/settings/
|
||||||
"""
|
"""
|
||||||
|
import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import os
|
import os
|
||||||
import configparser
|
import configparser
|
||||||
@@ -74,6 +74,10 @@ except configparser.NoSectionError:
|
|||||||
raise BaseException("No config found or no Django Secret is configured!")
|
raise BaseException("No config found or no Django Secret is configured!")
|
||||||
DEBUG = config.getboolean('django', 'debug', fallback=False)
|
DEBUG = config.getboolean('django', 'debug', fallback=False)
|
||||||
|
|
||||||
|
# Internal IPs
|
||||||
|
raw_config_value = config.get("django", "internal_ips", fallback=[])
|
||||||
|
INTERNAL_IPS = json.loads(raw_config_value)
|
||||||
|
|
||||||
""" DATABASE """
|
""" DATABASE """
|
||||||
DB_BACKEND = config.get("database", "backend", fallback="sqlite3")
|
DB_BACKEND = config.get("database", "backend", fallback="sqlite3")
|
||||||
DB_NAME = config.get("database", "name", fallback="notfellchen.sqlite3")
|
DB_NAME = config.get("database", "name", fallback="notfellchen.sqlite3")
|
||||||
@@ -85,6 +89,7 @@ DB_HOST = config.get("database", "host", fallback='')
|
|||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
LOCALE_PATHS = [os.path.join(BASE_DIR, 'locale')]
|
LOCALE_PATHS = [os.path.join(BASE_DIR, 'locale')]
|
||||||
|
|
||||||
|
|
||||||
""" CELERY + KEYDB """
|
""" CELERY + KEYDB """
|
||||||
CELERY_BROKER_URL = config.get("celery", "broker", fallback="redis://localhost:6379/0")
|
CELERY_BROKER_URL = config.get("celery", "broker", fallback="redis://localhost:6379/0")
|
||||||
CELERY_RESULT_BACKEND = config.get("celery", "backend", fallback="redis://localhost:6379/0")
|
CELERY_RESULT_BACKEND = config.get("celery", "backend", fallback="redis://localhost:6379/0")
|
||||||
@@ -130,6 +135,37 @@ ACCOUNT_ACTIVATION_DAYS = 7 # One-week activation window
|
|||||||
REGISTRATION_OPEN = True
|
REGISTRATION_OPEN = True
|
||||||
REGISTRATION_SALT = "notfellchen"
|
REGISTRATION_SALT = "notfellchen"
|
||||||
|
|
||||||
|
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 email
|
||||||
|
'allauth.account.auth_backends.AuthenticationBackend',
|
||||||
|
]
|
||||||
|
|
||||||
|
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
|
||||||
|
ACCOUNT_EMAIL_VERIFICATION_BY_CODE_ENABLED = True
|
||||||
|
|
||||||
|
ACCOUNT_SIGNUP_FIELDS = ['username*', "email*", "password1*"]
|
||||||
|
|
||||||
|
ACCOUNT_SIGNUP_FORM_CLASS = 'fellchensammlung.forms.AddedRegistrationForm'
|
||||||
|
|
||||||
|
MFA_SUPPORTED_TYPES = ["totp",
|
||||||
|
"webauthn",
|
||||||
|
"recovery_codes"]
|
||||||
|
|
||||||
|
MFA_TOTP_TOLERANCE = 1
|
||||||
|
MFA_TOTP_ISSUER = config.get('security', 'totp_issuer', fallback="Notfellchen")
|
||||||
|
|
||||||
|
MFA_PASSKEY_LOGIN_ENABLED = True
|
||||||
|
MFA_PASSKEY_SIGNUP_ENABLED = True
|
||||||
|
|
||||||
|
# Optional -- use for local development only: the WebAuthn uses the
|
||||||
|
#``fido2`` package, and versions up to including version 1.1.3 do not
|
||||||
|
# regard localhost as a secure origin, which is problematic during
|
||||||
|
# local development and testing.
|
||||||
|
MFA_WEBAUTHN_ALLOW_INSECURE_ORIGIN = config.get('security', 'webauth_allow_insecure_origin', fallback=False)
|
||||||
|
|
||||||
""" SECURITY.TXT """
|
""" SECURITY.TXT """
|
||||||
SEC_CONTACT = config.get("security", "Contact", fallback="julian-samuel@gebuehr.net")
|
SEC_CONTACT = config.get("security", "Contact", fallback="julian-samuel@gebuehr.net")
|
||||||
SEC_EXPIRES = config.get("security", "Expires", fallback="2028-03-17T07:00:00.000Z")
|
SEC_EXPIRES = config.get("security", "Expires", fallback="2028-03-17T07:00:00.000Z")
|
||||||
@@ -182,7 +218,11 @@ INSTALLED_APPS = [
|
|||||||
'django.contrib.auth',
|
'django.contrib.auth',
|
||||||
'django.contrib.contenttypes',
|
'django.contrib.contenttypes',
|
||||||
'django.contrib.sessions',
|
'django.contrib.sessions',
|
||||||
|
"django.contrib.humanize",
|
||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
|
'allauth',
|
||||||
|
'allauth.account',
|
||||||
|
'allauth.mfa',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
"django.contrib.sitemaps",
|
"django.contrib.sitemaps",
|
||||||
'fontawesomefree',
|
'fontawesomefree',
|
||||||
@@ -193,11 +233,13 @@ INSTALLED_APPS = [
|
|||||||
'rest_framework.authtoken',
|
'rest_framework.authtoken',
|
||||||
'drf_spectacular',
|
'drf_spectacular',
|
||||||
'drf_spectacular_sidecar', # required for Django collectstatic discovery
|
'drf_spectacular_sidecar', # required for Django collectstatic discovery
|
||||||
'widget_tweaks'
|
'widget_tweaks',
|
||||||
|
"debug_toolbar",
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
'django.middleware.security.SecurityMiddleware',
|
'django.middleware.security.SecurityMiddleware',
|
||||||
|
"debug_toolbar.middleware.DebugToolbarMiddleware",
|
||||||
# Static file serving & caching
|
# Static file serving & caching
|
||||||
'whitenoise.middleware.WhiteNoiseMiddleware',
|
'whitenoise.middleware.WhiteNoiseMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
@@ -208,6 +250,8 @@ MIDDLEWARE = [
|
|||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
|
# allauth middleware, needs to be after message middleware
|
||||||
|
"allauth.account.middleware.AccountMiddleware",
|
||||||
]
|
]
|
||||||
|
|
||||||
ROOT_URLCONF = 'notfellchen.urls'
|
ROOT_URLCONF = 'notfellchen.urls'
|
||||||
@@ -222,6 +266,7 @@ TEMPLATES = [
|
|||||||
'OPTIONS': {
|
'OPTIONS': {
|
||||||
'context_processors': [
|
'context_processors': [
|
||||||
'django.template.context_processors.debug',
|
'django.template.context_processors.debug',
|
||||||
|
# Needed for allauth
|
||||||
'django.template.context_processors.request',
|
'django.template.context_processors.request',
|
||||||
'django.contrib.auth.context_processors.auth',
|
'django.contrib.auth.context_processors.auth',
|
||||||
'django.template.context_processors.media',
|
'django.template.context_processors.media',
|
||||||
|
|||||||
@@ -18,12 +18,14 @@ from django.conf.urls.i18n import i18n_patterns
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from django.conf.urls.static import static
|
from django.conf.urls.static import static
|
||||||
|
|
||||||
|
from debug_toolbar.toolbar import debug_toolbar_urls
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
]
|
path('accounts/', include('allauth.urls')),
|
||||||
|
] + debug_toolbar_urls()
|
||||||
|
|
||||||
urlpatterns += i18n_patterns(
|
urlpatterns += i18n_patterns(
|
||||||
path("", include("fellchensammlung.urls")),
|
path("", include("fellchensammlung.urls")),
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
<div class="block">
|
<div class="block">
|
||||||
<a class="button is-warning" href="{% url 'password_reset' %}">{% translate "Passwort vergessen?" %}</a>
|
<a class="button is-warning" href="{% url 'password_reset' %}">{% translate "Passwort vergessen?" %}</a>
|
||||||
<a class="button is-link"
|
<a class="button is-link"
|
||||||
href="{% url 'django_registration_register' %}">{% translate "Registrieren" %}</a>
|
href="{% url 'account_signup' %}">{% translate "Registrieren" %}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
Reference in New Issue
Block a user