From 89f1edb100cf151560b732f141ecb16ab21878a5 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Sun, 16 Aug 2015 19:31:35 +0100 Subject: [PATCH 1/3] EventDuplicate now presents an edit view before saving --- RIGS/forms.py | 6 ++--- RIGS/rigboard.py | 36 ++++++++++++++--------------- RIGS/templates/RIGS/event_form.html | 4 +++- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/RIGS/forms.py b/RIGS/forms.py index dd6015d1..617eb1bc 100644 --- a/RIGS/forms.py +++ b/RIGS/forms.py @@ -89,10 +89,10 @@ class EventForm(forms.ModelForm): return items def _get_or_initialise_item(self, pk, data, event): - if (pk < 0): + try: + item = models.EventItem.objects.get(pk=pk,event=event) + except models.EventItem.DoesNotExist: item = models.EventItem() - else: - item = models.EventItem.objects.get(pk=pk) item.name = data['name'] item.description = data['description'] diff --git a/RIGS/rigboard.py b/RIGS/rigboard.py index 27f00307..f62ed2da 100644 --- a/RIGS/rigboard.py +++ b/RIGS/rigboard.py @@ -18,6 +18,7 @@ from PyPDF2 import PdfFileMerger, PdfFileReader from RIGS import models, forms import datetime import re +import copy __author__ = 'ghost' @@ -85,6 +86,23 @@ class EventUpdate(generic.UpdateView): def get_success_url(self): return reverse_lazy('event_detail', kwargs={'pk': self.object.pk}) +class EventDuplicate(EventUpdate): + def get_object(self, queryset=None): + old = super(EventDuplicate, self).get_object(queryset) # Get the object (the event you're duplicating) + new = copy.copy(old) # Make a copy of the object in memory + new.based_on = old # Make the new event based on the old event + + if self.request.method in ('POST', 'PUT'): # This only happens on save (otherwise items won't display in editor) + new.pk = None # This means a new event will be created on save, and all items will be re-created + + messages.info(self.request, 'Event data duplicated but not yet saved. Click save to complete operation.') + + return new + + def get_context_data(self, **kwargs): + context = super(EventDuplicate, self).get_context_data(**kwargs) + context["duplicate"] = True + return context class EventPrint(generic.View): def get(self, request, pk): @@ -132,24 +150,6 @@ class EventPrint(generic.View): response.write(merged.getvalue()) return response - -class EventDuplicate(generic.RedirectView): - permanent = False; - def get_redirect_url(self, *args, **kwargs): - new = get_object_or_404(models.Event, pk=kwargs['pk']) - new.pk = None - new.based_on = models.Event.objects.get(pk=kwargs['pk']) - new.save() - - old = get_object_or_404(models.Event, pk=kwargs['pk']) - for item in old.items.all(): - item.pk = None - item.event = new - item.save() - - return reverse_lazy('event_update', kwargs={'pk': new.pk}) - - class EventArchive(generic.ArchiveIndexView): model = models.Event date_field = "start_date" diff --git a/RIGS/templates/RIGS/event_form.html b/RIGS/templates/RIGS/event_form.html index cf627aa7..7da39132 100644 --- a/RIGS/templates/RIGS/event_form.html +++ b/RIGS/templates/RIGS/event_form.html @@ -119,7 +119,9 @@

