Repository: carpentries/amy

Issue:
Add checkbox and link to privacy policy when people fill out `update_profile/`
We should have a checkbox that says "I have read and agree to the privacy policy" http://software-carpentry.org/privacy/ when people fill out their profile updates.



Discussion:
More specifically, wherever people can enter information about themselves (profile update, applying for training), there needs to be a checkbox saying:

```
[] I have read and agree to <a href="http://software-carpentry.org/privacy/">the Software Carpentry Foundation's data privacy policy</a>. 
```


Resolving patch:
diff --git a/workshops/forms.py b/workshops/forms.py
--- a/workshops/forms.py
+++ b/workshops/forms.py
@@ -136,6 +136,14 @@ class BootstrapHelperFormsetInline(BootstrapHelper):
 bootstrap_helper_inline_formsets = BootstrapHelperFormsetInline()
 
 
+class PrivacyConsentMixin(forms.Form):
+    privacy_consent = forms.BooleanField(
+        label='*I have read and agree to <a href='
+              '"https://software-carpentry.org/privacy/" target="_blank">'
+              'the Software Carpentry Foundation\'s data privacy policy</a>.',
+        required=True)
+
+
 class WorkshopStaffForm(forms.Form):
     '''Represent instructor matching form.'''
 
@@ -710,7 +718,7 @@ class Meta:
         widgets = {'event': HiddenInput, }
 
 
-class SWCEventRequestForm(forms.ModelForm):
+class SWCEventRequestForm(PrivacyConsentMixin, forms.ModelForm):
     captcha = ReCaptchaField()
     workshop_type = forms.CharField(initial='swc', widget=forms.HiddenInput())
     understand_admin_fee = forms.BooleanField(
@@ -779,7 +787,7 @@ class Meta:
         exclude = ('active', 'created_at', 'last_updated_at', 'assigned_to')
 
 
-class EventSubmitForm(EventSubmitFormNoCaptcha):
+class EventSubmitForm(EventSubmitFormNoCaptcha, PrivacyConsentMixin):
     captcha = ReCaptchaField()
 
     helper = BootstrapHelper(wider_labels=True)
@@ -810,7 +818,7 @@ class Meta:
 
 
 class DCSelfOrganizedEventRequestForm(
-        DCSelfOrganizedEventRequestFormNoCaptcha):
+        DCSelfOrganizedEventRequestFormNoCaptcha, PrivacyConsentMixin):
     captcha = ReCaptchaField()
 
     helper = BootstrapHelper(wider_labels=True)
@@ -843,7 +851,8 @@ def clean_twitter(self):
         return re.sub('^@+', '', twitter_handle)
 
 
-class ProfileUpdateRequestForm(ProfileUpdateRequestFormNoCaptcha):
+class ProfileUpdateRequestForm(ProfileUpdateRequestFormNoCaptcha,
+                               PrivacyConsentMixin):
     captcha = ReCaptchaField()
 
     helper = BootstrapHelper(wider_labels=True)
@@ -1045,7 +1054,7 @@ class Meta:
         )
 
 
-class TrainingRequestForm(forms.ModelForm):
+class TrainingRequestForm(PrivacyConsentMixin, forms.ModelForm):
     agreed_to_code_of_conduct = forms.BooleanField(
         required=True,
         initial=False,
@@ -1149,7 +1158,7 @@ class Meta:
         }
 
 
-class AutoUpdateProfileForm(forms.ModelForm):
+class AutoUpdateProfileForm(PrivacyConsentMixin, forms.ModelForm):
     username = forms.CharField(disabled=True, required=False)
     github = forms.CharField(
         disabled=True, required=False,


Test patch:
diff --git a/workshops/test/test_autoupdate_profile.py b/workshops/test/test_autoupdate_profile.py
--- a/workshops/test/test_autoupdate_profile.py
+++ b/workshops/test/test_autoupdate_profile.py
@@ -47,6 +47,7 @@ def test_update_profile(self):
             'languages_1': [self.latin.pk, self.french.pk],
             'domains': [self.chemistry.pk],
             'lessons': [self.git.pk, self.matlab.pk],
+            'privacy_consent': True,
         }
 
         rv = self.client.post(reverse('autoupdate_profile'), data, follow=True)
diff --git a/workshops/test/test_dc_selforganized_event_requests.py b/workshops/test/test_dc_selforganized_event_requests.py
--- a/workshops/test/test_dc_selforganized_event_requests.py
+++ b/workshops/test/test_dc_selforganized_event_requests.py
@@ -41,7 +41,8 @@ def test_exact_fields(self):
             'dates', 'domains', 'domains_other', 'topics', 'topics_other',
             'attendee_academic_levels', 'attendee_data_analysis_level',
             'payment', 'fee_waiver_reason', 'handle_registration',
-            'distribute_surveys', 'follow_code_of_conduct', 'captcha',
+            'distribute_surveys', 'follow_code_of_conduct', 'privacy_consent',
+            'captcha',
         ]
         self.assertEqual(fields_left, fields_right)
 
