From 1091c0db2dd939d852280507df49f7491b2a5711 Mon Sep 17 00:00:00 2001 From: Nicolas Dietrich Date: Tue, 4 Mar 2014 19:41:14 +0100 Subject: [PATCH 1/8] Show 403 instead of login if login wouldn't help --- src/adhocracy/lib/auth/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/adhocracy/lib/auth/__init__.py b/src/adhocracy/lib/auth/__init__.py index e67add1d7..ad219d810 100644 --- a/src/adhocracy/lib/auth/__init__.py +++ b/src/adhocracy/lib/auth/__init__.py @@ -139,7 +139,7 @@ def check(self, *a, **kw): return self.closure() else: return auth_check - elif auth_check.need_login(): + elif auth_check.propose_login(): # Authentication might help from adhocracy.lib.helpers import login_redirect_url from pylons.controllers.util import redirect From 442222e4e25f04b36f9c421ca529c5d587ebe347 Mon Sep 17 00:00:00 2001 From: Nicolas Dietrich Date: Tue, 4 Mar 2014 19:43:02 +0100 Subject: [PATCH 2/8] Show ask_join page instead of 403 if join would help --- src/adhocracy/config/routing.py | 1 + src/adhocracy/controllers/instance.py | 6 ++++++ src/adhocracy/lib/auth/__init__.py | 4 ++++ src/adhocracy/lib/helpers/__init__.py | 4 ++++ .../templates/instance/ask_join.html | 21 +++++++++++++++++++ 5 files changed, 36 insertions(+) create mode 100644 src/adhocracy/templates/instance/ask_join.html diff --git a/src/adhocracy/config/routing.py b/src/adhocracy/config/routing.py index af1ac4e68..d9b165c1c 100644 --- a/src/adhocracy/config/routing.py +++ b/src/adhocracy/config/routing.py @@ -462,6 +462,7 @@ def make_map(config): conditions=dict(method=['POST'])) map.resource('instance', 'instance', member={'join': 'GET', + 'ask_join': 'GET', 'leave': 'POST', 'filter': 'GET', 'ask_leave': 'GET', diff --git a/src/adhocracy/controllers/instance.py b/src/adhocracy/controllers/instance.py index ec4ab8ffe..791b29a61 100644 --- a/src/adhocracy/controllers/instance.py +++ b/src/adhocracy/controllers/instance.py @@ -962,6 +962,12 @@ def delete(self, id, format='html'): c.page_instance.label, force_path='/') + @RequireInstance + def ask_join(self, id, format='html'): + c.page_instance = self._get_current_instance(id) + require.instance.join(c.page_instance) + return render('/instance/ask_join.html') + @RequireInstance @csrf.RequireInternalRequest() def join(self, id, format='html'): diff --git a/src/adhocracy/lib/auth/__init__.py b/src/adhocracy/lib/auth/__init__.py index ad219d810..2310c43bc 100644 --- a/src/adhocracy/lib/auth/__init__.py +++ b/src/adhocracy/lib/auth/__init__.py @@ -144,6 +144,10 @@ def check(self, *a, **kw): from adhocracy.lib.helpers import login_redirect_url from pylons.controllers.util import redirect redirect(login_redirect_url()) + elif auth_check.propose_join(): + from adhocracy.lib.helpers import join_redirect_url + from pylons.controllers.util import redirect + redirect(join_redirect_url()) else: from adhocracy.lib.templating import ret_abort log.debug("Aborting due to authorisation error: %s" % diff --git a/src/adhocracy/lib/helpers/__init__.py b/src/adhocracy/lib/helpers/__init__.py index 157a082ee..05c1e1533 100644 --- a/src/adhocracy/lib/helpers/__init__.py +++ b/src/adhocracy/lib/helpers/__init__.py @@ -208,6 +208,10 @@ def register_redirect_url(entity=None, **kwargs): return get_redirect_url(u'register', entity, **kwargs) +def join_redirect_url(entity=None, **kwargs): + return get_redirect_url(u'instance/%s/ask_join' % c.instance.key, **kwargs) + + def entity_url(entity, **kwargs): if isinstance(entity, model.User): return user.url(entity, **kwargs) diff --git a/src/adhocracy/templates/instance/ask_join.html b/src/adhocracy/templates/instance/ask_join.html new file mode 100644 index 000000000..7ab108703 --- /dev/null +++ b/src/adhocracy/templates/instance/ask_join.html @@ -0,0 +1,21 @@ +<%inherit file="/template.html" /> +<%namespace name="components" file="/components.html"/> +<%def name="title()">${_(u'Join %s' % c.instance.label)} + +<%def name="breadcrumbs()"> + ${h.instance.breadcrumbs(c.page_instance)|n} ${_(u'Join')} + + +<%block name="headline"> +

