Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7332bf9
initial commit - new confirm delete page
joelwilliam2005 Jan 20, 2025
f422a6b
Added All word to warning statement for plural abtests
joelwilliam2005 Jan 20, 2025
9999dc4
added unit tests
joelwilliam2005 Jan 25, 2025
84a067c
added ab_test_delete view get request test
joelwilliam2005 Jan 25, 2025
19a2ac4
removed blank lines from the template
joelwilliam2005 Feb 17, 2025
4a22685
registered views using register_admin_urls hook
joelwilliam2005 Feb 17, 2025
51bd75e
added bad permissions handling
joelwilliam2005 Feb 17, 2025
456d9dd
added new line to html
joelwilliam2005 Mar 1, 2025
5ec5e4c
moved creating abtest objects to setUp, removed check abtest order
joelwilliam2005 Mar 1, 2025
40e862c
removed check abtest count
joelwilliam2005 Mar 1, 2025
f9954dc
used default delete view and added follow=True
joelwilliam2005 Mar 1, 2025
c43a964
added permission tests
joelwilliam2005 Mar 1, 2025
0cb0c5b
fixed var names
joelwilliam2005 Mar 1, 2025
ac02964
merged confirm_delete and delete function, renamed template
joelwilliam2005 Mar 1, 2025
951218b
rename template
joelwilliam2005 Mar 2, 2025
1dc95a3
removed test confirm_delete_view functions
joelwilliam2005 Mar 2, 2025
9a6bf66
removed unneccessary comments
joelwilliam2005 Mar 2, 2025
b55b19f
used double quotations
joelwilliam2005 Mar 2, 2025
d7a0a9b
repace blocktrans with trans for title
joelwilliam2005 Mar 2, 2025
33d1a2d
removed count from context, used .count in template
joelwilliam2005 Mar 2, 2025
4635216
removed form action
joelwilliam2005 Mar 2, 2025
edf9ef1
formatted template
joelwilliam2005 Mar 2, 2025
07bafd9
added initial perm check and modified test
joelwilliam2005 Mar 12, 2025
04e5768
removed url
joelwilliam2005 Mar 14, 2025
19b1460
updated test to check redirection to wagtailadmin_home
joelwilliam2005 Mar 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{% extends "wagtailadmin/base.html" %}
{% load i18n wagtailadmin_tags %}
{% block titletag %}{% trans "Delete A/B Tests" %} - {{ page.title }}{% endblock %}

{% block content %}
{% include "wagtailadmin/shared/header.html" with title=_("A/B Tests") subtitle=page.get_admin_display_title icon="doc-empty-inverse" %}

<div class="nice-padding">
<p>
{% blocktrans count counter=ab_tests.count %}
1 A/B test associated with this page will be permanently deleted.
{% plural %}
All {{ counter }} A/B tests associated with this page will be permanently deleted.
{% endblocktrans %}
</p>
<table class="listing">
<thead>
<tr>
<th>
{% trans "Test Name" %}
</th>
<th>
{% trans "Goal Event" %}
</th>
<th>
{% trans "Status" %}
</th>
<th>
{% trans "Created By" %}
</th>
<th>
{% trans "Start Date" %}
</th>
</tr>
</thead>
<tbody>
{% for test in ab_tests %}
<tr>
<td>
<a href="{% url 'wagtailadmin_pages:edit' page.id %}">
{{ test.name }}
</a>
</td>
<td>
<span class="status-tag primary">
{{ test.goal_event }}
</span>
</td>
<td>
<span class="status-tag primary">
{{ test.get_status_description }}
</span>
</td>
<td>
<span class="status-tag primary">
{{ test.created_by }}
</span>
</td>
<td>
<span class="status-tag primary">
{% trans "Not started" as not_started_str %}
{{ test.first_started_at|default:not_started_str }}
</span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<p class="status-msg failure" >This action cannot be undone.</p>
<form method="POST">
{% csrf_token %}
<input type="submit" value="{% trans 'Yes, delete A/B tests' %}" class="button serious">
<a href="{% url 'wagtailadmin_explore' page.get_parent.id %}" class="button button-secondary">{% trans "No, don't Delete" %}</a>
</form>
</div>
{% endblock %}
129 changes: 129 additions & 0 deletions wagtail_ab_testing/test/tests/test_delete_abtest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
from datetime import datetime

from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.test import RequestFactory, TestCase
from django.urls import reverse
from wagtail.models import GroupPagePermission, Page
from wagtail.test.utils import WagtailTestUtils

from wagtail_ab_testing.models import AbTest
from wagtail_ab_testing.test.models import SimplePage
from wagtail_ab_testing.wagtail_hooks import check_ab_tests_for_page


class TestDeleteAbTestConfirmationPage(WagtailTestUtils, TestCase):
def setUp(self):
self.user = self.login()

self.moderators_group = Group.objects.get(name="Moderators")
for permission in Permission.objects.filter(
content_type=ContentType.objects.get_for_model(AbTest)
):
self.moderators_group.permissions.add(permission)

self.user.is_superuser = False
self.user.groups.add(self.moderators_group)
self.user.save()

self.factory = RequestFactory()

self.page = Page.objects.get(id=1).add_child(
instance=SimplePage(title="Test", slug="test")
)
self.page.save_revision().publish()

