diff --git a/constants/activity.py b/constants/activity.py index e5127d69..1da320ca 100644 --- a/constants/activity.py +++ b/constants/activity.py @@ -10,6 +10,7 @@ class Verb: REPORTED_RATING = 'reported rating' REQUESTED_CHANGES = 'requested changes' REQUESTED_REVIEW = 'requested review' + UPLOADED_NEW_VERSION = 'uploaded new version' class Flag: diff --git a/extensions/signals.py b/extensions/signals.py index 85ae6dbd..edd2a48b 100644 --- a/extensions/signals.py +++ b/extensions/signals.py @@ -8,6 +8,7 @@ from django.db.models.signals import m2m_changed, pre_save, post_save, pre_delet from django.dispatch import receiver from constants.activity import Flag +from reviewers.models import ApprovalActivity import extensions.models import files.models @@ -165,3 +166,26 @@ def _auto_approve_subsequent_uploads( args = {'f_id': file.pk, 'pk': instance.pk, 'sender': sender, 's': file.source.name} logger.info('Auto-approving file pk=%(f_id)s of %(sender)s pk=%(pk)s source=%(s)s', args) file.save(update_fields={'status', 'date_modified'}) + + +@receiver(post_save, sender=extensions.models.Version) +def _create_approval_activity_for_new_version_if_listed( + sender: object, + instance: extensions.models.Version, + created: bool, + raw: bool, + **kwargs: object, +): + if raw: + return + if not created: + return + extension = instance.extension + if not extension.is_listed or not instance.file: + return + ApprovalActivity( + type=ApprovalActivity.ActivityType.UPLOADED_NEW_VERSION, + user=instance.file.user, + extension=instance.extension, + message=f'uploaded new version: {instance.version}', + ).save() diff --git a/extensions/tests/test_submit.py b/extensions/tests/test_submit.py index cda1712c..f54ab10a 100644 --- a/extensions/tests/test_submit.py +++ b/extensions/tests/test_submit.py @@ -10,6 +10,7 @@ from common.tests.factories.users import UserFactory from common.tests.utils import _get_all_form_errors from extensions.models import Extension, Version from files.models import File +from reviewers.models import ApprovalActivity import utils @@ -425,6 +426,14 @@ class NewVersionTest(TestCase): f'/add-ons/{self.extension.slug}/manage/versions/new/{file.pk}/', ) self.assertEqual(self.extension.versions.count(), 1) + self.extension.approve() + self.assertEqual( + ApprovalActivity.objects.filter( + extension=self.extension, + type=ApprovalActivity.ActivityType.UPLOADED_NEW_VERSION, + ).count(), + 0, + ) # Check step 2: finalise new version and send to review url = response['Location'] @@ -444,3 +453,10 @@ class NewVersionTest(TestCase): self.assertEqual(new_version.schema_version, '1.0.0') self.assertEqual(new_version.release_notes, 'new version') self.assertEqual(new_version.file.get_status_display(), 'Approved') + self.assertEqual( + ApprovalActivity.objects.filter( + extension=self.extension, + type=ApprovalActivity.ActivityType.UPLOADED_NEW_VERSION, + ).count(), + 1, + ) diff --git a/notifications/signals.py b/notifications/signals.py index 3c5e62da..f6630f24 100644 --- a/notifications/signals.py +++ b/notifications/signals.py @@ -18,6 +18,7 @@ VERB2FLAGS = { Verb.REPORTED_RATING: [Flag.MODERATOR], Verb.REQUESTED_CHANGES: [Flag.AUTHOR, Flag.REVIEWER], Verb.REQUESTED_REVIEW: [Flag.MODERATOR, Flag.REVIEWER], + Verb.UPLOADED_NEW_VERSION: [], } @@ -41,7 +42,7 @@ def _create_notifications( notifications = [] flags = VERB2FLAGS.get(instance.verb, None) - if not flags: + if flags is None: logger.warning(f'no follower flags for verb={instance.verb}, nobody will be notified') return diff --git a/reviewers/migrations/0009_alter_approvalactivity_type.py b/reviewers/migrations/0009_alter_approvalactivity_type.py new file mode 100644 index 00000000..082632c7 --- /dev/null +++ b/reviewers/migrations/0009_alter_approvalactivity_type.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.11 on 2024-04-29 17:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('reviewers', '0008_alter_approvalactivity_message'), + ] + + operations = [ + migrations.AlterField( + model_name='approvalactivity', + name='type', + field=models.CharField(choices=[('COM', 'Comment'), ('APR', 'Approved'), ('AWC', 'Awaiting Changes'), ('AWR', 'Awaiting Review'), ('UNV', 'Uploaded New Version')], default='COM', max_length=3), + ), + ] diff --git a/reviewers/models.py b/reviewers/models.py index 3daacd78..4a862e76 100644 --- a/reviewers/models.py +++ b/reviewers/models.py @@ -80,6 +80,7 @@ class ApprovalActivity(CreatedModifiedMixin, RecordDeletionMixin, models.Model): APPROVED = "APR", _("Approved") AWAITING_CHANGES = "AWC", _("Awaiting Changes") AWAITING_REVIEW = "AWR", _("Awaiting Review") + UPLOADED_NEW_VERSION = "UNV", _("Uploaded New Version") user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True) extension = models.ForeignKey( diff --git a/reviewers/signals.py b/reviewers/signals.py index 1e1b6a06..2311e524 100644 --- a/reviewers/signals.py +++ b/reviewers/signals.py @@ -30,6 +30,7 @@ def _create_action_from_review_and_follow( ApprovalActivity.ActivityType.AWAITING_CHANGES: Verb.REQUESTED_CHANGES, ApprovalActivity.ActivityType.AWAITING_REVIEW: Verb.REQUESTED_REVIEW, ApprovalActivity.ActivityType.COMMENT: Verb.COMMENTED, + ApprovalActivity.ActivityType.UPLOADED_NEW_VERSION: Verb.UPLOADED_NEW_VERSION, } action.send( instance.user,