diff --git a/experimenter/experimenter/nimbus_ui_new/forms.py b/experimenter/experimenter/nimbus_ui_new/forms.py index 6911a7b6ae..c04dcdf7fe 100644 --- a/experimenter/experimenter/nimbus_ui_new/forms.py +++ b/experimenter/experimenter/nimbus_ui_new/forms.py @@ -191,3 +191,35 @@ def __init__(self, *args, **kwargs): def get_changelog_message(self): return f"{self.request.user} updated metrics" + + +class SubscribeForm(NimbusChangeLogFormMixin, forms.ModelForm): + class Meta: + model = NimbusExperiment + fields = [] + + def __init__(self, *args, **kwargs): + self.user = kwargs.pop("user", None) + super().__init__(*args, **kwargs) + + def save(self, commit=True): + self.instance.subscribers.add(self.user) + if commit: + self.instance.save() + return self.instance + + +class UnsubscribeForm(NimbusChangeLogFormMixin, forms.ModelForm): + class Meta: + model = NimbusExperiment + fields = [] + + def __init__(self, *args, **kwargs): + self.user = kwargs.pop("user", None) + super().__init__(*args, **kwargs) + + def save(self, commit=True): + self.instance.subscribers.remove(self.user) + if commit: + self.instance.save() + return self.instance diff --git a/experimenter/experimenter/nimbus_ui_new/templates/nimbus_experiments/detail.html b/experimenter/experimenter/nimbus_ui_new/templates/nimbus_experiments/detail.html index 4377c43ccc..5e87761cd8 100644 --- a/experimenter/experimenter/nimbus_ui_new/templates/nimbus_experiments/detail.html +++ b/experimenter/experimenter/nimbus_ui_new/templates/nimbus_experiments/detail.html @@ -90,22 +90,16 @@

Overview

Team projects - + {% for project in experiment.projects.all %}

{{ project }}

{% empty %} Not set {% endfor %} - Subscribers - - {% for subscriber in experiment.subscribers.all %} -

{{ subscriber }}

- {% empty %} - Not set - {% endfor %} - + {% include 'nimbus_experiments/subscribers_list.html' %} + diff --git a/experimenter/experimenter/nimbus_ui_new/templates/nimbus_experiments/subscribers_list.html b/experimenter/experimenter/nimbus_ui_new/templates/nimbus_experiments/subscribers_list.html new file mode 100644 index 0000000000..d277f764b4 --- /dev/null +++ b/experimenter/experimenter/nimbus_ui_new/templates/nimbus_experiments/subscribers_list.html @@ -0,0 +1,35 @@ + + Subscribers + + {% for subscriber in experiment.subscribers.all %} +

{{ subscriber.email }}

