feat(nimbus): Subscribe/Unsubscribe to experiment on new summary page (#11639)
Because - We want to add functionality on the new summary page so that we can subscribe to the experiment This commit - Subscribe/Unsubscribe button option on the summary page Fixes #11611 <img width="1354" alt="Screenshot 2024-10-29 at 1 10 13 PM" src="https://github.com/user-attachments/assets/6e3435d2-3355-4b2e-ba42-01a439a90cfe"> <img width="1354" alt="Screenshot 2024-10-29 at 1 10 07 PM" src="https://github.com/user-attachments/assets/4b1246b9-e652-4ba3-b9f7-508842e7545d"> <img width="1354" alt="Screenshot 2024-10-29 at 1 04 16 PM" src="https://github.com/user-attachments/assets/8639fce2-ad06-45a0-b83f-5a6f55b2d931">
This commit is contained in:
Родитель
a277789cf8
Коммит
cabee0783b
|
@ -191,3 +191,31 @@ class MetricsForm(NimbusChangeLogFormMixin, forms.ModelForm):
|
|||
|
||||
def get_changelog_message(self):
|
||||
return f"{self.request.user} updated metrics"
|
||||
|
||||
|
||||
class SubscribeForm(NimbusChangeLogFormMixin, forms.ModelForm):
|
||||
class Meta:
|
||||
model = NimbusExperiment
|
||||
fields = []
|
||||
|
||||
def save(self, commit=True):
|
||||
experiment = super().save(commit=commit)
|
||||
experiment.subscribers.add(self.request.user)
|
||||
return experiment
|
||||
|
||||
def get_changelog_message(self):
|
||||
return f"{self.request.user} added subscriber"
|
||||
|
||||
|
||||
class UnsubscribeForm(NimbusChangeLogFormMixin, forms.ModelForm):
|
||||
class Meta:
|
||||
model = NimbusExperiment
|
||||
fields = []
|
||||
|
||||
def save(self, commit=True):
|
||||
experiment = super().save(commit=commit)
|
||||
experiment.subscribers.remove(self.request.user)
|
||||
return experiment
|
||||
|
||||
def get_changelog_message(self):
|
||||
return f"{self.request.user} removed subscriber"
|
||||
|
|
|
@ -93,22 +93,16 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<th>Team projects</th>
|
||||
<td>
|
||||
<td colspan="2">
|
||||
{% for project in experiment.projects.all %}
|
||||
<p>{{ project }}</p>
|
||||
{% empty %}
|
||||
<span class="text-danger">Not set</span>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<th>Subscribers</th>
|
||||
<td>
|
||||
{% for subscriber in experiment.subscribers.all %}
|
||||
<p>{{ subscriber }}</p>
|
||||
{% empty %}
|
||||
<span class="text-danger">Not set</span>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% include 'nimbus_experiments/subscribers_list.html' %}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
<tr class="subscribers-section">
|
||||
<th>Subscribers</th>
|
||||
<td id="subscribers-list"
|
||||
colspan="2"
|
||||
style="max-height: 150px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden">
|
||||
{% for subscriber in experiment.subscribers.all %}
|
||||
<p>{{ subscriber.email }}</p>
|
||||
{% empty %}
|
||||
<span class="text-danger">Not Set</span>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td style="text-align: right;">
|
||||
{% if request.user in experiment.subscribers.all %}
|
||||
<form method="post"
|
||||
action="{% url 'nimbus-new-unsubscribe' slug=experiment.slug %}"
|
||||
hx-post="{% url 'nimbus-new-unsubscribe' slug=experiment.slug %}"
|
||||
hx-target=".subscribers-section"
|
||||
hx-swap="outerHTML">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn btn-danger">Unsubscribe</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<form method="post"
|
||||
action="{% url 'nimbus-new-subscribe' slug=experiment.slug %}"
|
||||
hx-post="{% url 'nimbus-new-subscribe' slug=experiment.slug %}"
|
||||
hx-target=".subscribers-section"
|
||||
hx-swap="outerHTML">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn btn-success">Subscribe</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
|
@ -9,7 +9,9 @@ from experimenter.nimbus_ui_new.forms import (
|
|||
NimbusExperimentCreateForm,
|
||||
QAStatusForm,
|
||||
SignoffForm,
|
||||
SubscribeForm,
|
||||
TakeawaysForm,
|
||||
UnsubscribeForm,
|
||||
)
|
||||
from experimenter.openidc.tests.factories import UserFactory
|
||||
from experimenter.outcomes import Outcomes
|
||||
|
@ -275,3 +277,34 @@ class TestMetricsForm(RequestFormTestCase):
|
|||
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={}, request=self.request)
|
||||
self.assertTrue(form.is_valid())
|
||||
form.save()
|
||||
self.assertIn(self.request.user, self.experiment.subscribers.all())
|
||||
changelog = self.experiment.changes.get()
|
||||
self.assertEqual(changelog.changed_by, self.user)
|
||||
self.assertIn("dev@example.com added subscriber", changelog.message)
|
||||
|
||||
def test_unsubscribe_form_removes_subscriber(self):
|
||||
self.experiment.subscribers.add(self.request.user)
|
||||
form = UnsubscribeForm(instance=self.experiment, data={}, request=self.request)
|
||||
self.assertTrue(form.is_valid())
|
||||
form.save()
|
||||
self.assertNotIn(self.request.user, self.experiment.subscribers.all())
|
||||
changelog = self.experiment.changes.get()
|
||||
self.assertEqual(changelog.changed_by, self.user)
|
||||
self.assertIn("dev@example.com removed subscriber", changelog.message)
|
||||
|
|
|
@ -1090,6 +1090,33 @@ class NimbusExperimentDetailViewTest(AuthTestCase):
|
|||
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("nimbus-new-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("nimbus-new-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):
|
||||
|
|
|
@ -8,7 +8,9 @@ from experimenter.nimbus_ui_new.views import (
|
|||
NimbusExperimentsListTableView,
|
||||
QAStatusUpdateView,
|
||||
SignoffUpdateView,
|
||||
SubscribeView,
|
||||
TakeawaysUpdateView,
|
||||
UnsubscribeView,
|
||||
)
|
||||
|
||||
urlpatterns = [
|
||||
|
@ -52,4 +54,14 @@ urlpatterns = [
|
|||
NimbusExperimentsCreateView.as_view(),
|
||||
name="nimbus-new-create",
|
||||
),
|
||||
re_path(
|
||||
r"^(?P<slug>[\w-]+)/subscribe/",
|
||||
SubscribeView.as_view(),
|
||||
name="nimbus-new-subscribe",
|
||||
),
|
||||
re_path(
|
||||
r"^(?P<slug>[\w-]+)/unsubscribe/",
|
||||
UnsubscribeView.as_view(),
|
||||
name="nimbus-new-unsubscribe",
|
||||
),
|
||||
]
|
||||
|
|
|
@ -18,7 +18,9 @@ from experimenter.nimbus_ui_new.forms import (
|
|||
NimbusExperimentCreateForm,
|
||||
QAStatusForm,
|
||||
SignoffForm,
|
||||
SubscribeForm,
|
||||
TakeawaysForm,
|
||||
UnsubscribeForm,
|
||||
)
|
||||
|
||||
|
||||
|
@ -215,3 +217,21 @@ 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):
|
||||
super().form_valid(form)
|
||||
return self.render_to_response(self.get_context_data(form=form))
|
||||
|
||||
|
||||
class UnsubscribeView(NimbusExperimentViewMixin, RequestFormMixin, UpdateView):
|
||||
form_class = UnsubscribeForm
|
||||
template_name = "nimbus_experiments/subscribers_list.html"
|
||||
|
||||
def form_valid(self, form):
|
||||
super().form_valid(form)
|
||||
return self.render_to_response(self.get_context_data(form=form))
|
||||
|
|
Загрузка…
Ссылка в новой задаче