${_(u'Join instance')}

+ + +<%block name="main_content"> +
+ ${h.field_token()|n} + + ${_(u'In order to perform the requested action, you need to join this instance.')} + ${components.savebox(cancel_url=None, save_text=u'Join')} +
+ From 38882349e1fc8f68ad8b309a23fd55168f2b4919 Mon Sep 17 00:00:00 2001 From: Nicolas Dietrich Date: Tue, 4 Mar 2014 19:47:05 +0100 Subject: [PATCH 3/8] abstract activation_url helper function --- src/adhocracy/lib/helpers/user_helper.py | 6 ++++++ src/adhocracy/templates/root.html | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/adhocracy/lib/helpers/user_helper.py b/src/adhocracy/lib/helpers/user_helper.py index 3c2cb58fa..3325fa43f 100644 --- a/src/adhocracy/lib/helpers/user_helper.py +++ b/src/adhocracy/lib/helpers/user_helper.py @@ -126,3 +126,9 @@ def can_change_password(user): return asbool(config.get('adhocracy.allow_password_change', 'false')) else: return True + + +def activation_url(): + from adhocracy.lib.auth.csrf import url_token + from adhocracy.lib.helpers import base_url + return base_url('/user/%s/resend?%s' % (c.user.user_name, url_token())) diff --git a/src/adhocracy/templates/root.html b/src/adhocracy/templates/root.html index 1ae2f1e16..492a49a42 100644 --- a/src/adhocracy/templates/root.html +++ b/src/adhocracy/templates/root.html @@ -112,7 +112,7 @@

${_('Validate email to start contributing.')}