@@ -69,6 +70,7 @@ def test_submission_added(self):
             'attendee_academic_levels': [AcademicLevel.objects.first().pk],
             'attendee_data_analysis_level':
                 [DataAnalysisLevel.objects.first().pk],
+            'privacy_consent': True,
         }
         rv = self.client.post(reverse('dc_workshop_selforganized_request'),
                               data, follow=True)
@@ -99,6 +101,7 @@ def test_submission_sends_email(self):
             'attendee_academic_levels': [AcademicLevel.objects.first().pk],
             'attendee_data_analysis_level':
                 [DataAnalysisLevel.objects.first().pk],
+            'privacy_consent': True,
         }
         rv = self.client.post(reverse('dc_workshop_selforganized_request'),
                               data, follow=True)
diff --git a/workshops/test/test_event_requests.py b/workshops/test/test_event_requests.py
--- a/workshops/test/test_event_requests.py
+++ b/workshops/test/test_event_requests.py
@@ -21,7 +21,7 @@ def test_fields_presence(self):
             'attendee_academic_levels', 'attendee_computing_levels',
             'cover_travel_accomodation', 'understand_admin_fee',
             'travel_reimbursement', 'travel_reimbursement_other',
-            'admin_fee_payment', 'comment', 'captcha',
+            'admin_fee_payment', 'comment', 'captcha', 'privacy_consent',
         ])
         assert fields_left == fields_right
 
@@ -42,6 +42,7 @@ def test_request_added(self):
             'understand_admin_fee': True,
             'travel_reimbursement': 'book', 'travel_reimbursement_other': '',
             'admin_fee_payment': 'self-organized', 'comment': '',
+            'privacy_consent': True,
         }
         rv = self.client.post(reverse('swc_workshop_request'), data,
                               follow=True)
@@ -88,7 +89,7 @@ def test_fields_presence(self):
             'attendee_data_analysis_level', 'cover_travel_accomodation',
             'understand_admin_fee', 'fee_waiver_request',
             'travel_reimbursement', 'travel_reimbursement_other',
-            'comment', 'captcha',
+            'comment', 'privacy_consent', 'captcha',
         ])
         assert fields_left == fields_right
 
@@ -110,6 +111,7 @@ def test_request_added(self):
             'understand_admin_fee': True, 'fee_waiver_request': True,
             'travel_reimbursement': 'book', 'travel_reimbursement_other': '',
             'comment': '',
+            'privacy_consent': True,
         }
         rv = self.client.post(reverse('dc_workshop_request'), data,
                               follow=True)
diff --git a/workshops/test/test_event_submissions.py b/workshops/test/test_event_submissions.py
--- a/workshops/test/test_event_submissions.py
+++ b/workshops/test/test_event_submissions.py
@@ -20,7 +20,7 @@ def test_exact_fields(self):
         fields_left = list(form.fields.keys())
         fields_right = [
             'url', 'contact_name', 'contact_email',
-            'self_organized', 'notes', 'captcha',
+            'self_organized', 'notes', 'privacy_consent', 'captcha',
         ]
         self.assertEqual(fields_left, fields_right)
 
@@ -34,6 +34,7 @@ def test_submission_added(self):
             'self_organized': True,
             'url': 'http://example.org/2016-02-13-Howart',
             'notes': '',
+            'privacy_consent': True,
         }
         rv = self.client.post(reverse('event_submit'), data,
                               follow=True)
@@ -50,6 +51,7 @@ def test_submission_sends_email(self):
             'self_organized': True,
             'url': 'http://example.org/2016-02-13-Hogwart',
             'notes': '',
+            'privacy_consent': True,
         }
         rv = self.client.post(reverse('event_submit'), data,
                               follow=True)
diff --git a/workshops/test/test_profile_update_request.py b/workshops/test/test_profile_update_request.py
--- a/workshops/test/test_profile_update_request.py
+++ b/workshops/test/test_profile_update_request.py
@@ -26,6 +26,7 @@ def test_request_added(self):
             'orcid': '', 'website': '', 'gender': 'M',
             'domains': [1, 2],  # IDs
             'lessons': [1, 2],  # IDs
+            'privacy_consent': True,
         }
         rv = self.client.post(reverse('profileupdate_request'), data)
         assert rv.status_code == 200
diff --git a/workshops/test/test_training_request.py b/workshops/test/test_training_request.py
--- a/workshops/test/test_training_request.py
+++ b/workshops/test/test_training_request.py
@@ -54,6 +54,7 @@ def test_request_added(self):
             'agreed_to_code_of_conduct': 'on',
             'agreed_to_complete_training': 'on',
             'agreed_to_teach_workshops': 'on',
+            'privacy_consent': True,
             'recaptcha_response_field': 'PASSED',
         }
         rv = self.client.post(reverse('training_request'), data,