From 782822af9216e4d970728e4aca8892bfed18ce2a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Mon, 23 May 2022 10:53:56 +0200
Subject: [PATCH 3/3] lingo: import/export agenda config (#65361)

---
 lingo/pricing/urls.py         |  5 ++++
 lingo/pricing/views.py        | 33 +++++++++++++++++++++---
 tests/pricing/test_manager.py | 48 +++++++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+), 4 deletions(-)

diff --git a/lingo/pricing/urls.py b/lingo/pricing/urls.py
index 0ffd15f..95b64c9 100644
--- a/lingo/pricing/urls.py
+++ b/lingo/pricing/urls.py
@@ -138,6 +138,11 @@ urlpatterns = [
         staff_member_required(views.agenda_detail),
         name='lingo-manager-agenda-detail',
     ),
+    url(
+        r'^agenda/(?P<pk>\d+)/export/$',
+        staff_member_required(views.agenda_export),
+        name='lingo-manager-agenda-export',
+    ),
     url(
         r'^agenda/(?P<pk>\d+)/pricing/add/$',
         staff_member_required(views.agenda_pricing_add),
diff --git a/lingo/pricing/views.py b/lingo/pricing/views.py
index c821a51..a75ebf2 100644
--- a/lingo/pricing/views.py
+++ b/lingo/pricing/views.py
@@ -142,7 +142,7 @@ class ConfigImportView(FormView):
                 global_noop = False
                 count = len(obj_results['created'])
                 if not count:
-                    message1 = import_messages[obj_name]['create_noop']
+                    message1 = import_messages[obj_name].get('create_noop')
                 else:
                     message1 = import_messages[obj_name]['create'](count) % {'count': count}
 
@@ -154,14 +154,23 @@ class ConfigImportView(FormView):
 
                 obj_results['messages'] = "%s %s" % (message1, message2)
 
-        pc_count, pm_count = (
+        a_count, pc_count, pm_count = (
+            len(results['agendas']['all']),
             len(results['pricing_categories']['all']),
             len(results['pricing_models']['all']),
         )
-        if (pc_count, pm_count) == (1, 0):
+        if (a_count, pc_count, pm_count) == (1, 0, 0):
+            # only one agenda imported, redirect to agenda page
+            return HttpResponseRedirect(
+                reverse(
+                    'lingo-manager-agenda-detail',
+                    kwargs={'pk': results['agendas']['all'][0].pk},
+                )
+            )
+        if (a_count, pc_count, pm_count) == (0, 1, 0):
             # only one criteria category imported, redirect to criteria page
             return HttpResponseRedirect(reverse('lingo-manager-pricing-criteria-list'))
-        if (pc_count, pm_count) == (0, 1):
+        if (a_count, pc_count, pm_count) == (0, 0, 1):
             # only one pricing imported, redirect to pricing page
             return HttpResponseRedirect(
                 reverse(
@@ -619,6 +628,22 @@ class AgendaDetailView(AgendaMixin, DetailView):
 agenda_detail = AgendaDetailView.as_view()
 
 
+class AgendaExport(AgendaMixin, DetailView):
+    model = Agenda
+
+    def get(self, request, *args, **kwargs):
+        response = HttpResponse(content_type='application/json')
+        today = datetime.date.today()
+        response['Content-Disposition'] = 'attachment; filename="export_pricing_agenda_{}_{}.json"'.format(
+            self.get_object().slug, today.strftime('%Y%m%d')
+        )
+        json.dump({'agendas': [self.get_object().export_json()]}, response, indent=2)
+        return response
+
+
+agenda_export = AgendaExport.as_view()
+
+
 class AgendaPricingAddView(AgendaMixin, CreateView):
     template_name = 'lingo/pricing/manager_agenda_pricing_form.html'
     model = AgendaPricing
diff --git a/tests/pricing/test_manager.py b/tests/pricing/test_manager.py
index e282608..2b0ad88 100644
--- a/tests/pricing/test_manager.py
+++ b/tests/pricing/test_manager.py
@@ -697,6 +697,54 @@ def test_refresh_agendas(mock_refresh, app, admin_user):
     assert mock_refresh.call_args_list == [mock.call()]
 
 
+@pytest.mark.freeze_time('2021-07-08')
+def test_import_agenda(app, admin_user):
+    agenda = Agenda.objects.create(label='Foo Bar')
+
+    app = login(app)
+    resp = app.get('/manage/pricing/agenda/%s/export/' % agenda.pk)
+    assert resp.headers['content-type'] == 'application/json'
+    assert (
+        resp.headers['content-disposition']
+        == 'attachment; filename="export_pricing_agenda_foo-bar_20210708.json"'
+    )
+    agenda_export = resp.text
+
+    # existing agenda
+    resp = app.get('/manage/pricing/', status=200)
+    resp = resp.click('Import')
+    resp.form['config_json'] = Upload('export.json', agenda_export.encode('utf-8'), 'application/json')
+    resp = resp.form.submit()
+    assert resp.location.endswith('/manage/pricing/agenda/%s/' % agenda.pk)
+    resp = resp.follow()
+    assert 'An agenda has been updated.' not in resp.text
+    assert Agenda.objects.count() == 1
+
+    # unknown agenda
+    Agenda.objects.all().delete()
+    resp = app.get('/manage/pricing/', status=200)
+    resp = resp.click('Import')
+    resp.form['config_json'] = Upload('export.json', agenda_export.encode('utf-8'), 'application/json')
+    resp = resp.form.submit()
+    assert resp.context['form'].errors['config_json'] == ['Missing "foo-bar" agenda']
+
+    # multiple pricing
+    Agenda.objects.create(label='Foo Bar')
+    Agenda.objects.create(label='Foo Bar 2')
+    agendas = json.loads(agenda_export)
+    agendas['agendas'].append(copy.copy(agendas['agendas'][0]))
+    agendas['agendas'][1]['slug'] = 'foo-bar-2'
+
+    resp = app.get('/manage/pricing/', status=200)
+    resp = resp.click('Import')
+    resp.form['config_json'] = Upload('export.json', json.dumps(agendas).encode('utf-8'), 'application/json')
+    resp = resp.form.submit()
+    assert resp.location.endswith('/manage/pricing/')
+    resp = resp.follow()
+    assert '2 agendas have been updated.' in resp.text
+    assert Agenda.objects.count() == 2
+
+
 def test_add_agenda_pricing(app, admin_user):
     agenda = Agenda.objects.create(label='Foo Bar')
     pricing = Pricing.objects.create(label='Model')
-- 
2.35.1

