Skip to content

Commit

Permalink
Enable to rollback sponsorship applications to editing (#1711)
Browse files Browse the repository at this point in the history
* Enable rollback sponsorship to edit

* Admin view to rollback to edit

* Add button in sponsorship's change form
  • Loading branch information
berinhard committed Dec 28, 2020
1 parent be0e8b7 commit 2f5d501
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 1 deletion.
30 changes: 30 additions & 0 deletions sponsors/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,11 @@ def get_urls(self):
self.admin_site.admin_view(self.approve_sponsorship_view),
name="sponsors_sponsorship_approve",
),
path(
"<int:pk>/enable-edit",
self.admin_site.admin_view(self.rollback_to_editing_view),
name="sponsors_sponsorship_rollback_to_edit",
),
]
return my_urls + urls

Expand Down Expand Up @@ -322,6 +327,31 @@ def get_sponsor_contacts(self, obj):

get_sponsor_contacts.short_description = "Contacts"

def rollback_to_editing_view(self, request, pk):
sponsorship = get_object_or_404(self.get_queryset(request), pk=pk)

if request.method.upper() == "POST" and request.POST.get("confirm") == "yes":
try:
sponsorship.rollback_to_editing()
sponsorship.save()
self.message_user(
request, "Sponsorship is now editable!", messages.SUCCESS
)
except SponsorshipInvalidStatusException as e:
self.message_user(request, str(e), messages.ERROR)

redirect_url = reverse(
"admin:sponsors_sponsorship_change", args=[sponsorship.pk]
)
return redirect(redirect_url)

context = {"sponsorship": sponsorship}
return render(
request,
"sponsors/admin/rollback_sponsorship_to_editing.html",
context=context,
)

def reject_sponsorship_view(self, request, pk):
sponsorship = get_object_or_404(self.get_queryset(request), pk=pk)

Expand Down
9 changes: 9 additions & 0 deletions sponsors/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,15 @@ def approve(self):
self.status = self.APPROVED
self.approved_on = timezone.now().date()

def rollback_to_editing(self):
accepts_rollback = [self.APPLIED, self.APPROVED, self.REJECTED]
if self.status not in accepts_rollback:
msg = f"Can't rollback to edit a {self.get_status_display()} sponsorship."
raise SponsorshipInvalidStatusException(msg)
self.status = self.APPLIED
self.approved_on = None
self.rejected_on = None

@property
def verified_emails(self):
emails = [self.submited_by.email]
Expand Down
29 changes: 28 additions & 1 deletion sponsors/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
from django.utils import timezone

from ..models import Sponsor, SponsorshipBenefit, Sponsorship
from ..exceptions import SponsorWithExistingApplicationException
from ..exceptions import (
SponsorWithExistingApplicationException,
SponsorshipInvalidStatusException,
)


class SponsorshipBenefitModelTests(TestCase):
Expand Down Expand Up @@ -142,6 +145,30 @@ def test_approve_sponsorship(self):
self.assertEqual(sponsorship.status, Sponsorship.APPROVED)
self.assertEqual(sponsorship.approved_on, timezone.now().date())

def test_rollback_sponsorship_to_edit(self):
sponsorship = Sponsorship.new(self.sponsor, self.benefits)
can_rollback_from = [
Sponsorship.APPLIED,
Sponsorship.APPROVED,
Sponsorship.REJECTED,
]
for status in can_rollback_from:
sponsorship.status = status
sponsorship.save()
sponsorship.refresh_from_db()

sponsorship.rollback_to_editing()

self.assertEqual(sponsorship.status, Sponsorship.APPLIED)
self.assertIsNone(sponsorship.approved_on)
self.assertIsNone(sponsorship.rejected_on)

sponsorship.status = Sponsorship.FINALIZED
sponsorship.save()
sponsorship.refresh_from_db()
with self.assertRaises(SponsorshipInvalidStatusException):
sponsorship.rollback_to_editing()

def test_raise_exception_when_trying_to_create_sponsorship_for_same_sponsor(self):
sponsorship = Sponsorship.new(self.sponsor, self.benefits)
finalized_status = [Sponsorship.REJECTED, Sponsorship.FINALIZED]
Expand Down
102 changes: 102 additions & 0 deletions sponsors/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,108 @@ def test_redirect_user_back_to_benefits_selection_if_post_without_valid_set_of_b
self.assertRedirects(r, reverse("select_sponsorship_application_benefits"))


class RollbackSponsorshipToEditingAdminViewTests(TestCase):
def setUp(self):
self.user = baker.make(
settings.AUTH_USER_MODEL, is_staff=True, is_superuser=True
)
self.client.force_login(self.user)
self.sponsorship = baker.make(
Sponsorship,
status=Sponsorship.APPROVED,
submited_by=self.user,
_fill_optional=True,
)
self.url = reverse(
"admin:sponsors_sponsorship_rollback_to_edit", args=[self.sponsorship.pk]
)

