Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(#2102): Add archive sponsorship email templates option #2218

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
43 changes: 42 additions & 1 deletion mailing/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,63 @@
from django.http import HttpResponse
from django.urls import path
from django.shortcuts import get_object_or_404
from django.utils.translation import ugettext_lazy as _

from mailing.forms import BaseEmailTemplateForm


def archive_selected_email_templates(modeladmin, request, queryset):
queryset.update(active=False)
archive_selected_email_templates.short_description = "Archive selected Sponsor Email notification templates"


class EmailTemplateIsActiveListFilter(admin.SimpleListFilter):
title = _('Active')

parameter_name = 'active'

def lookups(self, request, model_admin):
return (
('all', _('All')),
(None, _('Yes')),
('no', _('No')),
)

def choices(self, cl):
for lookup, title in self.lookup_choices:
yield {
'selected': self.value() == lookup,
'query_string': cl.get_query_string({
self.parameter_name: lookup,
}, []),
'display': title,
}

def queryset(self, request, queryset):
if self.value() == 'no':
return queryset.filter(active=False)
elif self.value() is None:
return queryset.filter(active=True)
return queryset


class BaseEmailTemplateAdmin(admin.ModelAdmin):
change_form_template = "mailing/admin/base_email_template_form.html"
list_display = ["internal_name", "subject"]
list_display = ["internal_name", "subject", "active"]
list_filter = [EmailTemplateIsActiveListFilter]
readonly_fields = ["created_at", "updated_at"]
search_fields = ["internal_name"]
actions = [archive_selected_email_templates]
fieldsets = (
(None, {
'fields': ('internal_name',)
}),
('Email template', {
'fields': ('subject', 'content')
}),
(None, {
'fields': ('active',)
}),
('Timestamps', {
'classes': ('collapse',),
'fields': ('created_at', 'updated_at'),
Expand Down
1 change: 1 addition & 0 deletions mailing/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class BaseEmailTemplate(models.Model):
subject = models.CharField(max_length=128)
content = models.TextField()

active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

Expand Down
7 changes: 4 additions & 3 deletions sponsors/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,17 @@
from django.contrib import admin
from django.contrib.humanize.templatetags.humanize import intcomma
from django.forms import ModelForm
from django.urls import path, reverse, resolve
from django.urls import path, reverse
from django.utils.functional import cached_property
from django.utils.html import mark_safe

from mailing.admin import BaseEmailTemplateAdmin
from sponsors.models import *
from sponsors.models.benefits import RequiredAssetMixin
from sponsors import views_admin
from sponsors.forms import SponsorshipReviewAdminForm, SponsorBenefitAdminInlineForm, RequiredImgAssetConfigurationForm, \
SponsorshipBenefitAdminForm, CloneApplicationConfigForm
from cms.admin import ContentManageableModelAdmin
from sponsors.models.notifications import SPONSOR_TEMPLATE_ACTIVE_HELP_TEXT, SPONSOR_TEMPLATE_CONTENT_HELP_TEXT


def get_url_base_name(Model):
Expand Down Expand Up @@ -850,7 +850,8 @@ class SponsorEmailNotificationTemplateAdmin(BaseEmailTemplateAdmin):

def get_form(self, request, obj=None, **kwargs):
help_texts = {
"content": SPONSOR_TEMPLATE_HELP_TEXT,
"content": SPONSOR_TEMPLATE_CONTENT_HELP_TEXT,
"active": SPONSOR_TEMPLATE_ACTIVE_HELP_TEXT
}
kwargs.update({"help_texts": help_texts})
return super().get_form(request, obj, **kwargs)
Expand Down
4 changes: 2 additions & 2 deletions sponsors/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
SponsorEmailNotificationTemplate,
RequiredImgAssetConfiguration,
BenefitFeature,
SPONSOR_TEMPLATE_HELP_TEXT, SponsorshipCurrentYear,
SPONSOR_TEMPLATE_CONTENT_HELP_TEXT, SponsorshipCurrentYear,
)

SPONSORSHIP_YEAR_SELECT = forms.Select(
Expand Down Expand Up @@ -514,7 +514,7 @@ class SendSponsorshipNotificationForm(forms.Form):
content = forms.CharField(
widget=forms.widgets.Textarea(),
required=False,
help_text=SPONSOR_TEMPLATE_HELP_TEXT,
help_text=SPONSOR_TEMPLATE_CONTENT_HELP_TEXT,
)

def clean(self):
Expand Down
23 changes: 23 additions & 0 deletions sponsors/migrations/0093_auto_20221228_1936.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 2.2.24 on 2022-12-28 19:36

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('sponsors', '0092_auto_20220816_1517'),
]

operations = [
migrations.AddField(
model_name='sponsoremailnotificationtemplate',
name='active',
field=models.BooleanField(default=True),
),
migrations.AlterField(
model_name='sponsorshipbenefit',
name='package_only',
field=models.BooleanField(default=False, help_text='If a benefit is only available via a sponsorship package and not as an add-on, select this option.', verbose_name='Sponsor Package Only Benefit'),
),
]
2 changes: 1 addition & 1 deletion sponsors/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"""

from .assets import GenericAsset, ImgAsset, TextAsset, FileAsset, ResponseAsset
from .notifications import SponsorEmailNotificationTemplate, SPONSOR_TEMPLATE_HELP_TEXT
from .notifications import SponsorEmailNotificationTemplate, SPONSOR_TEMPLATE_CONTENT_HELP_TEXT
from .sponsors import Sponsor, SponsorContact, SponsorBenefit
from .benefits import BaseLogoPlacement, BaseTieredBenefit, BaseEmailTargetable, BenefitFeatureConfiguration, \
LogoPlacementConfiguration, TieredBenefitConfiguration, EmailTargetableConfiguration, BenefitFeature, \
Expand Down
3 changes: 2 additions & 1 deletion sponsors/models/notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from mailing.models import BaseEmailTemplate

SPONSOR_TEMPLATE_HELP_TEXT = (
SPONSOR_TEMPLATE_CONTENT_HELP_TEXT = (
"<br>"
"You can use the following template variables in the Subject and Content:"
" <pre>{{ sponsor_name }}</pre>"
Expand All @@ -12,6 +12,7 @@
" <pre>{{ sponsorship_status }}</pre>"
)

SPONSOR_TEMPLATE_ACTIVE_HELP_TEXT = "Only active templates will be shown on the admin page by default."

#################################
# Sponsor Email Notifications
Expand Down
54 changes: 52 additions & 2 deletions sponsors/tests/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@

from django.test import TestCase, RequestFactory

from sponsors.admin import SponsorshipStatusListFilter, SponsorshipAdmin
from sponsors.models import Sponsorship
from sponsors.admin import SponsorshipStatusListFilter, SponsorshipAdmin, SponsorEmailNotificationTemplateAdmin
from mailing.admin import EmailTemplateIsActiveListFilter
from sponsors.models import Sponsorship, SponsorEmailNotificationTemplate

class TestCustomSponsorshipStatusListFilter(TestCase):

Expand Down Expand Up @@ -63,3 +64,52 @@ def test_choices_with_custom_text_for_all(self):
self.assertEqual(choices[0]["display"], "Applied / Approved / Finalized")
for i, choice in enumerate(choices[1:]):
self.assertEqual(choice["display"], lookups[i][1])


class TestEmailTemplateIsActiveListFilter(TestCase):

def setUp(self):
self.request = RequestFactory().get("/")
self.model_admin = SponsorEmailNotificationTemplateAdmin
self.filter = EmailTemplateIsActiveListFilter(
request=self.request,
params={},
model=SponsorEmailNotificationTemplate,
model_admin=self.model_admin
)

def test_basic_configuration(self):
self.assertEqual("Active", self.filter.title)
self.assertEqual("active", self.filter.parameter_name)
self.assertIn(EmailTemplateIsActiveListFilter, self.model_admin.list_filter)

def test_lookups(self):
expected = (
("all", "All"),
(None, "Yes"),
("no", "No"),
)
self.assertEqual(expected, self.filter.lookups(self.request, self.model_admin))

def test_filter_queryset(self):
sponsor_email_templates = [
baker.make(SponsorEmailNotificationTemplate, active=True),
baker.make(SponsorEmailNotificationTemplate, active=False)
]

# filter active by default
qs = self.filter.queryset(self.request, SponsorEmailNotificationTemplate.objects.all())
self.assertEqual(1, qs.count())
self.assertNotIn(sponsor_email_templates[1], qs)

# Expected object count by filter
filter_count = {
"all": 2,
"no": 1
}

for filter_name in filter_count.keys():
self.filter.used_parameters[self.filter.parameter_name] = filter_name
qs = self.filter.queryset(self.request, SponsorEmailNotificationTemplate.objects.all())
self.assertEqual(filter_count[filter_name], qs.count())

16 changes: 16 additions & 0 deletions sponsors/tests/test_views_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from uuid import uuid4

from django.core.files.uploadedfile import SimpleUploadedFile
from mailing.admin import archive_selected_email_templates
from model_bakery import baker
from datetime import date, timedelta
from unittest.mock import patch, PropertyMock, Mock
Expand Down Expand Up @@ -1144,3 +1145,18 @@ def test_zip_file_organize_assets_within_sponsors_directories(self):
self.assertEqual("foo", cur_file.read().decode())
with zip_file.open("Sponsor Name/img_input.png") as cur_file:
self.assertEqual(self.img_asset.value.read(), cur_file.read())


class ArchiveSelectedEmailTemplatesTest(TestCase):
def setUp(self):
self.request_factory = RequestFactory()
self.request = self.request_factory.get("/")
self.sponsor_email_template = baker.make(SponsorEmailNotificationTemplate, active=True)
self.ModelAdmin = Mock()

def test_action_set_template_inactive(self):
queryset = SponsorEmailNotificationTemplate.objects.all()
archive_selected_email_templates(self.ModelAdmin, self.request, queryset)
self.sponsor_email_template.refresh_from_db()

self.assertFalse(self.sponsor_email_template.active)