+ {% empty %} + Not Set + {% endfor %} + + + {% if request.user in experiment.subscribers.all %} +
+ {% csrf_token %} + +
+ {% else %} +
+ {% csrf_token %} + +
+ {% endif %} + + diff --git a/experimenter/experimenter/nimbus_ui_new/tests/test_forms.py b/experimenter/experimenter/nimbus_ui_new/tests/test_forms.py index 6ccbd1614f..0140fdc5de 100644 --- a/experimenter/experimenter/nimbus_ui_new/tests/test_forms.py +++ b/experimenter/experimenter/nimbus_ui_new/tests/test_forms.py @@ -9,7 +9,9 @@ NimbusExperimentCreateForm, QAStatusForm, SignoffForm, + SubscribeForm, TakeawaysForm, + UnsubscribeForm, ) from experimenter.openidc.tests.factories import UserFactory from experimenter.outcomes import Outcomes @@ -274,3 +276,28 @@ def test_invalid_form_with_wrong_application_outcomes_and_segments(self): self.assertIn("primary_outcomes", form.errors) self.assertIn("secondary_outcomes", form.errors) self.assertIn("segments", form.errors) + + +class SubscriptionFormTests(RequestFormTestCase): + def setUp(self): + super().setUp() + self.experiment = NimbusExperimentFactory.create( + name="Test Experiment", + owner=self.user, + qa_signoff=False, + vp_signoff=False, + legal_signoff=False, + ) + + def test_subscribe_form_adds_subscriber(self): + form = SubscribeForm(instance=self.experiment, data={}, user=self.user) + self.assertTrue(form.is_valid()) + form.save() + self.assertIn(self.user, self.experiment.subscribers.all()) + + def test_unsubscribe_form_removes_subscriber(self): + self.experiment.subscribers.add(self.user) + form = UnsubscribeForm(instance=self.experiment, data={}, user=self.user) + self.assertTrue(form.is_valid()) + form.save() + self.assertNotIn(self.user, self.experiment.subscribers.all()) diff --git a/experimenter/experimenter/nimbus_ui_new/tests/test_views.py b/experimenter/experimenter/nimbus_ui_new/tests/test_views.py index 0b43db2971..71f9881bac 100644 --- a/experimenter/experimenter/nimbus_ui_new/tests/test_views.py +++ b/experimenter/experimenter/nimbus_ui_new/tests/test_views.py @@ -1090,6 +1090,33 @@ def test_signoff_edit_mode_post_valid_form(self): self.assertTrue(self.experiment.vp_signoff) self.assertTrue(self.experiment.legal_signoff) + def test_subscribe_to_experiment(self): + self.assertNotIn(self.user, self.experiment.subscribers.all()) + + response = self.client.post( + reverse("subscribe", kwargs={"slug": self.experiment.slug}) + ) + + self.experiment.refresh_from_db() + + self.assertIn(self.user, self.experiment.subscribers.all()) + self.assertEqual(response.status_code, 200) + + def test_unsubscribe_from_experiment(self): + self.experiment.subscribers.add(self.user) + self.experiment.save() + + self.assertIn(self.user, self.experiment.subscribers.all()) + + response = self.client.post( + reverse("unsubscribe", kwargs={"slug": self.experiment.slug}) + ) + + self.experiment.refresh_from_db() + + self.assertNotIn(self.user, self.experiment.subscribers.all()) + self.assertEqual(response.status_code, 200) + class TestNimbusExperimentsCreateView(AuthTestCase): def test_post_creates_experiment(self): diff --git a/experimenter/experimenter/nimbus_ui_new/urls.py b/experimenter/experimenter/nimbus_ui_new/urls.py index ac0b0581fe..2c1e766180 100644 --- a/experimenter/experimenter/nimbus_ui_new/urls.py +++ b/experimenter/experimenter/nimbus_ui_new/urls.py @@ -8,7 +8,9 @@ NimbusExperimentsListTableView, QAStatusUpdateView, SignoffUpdateView, + SubscribeView, TakeawaysUpdateView, + UnsubscribeView, ) urlpatterns = [ @@ -52,4 +54,10 @@ NimbusExperimentsCreateView.as_view(), name="nimbus-new-create", ), + re_path(r"^(?P[\w-]+)/subscribe/", SubscribeView.as_view(), name="subscribe"), + re_path( + r"^(?P[\w-]+)/unsubscribe/", + UnsubscribeView.as_view(), + name="unsubscribe", + ), ] diff --git a/experimenter/experimenter/nimbus_ui_new/views.py b/experimenter/experimenter/nimbus_ui_new/views.py index 081675176b..900dfdbd3a 100644 --- a/experimenter/experimenter/nimbus_ui_new/views.py +++ b/experimenter/experimenter/nimbus_ui_new/views.py @@ -1,5 +1,6 @@ from django.conf import settings from django.http import HttpResponse +from django.shortcuts import get_object_or_404, render from django.urls import reverse from django.views.generic import CreateView, DetailView from django.views.generic.edit import UpdateView @@ -18,7 +19,9 @@ NimbusExperimentCreateForm, QAStatusForm, SignoffForm, + SubscribeForm, TakeawaysForm, + UnsubscribeForm, ) @@ -215,3 +218,27 @@ class MetricsUpdateView(NimbusExperimentViewMixin, RequestFormMixin, UpdateView) def form_valid(self, form): super().form_valid(form) return self.render_to_response(self.get_context_data(form=form)) + + +class SubscribeView(NimbusExperimentViewMixin, RequestFormMixin, UpdateView): + form_class = SubscribeForm + template_name = "nimbus_experiments/subscribers_list.html" + + def form_valid(self, form): + experiment = get_object_or_404(NimbusExperiment, slug=self.kwargs["slug"]) + form.instance = experiment + form.user = self.request.user + form.save() + return render(self.request, self.template_name, {"experiment": experiment}) + + +class UnsubscribeView(NimbusExperimentViewMixin, RequestFormMixin, UpdateView): + form_class = UnsubscribeForm + template_name = "nimbus_experiments/subscribers_list.html" + + def form_valid(self, form): + experiment = get_object_or_404(NimbusExperiment, slug=self.kwargs["slug"]) + form.instance = experiment + form.user = self.request.user + form.save() + return render(self.request, self.template_name, {"experiment": experiment})