Skip to content

Commit

Permalink
Merge pull request #48 from plone/jensens/simplify_templates_registra…
Browse files Browse the repository at this point in the history
…tion

Simplify template registration and enable overrides with jbot
  • Loading branch information
agitator committed May 9, 2018
2 parents 8832954 + b879853 commit 835da66
Show file tree
Hide file tree
Showing 11 changed files with 326 additions and 350 deletions.
39 changes: 5 additions & 34 deletions README.rst
Expand Up @@ -32,48 +32,20 @@ and then running ``bin/buildout``. Install it as usual in /prefs_install_product
Compatibility
-------------

plone.login is tested to work with Plone 5.1.
``plone.login`` is tested to work with Plone 5.1.
It should work with Plone 5.0 as well but is not yet tested.


Customizing templates
---------------------

The templates for any ``plone.login`` can be customized because they're
based on ``plone.z3cform.templates.FormTemplateFactory``. This allows users
to customize the templates in their own packages without customizing the form
or formwrapper classes and having to reregister them through zcml.

Example of a file `adapters.py` in a package `your.addon`::

# -*- coding: utf-8 -*-
from plone.login.interfaces import ILoginForm
from plone.z3cform.templates import FormTemplateFactory
from your.addon.interfaces import IYourAddonLayer

import os


loginform_templatefactory = FormTemplateFactory(
os.path.join(os.path.dirname(__file__), 'templates/login.pt'),
form=ILoginForm,
request=IYourAddonLayer,
)

Then register that adapter in your `configure.zcml`::

<adapter factory="your.addon.adapters.loginform_templatefactory" />

Not you custom template in `templates/login.pt` will be used.

Please note that the login-templates cannot be customized with `z3c.jbot`.

The templates for any ``plone.login`` can be customized because they're simple browser-views.
Use `z3c.jbot <https://pypi.org/project/z3c.jbot/>`_ to apply your own overides.

Customize where to redirect after login
---------------------------------------

You can customize the location the user will be redirected to after successfuly
logging in to the site.
You can customize the location the user will be redirected to after successfuly logging in to the site.

Just write an adapter as follows

Expand Down Expand Up @@ -115,5 +87,4 @@ Then register the adapter through ZCML::
zope.publisher.interfaces.IRequest"
/>

As you can see, this adapter adapts context and request, so modify these
according to your needs.
As you can see, this adapter adapts context and request, so modify these according to your needs.
45 changes: 28 additions & 17 deletions src/plone/login/browser/configure.zcml
Expand Up @@ -14,59 +14,68 @@
template="templates/insufficient_privileges.pt"
/>


<!-- LOGIN: form with plone page around, can be rendered in modal -->
<browser:page
name="login"
for="plone.app.layout.navigation.interfaces.INavigationRoot"
permission="zope.Public"
class=".login.LoginFormView"
template="templates/form_wrapper.pt"
class=".login.LoginForm"
template="templates/login.pt"
/>

<!-- LOGIN: fail safe, simplified and unstyled form -->
<browser:page
name="failsafe_login"
for="plone.app.layout.navigation.interfaces.INavigationRoot"
permission="zope.Public"
class=".login.LoginForm"
template="templates/login_failsafe.pt"
/>

<!-- LOGIN: BBB name, same as 'login' do not use them to refer to the login -->
<browser:page
name="login_form"
for="plone.app.layout.navigation.interfaces.INavigationRoot"
permission="zope.Public"
class=".login.LoginFormView"
template="templates/form_wrapper.pt"
class=".login.LoginForm"
template="templates/login.pt"
/>

<!-- LOGIN: BBB name, same as 'failsafe_login' do not use it any longer-->
<browser:page
name="failsafe_login_form"
for="plone.app.layout.navigation.interfaces.INavigationRoot"
permission="zope.Public"
class=".login.LoginForm"
template="templates/form_wrapper.pt"
template="templates/login_failsafe.pt"
/>

<adapter factory=".login.wrapped_login_template" />

