feat: Add history tracking
This commit is contained in:
+2
-1
@@ -41,7 +41,8 @@ dependencies = [
|
||||
"django-super-deduper",
|
||||
"django-allauth[mfa]",
|
||||
"django_debug_toolbar",
|
||||
"django-admin-extra-buttons"
|
||||
"django-admin-extra-buttons",
|
||||
"django-simple-history"
|
||||
]
|
||||
|
||||
dynamic = ["version", "readme"]
|
||||
|
||||
@@ -8,6 +8,7 @@ from django.urls import reverse
|
||||
from django.utils.http import urlencode
|
||||
|
||||
from admin_extra_buttons.api import ExtraButtonsMixin, button, link
|
||||
from simple_history.admin import SimpleHistoryAdmin
|
||||
|
||||
from .models import Language, Text, ReportComment, ReportAdoptionNotice, Log, Timestamp, SearchSubscription, \
|
||||
SpeciesSpecificURL, ImportantLocation, SocialMediaPost
|
||||
@@ -50,7 +51,7 @@ class AdoptionNoticeAdmin(admin.ModelAdmin):
|
||||
|
||||
# Re-register UserAdmin
|
||||
@admin.register(User)
|
||||
class UserAdmin(admin.ModelAdmin):
|
||||
class UserAdmin(SimpleHistoryAdmin):
|
||||
search_fields = ("usernamname__icontains", "first_name__icontains", "last_name__icontains", "email__icontains")
|
||||
list_display = ("username", "email", "trust_level", "is_active", "view_adoption_notices")
|
||||
list_filter = ("is_active", "trust_level",)
|
||||
@@ -78,7 +79,7 @@ def _reported_content_link(obj):
|
||||
|
||||
|
||||
@admin.register(ReportComment)
|
||||
class ReportCommentAdmin(admin.ModelAdmin):
|
||||
class ReportCommentAdmin(SimpleHistoryAdmin):
|
||||
list_display = ["user_comment", "reported_content_link"]
|
||||
date_hierarchy = "created_at"
|
||||
|
||||
@@ -89,7 +90,7 @@ class ReportCommentAdmin(admin.ModelAdmin):
|
||||
|
||||
|
||||
@admin.register(ReportAdoptionNotice)
|
||||
class ReportAdoptionNoticeAdmin(admin.ModelAdmin):
|
||||
class ReportAdoptionNoticeAdmin(SimpleHistoryAdmin):
|
||||
list_display = ["user_comment", "reported_content_link"]
|
||||
date_hierarchy = "created_at"
|
||||
|
||||
@@ -104,7 +105,7 @@ class SpeciesSpecificURLInline(admin.StackedInline):
|
||||
|
||||
|
||||
@admin.register(RescueOrganization)
|
||||
class RescueOrganizationAdmin(admin.ModelAdmin):
|
||||
class RescueOrganizationAdmin(SimpleHistoryAdmin):
|
||||
search_fields = ("name", "description", "internal_comment", "location_string", "location__city")
|
||||
list_display = ("name", "trusted", "allows_using_materials", "website")
|
||||
list_filter = ("allows_using_materials", "trusted", ("external_source_identifier", EmptyFieldListFilter))
|
||||
@@ -115,12 +116,12 @@ class RescueOrganizationAdmin(admin.ModelAdmin):
|
||||
|
||||
|
||||
@admin.register(Text)
|
||||
class TextAdmin(admin.ModelAdmin):
|
||||
class TextAdmin(SimpleHistoryAdmin):
|
||||
search_fields = ("title__icontains", "text_code__icontains",)
|
||||
|
||||
|
||||
@admin.register(Comment)
|
||||
class CommentAdmin(admin.ModelAdmin):
|
||||
class CommentAdmin(SimpleHistoryAdmin):
|
||||
list_filter = ("user",)
|
||||
|
||||
|
||||
@@ -130,7 +131,7 @@ class BaseNotificationAdmin(admin.ModelAdmin):
|
||||
|
||||
|
||||
@admin.register(SearchSubscription)
|
||||
class SearchSubscriptionAdmin(admin.ModelAdmin):
|
||||
class SearchSubscriptionAdmin(SimpleHistoryAdmin):
|
||||
list_filter = ("owner",)
|
||||
|
||||
|
||||
@@ -158,7 +159,7 @@ class IsImportantListFilter(admin.SimpleListFilter):
|
||||
|
||||
|
||||
@admin.register(Location)
|
||||
class LocationAdmin(admin.ModelAdmin):
|
||||
class LocationAdmin(SimpleHistoryAdmin):
|
||||
search_fields = ("name__icontains", "city__icontains")
|
||||
list_filter = [IsImportantListFilter]
|
||||
inlines = [
|
||||
@@ -167,7 +168,7 @@ class LocationAdmin(admin.ModelAdmin):
|
||||
|
||||
|
||||
@admin.register(SocialMediaPost)
|
||||
class SocialMediaPostAdmin(admin.ModelAdmin):
|
||||
class SocialMediaPostAdmin(SimpleHistoryAdmin):
|
||||
list_filter = ("platform",)
|
||||
|
||||
|
||||
@@ -193,12 +194,13 @@ class LogAdmin(ExtraButtonsMixin, admin.ModelAdmin):
|
||||
def invisible(self, button):
|
||||
button.visible = False
|
||||
|
||||
admin.site.register(Animal)
|
||||
|
||||
admin.site.register(Animal, SimpleHistoryAdmin)
|
||||
admin.site.register(Species)
|
||||
admin.site.register(Rule)
|
||||
admin.site.register(Rule, SimpleHistoryAdmin)
|
||||
admin.site.register(Image)
|
||||
admin.site.register(ModerationAction)
|
||||
admin.site.register(ModerationAction, SimpleHistoryAdmin)
|
||||
admin.site.register(Language)
|
||||
admin.site.register(Announcement)
|
||||
admin.site.register(Subscriptions)
|
||||
admin.site.register(Announcement, SimpleHistoryAdmin)
|
||||
admin.site.register(Subscriptions, SimpleHistoryAdmin)
|
||||
admin.site.register(Timestamp)
|
||||
|
||||
+367
@@ -0,0 +1,367 @@
|
||||
# Generated by Django 5.2.8 on 2025-11-16 17:37
|
||||
|
||||
import django.contrib.auth.validators
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
import simple_history.models
|
||||
import uuid
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('fellchensammlung', '0070_user_mod_notes_alter_user_reason_for_signup'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='HistoricalAdoptionNotice',
|
||||
fields=[
|
||||
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
|
||||
('created_at', models.DateField(default=django.utils.timezone.now, verbose_name='Erstellt am')),
|
||||
('updated_at', models.DateTimeField(blank=True, editable=False)),
|
||||
('last_checked', models.DateTimeField(default=django.utils.timezone.now, verbose_name='Zuletzt überprüft am')),
|
||||
('searching_since', models.DateField(verbose_name='Sucht nach einem Zuhause seit')),
|
||||
('name', models.CharField(max_length=200, verbose_name='Titel der Vermittlung')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='Beschreibung')),
|
||||
('further_information', models.URLField(blank=True, help_text='Verlinke hier die Quelle der Vermittlung (z.B. die Website des Tierheims)', null=True, verbose_name='Link zu mehr Informationen')),
|
||||
('group_only', models.BooleanField(default=False, verbose_name='Ausschließlich Gruppenadoption')),
|
||||
('location_string', models.CharField(max_length=200, verbose_name='Ortsangabe')),
|
||||
('adoption_notice_status', models.TextField(choices=[('active_searching', 'Searching'), ('active_interested', 'Interested'), ('awaiting_action_waiting_for_review', 'Waiting for review'), ('awaiting_action_needs_additional_info', 'Needs additional info'), ('awaiting_action_unchecked', 'Unchecked'), ('closed_successful_with_notfellchen', 'Successful (with Notfellchen)'), ('closed_successful_without_notfellchen', 'Successful (without Notfellchen)'), ('closed_animal_died', 'Animal died'), ('closed_for_other_adoption_notice', 'Closed for other adoption notice'), ('closed_not_open_for_adoption_anymore', 'Not open for adoption anymore'), ('closed_link_to_more_info_not_reachable', 'Der Link zu weiteren Informationen ist nicht mehr erreichbar.'), ('closed_other', 'Other (closed)'), ('disabled_against_the_rules', 'Against the rules'), ('disabled_other', 'Other (disabled)')], max_length=64, verbose_name='Status')),
|
||||
('adoption_process', models.TextField(blank=True, choices=[('contact_person_in_an', 'Kontaktiere die Person im Vermittlungstext')], max_length=64, null=True, verbose_name='Adoptionsprozess')),
|
||||
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('history_date', models.DateTimeField(db_index=True)),
|
||||
('history_change_reason', models.CharField(max_length=100, null=True)),
|
||||
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
||||
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
('location', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='fellchensammlung.location')),
|
||||
('organization', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='fellchensammlung.rescueorganization', verbose_name='Organisation')),
|
||||
('owner', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Creator')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'historical Vermittlung',
|
||||
'verbose_name_plural': 'historical Vermittlungen',
|
||||
'ordering': ('-history_date', '-history_id'),
|
||||
'get_latest_by': ('history_date', 'history_id'),
|
||||
},
|
||||
bases=(simple_history.models.HistoricalChanges, models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='HistoricalAnimal',
|
||||
fields=[
|
||||
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
|
||||
('date_of_birth', models.DateField(verbose_name='Geburtsdatum')),
|
||||
('name', models.CharField(max_length=200, verbose_name='Name')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='Beschreibung')),
|
||||
('sex', models.CharField(choices=[('F', 'Weiblich'), ('M', 'Männlich'), ('M_N', 'Männlich, kastriert'), ('F_N', 'Weiblich, kastriert'), ('I', 'Intergeschlechtlich')], max_length=20, verbose_name='Geschlecht')),
|
||||
('updated_at', models.DateTimeField(blank=True, editable=False)),
|
||||
('created_at', models.DateTimeField(blank=True, editable=False)),
|
||||
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('history_date', models.DateTimeField(db_index=True)),
|
||||
('history_change_reason', models.CharField(max_length=100, null=True)),
|
||||
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
||||
('adoption_notice', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='fellchensammlung.adoptionnotice')),
|
||||
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
('owner', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
('species', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='fellchensammlung.species', verbose_name='Tierart')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'historical Tier',
|
||||
'verbose_name_plural': 'historical Tiere',
|
||||
'ordering': ('-history_date', '-history_id'),
|
||||
'get_latest_by': ('history_date', 'history_id'),
|
||||
},
|
||||
bases=(simple_history.models.HistoricalChanges, models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='HistoricalAnnouncement',
|
||||
fields=[
|
||||
('text_ptr', models.ForeignKey(auto_created=True, blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, parent_link=True, related_name='+', to='fellchensammlung.text')),
|
||||
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=100, verbose_name='Titel')),
|
||||
('content', models.TextField(verbose_name='Inhalt')),
|
||||
('text_code', models.CharField(blank=True, max_length=24, verbose_name='Text code')),
|
||||
('logged_in_only', models.BooleanField(default=False)),
|
||||
('created_at', models.DateTimeField(blank=True, editable=False)),
|
||||
('updated_at', models.DateTimeField(blank=True, editable=False)),
|
||||
('publish_start_time', models.DateTimeField(verbose_name='Veröffentlichungszeitpunkt')),
|
||||
('publish_end_time', models.DateTimeField(verbose_name='Veröffentlichungsende')),
|
||||
('type', models.CharField(choices=[('important', 'important'), ('warning', 'warning'), ('info', 'info')], default='info', max_length=100)),
|
||||
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('history_date', models.DateTimeField(db_index=True)),
|
||||
('history_change_reason', models.CharField(max_length=100, null=True)),
|
||||
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
||||
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
('language', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='fellchensammlung.language', verbose_name='Sprache')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'historical Banner',
|
||||
'verbose_name_plural': 'historical Banner',
|
||||
'ordering': ('-history_date', '-history_id'),
|
||||
'get_latest_by': ('history_date', 'history_id'),
|
||||
},
|
||||
bases=(simple_history.models.HistoricalChanges, models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='HistoricalComment',
|
||||
fields=[
|
||||
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
|
||||
('created_at', models.DateTimeField(blank=True, editable=False)),
|
||||
('updated_at', models.DateTimeField(blank=True, editable=False)),
|
||||
('text', models.TextField(verbose_name='Inhalt')),
|
||||
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('history_date', models.DateTimeField(db_index=True)),
|
||||
('history_change_reason', models.CharField(max_length=100, null=True)),
|
||||
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
||||
('adoption_notice', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='fellchensammlung.adoptionnotice', verbose_name='Vermittlung')),
|
||||
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
('reply_to', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='fellchensammlung.comment', verbose_name='Antwort auf')),
|
||||
('user', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Nutzer*in')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'historical Kommentar',
|
||||
'verbose_name_plural': 'historical Kommentare',
|
||||
'ordering': ('-history_date', '-history_id'),
|
||||
'get_latest_by': ('history_date', 'history_id'),
|
||||
},
|
||||
bases=(simple_history.models.HistoricalChanges, models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='HistoricalModerationAction',
|
||||
fields=[
|
||||
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
|
||||
('action', models.CharField(choices=[('user_banned', 'User was banned'), ('content_deleted', 'Content was deleted'), ('comment', 'Comment was added'), ('other_action_taken', 'Other action was taken'), ('no_action_taken', 'No action was taken')], max_length=30)),
|
||||
('created_at', models.DateTimeField(blank=True, editable=False)),
|
||||
('updated_at', models.DateTimeField(blank=True, editable=False)),
|
||||
('public_comment', models.TextField(blank=True)),
|
||||
('private_comment', models.TextField(blank=True)),
|
||||
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('history_date', models.DateTimeField(db_index=True)),
|
||||
('history_change_reason', models.CharField(max_length=100, null=True)),
|
||||
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
||||
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
('report', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='fellchensammlung.report')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'historical Moderationsaktion',
|
||||
'verbose_name_plural': 'historical Moderationsaktionen',
|
||||
'ordering': ('-history_date', '-history_id'),
|
||||
'get_latest_by': ('history_date', 'history_id'),
|
||||
},
|
||||
bases=(simple_history.models.HistoricalChanges, models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='HistoricalReport',
|
||||
fields=[
|
||||
('id', models.UUIDField(db_index=True, default=uuid.uuid4, help_text='ID dieses reports', verbose_name='ID')),
|
||||
('status', models.CharField(choices=[('action taken', 'Action was taken'), ('no action taken', 'No action was taken'), ('waiting', 'Waiting for moderator action')], max_length=30)),
|
||||
('user_comment', models.TextField(blank=True, verbose_name='Kommentar/Zusätzliche Information')),
|
||||
('updated_at', models.DateTimeField(blank=True, editable=False, verbose_name='Zuletzt geändert am')),
|
||||
('created_at', models.DateTimeField(blank=True, editable=False, verbose_name='Erstellt am')),
|
||||
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('history_date', models.DateTimeField(db_index=True)),
|
||||
('history_change_reason', models.CharField(max_length=100, null=True)),
|
||||
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
||||
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'historical Meldung',
|
||||
'verbose_name_plural': 'historical Meldungen',
|
||||
'ordering': ('-history_date', '-history_id'),
|
||||
'get_latest_by': ('history_date', 'history_id'),
|
||||
},
|
||||
bases=(simple_history.models.HistoricalChanges, models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='HistoricalRescueOrganization',
|
||||
fields=[
|
||||
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=200)),
|
||||
('trusted', models.BooleanField(default=False, verbose_name='Vertrauenswürdig')),
|
||||
('allows_using_materials', models.CharField(choices=[('allowed', 'Usage allowed'), ('requested', 'Usage requested'), ('denied', 'Usage denied'), ('other', "It's complicated"), ('not_asked', 'Not asked')], default='not_asked', max_length=200, verbose_name='Erlaubt Nutzung von Inhalten')),
|
||||
('location_string', models.CharField(blank=True, max_length=200, null=True, verbose_name='Ort der Organisation')),
|
||||
('instagram', models.URLField(blank=True, null=True, verbose_name='Instagram Profil')),
|
||||
('facebook', models.URLField(blank=True, null=True, verbose_name='Facebook Profil')),
|
||||
('fediverse_profile', models.URLField(blank=True, null=True, verbose_name='Fediverse Profil')),
|
||||
('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='E-Mail')),
|
||||
('phone_number', models.CharField(blank=True, max_length=15, null=True, verbose_name='Telefonnummer')),
|
||||
('website', models.URLField(blank=True, null=True, verbose_name='Website')),
|
||||
('updated_at', models.DateTimeField(blank=True, editable=False)),
|
||||
('created_at', models.DateTimeField(blank=True, editable=False)),
|
||||
('last_checked', models.DateTimeField(blank=True, editable=False, verbose_name='Datum der letzten Prüfung')),
|
||||
('internal_comment', models.TextField(blank=True, null=True, verbose_name='Interner Kommentar')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='Beschreibung')),
|
||||
('external_object_identifier', models.CharField(blank=True, max_length=200, null=True, verbose_name='External Object Identifier')),
|
||||
('external_source_identifier', models.CharField(blank=True, choices=[('OSM', 'Open Street Map')], max_length=200, null=True, verbose_name='External Source Identifier')),
|
||||
('exclude_from_check', models.BooleanField(default=False, help_text='Organisation von der manuellen Überprüfung ausschließen, z.B. weil Tiere nicht online geführt werden', verbose_name='Von Prüfung ausschließen')),
|
||||
('regular_check_status', 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')),
|
||||
('ongoing_communication', models.BooleanField(default=False, help_text='Es findet gerade Kommunikation zwischen Notfellchen und der Organisation statt.', verbose_name='In aktiver Kommunikation')),
|
||||
('twenty_id', models.UUIDField(blank=True, help_text='ID der der Organisation in Twenty', null=True, verbose_name='Twenty-ID')),
|
||||
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('history_date', models.DateTimeField(db_index=True)),
|
||||
('history_change_reason', models.CharField(max_length=100, null=True)),
|
||||
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
||||
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
('location', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='fellchensammlung.location')),
|
||||
('parent_org', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='fellchensammlung.rescueorganization')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'historical Tierschutzorganisation',
|
||||
'verbose_name_plural': 'historical Tierschutzorganisationen',
|
||||
'ordering': ('-history_date', '-history_id'),
|
||||
'get_latest_by': ('history_date', 'history_id'),
|
||||
},
|
||||
bases=(simple_history.models.HistoricalChanges, models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='HistoricalRule',
|
||||
fields=[
|
||||
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=200)),
|
||||
('rule_text', models.TextField(verbose_name='Regeltext')),
|
||||
('rule_identifier', models.CharField(help_text='Ein eindeutiger Identifikator der Regel. Ein Regelobjekt derselben Regel in einer anderen Sprache muss den gleichen Identifikator haben', max_length=24, verbose_name='Regel-ID')),
|
||||
('updated_at', models.DateTimeField(blank=True, editable=False, verbose_name='Zuletzt geändert am')),
|
||||
('created_at', models.DateTimeField(blank=True, editable=False, verbose_name='Erstellt am')),
|
||||
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('history_date', models.DateTimeField(db_index=True)),
|
||||
('history_change_reason', models.CharField(max_length=100, null=True)),
|
||||
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
||||
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
('language', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='fellchensammlung.language', verbose_name='Sprache')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'historical Regel',
|
||||
'verbose_name_plural': 'historical Regeln',
|
||||
'ordering': ('-history_date', '-history_id'),
|
||||
'get_latest_by': ('history_date', 'history_id'),
|
||||
},
|
||||
bases=(simple_history.models.HistoricalChanges, models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='HistoricalSearchSubscription',
|
||||
fields=[
|
||||
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
|
||||
('sex', models.CharField(choices=[('F', 'Weiblich'), ('M', 'Männlich'), ('M_N', 'Männlich, kastriert'), ('F_N', 'Weiblich Kastriert'), ('I', 'Intergeschlechtlich'), ('A', 'Alle')], max_length=20, verbose_name='Geschlecht')),
|
||||
('max_distance', models.IntegerField(choices=[(20, '20 km'), (50, '50 km'), (100, '100 km'), (200, '200 km'), (500, '500 km')], null=True)),
|
||||
('updated_at', models.DateTimeField(blank=True, editable=False, verbose_name='Zuletzt geändert am')),
|
||||
('created_at', models.DateTimeField(blank=True, editable=False, verbose_name='Erstellt am')),
|
||||
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('history_date', models.DateTimeField(db_index=True)),
|
||||
('history_change_reason', models.CharField(max_length=100, null=True)),
|
||||
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
||||
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
('location', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='fellchensammlung.location')),
|
||||
('owner', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'historical Abonnierte Suche',
|
||||
'verbose_name_plural': 'historical Abonnierte Suchen',
|
||||
'ordering': ('-history_date', '-history_id'),
|
||||
'get_latest_by': ('history_date', 'history_id'),
|
||||
},
|
||||
bases=(simple_history.models.HistoricalChanges, models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='HistoricalSocialMediaPost',
|
||||
fields=[
|
||||
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
|
||||
('created_at', models.DateField(default=django.utils.timezone.now, verbose_name='Erstellt am')),
|
||||
('platform', models.CharField(choices=[('fediverse', 'Fediverse')], max_length=255, verbose_name='Social Media Platform')),
|
||||
('url', models.URLField(verbose_name='URL')),
|
||||
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('history_date', models.DateTimeField(db_index=True)),
|
||||
('history_change_reason', models.CharField(max_length=100, null=True)),
|
||||
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
||||
('adoption_notice', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='fellchensammlung.adoptionnotice', verbose_name='Vermittlung')),
|
||||
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'historical social media post',
|
||||
'verbose_name_plural': 'historical social media posts',
|
||||
'ordering': ('-history_date', '-history_id'),
|
||||
'get_latest_by': ('history_date', 'history_id'),
|
||||
},
|
||||
bases=(simple_history.models.HistoricalChanges, models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='HistoricalSubscriptions',
|
||||
fields=[
|
||||
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
|
||||
('created_at', models.DateTimeField(blank=True, editable=False)),
|
||||
('updated_at', models.DateTimeField(blank=True, editable=False)),
|
||||
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('history_date', models.DateTimeField(db_index=True)),
|
||||
('history_change_reason', models.CharField(max_length=100, null=True)),
|
||||
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
||||
('adoption_notice', models.ForeignKey(blank=True, db_constraint=False, help_text='Vermittlung die abonniert wurde', null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='fellchensammlung.adoptionnotice', verbose_name='Vermittlung')),
|
||||
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
('owner', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Nutzer*in')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'historical Abonnement',
|
||||
'verbose_name_plural': 'historical Abonnements',
|
||||
'ordering': ('-history_date', '-history_id'),
|
||||
'get_latest_by': ('history_date', 'history_id'),
|
||||
},
|
||||
bases=(simple_history.models.HistoricalChanges, models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='HistoricalText',
|
||||
fields=[
|
||||
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=100, verbose_name='Titel')),
|
||||
('content', models.TextField(verbose_name='Inhalt')),
|
||||
('text_code', models.CharField(blank=True, max_length=24, verbose_name='Text code')),
|
||||
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('history_date', models.DateTimeField(db_index=True)),
|
||||
('history_change_reason', models.CharField(max_length=100, null=True)),
|
||||
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
||||
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
('language', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='fellchensammlung.language', verbose_name='Sprache')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'historical Text',
|
||||
'verbose_name_plural': 'historical Texte',
|
||||
'ordering': ('-history_date', '-history_id'),
|
||||
'get_latest_by': ('history_date', 'history_id'),
|
||||
},
|
||||
bases=(simple_history.models.HistoricalChanges, models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='HistoricalUser',
|
||||
fields=[
|
||||
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||
('username', models.CharField(db_index=True, error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
|
||||
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
|
||||
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
|
||||
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
|
||||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
||||
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
||||
('trust_level', models.IntegerField(choices=[(1, 'Member'), (2, 'Coordinator'), (3, 'Moderator'), (4, 'Admin')], default=1)),
|
||||
('updated_at', models.DateTimeField(blank=True, editable=False)),
|
||||
('reason_for_signup', models.TextField(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.", verbose_name='Grund für die Registrierung')),
|
||||
('mod_notes', models.TextField(blank=True, null=True, verbose_name='Moderationsnotizen')),
|
||||
('email_notifications', models.BooleanField(default=True, verbose_name='Benachrichtigung per E-Mail')),
|
||||
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('history_date', models.DateTimeField(db_index=True)),
|
||||
('history_change_reason', models.CharField(max_length=100, null=True)),
|
||||
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
||||
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
('organization_affiliation', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='fellchensammlung.rescueorganization', verbose_name='Organisation')),
|
||||
('preferred_language', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='fellchensammlung.language', verbose_name='Bevorzugte Sprache')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'historical Nutzer*in',
|
||||
'verbose_name_plural': 'historical Nutzer*innen',
|
||||
'ordering': ('-history_date', '-history_id'),
|
||||
'get_latest_by': ('history_date', 'history_id'),
|
||||
},
|
||||
bases=(simple_history.models.HistoricalChanges, models.Model),
|
||||
),
|
||||
]
|
||||
@@ -7,6 +7,7 @@ from django.contrib.auth.models import Group
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.core.exceptions import ValidationError
|
||||
import base64
|
||||
from simple_history.models import HistoricalRecords
|
||||
|
||||
from .tools import misc, geo
|
||||
from notfellchen.settings import MEDIA_URL, base_url
|
||||
@@ -187,6 +188,7 @@ class RescueOrganization(models.Model):
|
||||
specializations = models.ManyToManyField(Species, blank=True)
|
||||
twenty_id = models.UUIDField(verbose_name=_("Twenty-ID"), null=True, blank=True,
|
||||
help_text=_("ID der der Organisation in Twenty"))
|
||||
history = HistoricalRecords()
|
||||
|
||||
class Meta:
|
||||
unique_together = ('external_object_identifier', 'external_source_identifier',)
|
||||
@@ -250,6 +252,7 @@ class RescueOrganization(models.Model):
|
||||
|
||||
def set_checked(self):
|
||||
self.last_checked = timezone.now()
|
||||
self._change_reason = 'Organization checked'
|
||||
self.save()
|
||||
|
||||
@property
|
||||
@@ -311,6 +314,7 @@ class User(AbstractUser):
|
||||
reason_for_signup = models.TextField(verbose_name=reason_for_signup_label, help_text=reason_for_signup_help_text)
|
||||
mod_notes = models.TextField(verbose_name=_("Moderationsnotizen"), null=True, blank=True)
|
||||
email_notifications = models.BooleanField(verbose_name=_("Benachrichtigung per E-Mail"), default=True)
|
||||
history = HistoricalRecords()
|
||||
REQUIRED_FIELDS = ["reason_for_signup", "email"]
|
||||
|
||||
class Meta:
|
||||
@@ -406,6 +410,7 @@ class AdoptionNotice(models.Model):
|
||||
adoption_process = models.TextField(null=True, blank=True,
|
||||
max_length=64, verbose_name=_('Adoptionsprozess'),
|
||||
choices=AdoptionProcess)
|
||||
history = HistoricalRecords()
|
||||
|
||||
@property
|
||||
def animals(self):
|
||||
@@ -641,6 +646,7 @@ class Animal(models.Model):
|
||||
owner = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
history = HistoricalRecords()
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name}"
|
||||
@@ -704,6 +710,7 @@ class SearchSubscription(models.Model):
|
||||
max_distance = models.IntegerField(choices=DistanceChoices.choices, null=True)
|
||||
updated_at = models.DateTimeField(auto_now=True, verbose_name=_("Zuletzt geändert am"))
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Erstellt am"))
|
||||
history = HistoricalRecords()
|
||||
|
||||
def __str__(self):
|
||||
if self.location and self.max_distance:
|
||||
@@ -734,6 +741,7 @@ class Rule(models.Model):
|
||||
"Identifikator haben"))
|
||||
updated_at = models.DateTimeField(auto_now=True, verbose_name=_("Zuletzt geändert am"))
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Erstellt am"))
|
||||
history = HistoricalRecords()
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
@@ -759,6 +767,7 @@ class Report(models.Model):
|
||||
user_comment = models.TextField(blank=True, verbose_name=_("Kommentar/Zusätzliche Information"))
|
||||
updated_at = models.DateTimeField(auto_now=True, verbose_name=_("Zuletzt geändert am"))
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("Erstellt am"))
|
||||
history = HistoricalRecords()
|
||||
|
||||
def __str__(self):
|
||||
return f"[{self.status}]: {self.user_comment:.20}"
|
||||
@@ -845,6 +854,7 @@ class ModerationAction(models.Model):
|
||||
# Only visible to moderator
|
||||
private_comment = models.TextField(blank=True)
|
||||
report = models.ForeignKey(Report, on_delete=models.CASCADE)
|
||||
history = HistoricalRecords()
|
||||
|
||||
def __str__(self):
|
||||
return f"[{self.action}]: {self.public_comment}"
|
||||
@@ -866,6 +876,7 @@ class Text(models.Model):
|
||||
content = models.TextField(verbose_name="Inhalt")
|
||||
language = models.ForeignKey(Language, verbose_name="Sprache", on_delete=models.PROTECT)
|
||||
text_code = models.CharField(max_length=24, verbose_name="Text code", blank=True)
|
||||
history = HistoricalRecords()
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Text"
|
||||
@@ -909,6 +920,7 @@ class Announcement(Text):
|
||||
INFO: "info",
|
||||
}
|
||||
type = models.CharField(choices=TYPES, max_length=100, default=INFO)
|
||||
history = HistoricalRecords()
|
||||
|
||||
@property
|
||||
def is_active(self):
|
||||
@@ -955,6 +967,7 @@ class Comment(models.Model):
|
||||
adoption_notice = models.ForeignKey(AdoptionNotice, on_delete=models.CASCADE, verbose_name=_('Vermittlung'))
|
||||
text = models.TextField(verbose_name="Inhalt")
|
||||
reply_to = models.ForeignKey("self", verbose_name="Antwort auf", blank=True, null=True, on_delete=models.CASCADE)
|
||||
history = HistoricalRecords()
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.user} at {self.created_at.strftime('%H:%M %d.%m.%y')}: {self.text:.10}"
|
||||
@@ -1026,6 +1039,7 @@ class Subscriptions(models.Model):
|
||||
help_text=_("Vermittlung die abonniert wurde"))
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
history = HistoricalRecords()
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.owner} - {self.adoption_notice}"
|
||||
@@ -1087,6 +1101,7 @@ class SocialMediaPost(models.Model):
|
||||
choices=PlatformChoices.choices)
|
||||
adoption_notice = models.ForeignKey(AdoptionNotice, on_delete=models.CASCADE, verbose_name=_('Vermittlung'))
|
||||
url = models.URLField(verbose_name=_("URL"))
|
||||
history = HistoricalRecords()
|
||||
|
||||
@staticmethod
|
||||
def get_an_to_post():
|
||||
|
||||
@@ -237,6 +237,7 @@ INSTALLED_APPS = [
|
||||
'widget_tweaks',
|
||||
"debug_toolbar",
|
||||
'admin_extra_buttons',
|
||||
'simple_history',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
@@ -254,6 +255,7 @@ MIDDLEWARE = [
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
# allauth middleware, needs to be after message middleware
|
||||
"allauth.account.middleware.AccountMiddleware",
|
||||
'simple_history.middleware.HistoryRequestMiddleware',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'notfellchen.urls'
|
||||
|
||||
Reference in New Issue
Block a user