def test_display_confirmation_form_on_get(self):
response = self.client.get(self.url)
context = response.context
self.sponsorship.refresh_from_db()

self.assertTemplateUsed(
response, "sponsors/admin/rollback_sponsorship_to_editing.html"
)
self.assertEqual(context["sponsorship"], self.sponsorship)
self.assertNotEqual(
self.sponsorship.status, Sponsorship.APPLIED
) # did not update

def test_rollback_sponsorship_to_applied_on_post(self):
data = {"confirm": "yes"}
response = self.client.post(self.url, data=data)
self.sponsorship.refresh_from_db()

expected_url = reverse(
"admin:sponsors_sponsorship_change", args=[self.sponsorship.pk]
)
self.assertRedirects(response, expected_url, fetch_redirect_response=True)
self.assertEqual(self.sponsorship.status, Sponsorship.APPLIED)
msg = list(get_messages(response.wsgi_request))[0]
assertMessage(msg, "Sponsorship is now editable!", messages.SUCCESS)

def test_do_not_rollback_if_invalid_post(self):
response = self.client.post(self.url, data={})
self.sponsorship.refresh_from_db()
self.assertTemplateUsed(
response, "sponsors/admin/rollback_sponsorship_to_editing.html"
)
self.assertNotEqual(
self.sponsorship.status, Sponsorship.APPLIED
) # did not update

response = self.client.post(self.url, data={"confirm": "invalid"})
self.sponsorship.refresh_from_db()
self.assertTemplateUsed(
response, "sponsors/admin/rollback_sponsorship_to_editing.html"
)
self.assertNotEqual(self.sponsorship.status, Sponsorship.APPLIED)

def test_404_if_sponsorship_does_not_exist(self):
self.sponsorship.delete()
response = self.client.get(self.url)
self.assertEqual(response.status_code, 404)

def test_login_required(self):
login_url = reverse("admin:login")
redirect_url = f"{login_url}?next={self.url}"
self.client.logout()

r = self.client.get(self.url)

self.assertRedirects(r, redirect_url)

def test_staff_required(self):
login_url = reverse("admin:login")
redirect_url = f"{login_url}?next={self.url}"
self.user.is_staff = False
self.user.save()
self.client.force_login(self.user)

r = self.client.get(self.url)

self.assertRedirects(r, redirect_url, fetch_redirect_response=False)

def test_message_user_if_rejecting_invalid_sponsorship(self):
self.sponsorship.status = Sponsorship.FINALIZED
self.sponsorship.save()
data = {"confirm": "yes"}
response = self.client.post(self.url, data=data)
self.sponsorship.refresh_from_db()

expected_url = reverse(
"admin:sponsors_sponsorship_change", args=[self.sponsorship.pk]
)
self.assertRedirects(response, expected_url, fetch_redirect_response=True)
self.assertEqual(self.sponsorship.status, Sponsorship.FINALIZED)
msg = list(get_messages(response.wsgi_request))[0]
assertMessage(
msg, "Can't rollback to edit a Finalized sponsorship.", messages.ERROR
)


class RejectedSponsorshipAdminViewTests(TestCase):
def setUp(self):
self.user = baker.make(
Expand Down
35 changes: 35 additions & 0 deletions templates/sponsors/admin/rollback_sponsorship_to_editing.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{% extends 'admin/base_site.html' %}
{% load i18n admin_static sponsors %}

{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}">{% endblock %}

{% block title %}Rollback {{ sponsorship }} to editing| python.org{% endblock %}

{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> &gt
<a href="{% url 'admin:app_list' app_label='sponsors' %}">{% trans 'Sponsors' %}</a> &gt
<a href="{% url 'admin:sponsors_sponsorship_changelist' %}">{% trans 'Sponsorship' %}</a> &gt
<a href="{% url 'admin:sponsors_sponsorship_change' sponsorship.pk %}">{{ sponsorship }}</a> &gt
{% trans 'Rollback to editing' %}
</div>
{% endblock %}

{% block content %}
<h1>Rollback to Editing</h1>
<p>Please review the sponsorship application and click in the Rollback button if you want to proceed.</p>
<div id="content-main">
<form action="" method="post" id="new_psf_board_meeting_form">
{% csrf_token %}

<pre>{% full_sponsorship sponsorship display_fee=True %}</pre>

<input name="confirm" value="yes" style="display:none">

<div class="submit-row">
<input type="submit" value="Rollback" class="default">
</div>

</form>
<div>
</div>{% endblock %}
6 changes: 6 additions & 0 deletions templates/sponsors/admin/sponsorship_change_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@
</li>
{% endif %}

{% if sp.status != sp.FINALIZED and sp.status != sp.APPLIED %}
<li>
<a href="{% url 'admin:sponsors_sponsorship_rollback_to_edit' sp.pk %}">Rollback to Edit</a>
</li>
{% endif %}

{% endwith %}

{{ block.super }}
Expand Down

0 comments on commit 2f5d501

Please sign in to comment.