- ${_('Send activation link')} + ${_('Send activation link')} ${_("or")} ${_("Edit profile")} From 62e8ae365f79ec837ad6ecdda30050758055b0b6 Mon Sep 17 00:00:00 2001 From: Nicolas Dietrich Date: Tue, 4 Mar 2014 19:49:42 +0100 Subject: [PATCH 4/8] Show ask_validate page instead of 403 if email validation would help --- src/adhocracy/config/routing.py | 2 + src/adhocracy/controllers/user.py | 39 ++++++++++++++++--- src/adhocracy/lib/auth/__init__.py | 4 ++ src/adhocracy/lib/helpers/__init__.py | 5 +++ .../templates/user/ask_activate.html | 21 ++++++++++ .../templates/user/pending_activate.html | 16 ++++++++ 6 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 src/adhocracy/templates/user/ask_activate.html create mode 100644 src/adhocracy/templates/user/pending_activate.html diff --git a/src/adhocracy/config/routing.py b/src/adhocracy/config/routing.py index d9b165c1c..63a4ecca8 100644 --- a/src/adhocracy/config/routing.py +++ b/src/adhocracy/config/routing.py @@ -73,6 +73,8 @@ def make_map(config): 'revert': 'GET', 'reset': 'GET', 'activate': 'GET', + 'ask_activate': 'GET', + 'pending_activate': 'GET', 'resend': 'GET', 'set_password': 'POST', 'generate_welcome_link': 'POST'}, diff --git a/src/adhocracy/controllers/user.py b/src/adhocracy/controllers/user.py index da6f4eb51..972ea3b1e 100644 --- a/src/adhocracy/controllers/user.py +++ b/src/adhocracy/controllers/user.py @@ -726,13 +726,25 @@ def activate(self, id): instance_filter=False) code = self.form_result.get('c') + # If activate_came_from is set, we assume that we've tried to do + # validate email address during doing some other action. + activate_came_from = session.get('activate_came_from') + if activate_came_from: + c.came_from = activate_came_from + del session['activate_came_from'] + success_url = activate_came_from + no_success_url = h.validate_redirect_url() + else: + success_url = h.entity_url(c.page_user) + no_success_url = h.entity_url(c.page_user) + if c.page_user.activation_code != code: h.flash(_("The activation code is invalid. Please have it " "resent."), 'error') - redirect(h.entity_url(c.page_user)) + redirect(no_success_url) if c.page_user.activation_code is None: h.flash(_(u'Thank you, The address is already activated.')) - redirect(h.entity_url(c.page_user)) + redirect(success_url) c.page_user.activation_code = None model.meta.Session.commit() @@ -751,9 +763,19 @@ def activate(self, id): redirect(h.user.post_register_url(c.page_user)) else: h.flash(_("Your email has been confirmed."), 'success') - redirect(h.entity_url(c.page_user)) + redirect(success_url) - redirect(h.entity_url(c.page_user)) + redirect(success_url) + + def ask_activate(self, id): + c.page_user = get_entity_or_abort(model.User, id, + instance_filter=False) + return render('/user/ask_activate.html') + + def pending_activate(self, id): + c.page_user = get_entity_or_abort(model.User, id, + instance_filter=False) + return render('/user/pending_activate.html') @RequireInternalRequest() def resend(self, id): @@ -762,11 +784,18 @@ def resend(self, id): require.user.edit(c.page_user) libmail.send_activation_link(c.page_user) + if c.came_from: + session['activate_came_from'] = c.came_from + force_path = h.entity_url(c.page_user, member='pending_activate', + query={'came_from': c.came_from}) + else: + force_path = None + ret_success( message=_("The activation link has been re-sent to your email " "address."), category='success', entity=c.page_user, member='settings/notifications', - format=None, force_path=c.came_from) + format=None, force_path=force_path) @staticmethod def _get_profile_nav(user, active_key): diff --git a/src/adhocracy/lib/auth/__init__.py b/src/adhocracy/lib/auth/__init__.py index 2310c43bc..a206c2b83 100644 --- a/src/adhocracy/lib/auth/__init__.py +++ b/src/adhocracy/lib/auth/__init__.py @@ -148,6 +148,10 @@ def check(self, *a, **kw): from adhocracy.lib.helpers import join_redirect_url from pylons.controllers.util import redirect redirect(join_redirect_url()) + elif auth_check.propose_validate_email(): + from adhocracy.lib.helpers import validate_redirect_url + from pylons.controllers.util import redirect + redirect(validate_redirect_url()) else: from adhocracy.lib.templating import ret_abort log.debug("Aborting due to authorisation error: %s" % diff --git a/src/adhocracy/lib/helpers/__init__.py b/src/adhocracy/lib/helpers/__init__.py index 05c1e1533..a07c48a45 100644 --- a/src/adhocracy/lib/helpers/__init__.py +++ b/src/adhocracy/lib/helpers/__init__.py @@ -212,6 +212,11 @@ def join_redirect_url(entity=None, **kwargs): return get_redirect_url(u'instance/%s/ask_join' % c.instance.key, **kwargs) +def validate_redirect_url(entity=None, **kwargs): + return get_redirect_url(u'user/%s/ask_activate' % c.user.user_name, entity, + **kwargs) + + def entity_url(entity, **kwargs): if isinstance(entity, model.User): return user.url(entity, **kwargs) diff --git a/src/adhocracy/templates/user/ask_activate.html b/src/adhocracy/templates/user/ask_activate.html new file mode 100644 index 000000000..d9014c556 --- /dev/null +++ b/src/adhocracy/templates/user/ask_activate.html @@ -0,0 +1,21 @@ +<%inherit file="/template.html" /> +<%namespace name="components" file="/components.html"/> +<%def name="title()">${_(u'Validate email address')} + +<%def name="breadcrumbs()"> + ${h.instance.breadcrumbs(c.page_user)|n} ${_(u'Validate email address')} + + +<%block name="headline"> +

${_(u'Validate email address')}