self.ab_test = AbTest.objects.create(
page=self.page,
name="Test AB",
first_started_at=datetime(2023, 2, 15),
variant_revision=self.page.get_latest_revision(),
status=AbTest.STATUS_DRAFT,
sample_size=10,
)

def test_check_ab_tests_hook_with_tests(self):
response = self.client.get(
reverse("wagtailadmin_pages:delete", args=[self.page.id])
)

self.assertRedirects(
response,
reverse("wagtail_ab_testing_admin:ab_test_delete", args=[self.page.id]),
msg_prefix="Redirection to the delete A/B tests confirmation page failed.",
)

def test_check_ab_tests_hook_without_tests(self):
AbTest.objects.all().delete()
request = self.factory.get("/")
response = check_ab_tests_for_page(request, self.page)
self.assertIsNone(response)

def test_ab_test_delete_view(self):
response = self.client.get(
reverse("wagtailadmin_pages:delete", args=[self.page.id]),
follow=True,
)
self.assertTemplateUsed(response, "wagtail_ab_testing/delete_ab_tests.html")

response = self.client.post(
reverse("wagtail_ab_testing_admin:ab_test_delete", args=[self.page.id])
)

self.assertEqual(AbTest.objects.filter(page=self.page).count(), 0)

self.assertRedirects(
response,
reverse("wagtailadmin_pages:delete", args=[self.page.id]),
msg_prefix="The response did not redirect to the expected delete page. A/B Tests were not deleted.",
)

def test_ab_test_delete_view_without_delete_abtest_permission(self):
delete_abtest_permission = Permission.objects.get(codename="delete_abtest")
self.moderators_group.permissions.remove(delete_abtest_permission)
self.user.save()

response = self.client.get(
reverse("wagtail_ab_testing_admin:ab_test_delete", args=[self.page.id])
)

self.assertRedirects(response, reverse("wagtailadmin_home"))
self.assertEqual(
response.context["message"],
"Sorry, you do not have permission to access this area.",
)

response = self.client.post(
reverse("wagtail_ab_testing_admin:ab_test_delete", args=[self.page.id])
)

self.assertRedirects(response, reverse("wagtailadmin_home"))
self.assertEqual(
response.context["message"],
"Sorry, you do not have permission to access this area.",
)

def test_ab_test_delete_view_without_delete_page_permission(self):
GroupPagePermission.objects.filter(
group=self.moderators_group, permission__codename="change_page"
).delete()

response = self.client.get(
reverse("wagtail_ab_testing_admin:ab_test_delete", args=[self.page.id])
)

self.assertRedirects(response, reverse("wagtailadmin_home"))
self.assertEqual(
response.context["message"],
"Sorry, you do not have permission to access this area.",
)

response = self.client.post(
reverse("wagtail_ab_testing_admin:ab_test_delete", args=[self.page.id])
)

self.assertRedirects(response, reverse("wagtailadmin_home"))
self.assertEqual(
response.context["message"],
"Sorry, you do not have permission to access this area.",
)
28 changes: 28 additions & 0 deletions wagtail_ab_testing/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from django.db.models import F, Q, Sum
from django.shortcuts import get_object_or_404, redirect, render
from django.template.loader import render_to_string
from django.urls import reverse
from django.utils import formats, timezone
from django.utils.functional import cached_property
from django.utils.translation import gettext as _
Expand Down Expand Up @@ -713,3 +714,30 @@ def goal_reached(request):
test.log_conversion(version)

return Response()


def ab_test_delete(request, page_id):
page = get_object_or_404(Page, id=page_id)
ab_tests = page.ab_tests.order_by("-first_started_at")

if not (
page.permissions_for_user(request.user).can_delete()
and request.user.has_perm("wagtail_ab_testing.delete_abtest")
):
raise PermissionDenied

if request.method == "POST":
page.ab_tests.all().delete()

return redirect(
reverse("wagtailadmin_pages:delete", kwargs={"page_id": page_id})
)

return render(
request,
"wagtail_ab_testing/delete_ab_tests.html",
{
"page": page,
"ab_tests": ab_tests,
},
)
19 changes: 18 additions & 1 deletion wagtail_ab_testing/wagtail_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from django.conf import settings
from django.contrib.auth.models import Permission
from django.core.exceptions import PermissionDenied
from django.http import JsonResponse
from django.http import HttpResponseRedirect, JsonResponse
from django.shortcuts import redirect
from django.urls import include, path, reverse
from django.utils.html import escapejs, format_html
Expand Down Expand Up @@ -41,6 +41,11 @@ def register_admin_urls():
name="report_results",
),
path("results/<int:page_id>/<int:ab_test_id>/", views.results, name="results"),
path(
"pages/<int:page_id>/delete/abtests/",
views.ab_test_delete,
name="ab_test_delete",
),
]

return [
Expand Down Expand Up @@ -236,3 +241,15 @@ def register_add_abtest_permission():
return Permission.objects.filter(
content_type__app_label="wagtail_ab_testing", codename="add_abtest"
)


@hooks.register("before_delete_page")
def check_ab_tests_for_page(request, page):
if page.ab_tests.exists():
return HttpResponseRedirect(
reverse(
"wagtail_ab_testing_admin:ab_test_delete", kwargs={"page_id": page.id}
)
)

return None