<browser:page
name="logout"
name="login-help"
for="plone.app.layout.navigation.interfaces.INavigationRoot"
permission="zope.Public"
class=".logout.LogoutView"
class=".login_help.LoginHelpForm"
template="templates/login_help.pt"
/>


<browser:page
name="logged-out"
name="logout"
for="plone.app.layout.navigation.interfaces.INavigationRoot"
permission="zope.Public"
template="templates/logged_out.pt"
class=".logout.LoggedOutView"
class=".logout.LogoutView"
/>


<browser:page
name="login-help"
name="logged-out"
for="plone.app.layout.navigation.interfaces.INavigationRoot"
permission="zope.Public"
class=".login_help.LoginHelpFormView"
template="templates/form_wrapper.pt"
template="templates/logged_out.pt"
class=".logout.LoggedOutView"
/>

<adapter factory=".login_help.wrapped_loginhelp_template" />

<browser:page
name="require_login"
for="*"
Expand All @@ -79,13 +88,15 @@
for="plone.app.layout.navigation.interfaces.INavigationRoot"
class=".login.InitialLoginPasswordChange"
permission="cmf.SetOwnPassword"
template="templates/initial_login_password_change.pt"
/>

<browser:page
name="forced-password-change"
for="plone.app.layout.navigation.interfaces.INavigationRoot"
class=".login.ForcedPasswordChange"
permission="cmf.SetOwnPassword"
template="templates/forced_password_change.pt"
/>

</configure>
60 changes: 27 additions & 33 deletions src/plone/login/browser/login.py
Expand Up @@ -8,12 +8,9 @@
from plone.login.interfaces import ILoginFormSchema
from plone.login.interfaces import IRedirectAfterLogin
from plone.registry.interfaces import IRegistry
from plone.z3cform import layout
from plone.z3cform.templates import FormTemplateFactory
from Products.CMFCore.utils import getToolByName
from Products.CMFPlone.interfaces import ISecuritySchema
from Products.Five.browser import BrowserView
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from Products.statusmessages.interfaces import IStatusMessage
from six.moves.urllib import parse
from z3c.form import button
Expand All @@ -25,28 +22,26 @@
from zope.component import queryUtility
from zope.interface import implementer

import os


# TODO: Scale down this list now that we've removed a lot of
# templates.
LOGIN_TEMPLATE_IDS = [
'localhost',
'logged-out',
'logged_in',
'login',
'login_success',
'login_password',
'login_failed',
'login_form',
'logged_in',
'login_password',
'login_success',
'logout',
'logged-out',
'registered',
'mail_password',
'mail_password_form',
'register',
'require_login',
'member_search_results',
'pwreset_finish',
'localhost',
'register',
'registered',
'require_login',
]


Expand All @@ -62,6 +57,9 @@ class LoginForm(form.EditForm):
ignoreContext = True
prefix = ''

def render(self):
return self.index()

def _get_auth(self):
try:
return self.context.acl_users.credentials_cookie_auth
Expand Down Expand Up @@ -177,8 +175,10 @@ def force_password_change(self):
handler()

def redirect_after_login(self, came_from=None, is_initial_login=False):
adapter = queryMultiAdapter((self.context, self.request),
IRedirectAfterLogin)
adapter = queryMultiAdapter(
(self.context, self.request),
IRedirectAfterLogin
)
if adapter:
came_from = adapter(came_from, is_initial_login)
if not came_from:
Expand All @@ -189,26 +189,20 @@ def redirect_after_login(self, came_from=None, is_initial_login=False):
def self_registration_enabled(self):
registry = queryUtility(IRegistry)
security_settings = registry.forInterface(
ISecuritySchema, prefix='plone')
ISecuritySchema,
prefix='plone'
)
return security_settings.enable_self_reg

def use_email_as_login(self):
registry = queryUtility(IRegistry)
security_settings = registry.forInterface(
ISecuritySchema, prefix='plone')
ISecuritySchema,
prefix='plone'
)
return security_settings.use_email_as_login


class LoginFormView(layout.FormWrapper):
form = LoginForm