+ + +<%block name="main_content"> +
+ ${h.field_token()|n} + + ${_(u'In order to perform the requested action, you need to validate your email address.')} + ${components.savebox(cancel_url=None, save_text=u'Send activation link')} +
+ diff --git a/src/adhocracy/templates/user/pending_activate.html b/src/adhocracy/templates/user/pending_activate.html new file mode 100644 index 000000000..b6c9d4012 --- /dev/null +++ b/src/adhocracy/templates/user/pending_activate.html @@ -0,0 +1,16 @@ +<%inherit file="/template.html" /> +<%namespace name="components" file="/components.html"/> +<%def name="title()">${_(u'Validate email address')} + +<%def name="breadcrumbs()"> + ${h.instance.breadcrumbs(c.page_user)|n} ${_(u'Validate email address')} + + +<%block name="headline"> +

${_(u'Validation email sent')}

+ + +<%block name="main_content"> + ${_(u'An email has been sent to you. Please click on the validation link in this email in order to proceed.')} + + From 5423192a73ee0c7c2c151a59fa81c919b897aaa3 Mon Sep 17 00:00:00 2001 From: Nicolas Dietrich Date: Tue, 4 Mar 2014 22:48:52 +0100 Subject: [PATCH 5/8] Address registration case in ask_validate --- src/adhocracy/templates/user/ask_activate.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/adhocracy/templates/user/ask_activate.html b/src/adhocracy/templates/user/ask_activate.html index d9014c556..50e29ade5 100644 --- a/src/adhocracy/templates/user/ask_activate.html +++ b/src/adhocracy/templates/user/ask_activate.html @@ -15,7 +15,11 @@

${_(u'Validate email address')}

action="${h.user.activation_url()}"> ${h.field_token()|n} - ${_(u'In order to perform the requested action, you need to validate your email address.')} - ${components.savebox(cancel_url=None, save_text=u'Send activation link')} + +

${_(u'You have not yet validated your email address.')}

+

${_(u'An email with a validation link has been sent to your email address (%s) right after registration. Please follow that link in order to proceed.' % c.user.email)}

+

${_(u'If you click on the button below, the validation link will be resent to you.')}

+ + ${components.savebox(cancel_url=None, save_text=u'Resend activation link')} From 3115d71a7b73defb029622171cd72b447c324c09 Mon Sep 17 00:00:00 2001 From: Nicolas Dietrich Date: Tue, 4 Mar 2014 23:10:49 +0100 Subject: [PATCH 6/8] pep8 --- src/adhocracy/templates/components.html | 137 +++++++++++++----------- 1 file changed, 73 insertions(+), 64 deletions(-) diff --git a/src/adhocracy/templates/components.html b/src/adhocracy/templates/components.html index 11f493143..ab898d19f 100644 --- a/src/adhocracy/templates/components.html +++ b/src/adhocracy/templates/components.html @@ -358,7 +358,7 @@ ${_('Proposal Category')} %if selected: <% (cat_id, key) = selected %> - + @@ -404,67 +404,76 @@ <%def name="attention_getter()"> - %if not h.config.get_bool(u'adhocracy.readonly') and c.instance is not None and (c.user is None or can.instance.join(c.instance) or (c.instance.requires_valid_email() and c.user and not c.user.is_email_activated()) or (h.config.get('adhocracy.propose_optional_attributes') and c.user.optional_attributes is None)): - <%doc>add an attention getter on instances -
-
-
- %if c.user is None: -
- %if h.allow_user_registration(): - ${_('Register')} - ${_("or")} - %endif - ${_('Login')} -
-

- %if h.allow_user_registration(): - ${_('Get an account to participate in the discussion.')} - %else: - ${_('Log in to participate in the discussion.')} - %endif -

- %elif can.instance.join(c.instance): - -

- ${_('Join this instance to start contributing.')} -

- %elif c.instance.require_valid_email and c.user and not c.user.is_email_activated(): - %if c.user.email is None: - -

- ${_('You need to set an email in your profile in order to contribute to this instance.')} -

- %else: - -

- ${_('Please validate your email address in order to contribute to this instance.')}
- ${_('Your registered email address is:')} ${c.user.email} -

- %endif - %else: # h.config.get('adhocracy.propose_optional_attributes') and c.user.optional_attributes is None)): - -

- ${_(u'Please provide statistical information to help scientific evaluation!')}
-

