diff --git a/config/settings/base.py b/config/settings/base.py index b55bd83..4e4bdfa 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -335,6 +335,11 @@ True, ) +NOTIFY_BOOKS = DynamicSetting( + "core.GrumpySettings.notify_books", + False, +) + PASSWORD_MIN_LENGTH = DynamicSetting( "core.GrumpySettings.password_min_length", 8, diff --git a/grumpy/books/views.py b/grumpy/books/views.py index 540d41b..88f1f31 100644 --- a/grumpy/books/views.py +++ b/grumpy/books/views.py @@ -1,11 +1,17 @@ +import copy import logging +from django.conf import settings from django.contrib import messages from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin +from django.contrib.sites.shortcuts import get_current_site +from django.core.mail import mail_managers from django.views.generic.edit import CreateView, DeleteView, UpdateView from django.views.generic.list import ListView from django.urls import reverse_lazy +from allauth.account.adapter import get_adapter + from grumpy.core.utils import is_error from grumpy.books.forms import BookForm from grumpy.books.models import Book @@ -13,6 +19,13 @@ logger = logging.getLogger(__name__) +def notify(request, subject, message): + adapter = get_adapter(request) + subject = adapter.format_email_subject(subject) + message = f"{message} [{get_current_site(request)}]" + mail_managers(subject, message, fail_silently=True) + + class BookListView(LoginRequiredMixin, ListView): model = Book fields = [ @@ -49,6 +62,14 @@ def form_valid(self, form): messages.add_message( self.request, messages.SUCCESS, f'Successfully added "{self.object}".' ) + + if settings.NOTIFY_BOOKS: + notify( + self.request, + "new book created", + f"User {current_user} created a new book: {self.object.id}.", + ) + return response def test_func(self): @@ -104,9 +125,20 @@ def test_func(self): return user_can_delete_book def form_valid(self, form): + deleted_book = copy.copy( + self.object + ) # shallow copy to refer to book details after it's been deleted response = super().form_valid(form) if not is_error(response.status_code): messages.add_message( self.request, messages.SUCCESS, f'Successfully deleted "{self.object}".' ) + + if settings.NOTIFY_BOOKS: + notify( + self.request, + "book deleted", + f"User {self.request.user} deleted a book: {deleted_book.id}.", + ) + return response diff --git a/grumpy/core/admin/admin_settings.py b/grumpy/core/admin/admin_settings.py index 1036c70..7b4890b 100644 --- a/grumpy/core/admin/admin_settings.py +++ b/grumpy/core/admin/admin_settings.py @@ -10,6 +10,7 @@ class GrumpySettingsAdmin(admin.ModelAdmin): "allow_signup", "require_approval", "notify_signups", + "notify_books", "password_min_length", "password_max_length", "password_strength", diff --git a/grumpy/core/migrations/0005_grumpysettings_notify_books.py b/grumpy/core/migrations/0005_grumpysettings_notify_books.py new file mode 100644 index 0000000..4b82a1f --- /dev/null +++ b/grumpy/core/migrations/0005_grumpysettings_notify_books.py @@ -0,0 +1,21 @@ +# Generated by Django 5.2.7 on 2026-08-14 09:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("core", "0004_grumpysettings_notify_signups"), + ] + + operations = [ + migrations.AddField( + model_name="grumpysettings", + name="notify_books", + field=models.BooleanField( + default=False, + help_text="Notify managers when a book is added or deleted.", + ), + ), + ] diff --git a/grumpy/core/models/models_settings.py b/grumpy/core/models/models_settings.py index 5477b15..433cb1e 100644 --- a/grumpy/core/models/models_settings.py +++ b/grumpy/core/models/models_settings.py @@ -35,6 +35,11 @@ class Meta: help_text=_("Notify managers when a new user signs up."), ) + notify_books = models.BooleanField( + default=False, + help_text=_("Notify managers when a book is added or deleted."), + ) + password_min_length = models.PositiveIntegerField( default=6, help_text=_("Minimum length of a user password") )