Notification emails #80
@ -3,14 +3,17 @@ class Verb:
|
|||||||
changing the values will result in a mismatch with historical values stored in db.
|
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'
|
APPROVED = 'approved'
|
||||||
COMMENTED = 'commented'
|
COMMENTED = 'commented'
|
||||||
|
RATED_EXTENSION = 'rated extension'
|
||||||
|
REPORTED_EXTENSION = 'reported extension'
|
||||||
|
REPORTED_REVIEW = 'reported review'
|
||||||
REQUESTED_CHANGES = 'requested changes'
|
REQUESTED_CHANGES = 'requested changes'
|
||||||
REQUESTED_REVIEW = 'requested review'
|
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.db.models.signals import pre_save, post_save, post_delete
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
|
from constants.activity import Flag
|
||||||
import extensions.models
|
import extensions.models
|
||||||
import extensions.tasks
|
import extensions.tasks
|
||||||
import files.models
|
import files.models
|
||||||
@ -91,6 +92,6 @@ def _setup_followers(
|
|||||||
return
|
return
|
||||||
|
|
||||||
for user in instance.authors.all():
|
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():
|
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
|
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.db.models.signals import post_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
|
from constants.activity import Flag, Verb
|
||||||
from notifications.models import Notification
|
from notifications.models import Notification
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
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)
|
@receiver(post_save, sender=Action)
|
||||||
def _create_notifications(
|
def _create_notifications(
|
||||||
@ -23,11 +36,21 @@ def _create_notifications(
|
|||||||
return
|
return
|
||||||
|
|
||||||
if not instance.target:
|
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
|
return
|
||||||
|
|
||||||
notifications = []
|
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:
|
if recipient == instance.actor:
|
||||||
continue
|
continue
|
||||||
notifications.append(Notification(recipient=recipient, action=instance))
|
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.db.models.signals import post_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
from constants.activity import Verb
|
from constants.activity import Flag, Verb
|
||||||
from reviewers.models import ApprovalActivity
|
from reviewers.models import ApprovalActivity
|
||||||
|
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ def _create_action_from_review_and_follow(
|
|||||||
# automatically follow after an interaction
|
# automatically follow after an interaction
|
||||||
# if a user had unfollowed this extension before,
|
# if a user had unfollowed this extension before,
|
||||||
# we are making them a follower again
|
# 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 = {
|
activity_type2verb = {
|
||||||
ApprovalActivity.ActivityType.APPROVED: Verb.APPROVED,
|
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 blender_id_oauth_client import signals as bid_signals
|
||||||
|
|
||||||
|
from constants.activity import Flag
|
||||||
from extensions.models import Extension
|
from extensions.models import Extension
|
||||||
from users.blender_id import BIDSession
|
from users.blender_id import BIDSession
|
||||||
|
|
||||||
@ -44,7 +45,7 @@ def update_user(
|
|||||||
def update_moderator_follows(instance, action, model, reverse, pk_set, **kwargs):
|
def update_moderator_follows(instance, action, model, reverse, pk_set, **kwargs):
|
||||||
"""Users becoming moderators should follow all extensions,
|
"""Users becoming moderators should follow all extensions,
|
||||||
and users that stop being moderators should no longer 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.
|
other than moderator's duties.
|
||||||
"""
|
"""
|
||||||
moderators = Group.objects.get(name='moderators')
|
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:
|
for user in users:
|
||||||
if action == 'post_remove':
|
if action == 'post_remove':
|
||||||
for extension in extensions:
|
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':
|
elif action == 'post_add':
|
||||||
for extension in extensions:
|
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