-
- %endif -
-
- - %endif +<% show_attention_getter = ( + not h.config.get_bool(u'adhocracy.readonly') + and c.instance is not None + and (c.user is None + or can.instance.join(c.instance) + or (c.instance.requires_valid_email() + and c.user + and not c.user.is_email_activated()) + or (h.config.get('adhocracy.propose_optional_attributes') + and c.user.optional_attributes is None))) %> + +%if show_attention_getter: +
+
+
+ %if c.user is None: +
+ %if h.allow_user_registration(): + ${_('Register')} + ${_("or")} + %endif + ${_('Login')} +
+

+ %if h.allow_user_registration(): + ${_('Get an account to participate in the discussion.')} + %else: + ${_('Log in to participate in the discussion.')} + %endif +

+ %elif can.instance.join(c.instance): + +

+ ${_('Join this instance to start contributing.')} +

+ %elif c.instance.require_valid_email and c.user and not c.user.is_email_activated(): + %if c.user.email is None: + +

+ ${_('You need to set an email in your profile in order to contribute to this instance.')} +

+ %else: + +

+ ${_('Please validate your email address in order to contribute to this instance.')}
+ ${_('Your registered email address is:')} ${c.user.email} +

+ %endif + %else: # h.config.get('adhocracy.propose_optional_attributes') and c.user.optional_attributes is None)): + +

+ ${_(u'Please provide statistical information to help scientific evaluation!')} +

+ %endif +
+
+
+%endif From c440fe7ed62eb2bc3f195106ab70f0400ec2c824 Mon Sep 17 00:00:00 2001 From: Nicolas Dietrich Date: Tue, 4 Mar 2014 23:23:52 +0100 Subject: [PATCH 7/8] Hide attention getter when already dealing with validation --- src/adhocracy/controllers/user.py | 2 ++ src/adhocracy/templates/components.html | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/adhocracy/controllers/user.py b/src/adhocracy/controllers/user.py index 972ea3b1e..50b5c066f 100644 --- a/src/adhocracy/controllers/user.py +++ b/src/adhocracy/controllers/user.py @@ -770,11 +770,13 @@ def activate(self, id): def ask_activate(self, id): c.page_user = get_entity_or_abort(model.User, id, instance_filter=False) + c.hide_activate_attention_getter = True return render('/user/ask_activate.html') def pending_activate(self, id): c.page_user = get_entity_or_abort(model.User, id, instance_filter=False) + c.hide_activate_attention_getter = True return render('/user/pending_activate.html') @RequireInternalRequest() diff --git a/src/adhocracy/templates/components.html b/src/adhocracy/templates/components.html index ab898d19f..cb65a348d 100644 --- a/src/adhocracy/templates/components.html +++ b/src/adhocracy/templates/components.html @@ -411,7 +411,8 @@ or can.instance.join(c.instance) or (c.instance.requires_valid_email() and c.user - and not c.user.is_email_activated()) + and not c.user.is_email_activated() + and not c.hide_activate_attention_getter) or (h.config.get('adhocracy.propose_optional_attributes') and c.user.optional_attributes is None))) %> From c35a0f429f64e1122594879bd5a158d765b84806 Mon Sep 17 00:00:00 2001 From: Nicolas Dietrich Date: Tue, 4 Mar 2014 23:33:16 +0100 Subject: [PATCH 8/8] Don't show validation intermediate pages if already validated --- src/adhocracy/controllers/user.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/adhocracy/controllers/user.py b/src/adhocracy/controllers/user.py index 50b5c066f..d2593078b 100644 --- a/src/adhocracy/controllers/user.py +++ b/src/adhocracy/controllers/user.py @@ -770,12 +770,24 @@ def activate(self, id): def ask_activate(self, id): c.page_user = get_entity_or_abort(model.User, id, instance_filter=False) + if c.page_user.is_email_activated(): + if c.came_from: + redirect(c.came_from) + else: + redirect(h.entity_url(c.page_user)) + c.hide_activate_attention_getter = True return render('/user/ask_activate.html') def pending_activate(self, id): c.page_user = get_entity_or_abort(model.User, id, instance_filter=False) + if c.page_user.is_email_activated(): + if c.came_from: + redirect(c.came_from) + else: + redirect(h.entity_url(c.page_user)) + c.hide_activate_attention_getter = True return render('/user/pending_activate.html')