From 8bd0a9e6c2d9834e13087a807a84534cd835ac1d Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Feb 09 2016 08:12:35 +0000 Subject: [PATCH 1/6] Add method in the internal API to re-send a confirmation email if asked --- diff --git a/pagure/lib/__init__.py b/pagure/lib/__init__.py index 0eae87d..552b6a6 100644 --- a/pagure/lib/__init__.py +++ b/pagure/lib/__init__.py @@ -2188,6 +2188,29 @@ def add_user_pending_email(session, userobj, email): pagure.lib.notify.notify_new_email(tmpemail, user=userobj) +def resend_pending_email(session, userobj, email): + ''' Resend to the user the confirmation email for the provided email + address. + ''' + other_user = search_user(session, email=email) + if other_user and other_user != userobj: + raise pagure.exceptions.PagureException( + 'Someone else has already registered this email' + ) + + pending_email = search_pending_email(session, email=email) + if not pending_email: + raise pagure.exceptions.PagureException( + 'This email has already been confirmed' + ) + + pending_email.token=pagure.lib.login.id_generator(40) + session.add(pending_email) + session.flush() + + pagure.lib.notify.notify_new_email(pending_email, user=userobj) + + def search_pending_email(session, email=None, token=None): ''' Searches the database for the pending email matching the given criterias. From afab724c88f3f62502b64d81e81a78432133b33b Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Feb 09 2016 08:12:35 +0000 Subject: [PATCH 2/6] Add a new endpoint to re-send a confirmation email for an email address --- diff --git a/pagure/ui/app.py b/pagure/ui/app.py index 3c229de..22a6a43 100644 --- a/pagure/ui/app.py +++ b/pagure/ui/app.py @@ -589,6 +589,39 @@ def set_default_email(): return flask.redirect(flask.url_for('.user_settings')) +@APP.route('/settings/email/resend', methods=['POST']) +@login_required +def reconfirm_email(): + """ Re-send the email address of the user. + """ + if admin_session_timedout(): + return flask.redirect( + flask.url_for('auth_login', next=flask.request.url)) + + user = pagure.lib.search_user( + SESSION, username=flask.g.fas_user.username) + if not user: + flask.abort(404, 'User not found') + + form = pagure.forms.UserEmailForm() + if form.validate_on_submit(): + email = form.email.data + + try: + pagure.lib.resend_pending_email(SESSION, user, email) + SESSION.commit() + flask.flash('Confirmation email re-sent') + except pagure.exceptions.PagureException as err: + flask.flash(str(err), 'error') + except SQLAlchemyError as err: # pragma: no cover + SESSION.rollback() + APP.logger.exception(err) + flask.flash('Confirmation email could not be re-sent', 'error') + + return flask.redirect(flask.url_for('.user_settings')) + + + @APP.route('/settings/email/confirm//') @APP.route('/settings/email/confirm/') def confirm_email(token): From 012c112f964afded0e1d66f66c7bafa6628c1f03 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Feb 09 2016 08:12:35 +0000 Subject: [PATCH 3/6] Add a button in the user's setting to ask for a confirmation email to be re-sent --- diff --git a/pagure/templates/user_settings.html b/pagure/templates/user_settings.html index 0ff9e40..58996a1 100644 --- a/pagure/templates/user_settings.html +++ b/pagure/templates/user_settings.html @@ -4,12 +4,12 @@ {% block title %}{{ user.user }}'s settings{% endblock %} {% set tag = "users"%} -{% macro render_email(email, form=None) %} -
+{% macro render_email(email, form, validated=True) %} +
 {{ email.email }} - {% if form %} + {% if validated %}
+ action="{{ url_for('remove_user_email') }}"> {{ form.csrf_token }}
+ +
{% endif %}
{% endmacro %} @@ -68,7 +84,7 @@ {{ render_email(email, form) }} {% endfor %} {% for email in user.emails_pending %} - {{ render_email(email) }} + {{ render_email(email, form, validated=False) }} {% endfor %} From 4966058538f9e25e96989cea298a97910d84aff5 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Feb 09 2016 08:12:35 +0000 Subject: [PATCH 4/6] Add and adjust unit-tests for the possibility to re-send a confirmation email --- diff --git a/tests/test_pagure_flask_ui_app.py b/tests/test_pagure_flask_ui_app.py index c15c844..7eee5a5 100644 --- a/tests/test_pagure_flask_ui_app.py +++ b/tests/test_pagure_flask_ui_app.py @@ -467,8 +467,8 @@ class PagureFlaskApptests(tests.Modeltests): '\n Email pending validation', output.data) self.assertEqual(output.data.count('foo@pingou.com'), 4) - self.assertEqual(output.data.count('bar@pingou.com'), 4) - self.assertEqual(output.data.count('foobar@pingou.com'), 1) + self.assertEqual(output.data.count('bar@pingou.com'), 5) + self.assertEqual(output.data.count('foobar@pingou.com'), 2) # User already has this email data = { @@ -584,6 +584,97 @@ class PagureFlaskApptests(tests.Modeltests): output = self.app.post('/settings/email/default', data=data) self.assertEqual(output.status_code, 302) + @patch('pagure.lib.notify.send_email') + @patch('pagure.ui.app.admin_session_timedout') + def test_reconfirm_email(self, ast, send_email): + """ Test the reconfirm_email endpoint. """ + send_email.return_value = True + ast.return_value = False + self.test_new_project() + + # Add a pending email to pingou + userobj = pagure.lib.search_user(self.session, username='pingou') + + self.assertEqual(len(userobj.emails), 2) + + email_pend = pagure.lib.model.UserEmailPending( + user_id=userobj.id, + email='foo@fp.o', + token='abcdef', + ) + self.session.add(email_pend) + self.session.commit() + + user = tests.FakeUser() + with tests.user_set(pagure.APP, user): + output = self.app.post('/settings/email/resend') + self.assertEqual(output.status_code, 404) + self.assertTrue('

Page not found (404)

' in output.data) + + user.username = 'pingou' + with tests.user_set(pagure.APP, user): + output = self.app.get('/settings/') + self.assertEqual(output.status_code, 200) + self.assertIn( + '
\n Basic Information\n' + '
', output.data) + self.assertIn( + '', output.data) + + csrf_token = output.data.split( + 'name="csrf_token" type="hidden" value="')[1].split('">')[0] + + data = { + 'email': 'foo@pingou.com', + } + + output = self.app.post( + '/settings/email/resend', data=data, follow_redirects=True) + self.assertEqual(output.status_code, 200) + self.assertIn( + '
\n Basic Information\n' + '
', output.data) + self.assertEqual(output.data.count('foo@pingou.com'), 4) + + # Set invalid default email + data = { + 'csrf_token': csrf_token, + 'email': 'foobar@pingou.com', + } + + output = self.app.post( + '/settings/email/resend', data=data, follow_redirects=True) + self.assertEqual(output.status_code, 200) + self.assertIn( + '
\n Basic Information\n' + '
', output.data) + self.assertEqual(output.data.count('foo@pingou.com'), 4) + self.assertIn( + '\n This email has already ' + 'been confirmed', output.data) + + # Validate a non-validated email + data = { + 'csrf_token': csrf_token, + 'email': 'foo@fp.o', + } + + output = self.app.post( + '/settings/email/resend', data=data, follow_redirects=True) + self.assertEqual(output.status_code, 200) + self.assertIn( + '
\n Basic Information\n' + '
', output.data) + self.assertEqual(output.data.count('foo@pingou.com'), 4) + self.assertIn( + '\n Confirmation email re-sent', + output.data) + + ast.return_value = True + output = self.app.post('/settings/email/resend', data=data) + self.assertEqual(output.status_code, 302) + @patch('pagure.ui.app.admin_session_timedout') def test_confirm_email(self, ast): """ Test the confirm_email endpoint. """ From 3232503dc73e75a5ed3c3b62c9df0e0d2c9e5da0 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Feb 09 2016 08:12:35 +0000 Subject: [PATCH 5/6] Use email address instead of just email in the messages returned to the users --- diff --git a/pagure/lib/__init__.py b/pagure/lib/__init__.py index 552b6a6..d6139cd 100644 --- a/pagure/lib/__init__.py +++ b/pagure/lib/__init__.py @@ -2195,13 +2195,13 @@ def resend_pending_email(session, userobj, email): other_user = search_user(session, email=email) if other_user and other_user != userobj: raise pagure.exceptions.PagureException( - 'Someone else has already registered this email' + 'Someone else has already registered this email address' ) pending_email = search_pending_email(session, email=email) if not pending_email: raise pagure.exceptions.PagureException( - 'This email has already been confirmed' + 'This email address has already been confirmed' ) pending_email.token=pagure.lib.login.id_generator(40) From 37f6c297e400325983a4ccc9228297f7a1815696 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Feb 09 2016 08:12:35 +0000 Subject: [PATCH 6/6] Fix unit-tests for the change in the information message returned --- diff --git a/tests/test_pagure_flask_ui_app.py b/tests/test_pagure_flask_ui_app.py index 7eee5a5..3cd7f14 100644 --- a/tests/test_pagure_flask_ui_app.py +++ b/tests/test_pagure_flask_ui_app.py @@ -651,8 +651,8 @@ class PagureFlaskApptests(tests.Modeltests): ' ', output.data) self.assertEqual(output.data.count('foo@pingou.com'), 4) self.assertIn( - '\n This email has already ' - 'been confirmed', output.data) + '\n This email address has ' + 'already been confirmed', output.data) # Validate a non-validated email data = {