diff --git a/example/app.py b/example/app.py index 9d5d285..1d7b596 100644 --- a/example/app.py +++ b/example/app.py @@ -41,6 +41,38 @@ def populate_data(): create_users() +def add_ctx_processors(app): + s = app.security + + @s.context_processor + def for_all(): + return dict() + + @s.forgot_password_context_processor + def forgot_password(): + return dict() + + @s.login_context_processor + def login(): + return dict() + + @s.register_context_processor + def register(): + return dict() + + @s.reset_password_context_processor + def reset_password(): + return dict() + + @s.send_confirmation_context_processor + def send_confirmation(): + return dict() + + @s.send_login_context_processor + def send_login(): + return dict() + + def create_app(auth_config): app = Flask(__name__) app.debug = True @@ -192,6 +224,8 @@ def create_sqlalchemy_app(auth_config=None, register_blueprint=True): db.create_all() populate_data() + add_ctx_processors(app) + return app @@ -228,6 +262,8 @@ def create_mongoengine_app(auth_config=None): Role.drop_collection() populate_data() + add_ctx_processors(app) + return app if __name__ == '__main__': diff --git a/flask_security/core.py b/flask_security/core.py index 19dc343..b548b29 100644 --- a/flask_security/core.py +++ b/flask_security/core.py @@ -219,6 +219,49 @@ class _SecurityState(object): for key, value in kwargs.items(): setattr(self, key.lower(), value) + def _add_ctx_processor(self, endpoint, fn): + c = self.context_processors + + if endpoint not in c: + c[endpoint] = [] + + if fn not in c[endpoint]: + c[endpoint].append(fn) + + def _run_ctx_processor(self, endpoint): + fns = [] + rv = {} + + for g in ['all', endpoint]: + if g in self.context_processors: + fns += self.context_processors[g] + + for fn in fns: + rv.update(fn()) + + return rv + + def context_processor(self, fn): + self._add_ctx_processor('all', fn) + + def forgot_password_context_processor(self, fn): + self._add_ctx_processor('forgot_password', fn) + + def login_context_processor(self, fn): + self._add_ctx_processor('login', fn) + + def register_context_processor(self, fn): + self._add_ctx_processor('register', fn) + + def reset_password_context_processor(self, fn): + self._add_ctx_processor('reset_password', fn) + + def send_confirmation_context_processor(self, fn): + self._add_ctx_processor('send_confirmation', fn) + + def send_login_context_processor(self, fn): + self._add_ctx_processor('send_login', fn) + class Security(object): """The :class:`Security` class initializes the Flask-Security extension. @@ -286,6 +329,8 @@ class Security(object): ('token_auth_serializer', _get_token_auth_serializer(app))]: kwargs[key] = value + kwargs['context_processors'] = {} + kwargs['login_serializer'] = ( _get_login_serializer(app) if kwargs['passwordless'] else None) diff --git a/flask_security/templates/security/reset_password.html b/flask_security/templates/security/reset_password.html index b383df0..0adcad8 100644 --- a/flask_security/templates/security/reset_password.html +++ b/flask_security/templates/security/reset_password.html @@ -1,7 +1,7 @@ {% from "security/_macros.html" import render_field_with_errors, render_field %} {% include "security/_messages.html" %}

Reset password

-
+ {{ reset_password_form.hidden_tag() }} {{ render_field_with_errors(reset_password_form.password) }} {{ render_field_with_errors(reset_password_form.password_confirm) }} diff --git a/flask_security/utils.py b/flask_security/utils.py index 412d2ac..0ca0245 100644 --- a/flask_security/utils.py +++ b/flask_security/utils.py @@ -126,6 +126,10 @@ def get_url(endpoint_or_url): return endpoint_or_url +def get_security_endpoint_name(endpoint): + return '%s.%s' % (_security.blueprint_name, endpoint) + + def url_for_security(endpoint, **values): """Return a URL for the security blueprint @@ -137,7 +141,7 @@ def url_for_security(endpoint, **values): :param _anchor: if provided this is added as anchor to the URL. :param _method: if provided this explicitly specifies an HTTP method. """ - endpoint = '%s.%s' % (_security.blueprint_name, endpoint) + endpoint = get_security_endpoint_name(endpoint) return url_for(endpoint, **values) diff --git a/flask_security/views.py b/flask_security/views.py index de03d74..8390dfe 100644 --- a/flask_security/views.py +++ b/flask_security/views.py @@ -104,7 +104,8 @@ def login(): form = PasswordlessLoginForm() if _security.passwordless else LoginForm() template = 'send_login' if _security.passwordless else 'login' - return render_template('security/%s.html' % template, login_form=form) + return render_template('security/%s.html' % template, login_form=form, + **_security._run_ctx_processor('login')) @login_required @@ -148,7 +149,8 @@ def register(): get_url(_security.post_login_view)) return render_template('security/register.html', - register_user_form=form) + register_user_form=form, + **_security._run_ctx_processor('register')) @anonymous_user_required @@ -164,7 +166,8 @@ def send_login(): else: do_flash(*get_message('DISABLED_ACCOUNT')) - return render_template('security/send_login.html', login_form=form) + return render_template('security/send_login.html', login_form=form, + **_security._run_ctx_processor('send_login')) @anonymous_user_required @@ -203,7 +206,8 @@ def send_confirmation(): do_flash(*get_message('CONFIRMATION_REQUEST', email=user.email)) return render_template('security/send_confirmation.html', - reset_confirmation_form=form) + reset_confirmation_form=form, + **_security._run_ctx_processor('send_confirmation')) def confirm_email(token): @@ -256,7 +260,8 @@ def forgot_password(): do_flash(value[0], 'error') return render_template('security/forgot_password.html', - forgot_password_form=form) + forgot_password_form=form, + **_security._run_ctx_processor('forgot_password')) @anonymous_user_required @@ -297,7 +302,8 @@ def reset_password(token): return render_template('security/reset_password.html', reset_password_form=form, - password_reset_token=token) + reset_password_token=token, + **_security._run_ctx_processor('reset_password')) def create_blueprint(app, name, import_name, **kwargs):