From b52ad962159796f77b6465173836d98d34dc2c09 Mon Sep 17 00:00:00 2001 From: Diana Boiangiu Date: Mon, 2 Apr 2018 14:25:00 +0300 Subject: [PATCH 1/4] [refs #94403] Implement data clone --- insitu/forms.py | 37 ++++++++++++++++++++++++ insitu/templates/data/add.html | 10 ++++--- insitu/templates/data/detail.html | 7 +++++ insitu/views/data.py | 48 +++++++++++++++++++++++++++++-- 4 files changed, 96 insertions(+), 6 deletions(-) diff --git a/insitu/forms.py b/insitu/forms.py index 845276f1..4f746b85 100644 --- a/insitu/forms.py +++ b/insitu/forms.py @@ -273,6 +273,37 @@ class Meta: 'quality_control_procedure', 'dissemination', 'inspire_themes', 'essential_variables'] + def save(self, created_by='', commit=True): + if created_by: + self.instance.created_by = created_by + else: + created_by = self.instance.created_by + inspire_themes = self.cleaned_data.pop('inspire_themes') + essential_variables = self.cleaned_data.pop('essential_variables') + if not self.initial: + data = models.Data.objects.create(created_by=created_by, + **self.cleaned_data) + + else: + data = models.Data.objects.filter(pk=self.instance.pk) + data.update(created_by=created_by, **self.cleaned_data) + data = data.first() + for inspire_theme in data.inspire_themes.all(): + data.inspire_themes.remove(inspire_theme) + for essential_variable in data.essential_variables.all(): + data.essential_variables.remove(essential_variable) + + for inspire_theme in inspire_themes: + data.inspire_themes.add(inspire_theme.id) + for essential_variable in essential_variables: + data.essential_variables.add(essential_variable.id) + return data + +class DataCloneForm(DataForm): + def save(self, created_by='', commit=True): + self.initial = None + return super(DataCloneForm, self).save(created_by, commit) + class DataReadyForm(RequiredFieldsMixin, DataForm): class Meta: @@ -297,6 +328,12 @@ def clean(self): self.add_error("essential_variables", error) +class DataReadyCloneForm(DataForm): + def save(self, created_by='', commit=True): + self.initial = None + return super(DataReadyCloneForm, self).save(created_by, commit) + + class DataRequirementBaseForm(forms.ModelForm): requirement = forms.ModelChoiceField( disabled=True, diff --git a/insitu/templates/data/add.html b/insitu/templates/data/add.html index 6fd981a3..4ae1536b 100644 --- a/insitu/templates/data/add.html +++ b/insitu/templates/data/add.html @@ -30,11 +30,11 @@

{% if ready_form %}
- This form has mandatory fields! If you want to access a draft version click here. + This form has mandatory fields! If you want to access a draft version click here.
{% else %}
- This form has no mandatory fields! You can access the form with required validation here. + This form has no mandatory fields! You can access the form with required validation here.
{% endif %}
@@ -54,10 +54,12 @@

+ id="id_start_time_coverage" data-provide="datepicker" + value="{{ form.start_time_coverage.value|date:'m/d/Y'}}"/> to + id="id_end_time_coverage" data-provide="datepicker" + value="{{ form.end_time_coverage.value|date:'m/d/Y'}}"/>
diff --git a/insitu/templates/data/detail.html b/insitu/templates/data/detail.html index 7bc8a7b9..f9a6d623 100644 --- a/insitu/templates/data/detail.html +++ b/insitu/templates/data/detail.html @@ -33,6 +33,13 @@

{% endif %} {% endif %} +
+ + + Clone data + +

diff --git a/insitu/views/data.py b/insitu/views/data.py index cd5a1ef8..3d5717b9 100644 --- a/insitu/views/data.py +++ b/insitu/views/data.py @@ -14,7 +14,6 @@ from insitu.views.protected.permissions import IsDraftObject from picklists import models as pickmodels - class DataList(LoggingProtectedTemplateView): template_name = 'data/list.html' permission_classes = (IsAuthenticated, ) @@ -75,14 +74,59 @@ class DataAdd(CreatedByMixin, LoggingProtectedCreateView): permission_denied_redirect = reverse_lazy('data:list') target_type = 'data' + def get_data(self): + try: + return self.get_object() + except AttributeError: + pk = self.request.GET.get('pk', None) + try: + return models.Data.objects.get(pk=pk) + except ObjectDoesNotExist: + return + + def get_initial(self): + data = None + try: + data = self.get_data() + except: + pass + if not data: + return super().get_initial() + + initial_data = super().get_initial() + for field in ['name', 'note', 'update_frequency', + 'area', 'start_time_coverage', 'end_time_coverage', + 'timeliness', 'data_policy', 'data_type', + 'data_format', 'quality_control_procedure', + 'dissemination']: + initial_data[field] = getattr(data, field) + initial_data['inspire_themes'] = getattr(data, 'inspire_themes').all() + initial_data['essential_variables'] = getattr(data, 'essential_variables').all() + return initial_data.copy() + def get_form_class(self): + data = None + try: + data = self.get_data() + except: + pass + if data: + self.post_action = 'cloned data {pk} to'.format( + pk=data.pk) + self.post_action_failed = 'tried to clone data {pk} of'.format( + pk=data.pk + ) + + if 'ready' in self.request.GET: + return forms.DataReadyCloneForm + return forms.DataCloneForm if 'ready' in self.request.GET: return forms.DataReadyForm return forms.DataForm def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - if self.get_form_class() == forms.DataReadyForm: + if self.get_form_class() == forms.DataReadyForm or self.get_form_class() == forms.DataReadyCloneForm: context['ready_form'] = True return context From ef6960cedf4472c9c84c3f5969c5ad0cc3f710c5 Mon Sep 17 00:00:00 2001 From: Diana Boiangiu Date: Mon, 2 Apr 2018 15:33:14 +0300 Subject: [PATCH 2/4] [refs #94403] Add tests for data clone --- insitu/tests/test_data.py | 45 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/insitu/tests/test_data.py b/insitu/tests/test_data.py index 3abe20e2..aaddfc27 100644 --- a/insitu/tests/test_data.py +++ b/insitu/tests/test_data.py @@ -63,6 +63,25 @@ def setUp(self): base.TeamFactory(user=self.creator) self.client.force_login(self.creator) + def _create_clone_data(self, data): + DATA_FOR_CLONE = { + 'name': data.name, + 'note': 'TEST note', + 'dissemination': data.dissemination.pk, + 'update_frequency': data.update_frequency.pk, + 'area': data.area.pk, + 'timeliness': data.timeliness.pk, + 'data_policy': data.data_policy.pk, + 'data_type': data.data_type.pk, + 'data_format': data.data_format.pk, + 'start_time_coverage': datetime.date(day=1, month=1, year=2000), + 'end_time_coverage': datetime.date(day=1, month=1, year=2000), + 'quality_control_procedure': data.quality_control_procedure.pk, + 'inspire_themes': [], + 'essential_variables': [], + } + return DATA_FOR_CLONE + def test_list_data_json(self): base.DataFactory(created_by=self.creator) resp = self.client.get(reverse('data:json')) @@ -141,6 +160,32 @@ def test_add_data_either_essential_variable_or_inspire_theme_required(self): self.check_object(models.Data.objects.last(), data) self.logging() + def test_get_add_with_clone(self): + self.erase_logging_file() + data = base.DataFactory(created_by=self.creator) + resp = self.client.get(reverse('data:add') + '?ready&pk=' + str(data.pk), + {}) + self.assertEqual(resp.status_code, 200) + form_data = [ value for field, value in resp.context['form'].initial.items()] + self.assertTrue(form_data) + self.logging() + + def test_post_add_with_clone(self): + data = base.DataFactory(created_by=self.creator) + cloned_data = self._create_clone_data(data) + resp = self.client.post(reverse('data:add') + '?ready&pk=' + str(data.pk), + cloned_data) + self.assertEqual(resp.status_code, 302) + self.check_object(models.Data.objects.last(), cloned_data) + + def test_post_add_clone_without_ready(self): + data = base.DataFactory(created_by=self.creator) + cloned_data = self._create_clone_data(data) + resp = self.client.post(reverse('data:add') + '?pk=' + str(data.pk), + cloned_data) + self.assertEqual(resp.status_code, 302) + self.check_object(models.Data.objects.last(), cloned_data) + def test_detail_data(self): self.erase_logging_file() data = base.DataFactory(created_by=self.creator) From 6b43833656e43d0b249abac75065a64f8f649c63 Mon Sep 17 00:00:00 2001 From: Diana Boiangiu Date: Tue, 3 Apr 2018 14:37:32 +0300 Subject: [PATCH 3/4] [refs #94403] Fix data clone ready form --- insitu/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/insitu/forms.py b/insitu/forms.py index 4f746b85..bbd7bbfd 100644 --- a/insitu/forms.py +++ b/insitu/forms.py @@ -328,7 +328,7 @@ def clean(self): self.add_error("essential_variables", error) -class DataReadyCloneForm(DataForm): +class DataReadyCloneForm(DataReadyForm): def save(self, created_by='', commit=True): self.initial = None return super(DataReadyCloneForm, self).save(created_by, commit) From 4aa968c12e2500f3b298979ed2f0a725371b499c Mon Sep 17 00:00:00 2001 From: Diana Boiangiu Date: Tue, 3 Apr 2018 14:43:24 +0300 Subject: [PATCH 4/4] [refs #94403] Test data clone ready form errors --- insitu/tests/test_data.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/insitu/tests/test_data.py b/insitu/tests/test_data.py index aaddfc27..ab28cd5b 100644 --- a/insitu/tests/test_data.py +++ b/insitu/tests/test_data.py @@ -64,6 +64,8 @@ def setUp(self): self.client.force_login(self.creator) def _create_clone_data(self, data): + inspire_themes = [base.InspireThemeFactory(), + base.InspireThemeFactory()] DATA_FOR_CLONE = { 'name': data.name, 'note': 'TEST note', @@ -77,7 +79,8 @@ def _create_clone_data(self, data): 'start_time_coverage': datetime.date(day=1, month=1, year=2000), 'end_time_coverage': datetime.date(day=1, month=1, year=2000), 'quality_control_procedure': data.quality_control_procedure.pk, - 'inspire_themes': [], + 'inspire_themes': [inspire_theme.pk for inspire_theme + in inspire_themes], 'essential_variables': [], } return DATA_FOR_CLONE @@ -170,11 +173,19 @@ def test_get_add_with_clone(self): self.assertTrue(form_data) self.logging() - def test_post_add_with_clone(self): + def test_post_add_with_clone_ready_errors(self): + data = base.DataFactory(created_by=self.creator) + self._create_clone_data(data) + resp = self.client.post(reverse('data:add') + '?ready&pk=' + str(data.pk), + {}) + self.assertEqual(resp.status_code, 200) + self.check_required_errors(resp, self.errors) + + def test_post_add_with_clone_ready(self): data = base.DataFactory(created_by=self.creator) cloned_data = self._create_clone_data(data) resp = self.client.post(reverse('data:add') + '?ready&pk=' + str(data.pk), - cloned_data) + cloned_data) self.assertEqual(resp.status_code, 302) self.check_object(models.Data.objects.last(), cloned_data)