feat: Add mod notes and user activation and deavtivation

This commit is contained in:
2025-11-16 18:07:13 +01:00
parent 8d0e4c62f7
commit c529153373
8 changed files with 133 additions and 13 deletions

View File

@@ -116,6 +116,12 @@ class ReportCommentForm(forms.ModelForm):
fields = ('reported_broken_rules', 'user_comment') fields = ('reported_broken_rules', 'user_comment')
class UserModCommentForm(forms.ModelForm):
class Meta:
model = User
fields = ('mod_notes',)
class CommentForm(forms.ModelForm): class CommentForm(forms.ModelForm):
class Meta: class Meta:
model = Comment model = Comment

View File

@@ -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'),
),
]

View File

@@ -309,6 +309,7 @@ class User(AbstractUser):
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=reason_for_signup_label, help_text=reason_for_signup_help_text) 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) email_notifications = models.BooleanField(verbose_name=_("Benachrichtigung per E-Mail"), default=True)
REQUIRED_FIELDS = ["reason_for_signup", "email"] REQUIRED_FIELDS = ["reason_for_signup", "email"]

View File

@@ -98,6 +98,27 @@
</details> </details>
</div> </div>
{% endif %}
{% if show_mod_actions %}
<div class="block">
<h2 class="title is-2">{% trans 'Moderation' %}</h2>
<div class="block">
<p><strong>{% translate 'Moderationsnotizen' %}:</strong> {{ user.mod_notes }}</p>
</div>
<div class="block">
{% if user.is_active %}
<a href="{% url 'user-deactivate' user_id=user.pk %}" class="button is-danger">
{% translate 'User deaktivieren' %}
</a>
{% else %}
<a href="{% url 'user-activate' user_id=user.pk %}" class="button is-info">
{% translate 'User aktivieren' %}
</a>
{% endif %}
</div>
</div>
{% endif %}
<h2 class="title is-2">{% translate 'Benachrichtigungen' %}</h2> <h2 class="title is-2">{% translate 'Benachrichtigungen' %}</h2>
{% include "fellchensammlung/lists/list-notifications.html" %} {% include "fellchensammlung/lists/list-notifications.html" %}
@@ -105,8 +126,7 @@
<h2 class="title is-2">{% translate 'Abonnierte Suchen' %}</h2> <h2 class="title is-2">{% translate 'Abonnierte Suchen' %}</h2>
{% include "fellchensammlung/lists/list-search-subscriptions.html" %} {% include "fellchensammlung/lists/list-search-subscriptions.html" %}
<h2 class="title is-2">{% translate 'Meine Vermittlungen' %}</h2> <h2 class="title is-2">{% translate 'Vermittlungen' %}</h2>
{% include "fellchensammlung/lists/list-adoption-notices.html" %} {% include "fellchensammlung/lists/list-adoption-notices.html" %}
{% endif %}
{% endblock %} {% endblock %}

View File

@@ -0,0 +1,17 @@
{% extends "fellchensammlung/base.html" %}
{% load i18n %}
{% block description %}
<meta name="description" content="{% trans 'User aktivieren' %}">
{% endblock %}
{% block content %}
<h1 class="title is-1">{% trans 'User aktivieren' %}</h1>
{% blocktranslate %}
Hier kannst du einen User manuell aktivieren und optional eine Notiz hinterlassen.
{% endblocktranslate %}
<form method="post">
{% csrf_token %}
{{ form }}
<button class="button is-info is-fullwidth" type="submit">{% translate "Aktivieren" %}</button>
</form>
{% endblock %}

View File

@@ -0,0 +1,19 @@
{% extends "fellchensammlung/base.html" %}
{% load i18n %}
{% block description %}
<meta name="description" content="{% trans 'User deaktivieren' %}">
{% endblock %}
{% block content %}
<h1 class="title is-1">{% trans 'User deaktivieren' %}</h1>
{% url "about" as rule_url %}
{% blocktranslate %}
Wenn dieser User unseren <a href='{{ rule_url }}'>Regeln</a> zuwider gehandelt hat oder seit langem inaktiv
ist, kannst du ihn deaktivieren.
{% endblocktranslate %}
<form method="post">
{% csrf_token %}
{{ form }}
<button class="button is-danger is-fullwidth" type="submit">{% translate "Deaktivieren" %}</button>
</form>
{% endblock %}

View File

@@ -90,11 +90,12 @@ urlpatterns = [
########### ###########
# ex: user/1 # ex: user/1
path("user/<int:user_id>/", views.user_by_id, name="user-detail"), path("user/<int:user_id>/", views.user_by_id, name="user-detail"),
path("user/<int:user_id>/deactivate/", views.user_deactivate, name="user-deactivate"),
path("user/<int:user_id>/activate/", views.user_activate, name="user-activate"),
path("user/me/", views.my_profile, name="user-me"), path("user/me/", views.my_profile, name="user-me"),
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('change-language', views.change_language, name="change-language"), path('change-language', views.change_language, name="change-language"),
########### ###########
@@ -120,7 +121,7 @@ urlpatterns = [
################### ###################
## External Site ## ## External Site ##
################### ###################
path('bulma/external-site/', views.external_site_warning, name="external-site"), path('external-site/', views.external_site_warning, name="external-site"),
############### ###############
## TECHNICAL ## ## TECHNICAL ##

View File

@@ -25,7 +25,7 @@ from .models import AdoptionNotice, Text, Animal, Rule, Image, Report, Moderatio
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 UpdateRescueOrgRegularCheckStatus, UserModCommentForm
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
@@ -611,6 +611,9 @@ def user_detail(request, user, token=None):
user_detail_profile.add_status("Finished - returning to renderer") user_detail_profile.add_status("Finished - returning to renderer")
if request.user.is_superuser: if request.user.is_superuser:
context["profile"] = user_detail_profile.as_relative_with_ms 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) 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) 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) @user_passes_test(user_is_trust_level_or_above)
def modqueue(request): def modqueue(request):
open_reports = Report.objects.select_related("reportadoptionnotice", "reportcomment").filter(status=Report.WAITING) open_reports = Report.objects.select_related("reportadoptionnotice", "reportcomment").filter(status=Report.WAITING)