diff --git a/src/fellchensammlung/forms.py b/src/fellchensammlung/forms.py
index af21430..3e59f1d 100644
--- a/src/fellchensammlung/forms.py
+++ b/src/fellchensammlung/forms.py
@@ -116,6 +116,12 @@ class ReportCommentForm(forms.ModelForm):
fields = ('reported_broken_rules', 'user_comment')
+class UserModCommentForm(forms.ModelForm):
+ class Meta:
+ model = User
+ fields = ('mod_notes',)
+
+
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
diff --git a/src/fellchensammlung/migrations/0070_user_mod_notes_alter_user_reason_for_signup.py b/src/fellchensammlung/migrations/0070_user_mod_notes_alter_user_reason_for_signup.py
new file mode 100644
index 0000000..bc2af60
--- /dev/null
+++ b/src/fellchensammlung/migrations/0070_user_mod_notes_alter_user_reason_for_signup.py
@@ -0,0 +1,23 @@
+# Generated by Django 5.2.8 on 2025-11-16 16:50
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('fellchensammlung', '0069_rescueorganization_regular_check_status'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='user',
+ name='mod_notes',
+ field=models.TextField(blank=True, null=True, verbose_name='Moderationsnotizen'),
+ ),
+ migrations.AlterField(
+ model_name='user',
+ name='reason_for_signup',
+ field=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'),
+ ),
+ ]
diff --git a/src/fellchensammlung/models.py b/src/fellchensammlung/models.py
index 7f73b4a..0df8e64 100644
--- a/src/fellchensammlung/models.py
+++ b/src/fellchensammlung/models.py
@@ -309,6 +309,7 @@ class User(AbstractUser):
organization_affiliation = models.ForeignKey(RescueOrganization, on_delete=models.PROTECT, null=True, blank=True,
verbose_name=_('Organisation'))
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)
REQUIRED_FIELDS = ["reason_for_signup", "email"]
diff --git a/src/fellchensammlung/templates/fellchensammlung/details/detail-user.html b/src/fellchensammlung/templates/fellchensammlung/details/detail-user.html
index 3e1c181..06979ce 100644
--- a/src/fellchensammlung/templates/fellchensammlung/details/detail-user.html
+++ b/src/fellchensammlung/templates/fellchensammlung/details/detail-user.html
@@ -98,15 +98,35 @@
-
-
{% translate 'Benachrichtigungen' %}
- {% include "fellchensammlung/lists/list-notifications.html" %}
-
- {% translate 'Abonnierte Suchen' %}
- {% include "fellchensammlung/lists/list-search-subscriptions.html" %}
-
- {% translate 'Meine Vermittlungen' %}
- {% include "fellchensammlung/lists/list-adoption-notices.html" %}
-
{% endif %}
+
+ {% if show_mod_actions %}
+
+
{% trans 'Moderation' %}
+
+
{% translate 'Moderationsnotizen' %}: {{ user.mod_notes }}
+
+
+
+ {% endif %}
+
+ {% translate 'Benachrichtigungen' %}
+ {% include "fellchensammlung/lists/list-notifications.html" %}
+
+ {% translate 'Abonnierte Suchen' %}
+ {% include "fellchensammlung/lists/list-search-subscriptions.html" %}
+
+ {% translate 'Vermittlungen' %}
+ {% include "fellchensammlung/lists/list-adoption-notices.html" %}
+
{% endblock %}
\ No newline at end of file
diff --git a/src/fellchensammlung/templates/fellchensammlung/forms/form-activate-user.html b/src/fellchensammlung/templates/fellchensammlung/forms/form-activate-user.html
new file mode 100644
index 0000000..d179b81
--- /dev/null
+++ b/src/fellchensammlung/templates/fellchensammlung/forms/form-activate-user.html
@@ -0,0 +1,17 @@
+{% extends "fellchensammlung/base.html" %}
+{% load i18n %}
+
+{% block description %}
+
+{% endblock %}
+{% block content %}
+ {% trans 'User aktivieren' %}
+ {% blocktranslate %}
+ Hier kannst du einen User manuell aktivieren und optional eine Notiz hinterlassen.
+ {% endblocktranslate %}
+
+{% endblock %}
\ No newline at end of file
diff --git a/src/fellchensammlung/templates/fellchensammlung/forms/form-deactivate-user.html b/src/fellchensammlung/templates/fellchensammlung/forms/form-deactivate-user.html
new file mode 100644
index 0000000..629c7bb
--- /dev/null
+++ b/src/fellchensammlung/templates/fellchensammlung/forms/form-deactivate-user.html
@@ -0,0 +1,19 @@
+{% extends "fellchensammlung/base.html" %}
+{% load i18n %}
+
+{% block description %}
+
+{% endblock %}
+{% block content %}
+ {% trans 'User deaktivieren' %}
+ {% url "about" as rule_url %}
+ {% blocktranslate %}
+ Wenn dieser User unseren Regeln zuwider gehandelt hat oder seit langem inaktiv
+ ist, kannst du ihn deaktivieren.
+ {% endblocktranslate %}
+
+{% endblock %}
\ No newline at end of file
diff --git a/src/fellchensammlung/urls.py b/src/fellchensammlung/urls.py
index c007eca..cf24cc4 100644
--- a/src/fellchensammlung/urls.py
+++ b/src/fellchensammlung/urls.py
@@ -90,11 +90,12 @@ urlpatterns = [
###########
# ex: user/1
path("user//", views.user_by_id, name="user-detail"),
+ path("user//deactivate/", views.user_deactivate, name="user-deactivate"),
+ path("user//activate/", views.user_activate, name="user-activate"),
path("user/me/", views.my_profile, name="user-me"),
path("user/notifications/", views.my_notifications, name="user-notifications"),
path('user/me/export/', views.export_own_profile, name='user-me-export'),
-
path('change-language', views.change_language, name="change-language"),
###########
@@ -120,7 +121,7 @@ urlpatterns = [
###################
## External Site ##
###################
- path('bulma/external-site/', views.external_site_warning, name="external-site"),
+ path('external-site/', views.external_site_warning, name="external-site"),
###############
## TECHNICAL ##
diff --git a/src/fellchensammlung/views.py b/src/fellchensammlung/views.py
index 2d639e4..8fd66f6 100644
--- a/src/fellchensammlung/views.py
+++ b/src/fellchensammlung/views.py
@@ -25,7 +25,7 @@ from .models import AdoptionNotice, Text, Animal, Rule, Image, Report, Moderatio
ImportantLocation, SpeciesSpecificURL, NotificationTypeChoices, SocialMediaPost
from .forms import AdoptionNoticeForm, ImageForm, ReportAdoptionNoticeForm, \
CommentForm, ReportCommentForm, AnimalForm, AdoptionNoticeFormAutoAnimal, SpeciesURLForm, RescueOrgInternalComment, \
- UpdateRescueOrgRegularCheckStatus
+ UpdateRescueOrgRegularCheckStatus, UserModCommentForm
from .models import Language, Announcement
from .tools import i18n, img
from .tools.fedi import post_an_to_fedi
@@ -611,6 +611,9 @@ def user_detail(request, user, token=None):
user_detail_profile.add_status("Finished - returning to renderer")
if request.user.is_superuser:
context["profile"] = user_detail_profile.as_relative_with_ms
+ if request.user.trust_level > TrustLevel.MODERATOR:
+ context["show_mod_actions"] = True
+
return render(request, 'fellchensammlung/details/detail-user.html', context=context)
@@ -685,6 +688,36 @@ def my_notifications(request):
return render(request, 'fellchensammlung/notifications.html', context=context)
+def user_activate(request, user_id):
+ return user_de_activation(request, user_id, True)
+
+
+def user_deactivate(request, user_id):
+ return user_de_activation(request, user_id, False)
+
+
+def user_de_activation(request, user_id, is_to_be_active):
+ """
+ Activates or deactivates a user
+ """
+ user = User.objects.get(id=user_id)
+ if request.method == 'POST':
+ form = UserModCommentForm(request.POST, instance=user)
+
+ if form.is_valid():
+ user_instance = form.save(commit=False)
+ user_instance.is_active = is_to_be_active
+ user_instance.save()
+ return redirect(reverse("user-detail", args=[user_instance.pk], ))
+ else:
+ form = UserModCommentForm(instance=user)
+ if is_to_be_active:
+ template = 'fellchensammlung/forms/form-activate-user.html'
+ else:
+ template = 'fellchensammlung/forms/form-deactivate-user.html'
+ return render(request, template, {'form': form})
+
+
@user_passes_test(user_is_trust_level_or_above)
def modqueue(request):
open_reports = Report.objects.select_related("reportadoptionnotice", "reportcomment").filter(status=Report.WAITING)