Repository: ocadotechnology/codeforlife-portal

Issue:
Special characters error when there are no special characters
As pointed out in many e-mails by the users of the Code For Life portal - the contact form returns the following error in many cases:

`Your message may not contain special characters.`

This originates from the `portal/forms/home.py` file and the `clean_message` method.

```python
    def clean_message(self):
        message = self.cleaned_data.get("message", None)
        if re.match(re.compile('^[ -~]+$'), message) is None:
            raise forms.ValidationError("Your message may not contain special characters.")

        return message
```

The regex `^[ -~]+$` creates issues when you add a return character in the message; what you can check [here](https://regex101.com/).



Discussion:

Resolving patch:
diff --git a/portal/forms/home.py b/portal/forms/home.py
--- a/portal/forms/home.py
+++ b/portal/forms/home.py
@@ -35,6 +35,7 @@
 # program; modified versions of the program must be marked as such and not
 # identified as the original program.
 from django import forms
+from portal.helpers.regex import get_regex_name, get_regex_message, get_regex_telephone
 import re
 
 
@@ -58,21 +59,26 @@ def clean(self):
 
     def clean_name(self):
         name = self.cleaned_data.get("name", None)
-        if re.match(re.compile('^[\w ]+$'), name) is None:
+
+        if get_regex_name().match(name) is None:
             raise forms.ValidationError("Names may only contain letters, numbers, dashes, underscores, and spaces.")
 
         return name
 
     def clean_message(self):
         message = self.cleaned_data.get("message", None)
-        if re.match(re.compile('^[ -~]+$'), message) is None:
-            raise forms.ValidationError("Your message may not contain special characters.")
+        line_list = message.splitlines()
+
+        for line in line_list:
+            if get_regex_message().match(line) is None:
+                raise forms.ValidationError("Your message may not contain special characters.")
 
         return message
 
     def clean_telephone(self):
         telephone = self.cleaned_data.get("telephone", None)
-        if re.match(re.compile('^[0-9()\-+ ]+$'), telephone) is None:
+
+        if get_regex_telephone().match(telephone) is None:
             raise forms.ValidationError("Invalid phone number")
 
         return telephone
diff --git a/portal/helpers/regex.py b/portal/helpers/regex.py
new file mode 100644
--- /dev/null
+++ b/portal/helpers/regex.py
@@ -0,0 +1,54 @@
+# -*- coding: utf-8 -*-
+# Code for Life
+#
+# Copyright (C) 2017, Ocado Innovation Limited
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# ADDITIONAL TERMS – Section 7 GNU General Public Licence
+#
+# This licence does not grant any right, title or interest in any “Ocado” logos,
+# trade names or the trademark “Ocado” or any other trademarks or domain names
+# owned by Ocado Innovation Limited or the Ocado group of companies or any other
+# distinctive brand features of “Ocado” as may be secured from time to time. You
+# must not distribute any modification of this program using the trademark
+# “Ocado” or claim any affiliation or association with Ocado or its employees.
+#
+# You are not authorised to use the name Ocado (or any of its trade names) or
+# the names of any author or contributor in advertising or for publicity purposes
+# pertaining to the distribution of this program, without the prior written
+# authorisation of Ocado.
+#
+# Any propagation, distribution or conveyance of this program must include this
+# copyright notice and these terms. You must not misrepresent the origins of this
+# program; modified versions of the program must be marked as such and not
+# identified as the original program.
+
+import re
+
+name_regex = re.compile('^[\w ]+$')
+message_regex = re.compile('^[ -~]+$')
+telephone_regex = re.compile('^[0-9()\-+ ]+$')
+
+
+def get_regex_name():
+    return name_regex
+
+
+def get_regex_message():
+    return message_regex
+
+
+def get_regex_telephone():
+    return telephone_regex


Test patch: