Repository: mozmeao/snippets-service

Issue:
Integrate Slack to post updates when ASRSnippet changes
See also #751

<!-- probot = {"419912":{"who":"glogiotatidis","what":"re-eval","when":"2018-11-12T09:00:00.000Z"}} -->


Discussion:
This waits for #751 to get deployed and approved by the @mozmeao/lcm-team 
/remind me to re-eval in 2 weeks
@glogiotatidis set a reminder for **Nov 12th 2018**
:wave: @glogiotatidis, re-eval
The Slack integration proved useful, let's implement this 
To clarify: Everytime a snippet is changed, a status update pushes to slack?

If so, that seems unnecessary.

The slack channel is so we can keep an eye on snippets that need reviewing,
and so content creators can get notified when their snippets have been
reviewed and published -- not as a catch-all for snippet activity.

On Wed, Nov 14, 2018, 12:19 AM Giorgos Logiotatidis <
notifications@github.com wrote:

> The Slack integration proved useful, let's implement this
>
> —
> You are receiving this because you are subscribed to this thread.
> Reply to this email directly, view it on GitHub
> <https://github.com/mozmeao/snippets-service/issues/771#issuecomment-438576221>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AlkJtWxzifj8rnj139PFoDXqKkEVbKb-ks5uu9IUgaJpZM4XtLDk>
> .
>

@mediaChick this issue so that we implement the same Slack messages as we have now for Snippet but this time for ASRSnippets. So it's only for drafts and new publications.

I agree that posting on every change is unnecessary 
Let's definitely do this for ASR when it rolls out next week, thanks!

Resolving patch:
diff --git a/snippets/base/admin/adminmodels.py b/snippets/base/admin/adminmodels.py
--- a/snippets/base/admin/adminmodels.py
+++ b/snippets/base/admin/adminmodels.py
@@ -1,6 +1,6 @@
 import re
 
-from django.contrib import admin
+from django.contrib import admin, messages
 from django.db import transaction
 from django.db.models import TextField, Q
 from django.template.loader import get_template
@@ -12,8 +12,7 @@
 from jinja2.meta import find_undeclared_variables
 from django_admin_listfilter_dropdown.filters import RelatedDropdownFilter
 
-from snippets.base import forms, models
-from snippets.base.models import JINJA_ENV, STATUS_CHOICES
+from snippets.base import forms, models, slack
 from snippets.base.admin import actions, filters
 
 
@@ -70,7 +69,7 @@ def save_related(self, request, form, formsets, change):
                                                        change)
 
         # Parse the template code and find any undefined variables.
-        ast = JINJA_ENV.env.parse(form.instance.code)
+        ast = models.JINJA_ENV.env.parse(form.instance.code)
         new_vars = find_undeclared_variables(ast)
         var_manager = form.instance.variable_set
 
@@ -259,11 +258,26 @@ def get_form(self, request, obj=None, **kwargs):
         form.current_user = request.user
         return form
 
-    @transaction.atomic
     def make_published(self, request, queryset):
-        for snippet in queryset:
-            snippet.status = STATUS_CHOICES['Published']
-            snippet.save()
+        clean_queryset = queryset.exclude(status=models.STATUS_CHOICES['Published'])
+        no_snippets = clean_queryset.count()
+        no_already_published_snippets = queryset.count() - no_snippets
+
+        snippets = []
+        with transaction.atomic():
+            for snippet in clean_queryset:
+                snippet.status = models.STATUS_CHOICES['Published']
+                snippet.save()
+                snippets.append(snippet)
+
+        for snippet in snippets:
+            slack.send_slack('asr_published', snippet)
+
+        if no_already_published_snippets:
+            messages.warning(
+                request, f'Skipped {no_already_published_snippets} already published snippets.')
+        messages.success(request, f'Published {no_snippets} snippets.')
+
     make_published.short_description = 'Publish selected snippets'
 
     # Only users with Publishing permissions on all channels are allowed to
diff --git a/snippets/base/forms.py b/snippets/base/forms.py
--- a/snippets/base/forms.py
+++ b/snippets/base/forms.py
@@ -627,6 +627,19 @@ def clean(self):
 
         return cleaned_data
 
+    def save(self, *args, **kwargs):
+        snippet = super().save(*args, **kwargs)
+
+        if (('status' in self.changed_data and
+             self.instance.status == STATUS_CHOICES['Ready for review'])):
+            send_slack('asr_ready_for_review', snippet)
+
+        if (('status' in self.changed_data and
+             self.instance.status == STATUS_CHOICES['Published'])):
+            send_slack('asr_published', snippet)
+
+        return snippet
+
 
 class TargetAdminForm(forms.ModelForm):
     filtr_is_default_browser = fields.JEXLChoiceField(
diff --git a/snippets/base/models.py b/snippets/base/models.py
--- a/snippets/base/models.py
+++ b/snippets/base/models.py
@@ -708,6 +708,16 @@ def render(self, preview=False):
 
         return rendered_snippet
 
+    @property
+    def channels(self):
+        channels = []
+
+        for target in self.targets.all():
+            for channel in CHANNELS:
+                if getattr(target, 'on_{0}'.format(channel), False):
+                    channels.append(channel)
+        return set(channels)
+
     def get_preview_url(self):
         url = reverse('asr-preview', kwargs={'uuid': self.uuid})
         full_url = urljoin(settings.SITE_URL, url)


Test patch:
diff --git a/snippets/base/tests/test_admin.py b/snippets/base/tests/test_admin.py
--- a/snippets/base/tests/test_admin.py
+++ b/snippets/base/tests/test_admin.py
@@ -222,9 +222,14 @@ def test_make_published(self):
             to_be_published[1].id,
             already_published.id
         ])
-        ASRSnippetAdmin(ASRSnippet, None).make_published(None, queryset)
+
+        with patch('snippets.base.admin.adminmodels.messages.warning') as warning:
+            with patch('snippets.base.admin.adminmodels.messages.success') as success:
+                ASRSnippetAdmin(ASRSnippet, None).make_published(None, queryset)
 
         self.assertEqual(
             set(ASRSnippet.objects.filter(status=STATUS_CHOICES['Published'])),
             set(to_be_published + [already_published])
         )
+        self.assertTrue(warning.called)
+        self.assertTrue(success.called)
diff --git a/snippets/base/tests/test_models.py b/snippets/base/tests/test_models.py
--- a/snippets/base/tests/test_models.py
+++ b/snippets/base/tests/test_models.py
@@ -417,3 +417,14 @@ def test_get_admin_url(self):
         snippet = ASRSnippetFactory.create()
         self.assertTrue(snippet.get_admin_url().startswith('http://example.com'))
         self.assertTrue(snippet.get_admin_url(full=False).startswith('/'))
+
+    def test_channels(self):
+        snippet = ASRSnippetFactory.create(
+            targets=[
+                TargetFactory.create(on_release=True),
+                TargetFactory.create(on_beta=True, on_nightly=True),
+                TargetFactory.create(on_release=False, on_esr=False,
+                                     on_aurora=False, on_beta=False, on_nightly=False),
+            ])
+
+        self.assertTrue(snippet.channels, set(['release', 'beta', 'nightly']))