Repository: collective/collective.polls (language: python)

Issue:
Prevent multiple form submission
I discovered that a user can vote multiple times when the response has not being received; this leads to unexpected behavior and 500 HTTP status codes.:

![selection_023](https://user-images.githubusercontent.com/341393/43105676-1b810b74-8eac-11e8-92b4-4e497e5b0dbb.png)

```
127.0.0.1 - Anonymous [23/Jul/2018:19:02:07 -0200] "POST /Plone/foo/bar HTTP/1.1" 200 39544 "https://www.conversaafiada.com.br/economia/o-cunha-vai-pegar-o-temer" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
127.0.0.1 - Anonymous [23/Jul/2018:19:02:09 -0200] "POST /Plone/foo/bar HTTP/1.1" 200 39545 "https://www.conversaafiada.com.br/economia/o-cunha-vai-pegar-o-temer" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
127.0.0.1 - Anonymous [23/Jul/2018:19:02:12 -0200] "POST /Plone/foo/bar HTTP/1.1" 200 39545 "https://www.conversaafiada.com.br/economia/o-cunha-vai-pegar-o-temer" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
127.0.0.1 - Anonymous [23/Jul/2018:19:02:16 -0200] "POST /Plone/foo/bar HTTP/1.1" 200 39545 "https://www.conversaafiada.com.br/economia/o-cunha-vai-pegar-o-temer" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
127.0.0.1 - Anonymous [23/Jul/2018:19:02:20 -0200] "POST /Plone/foo/bar HTTP/1.1" 200 39545 "https://www.conversaafiada.com.br/economia/o-cunha-vai-pegar-o-temer" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
127.0.0.1 - Anonymous [23/Jul/2018:19:02:23 -0200] "POST /Plone/foo/bar HTTP/1.1" 200 39545 "https://www.conversaafiada.com.br/economia/o-cunha-vai-pegar-o-temer" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
127.0.0.1 - Anonymous [23/Jul/2018:19:02:24 -0200] "POST /Plone/foo/bar HTTP/1.1" 500 2631 "https://www.conversaafiada.com.br/economia/o-cunha-vai-pegar-o-temer" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
```


Discussion / hints:

Fix patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index a7e4d1a..4c9973f 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -3,10 +3,11 @@ Changelog
 
 There's a frood who really knows where his towel is.
 
-2.0b2 (unreleased)
-^^^^^^^^^^^^^^^^^^
+2.0.1b2 (unreleased)
+^^^^^^^^^^^^^^^^^^^^
 
-- Nothing changed yet.
+- Disable poll form after submit (fixes `#132 <https://github.com/collective/collective.polls/issues/132>`_).
+  [rodfersou]
 
 
 2.0b1 (2018-07-23)
diff --git a/src/collective/polls/profiles/default/metadata.xml b/src/collective/polls/profiles/default/metadata.xml
index 554ef64..fc9b811 100644
--- a/src/collective/polls/profiles/default/metadata.xml
+++ b/src/collective/polls/profiles/default/metadata.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <metadata>
-  <version>6</version>
+  <version>7</version>
     <dependencies>
       <dependency>profile-plone.app.dexterity:default</dependency>
     </dependencies>
diff --git a/src/collective/polls/static/js/collective.poll.js b/src/collective/polls/static/js/collective.poll.js
index e408b6d..c304a0a 100644
--- a/src/collective/polls/static/js/collective.poll.js
+++ b/src/collective/polls/static/js/collective.poll.js
@@ -51,6 +51,8 @@
       // stop form submit and submit with ajax
       e.preventDefault();
       var $form = $(this);
+      // avoid multiple submits
+      $('input[type=submit]', $form).attr('disabled', 'disabled');
       $.ajax({
         type: 'POST',
         url: $form.attr('action'),
diff --git a/src/collective/polls/upgrades/configure.zcml b/src/collective/polls/upgrades/configure.zcml
index 6250e6e..a6e2def 100644
--- a/src/collective/polls/upgrades/configure.zcml
+++ b/src/collective/polls/upgrades/configure.zcml
@@ -2,5 +2,6 @@
 
   <include package=".v5" />
   <include package=".v6" />
+  <include package=".v7" />
 
 </configure>
diff --git a/src/collective/polls/upgrades/v7/__init__.py b/src/collective/polls/upgrades/v7/__init__.py
new file mode 100644
index 0000000..40a96af
--- /dev/null
+++ b/src/collective/polls/upgrades/v7/__init__.py
@@ -0,0 +1,1 @@
+# -*- coding: utf-8 -*-
diff --git a/src/collective/polls/upgrades/v7/configure.zcml b/src/collective/polls/upgrades/v7/configure.zcml
new file mode 100644
index 0000000..3876a4b
--- /dev/null
+++ b/src/collective/polls/upgrades/v7/configure.zcml
@@ -0,0 +1,17 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:genericsetup="http://namespaces.zope.org/genericsetup">
+
+  <genericsetup:upgradeSteps
+      source="6"
+      destination="7"
+      profile="collective.polls:default">
+
+    <genericsetup:upgradeStep
+        title="Cook JS resources"
+        handler="..cook_javascript_resources"
+        />
+
+  </genericsetup:upgradeSteps>
+
+</configure>


Test patch:
diff --git a/src/collective/polls/tests/test_setup.py b/src/collective/polls/tests/test_setup.py
index d885b46..93ffc62 100644
--- a/src/collective/polls/tests/test_setup.py
+++ b/src/collective/polls/tests/test_setup.py
@@ -44,7 +44,7 @@ def test_installed_BBB(self):
     def test_profile_version(self):
         setup_tool = self.portal['portal_setup']
         self.assertEqual(
-            setup_tool.getLastVersionForProfile(PROFILE), (u'6',))
+            setup_tool.getLastVersionForProfile(PROFILE), (u'7',))
 
     def test_add_permission(self):
         permission = 'collective.polls: Add poll'
diff --git a/src/collective/polls/tests/test_upgrades.py b/src/collective/polls/tests/test_upgrades.py
index b15f662..7dfd1ee 100644
--- a/src/collective/polls/tests/test_upgrades.py
+++ b/src/collective/polls/tests/test_upgrades.py
@@ -84,3 +84,14 @@ def test_remove_excanvas_script(self):
         # run the upgrade step to validate the update
         self._do_upgrade_step(step)
         self.assertNotIn(script, js_tool.getResourceIds())
+
+
+class Upgrade6to7TestCase(UpgradeTestCaseBase):
+
+    def setUp(self):
+        UpgradeTestCaseBase.setUp(self, u'6', u'7')
+
+    def test_upgrade_to_6_registrations(self):
+        version = self.setup.getLastVersionForProfile(PROFILE)[0]
+        self.assertGreaterEqual(int(version), int(self.to_version))
+        self.assertEqual(self._how_many_upgrades_to_do(), 1)