wrapped_login_template = FormTemplateFactory(
os.path.join(os.path.dirname(__file__), 'templates', 'login.pt'),
form=ILoginForm,
)


class RequireLoginView(BrowserView):

def __call__(self):
Expand All @@ -235,9 +229,9 @@ def request_url(self):


class InitialLoginPasswordChange(PasswordPanel):
template = ViewPageTemplateFile(
'templates/initial_login_password_change.pt',
)

def render(self):
return self.index()

@button.buttonAndHandler(
_(u'label_change_password', default=u'Change Password'),
Expand All @@ -251,9 +245,9 @@ def action_reset_passwd(self, action):


class ForcedPasswordChange(PasswordPanel):
template = ViewPageTemplateFile(
'templates/forced_password_change.pt',
)

def render(self):
return self.index()

@button.buttonAndHandler(
_(u'label_change_password', default=u'Change Password'),
Expand Down
34 changes: 15 additions & 19 deletions src/plone/login/browser/login_help.py
Expand Up @@ -5,8 +5,6 @@
from plone.login.interfaces import ILoginHelpForm
from plone.login.interfaces import ILoginHelpFormSchema
from plone.registry.interfaces import IRegistry
from plone.z3cform import layout
from plone.z3cform.templates import FormTemplateFactory
from Products.CMFCore.utils import getToolByName
from Products.CMFPlone.interfaces import ISecuritySchema
from Products.CMFPlone.interfaces.controlpanel import IMailSchema
Expand All @@ -23,7 +21,6 @@
from zope.interface import implementer

import logging
import os


SEND_USERNAME_TEMPLATE = u"""From: {encoded_mail_sender}
Expand Down Expand Up @@ -59,12 +56,15 @@ class RequestResetPassword(form.Form):
def updateWidgets(self):
super(RequestResetPassword, self).updateWidgets()
if self.use_email_as_login():
self.widgets['reset_password'].label = _(u'label_email',
default=u'Email')
self.widgets['reset_password'].label = _(
u'label_email',
default=u'Email'
)

@button.buttonAndHandler(
_(u'button_pwreset_reset_password', default=u'Reset your password'),
name='reset')
name='reset'
)
def handleResetPassword(self, action):
data, errors = self.extractData()
if errors:
Expand Down Expand Up @@ -104,7 +104,8 @@ class RequestUsername(form.Form):

@button.buttonAndHandler(
_(u'button_pwreset_get_username', default='Get your username'),
name='get_username')
name='get_username'
)
def handleGetUsername(self, action):
data, errors = self.extractData()
if errors:
Expand All @@ -130,8 +131,10 @@ def handleGetUsername(self, action):
# Because of this we always act as if that an email has been sent.
# Instead we log the error-message.
IStatusMessage(self.request).addStatusMessage(
_(u'statusmessage_pwreset_username_mail_sent', default=u'An '
u'email has been sent with your username.'), 'info')
_(u'statusmessage_pwreset_username_mail_sent',
default=u'An email has been sent with your username.'),
'info'
)

def send_username(self, portal, userinfo):
registry = getUtility(IRegistry)
Expand Down Expand Up @@ -191,6 +194,9 @@ class LoginHelpForm(form.EditForm):

ignoreContext = True

def render(self):
return self.index()

def can_reset_password(self):
# TODO: Actually check that the site allows reseting password
return True
Expand Down Expand Up @@ -219,13 +225,3 @@ def use_email_as_login(self):
security_settings = registry.forInterface(
ISecuritySchema, prefix='plone')
return security_settings.use_email_as_login


class LoginHelpFormView(layout.FormWrapper):
form = LoginHelpForm


wrapped_loginhelp_template = FormTemplateFactory(
os.path.join(os.path.dirname(__file__), 'templates', 'login_help.pt'),
form=ILoginHelpForm,
)
17 changes: 0 additions & 17 deletions src/plone/login/browser/templates/form_wrapper.pt

This file was deleted.

0 comments on commit 835da66

Please sign in to comment.