- {% if object.pk %} + {% if duplicate %} + Duplicate of Event N{{ object.pk|stringformat:"05d" }} + {% elif object.pk %} Event N{{ object.pk|stringformat:"05d" }} {% else %} New Event From e8265faf5d3eee79078ecd0f3a85b2301da516f0 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Sun, 16 Aug 2015 20:04:59 +0100 Subject: [PATCH 2/3] Added tests for EventDuplicate --- RIGS/test_functional.py | 77 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/RIGS/test_functional.py b/RIGS/test_functional.py index 514e030f..cd216096 100644 --- a/RIGS/test_functional.py +++ b/RIGS/test_functional.py @@ -416,6 +416,83 @@ class EventTest(LiveServerTestCase): event = models.Event.objects.get(name='Test Event Name') self.assertIn("N0000%d | Test Event Name"%event.pk, self.browser.find_element_by_xpath('//h1').text) + def testEventDuplicate(self): + testEvent = models.Event.objects.create(name="TE E1", status=models.Event.PROVISIONAL, start_date=date.today() + timedelta(days=6), description="start future no end") + + item1 = models.EventItem( + event=testEvent, + name="Test Item 1", + cost="10.00", + quantity="1", + order=1 + ).save() + item2 = models.EventItem( + event=testEvent, + name="Test Item 2", + description="Foo", + cost="9.72", + quantity="3", + order=2, + ).save() + + self.browser.get(self.live_server_url + '/event/' + str(testEvent.pk) + '/duplicate/') + self.authenticate('/event/' + str(testEvent.pk) + '/duplicate/') + + wait = WebDriverWait(self.browser, 10) #setup WebDriverWait to use later (to wait for animations) + self.browser.implicitly_wait(3) #Set session-long wait (only works for non-existant DOM objects) + + save = self.browser.find_element_by_xpath( + '(//button[@type="submit"])[3]') + form = self.browser.find_element_by_tag_name('form') + + + # Check the items are visible + table = self.browser.find_element_by_id('item-table') # ID number is known, see above + self.assertIn("Test Item 1", table.text) + self.assertIn("Test Item 2", table.text) + + # Add item + form.find_element_by_xpath('//button[contains(@class, "item-add")]').click() + wait.until(animation_is_finished()) + modal = self.browser.find_element_by_id("itemModal") + modal.find_element_by_id("item_name").send_keys("Test Item 3") + modal.find_element_by_id("item_description").send_keys("This is an item description\nthat for reasons unkown spans two lines") + e = modal.find_element_by_id("item_quantity") + e.click() + e.send_keys(Keys.UP) + e.send_keys(Keys.UP) + e = modal.find_element_by_id("item_cost") + e.send_keys("23.95") + e.send_keys(Keys.ENTER) # enter submit + + # Attempt to save + save.click() + + self.assertNotIn("N0000%d"%testEvent.pk, self.browser.find_element_by_xpath('//h1').text) + + # Check the new items are visible + table = self.browser.find_element_by_id('item-table') # ID number is known, see above + self.assertIn("Test Item 1", table.text) + self.assertIn("Test Item 2", table.text) + self.assertIn("Test Item 3", table.text) + + infoPanel = self.browser.find_element_by_xpath('//div[contains(text(), "Event Info")]/..') + self.assertIn("N0000%d"%testEvent.pk, infoPanel.find_element_by_xpath('//dt[text()="Based On"]/following-sibling::dd[1]').text) + + + + self.browser.get(self.live_server_url + '/event/' + str(testEvent.pk)) #Go back to the old event + + #Check that based-on hasn't crept into the old event + infoPanel = self.browser.find_element_by_xpath('//div[contains(text(), "Event Info")]/..') + self.assertNotIn("N0000%d"%testEvent.pk, infoPanel.find_element_by_xpath('//dt[text()="Based On"]/following-sibling::dd[1]').text) + + # Check the items are as they were + table = self.browser.find_element_by_id('item-table') # ID number is known, see above + self.assertIn("Test Item 1", table.text) + self.assertIn("Test Item 2", table.text) + self.assertNotIn("Test Item 3", table.text) + def testDateValidation(self): self.browser.get(self.live_server_url + '/event/create/') # Gets redirected to login and back From b316dde25d1258794ce80aafc9640ff849e6fa1a Mon Sep 17 00:00:00 2001 From: David Taylor Date: Fri, 28 Aug 2015 00:12:29 +0100 Subject: [PATCH 3/3] Added comments to EventItem creation --- RIGS/forms.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/RIGS/forms.py b/RIGS/forms.py index 7c18d0d2..922558c3 100644 --- a/RIGS/forms.py +++ b/RIGS/forms.py @@ -87,8 +87,13 @@ class EventForm(forms.ModelForm): try: item = models.EventItem.objects.get(pk=pk,event=event) except models.EventItem.DoesNotExist: + # This occurs for one of two reasons + # 1) The event has been duplicated, so the item PKs belong to another event + # 2) The items are brand new, with negative PK values + # In either case, we want to create the items item = models.EventItem() + # Take the data from the form and update the item object item.name = data['name'] item.description = data['description'] item.quantity = data['quantity']