Notification emails #80
@ -3,14 +3,17 @@ class Verb:
|
||||
changing the values will result in a mismatch with historical values stored in db.
|
||||
"""
|
||||
|
||||
SUBMITTED_FOR_REVIEW = 'submitted for review'
|
||||
|
||||
REPORTED_EXTENSION = 'reported extension'
|
||||
REPORTED_REVIEW = 'reported review'
|
||||
|
||||
APPROVED = 'approved'
|
||||
COMMENTED = 'commented'
|
||||
RATED_EXTENSION = 'rated extension'
|
||||
REPORTED_EXTENSION = 'reported extension'
|
||||
REPORTED_REVIEW = 'reported review'
|
||||
REQUESTED_CHANGES = 'requested changes'
|
||||
REQUESTED_REVIEW = 'requested review'
|
||||
SUBMITTED_FOR_REVIEW = 'submitted for review'
|
||||
|
||||
RATED_EXTENSION = 'rated extension'
|
||||
|
||||
class Flag:
|
||||
AUTHOR = 'author'
|
||||
MODERATOR = 'moderator'
|
||||
REVIEWER = 'reviewer'
|
||||
|
@ -5,6 +5,7 @@ from django.contrib.auth.models import Group
|
||||
from django.db.models.signals import pre_save, post_save, post_delete
|
||||
from django.dispatch import receiver
|
||||
|
||||
from constants.activity import Flag
|
||||
import extensions.models
|
||||
import extensions.tasks
|
||||
import files.models
|
||||
@ -91,6 +92,6 @@ def _setup_followers(
|
||||
return
|
||||
|
||||
for user in instance.authors.all():
|
||||
follow(user, instance, send_action=False, flag='author')
|
||||
follow(user, instance, send_action=False, flag=Flag.AUTHOR)
|
||||
for user in Group.objects.get(name='moderators').user_set.all():
|
||||
follow(user, instance, send_action=False, flag='moderator')
|
||||
follow(user, instance, send_action=False, flag=Flag.MODERATOR)
|
||||
|
38
notifications/migrations/0002_setup_followers.py
Normal file
38
notifications/migrations/0002_setup_followers.py
Normal file
@ -0,0 +1,38 @@
|
||||
# Generated by Django 4.2.11 on 2024-04-15 10:18
|
||||
|
||||
from actstream.actions import follow
|
||||
from django.contrib.auth.models import Group
|
||||
from django.db import migrations
|
||||
|
||||
from constants.activity import Flag
|
||||
|
||||
|
||||
def setup_followers(apps, schema_editor):
|
||||
# !!! not using apps.get_model('extensions', 'Extension')
|
||||
# because it doesn't work with actstream.registry:
|
||||
#
|
||||
# File ".../site-packages/actstream/actions.py", line 34, in follow
|
||||
# check(obj)
|
||||
# File ".../site-packages/actstream/registry.py", line 105, in check
|
||||
# raise ImproperlyConfigured(
|
||||
# django.core.exceptions.ImproperlyConfigured: The model Extension is not registered.
|
||||
# Please use actstream.registry to register it.
|
||||
#
|
||||
# if this ever causes issues in the future, delete this code or find a workaround
|
||||
from extensions.models import Extension
|
||||
for extension in Extension.objects.all():
|
||||
for user in extension.authors.all():
|
||||
follow(user, extension, send_action=False, flag=Flag.AUTHOR)
|
||||
for user in Group.objects.get(name='moderators').user_set.all():
|
||||
follow(user, extension, send_action=False, flag=Flag.MODERATOR)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('notifications', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(setup_followers, reverse_code=migrations.RunPython.noop),
|
||||
]
|
@ -1,13 +1,26 @@
|
||||
import logging
|
||||
|
||||
from actstream.models import Action, followers
|
||||
from actstream.models import Action, Follow
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
|
||||
from constants.activity import Flag, Verb
|
||||
from notifications.models import Notification
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
VERB2FLAGS = {
|
||||
Verb.APPROVED: [Flag.AUTHOR, Flag.MODERATOR, Flag.REVIEWER],
|
||||
Verb.COMMENTED: [Flag.AUTHOR, Flag.MODERATOR, Flag.REVIEWER],
|
||||
Verb.RATED_EXTENSION: [Flag.AUTHOR],
|
||||
Verb.REPORTED_EXTENSION: [Flag.MODERATOR],
|
||||
Verb.REPORTED_REVIEW: [Flag.MODERATOR],
|
||||
Verb.REQUESTED_CHANGES: [Flag.AUTHOR, Flag.MODERATOR, Flag.REVIEWER],
|
||||
Verb.REQUESTED_REVIEW: [Flag.MODERATOR, Flag.REVIEWER],
|
||||
Verb.SUBMITTED_FOR_REVIEW: [Flag.MODERATOR],
|
||||
}
|
||||
|
||||
|
||||
@receiver(post_save, sender=Action)
|
||||
def _create_notifications(
|
||||
@ -23,11 +36,21 @@ def _create_notifications(
|
||||
return
|
||||
|
||||
if not instance.target:
|
||||
logger.warning('ignoring an unexpected Action without a target, verb={instance.verb}')
|
||||
logger.warning(f'ignoring an unexpected Action without a target, verb={instance.verb}')
|
||||
return
|
||||
|
||||
notifications = []
|
||||
for recipient in followers(instance.target):
|
||||
|
||||
flags = VERB2FLAGS.get(instance.verb, None)
|
||||
if not flags:
|
||||
logger.warning(f'no follower flags for verb={instance.verb}, nobody will be notified')
|
||||
return
|
||||
|
||||
followers = Follow.objects.for_object(instance.target).filter(flag__in=flags)
|
||||
user_ids = followers.values_list('user', flat=True)
|
||||
followers = get_user_model().objects.filter(id__in=user_ids)
|
||||
|
||||
for recipient in followers:
|
||||
if recipient == instance.actor:
|
||||
continue
|
||||
notifications.append(Notification(recipient=recipient, action=instance))
|
||||
|
@ -3,7 +3,7 @@ from actstream.actions import follow
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
|
||||
from constants.activity import Verb
|
||||
from constants.activity import Flag, Verb
|
||||
from reviewers.models import ApprovalActivity
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@ def _create_action_from_review_and_follow(
|
||||
# automatically follow after an interaction
|
||||
# if a user had unfollowed this extension before,
|
||||
# we are making them a follower again
|
||||
follow(instance.user, instance.extension, send_action=False)
|
||||
follow(instance.user, instance.extension, send_action=False, flag=Flag.REVIEWER)
|
||||
|
||||
activity_type2verb = {
|
||||
ApprovalActivity.ActivityType.APPROVED: Verb.APPROVED,
|
||||
|
@ -9,6 +9,7 @@ from django.dispatch import receiver
|
||||
|
||||
from blender_id_oauth_client import signals as bid_signals
|
||||
|
||||
from constants.activity import Flag
|
||||
from extensions.models import Extension
|
||||
from users.blender_id import BIDSession
|
||||
|
||||
@ -44,7 +45,7 @@ def update_user(
|
||||
def update_moderator_follows(instance, action, model, reverse, pk_set, **kwargs):
|
||||
"""Users becoming moderators should follow all extensions,
|
||||
and users that stop being moderators should no longer follow all extensions.
|
||||
The flag='moderator' is used to avoid deleting follow relations that were created in contexts
|
||||
The flag=Flag.MODERATOR is used to avoid deleting follow relations that were created in contexts
|
||||
other than moderator's duties.
|
||||
"""
|
||||
moderators = Group.objects.get(name='moderators')
|
||||
@ -62,7 +63,7 @@ def update_moderator_follows(instance, action, model, reverse, pk_set, **kwargs)
|
||||
for user in users:
|
||||
if action == 'post_remove':
|
||||
for extension in extensions:
|
||||
unfollow(user, extension, send_action=False, flag='moderator')
|
||||
unfollow(user, extension, send_action=False, flag=Flag.MODERATOR)
|
||||
elif action == 'post_add':
|
||||
for extension in extensions:
|
||||
follow(user, extension, send_action=False, flag='moderator')
|
||||
follow(user, extension, send_action=False, flag=Flag.MODERATOR)
|
||||
|
Loading…
Reference in New Issue
Block a user