Skip to content

Commit d10b8a4

Browse files
authored
Merge pull request #1083 from readthedocs/davidfischer/improve-copy-ads
Improve the copy ads screen
2 parents 2d873b5 + 8c1f807 commit d10b8a4

File tree

4 files changed

+73
-4
lines changed

4 files changed

+73
-4
lines changed

adserver/forms.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1371,11 +1371,20 @@ def get_ads(self):
13711371
class AdvertisementCopyForm(forms.Form):
13721372
"""Used by advertisers to re-use their ads."""
13731373

1374+
MAXIMUM_ADS = 100
1375+
DEFAULT_ORDER = "-modified"
1376+
13741377
advertisements = AdvertisementMultipleChoiceField(
13751378
queryset=Advertisement.objects.none(),
13761379
required=False,
13771380
help_text=_("Copy the following advertisements"),
13781381
)
1382+
live_after_copy = forms.BooleanField(
1383+
required=False,
1384+
initial=False,
1385+
label=_("Make copied ads live"),
1386+
help_text=_("If checked, the copied ads will be live immediately"),
1387+
)
13791388

13801389
def __init__(self, *args, **kwargs):
13811390
"""Add the form helper and customize the look of the form."""
@@ -1384,14 +1393,24 @@ def __init__(self, *args, **kwargs):
13841393
else:
13851394
raise RuntimeError("'flight' is required for the ad form")
13861395

1396+
if "order" in kwargs:
1397+
order = kwargs.pop("order")
1398+
else:
1399+
order = self.DEFAULT_ORDER
1400+
13871401
super().__init__(*args, **kwargs)
13881402

1403+
# Use the passed order to sort the ads on the form
13891404
self.fields["advertisements"].queryset = (
13901405
Advertisement.objects.filter(flight__campaign=self.flight.campaign)
1391-
.order_by("-flight__start_date", "slug")
1406+
.order_by(order, "slug")
13921407
.select_related()
13931408
.prefetch_related("ad_types")
13941409
)
1410+
# Limit the choices so the form isn't *too* long
1411+
self.fields["advertisements"].choices = self.fields["advertisements"].choices[
1412+
: self.MAXIMUM_ADS
1413+
]
13951414

13961415
self.helper = FormHelper()
13971416
self.helper.attrs = {"id": "advertisements-copy"}
@@ -1403,6 +1422,10 @@ def __init__(self, *args, **kwargs):
14031422
"advertisements",
14041423
template="adserver/includes/widgets/advertisement-form-option.html",
14051424
),
1425+
Fieldset(
1426+
_("Options"),
1427+
Field("live_after_copy"),
1428+
),
14061429
css_class="my-3",
14071430
),
14081431
Submit("submit", _("Copy existing ads")),
@@ -1413,6 +1436,8 @@ def save(self):
14131436
for ad in self.cleaned_data["advertisements"]:
14141437
new_ad = ad.__copy__()
14151438
new_ad.flight = self.flight
1439+
if self.cleaned_data["live_after_copy"]:
1440+
new_ad.live = True
14161441
new_ad.save()
14171442

14181443
return len(self.cleaned_data["advertisements"])

adserver/templates/adserver/advertiser/advertisement-copy.html

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,23 @@ <h1>{% block heading %}{% trans 'Copy advertisements' %}{% endblock heading %}</
2929
<div class="row">
3030

3131
<div class="col-md-8">
32+
33+
<form method="get">
34+
<div class="form-row">
35+
<div class="col-4">
36+
<select class="form-control form-control-sm" name="order">
37+
{% for ordering, display in ordering_options %}
38+
<option value="{{ ordering }}" {% if ordering == order %}selected{% endif %}>{{ display }}</option>
39+
{% endfor %}
40+
</select>
41+
</div>
42+
43+
<div class="col-2">
44+
<button class="btn btn-sm btn-outline-secondary" type="submit">{% trans 'Filter and order' %}</button>
45+
</div>
46+
</div> <!-- /form-row -->
47+
</form>
48+
3249
{% crispy form form.helper %}
3350
</div>
3451

adserver/tests/test_advertiser_dashboard.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -984,11 +984,22 @@ def test_ad_copy_view(self):
984984
self.assertContains(response, "Re-use your previous ads")
985985
self.assertContains(response, self.ad1.name)
986986

987-
# Perform the copy
987+
# Perform the copy - new ad isn't live by default
988988
count_ads = Advertisement.objects.all().count()
989-
response = self.client.post(url, data={"advertisements": [self.ad1.pk]})
990-
self.assertEqual(response.status_code, 302)
989+
live_ads = Advertisement.objects.filter(live=True).count()
990+
response = self.client.post(url, data={"advertisements": [self.ad1.pk]}, follow=True)
991+
self.assertEqual(response.status_code, 200)
992+
self.assertContains(response, "Successfully copied 1 ads to flight")
993+
# Ads is +1 but live ads is the same
991994
self.assertEqual(Advertisement.objects.all().count(), count_ads + 1)
995+
self.assertEqual(Advertisement.objects.filter(live=True).count(), live_ads)
996+
997+
# Copy again - new ad is live
998+
live_ads = Advertisement.objects.filter(live=True).count()
999+
response = self.client.post(url, data={"advertisements": [self.ad1.pk], "live_after_copy": True}, follow=True)
1000+
self.assertEqual(response.status_code, 200)
1001+
self.assertContains(response, "Successfully copied 1 ads to flight")
1002+
self.assertEqual(Advertisement.objects.filter(live=True).count(), live_ads + 1)
9921003

9931004
def test_deprecated_ad_type(self):
9941005
url = reverse(

adserver/views.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -929,6 +929,13 @@ class AdvertisementCopyView(
929929
):
930930
"""Create a copy of an existing ad."""
931931

932+
ORDERING_OPTIONS = (
933+
("-modified", "Most recent"),
934+
("-flight__start_date", "By flight start date"),
935+
("-sampled_ctr", "Top performing"),
936+
("name", "By name"),
937+
)
938+
932939
form_class = AdvertisementCopyForm
933940
model = Advertisement
934941
template_name = "adserver/advertiser/advertisement-copy.html"
@@ -963,15 +970,24 @@ def get_context_data(self, **kwargs):
963970
{
964971
"advertiser": self.advertiser,
965972
"flight": self.flight,
973+
"order": self.get_order(),
974+
"ordering_options": self.ORDERING_OPTIONS,
966975
}
967976
)
968977
return context
969978

970979
def get_form_kwargs(self):
971980
kwargs = super().get_form_kwargs()
972981
kwargs["flight"] = self.flight
982+
kwargs["order"] = self.get_order()
973983
return kwargs
974984

985+
def get_order(self):
986+
order = self.request.GET.get("order")
987+
if not order or order not in [o[0] for o in self.ORDERING_OPTIONS]:
988+
order = self.ORDERING_OPTIONS[0][0]
989+
return order
990+
975991
def get_success_url(self):
976992
return reverse(
977993
"flight_detail",

0 commit comments

Comments
 (0)