mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2024-11-26 11:31:08 +00:00
parent
ab9cea1742
commit
01d4381898
5 changed files with 182 additions and 6 deletions
48
bookwyrm/migrations/0186_invite_request_notification.py
Normal file
48
bookwyrm/migrations/0186_invite_request_notification.py
Normal file
|
@ -0,0 +1,48 @@
|
|||
# Generated by Django 3.2.20 on 2023-11-14 10:02
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("bookwyrm", "0185_alter_notification_notification_type"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="notification",
|
||||
name="related_invite_requests",
|
||||
field=models.ManyToManyField(to="bookwyrm.InviteRequest"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="notification",
|
||||
name="notification_type",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("FAVORITE", "Favorite"),
|
||||
("BOOST", "Boost"),
|
||||
("REPLY", "Reply"),
|
||||
("MENTION", "Mention"),
|
||||
("TAG", "Tag"),
|
||||
("FOLLOW", "Follow"),
|
||||
("FOLLOW_REQUEST", "Follow Request"),
|
||||
("IMPORT", "Import"),
|
||||
("ADD", "Add"),
|
||||
("REPORT", "Report"),
|
||||
("LINK_DOMAIN", "Link Domain"),
|
||||
("INVITE_REQUEST", "Invite Request"),
|
||||
("INVITE", "Invite"),
|
||||
("ACCEPT", "Accept"),
|
||||
("JOIN", "Join"),
|
||||
("LEAVE", "Leave"),
|
||||
("REMOVE", "Remove"),
|
||||
("GROUP_PRIVACY", "Group Privacy"),
|
||||
("GROUP_NAME", "Group Name"),
|
||||
("GROUP_DESCRIPTION", "Group Description"),
|
||||
("MOVE", "Move"),
|
||||
],
|
||||
max_length=255,
|
||||
),
|
||||
),
|
||||
]
|
|
@ -4,6 +4,7 @@ from django.dispatch import receiver
|
|||
from .base_model import BookWyrmModel
|
||||
from . import Boost, Favorite, GroupMemberInvitation, ImportJob, LinkDomain
|
||||
from . import ListItem, Report, Status, User, UserFollowRequest
|
||||
from .site import InviteRequest
|
||||
|
||||
|
||||
class NotificationType(models.TextChoices):
|
||||
|
@ -29,6 +30,7 @@ class NotificationType(models.TextChoices):
|
|||
# Admin
|
||||
REPORT = "REPORT"
|
||||
LINK_DOMAIN = "LINK_DOMAIN"
|
||||
INVITE_REQUEST = "INVITE_REQUEST"
|
||||
|
||||
# Groups
|
||||
INVITE = "INVITE"
|
||||
|
@ -64,8 +66,9 @@ class Notification(BookWyrmModel):
|
|||
related_list_items = models.ManyToManyField(
|
||||
"ListItem", symmetrical=False, related_name="notifications"
|
||||
)
|
||||
related_reports = models.ManyToManyField("Report", symmetrical=False)
|
||||
related_link_domains = models.ManyToManyField("LinkDomain", symmetrical=False)
|
||||
related_reports = models.ManyToManyField("Report")
|
||||
related_link_domains = models.ManyToManyField("LinkDomain")
|
||||
related_invite_requests = models.ManyToManyField("InviteRequest")
|
||||
|
||||
@classmethod
|
||||
@transaction.atomic
|
||||
|
@ -233,8 +236,7 @@ def notify_admins_on_report(sender, instance, created, *args, **kwargs):
|
|||
return
|
||||
|
||||
# moderators and superusers should be notified
|
||||
admins = User.admins()
|
||||
for admin in admins:
|
||||
for admin in User.admins():
|
||||
notification, _ = Notification.objects.get_or_create(
|
||||
user=admin,
|
||||
notification_type=NotificationType.REPORT,
|
||||
|
@ -253,8 +255,7 @@ def notify_admins_on_link_domain(sender, instance, created, *args, **kwargs):
|
|||
return
|
||||
|
||||
# moderators and superusers should be notified
|
||||
admins = User.admins()
|
||||
for admin in admins:
|
||||
for admin in User.admins():
|
||||
notification, _ = Notification.objects.get_or_create(
|
||||
user=admin,
|
||||
notification_type=NotificationType.LINK_DOMAIN,
|
||||
|
@ -263,6 +264,24 @@ def notify_admins_on_link_domain(sender, instance, created, *args, **kwargs):
|
|||
notification.related_link_domains.add(instance)
|
||||
|
||||
|
||||
@receiver(models.signals.post_save, sender=InviteRequest)
|
||||
@transaction.atomic
|
||||
# pylint: disable=unused-argument
|
||||
def notify_admins_on_invite_request(sender, instance, created, *args, **kwargs):
|
||||
"""need to handle a new invite request"""
|
||||
if not created:
|
||||
return
|
||||
|
||||
# moderators and superusers should be notified
|
||||
for admin in User.admins():
|
||||
notification, _ = Notification.objects.get_or_create(
|
||||
user=admin,
|
||||
notification_type=NotificationType.INVITE_REQUEST,
|
||||
read=False,
|
||||
)
|
||||
notification.related_invite_requests.add(instance)
|
||||
|
||||
|
||||
@receiver(models.signals.post_save, sender=GroupMemberInvitation)
|
||||
# pylint: disable=unused-argument
|
||||
def notify_user_on_group_invite(sender, instance, *args, **kwargs):
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
{% include 'notifications/items/report.html' %}
|
||||
{% elif notification.notification_type == 'LINK_DOMAIN' %}
|
||||
{% include 'notifications/items/link_domain.html' %}
|
||||
{% elif notification.notification_type == 'INVITE_REQUEST' %}
|
||||
{% include 'notifications/items/invite_request.html' %}
|
||||
{% elif notification.notification_type == 'INVITE' %}
|
||||
{% include 'notifications/items/invite.html' %}
|
||||
{% elif notification.notification_type == 'ACCEPT' %}
|
||||
|
|
20
bookwyrm/templates/notifications/items/invite_request.html
Normal file
20
bookwyrm/templates/notifications/items/invite_request.html
Normal file
|
@ -0,0 +1,20 @@
|
|||
{% extends 'notifications/items/layout.html' %}
|
||||
{% load humanize %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block primary_link %}{% spaceless %}
|
||||
{% url 'settings-invite-requests' %}
|
||||
{% endspaceless %}{% endblock %}
|
||||
|
||||
{% block icon %}
|
||||
<span class="icon icon-envelope"></span>
|
||||
{% endblock %}
|
||||
|
||||
{% block description %}
|
||||
{% url 'settings-invite-requests' as path %}
|
||||
{% blocktrans trimmed count counter=notification.related_invite_requests.count with display_count=notification.related_invite_requests.count|intcomma %}
|
||||
New <a href="{{ path }}">invite request</a> awaiting response
|
||||
{% plural %}
|
||||
{{ display_count }} new <a href="{{ path }}">invite requests</a> awaiting response
|
||||
{% endblocktrans %}
|
||||
{% endblock %}
|
|
@ -192,3 +192,90 @@ class Notification(TestCase):
|
|||
notification_type=models.NotificationType.FAVORITE,
|
||||
)
|
||||
self.assertFalse(models.Notification.objects.exists())
|
||||
|
||||
|
||||
class NotifyInviteRequest(TestCase):
|
||||
"""let admins know of invite requests"""
|
||||
|
||||
def setUp(self):
|
||||
"""ensure there is one admin"""
|
||||
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
|
||||
"bookwyrm.activitystreams.populate_stream_task.delay"
|
||||
), patch("bookwyrm.lists_stream.populate_lists_task.delay"):
|
||||
self.local_user = models.User.objects.create_user(
|
||||
"mouse@local.com",
|
||||
"mouse@mouse.mouse",
|
||||
"password",
|
||||
local=True,
|
||||
localname="mouse",
|
||||
is_superuser=True,
|
||||
)
|
||||
|
||||
def test_invite_request_triggers_notification(self):
|
||||
"""requesting an invite notifies the admin"""
|
||||
admin = models.User.objects.filter(is_superuser=True).first()
|
||||
request = models.InviteRequest.objects.create(email="user@example.com")
|
||||
|
||||
self.assertEqual(models.Notification.objects.count(), 1)
|
||||
|
||||
notification = models.Notification.objects.first()
|
||||
self.assertEqual(notification.user, admin)
|
||||
self.assertEqual(
|
||||
notification.notification_type, models.NotificationType.INVITE_REQUEST
|
||||
)
|
||||
self.assertEqual(notification.related_invite_requests.count(), 1)
|
||||
self.assertEqual(notification.related_invite_requests.first(), request)
|
||||
|
||||
def test_notify_only_created(self):
|
||||
"""updating an invite request does not trigger a notification"""
|
||||
request = models.InviteRequest.objects.create(email="user@example.com")
|
||||
notification = models.Notification.objects.first()
|
||||
|
||||
notification.delete()
|
||||
self.assertEqual(models.Notification.objects.count(), 0)
|
||||
|
||||
request.ignored = True
|
||||
request.save()
|
||||
self.assertEqual(models.Notification.objects.count(), 0)
|
||||
|
||||
def test_notify_grouping(self):
|
||||
"""invites group into the same notification, until read"""
|
||||
requests = [
|
||||
models.InviteRequest.objects.create(email="user1@example.com"),
|
||||
models.InviteRequest.objects.create(email="user2@example.com"),
|
||||
]
|
||||
self.assertEqual(models.Notification.objects.count(), 1)
|
||||
|
||||
notification = models.Notification.objects.first()
|
||||
self.assertEqual(notification.related_invite_requests.count(), 2)
|
||||
self.assertCountEqual(notification.related_invite_requests.all(), requests)
|
||||
|
||||
notification.read = True
|
||||
notification.save()
|
||||
|
||||
request = models.InviteRequest.objects.create(email="user3@example.com")
|
||||
_, notification = models.Notification.objects.all()
|
||||
|
||||
self.assertEqual(models.Notification.objects.count(), 2)
|
||||
self.assertEqual(notification.related_invite_requests.count(), 1)
|
||||
self.assertEqual(notification.related_invite_requests.first(), request)
|
||||
|
||||
def test_notify_multiple_admins(self):
|
||||
"""all admins are notified"""
|
||||
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
|
||||
"bookwyrm.activitystreams.populate_stream_task.delay"
|
||||
), patch("bookwyrm.lists_stream.populate_lists_task.delay"):
|
||||
self.local_user = models.User.objects.create_user(
|
||||
"admin@local.com",
|
||||
"admin@example.com",
|
||||
"password",
|
||||
local=True,
|
||||
localname="root",
|
||||
is_superuser=True,
|
||||
)
|
||||
models.InviteRequest.objects.create(email="user@example.com")
|
||||
admins = models.User.objects.filter(is_superuser=True).all()
|
||||
notifications = models.Notification.objects.all()
|
||||
|
||||
self.assertEqual(len(notifications), 2)
|
||||
self.assertCountEqual([notif.user for notif in notifications], admins)
|
||||
|
|
Loading…
Reference in a new issue