Skip to main content

Pagelet layer setup for Zope3

Project description

This package provides a pagelet based layer setup for Zope3.

Pagelet-based Layer for Zope 3

This package contains the pagelet layer. This layer supports a correct set of component registration and can be used for inheritation in custom skins.

Right now the default implementation in Zope3 has different restriction in the traversal concept and use to much registration on the default layer.

Important

This layer ia based on the pagelet pattern. This means every page e.g. the error page is based on the pagelet concept.

IPageletBrowserLayer Layer

The pagelet layer is useful for build custom presentation skins without access to ZMI menus like zmi_views etc. This means there is no menu item registred if you use this layer.

This layer is NOT derived from IDefaultBrowserLayer layer. Therefore it provides only a minimal set of the most important public views such as @@absolute_url. The following packages are accounted:

  • zope.app.http.exception

  • zope.app.publication

  • zope.app.publisher.browser

  • zope.app.traversing

  • zope.app.traversing.browser

Testing

For testing the IPageletBrowserLayer layer we use the testing skin defined in the tests package which uses the IPageletBrowserLayer layer as the only base layer. This means, that our testing skin provides only the views defined in the minimal package and it’s testing views defined in tests.

Login as manager first:

>>> from zope.testbrowser.testing import Browser
>>> manager = Browser()

Check if we can access the page.html view which is registred in the ftesting.zcml file with our skin:

>>> skinURL = 'http://localhost/++skin++PageletTestSkin'
>>> manager.open(skinURL + '/page.html')
>>> manager.url
'http://localhost/++skin++PageletTestSkin/page.html'
>>> print manager.contents
<!DOCTYPE...
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>PageletTestLayout</title>
</head>
<body>
  test page
<BLANKLINE>
</body>
</html>
<BLANKLINE>

Not Found

Now check the not found page which is a exception view on the exception zope.publisher.interfaces.INotFound:

>>> manager.open(skinURL + '/foobar.html')
Traceback (most recent call last):
...
httperror_seek_wrapper: HTTP Error 404: Not Found
>>> print manager.contents
<!DOCTYPE...
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>PageletTestLayout</title>
</head>
<body>
  <div>
  <br />
  <br />
  <h3>
    The page you are trying to access is not available
  </h3>
  <br />
  <b>
    Please try the following:
  </b>
  <br />
  <ol>
    <li>
      Make sure that the Web site address is spelled correctly.
    </li>
    <li>
      <a href="javascript:history.back(1);">
        Go back and try another URL.
      </a>
    </li>
  </ol>
</div>
<BLANKLINE>
</body>
</html>
<BLANKLINE>

User error

And check the user error page which is a view registred for zope.exceptions.interfaces.IUserError exceptions:

>>> manager.open(skinURL + '/@@usererror.html')
>>> print manager.contents
<!DOCTYPE ...
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>PageletTestLayout</title>
</head>
<body>
  <div>
  <div>simply user error</div>
</div>
<BLANKLINE>
</body>
</html>
<BLANKLINE>

Common exception (system error)

And check error view registred for zope.interface.common.interfaces.IException:

>>> manager.open(skinURL + '/@@systemerror.html')
>>> print manager.contents
<!DOCTYPE...
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>PageletTestLayout</title>
</head>
<body>
  <div>
  <br />
  <br />
  <h3>A system error occurred</h3>
  <br />
  <b>Please contact the administrator.</b>
  <a href="javascript:history.back(1);">
    Go back and try another URL.
  </a>
</div>
<BLANKLINE>
</body>
</html>
<BLANKLINE>

Unauthorized

To check the zope.security.interfaces.IUnauthorized view, we use a new unregistred user (test browser). As we have defined an unauthenticatedPrincipal in ZCML (see tests/ftesting.zcml) 401 Unauthorized is returned instead of 403 Forbidden which would show up otherwise:

>>> unauthorized = Browser()
>>> unauthorized.open(skinURL + '/@@forbidden.html')
Traceback (most recent call last):
...
HTTPError: HTTP Error 401: Unauthorized
>>> print unauthorized.contents
<!DOCTYPE ...
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>PageletTestLayout</title>
</head>
<body>
  <div>
  <br />
  <br />
  <h3>Unauthorized</h3>
  <br />
  <b>You are not authorized.</b>
</div>
<BLANKLINE>
</body>
</html>
<BLANKLINE>

Login and logout

Login and logout work both for basic auth and cookie auth.

Setup

The layout page template has to include two content providers (viewlet mangers):

  • login-logout-head inside the head tag to get automatic redirects and JavaScript code which does the logout for basic auth and

  • login-logout inside the body tag to get login and logout links.

The sample template looks like this:

>>> import os.path
>>> template_path = os.path.join(os.path.dirname(__file__), "tests",
...     "login-logout-template.pt")
>>> print file(template_path, "r").read()
<!DOCTYPE ...>
<html ...>
  <head>
    <title>PageletTest</title>
    <tal:block replace="structure provider:login-logout-head" />
  </head>
  <body>
    <tal:block replace="structure provider:login-logout" />
    <tal:block replace="structure provider:pagelet" />
  </body>
</html>

This template is registered for the IContainer interface in ftesting.zcml. After creating a container the template is used when browsing the container:

>>> from zope.container.btree import BTreeContainer
>>> getRootFolder()['container'] = BTreeContainer()

Basic auth

When the user is not logged in the login link is displayed:

>>> from zope.testbrowser.testing import Browser
>>> skinURL = 'http://localhost/++skin++PageletTestSkin/'
>>> browser = Browser()
>>> browser.handleErrors = False
>>> browser.open(skinURL + 'container/@@default.html')
>>> browser.url
'http://localhost/++skin++PageletTestSkin/container/@@default.html'
>>> print browser.contents
<!DOCTYPE ...>
<html ...>
  <head>
    <title>PageletTest</title>
  </head>
  <body>
    <a href="http://localhost/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Login</a>
  </body>
</html>

Selecting the link leads to the login page, as we use basic auth here, we get an HTTP error 401 (unauthorized):

>>> login_url = browser.getLink('Login').url
>>> browser.getLink('Login').click()
Traceback (most recent call last):
httperror_seek_wrapper: HTTP Error 401: Unauthorized
>>> browser.url
'http://localhost/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html'

When adding correct credentials we get authorized:

>>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
>>> browser.reload()

We are redirected to the page where we selected the login link. After logging in the login link is no longer displayed. As we did not specify that logout is supported, no logout link is displayed:

>>> browser.url
'http://localhost/++skin++PageletTestSkin/container/@@default.html'
>>> print browser.contents
<!DOCTYPE ...>
<html ...>
  <head>
    <title>PageletTest</title>
  </head>
  <body>
  </body>
</html>

Calling the login URL again leads directly to the page referred in nextURL:

>>> browser.open(login_url)
>>> browser.url
'http://localhost/++skin++PageletTestSkin/container/@@default.html'
>>> print browser.contents
<!DOCTYPE ...>
<html ...>
  <head>
    <title>PageletTest</title>
  </head>
  <body>
  </body>
</html>

Calling the login URL again without the query parameter leeds to a confirmation page telling that login was successfull:

>>> browser.open(login_url.split('?')[0])
>>> browser.url
'http://localhost/++skin++PageletTestSkin/container/@@login.html'
>>> print browser.contents
<!DOCTYPE ...>
<html ...>
<head>
<title>PageletTestLayout</title>
</head>
<body>
  <div>
   <h1>Login successful!</h1>
   <p style="font-size: 200%"> You are now logged in as <em>Manager</em>. </p>
   <a href=".">Back to the main page.</a>
  </div>
</body>
</html>

Selecting the Back to the main page. link send the user back to the default view of the container. (ftesting.zcml defines @@default.html as the default view.):

>>> browser.getLink('Back to the main page.').click()
>>> browser.url
'http://localhost/++skin++PageletTestSkin/container/'
>>> print browser.contents
<!DOCTYPE ...>
<html ...>
  <head>
    <title>PageletTest</title>
  </head>
  <body>
  </body>
</html>

Providing an ILogoutSupported adapter leads to a logout link being displayed:

>>> from zope.app.testing import ztapi
>>> import zope.interface
>>> import zope.authentication.logout
>>> import zope.authentication.interfaces
>>> ztapi.provideAdapter(
...     zope.interface.Interface,
...     zope.authentication.interfaces.ILogoutSupported,
...     zope.authentication.logout.LogoutSupported)
>>> browser.reload()
>>> browser.url
'http://localhost/++skin++PageletTestSkin/container/'
>>> print browser.contents
<!DOCTYPE ...>
<html ...>
  <head>
    <title>PageletTest</title>
  </head>
  <body>
    <a href="http://localhost/++skin++PageletTestSkin/container/@@logout.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Logout</a>
  </body>
</html>

Logout is done using JavaScript and a redirect. zope.testbrowser follows the redirects even if they use the meta tag instead of the status code. So I have to use a non API call to change this behavior to show the file contents:

>>> browser.mech_browser.set_handle_refresh(False)

As testbrowser is not able to execute JavaScript the user remains authenticated:

>>> logout_url = browser.getLink('Logout').url
>>> browser.getLink('Logout').click()
>>> browser.url
'http://localhost/++skin++PageletTestSkin/container/@@logout.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html'
>>> print browser.contents
<!DOCTYPE ...>
<html ...>
  <head>
    <title>PageletTest</title>
    <script type="text/javascript"><!--
  // clear HTTP Authentication
  ...
  //-->
</script>
<meta http-equiv="refresh"
      content="0;url=http://localhost/++skin++PageletTestSkin/container/@@default.html" />
  </head>
  <body>
    <a href="http://localhost/++skin++PageletTestSkin/container/@@logout.html/@@logout.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40logout.html">Logout</a>
    <div>
  <h1>You are being redirected!</h1>
  <p style="font-size: 150%">
    <a href="http://localhost/++skin++PageletTestSkin/container/@@default.html">
      If you see this screen for more than 5 seconds, click here.
    </a>
  </p>
</div>
  </body>
</html>

Calling the logout URL again after logout (simulated using a new browser instance) leads directly to the page referred in nextURL:

>>> browser2 = Browser(logout_url)
>>> browser2.url
'http://localhost/++skin++PageletTestSkin/container/@@default.html'
>>> print browser2.contents
<!DOCTYPE ...>
<html ...>
  <head>
    <title>PageletTest</title>
  </head>
  <body>
    <a href="http://localhost/++skin++PageletTestSkin/container/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40default.html">Login</a>
  </body>
</html>

Calling the logout URL again without the query parameter leeds to a confirmation page telling that logout was successfull:

>>> browser2.open(logout_url.split('?')[0])
>>> browser2.url
'http://localhost/++skin++PageletTestSkin/container/@@logout.html'
>>> print browser2.contents
<!DOCTYPE ...>
<html ...>
  <head>
    <title>PageletTest</title>
    <script type="text/javascript"><!--
  // clear HTTP Authentication
  ...
  //-->
</script>
  </head>
  <body>
    <a href="http://localhost/++skin++PageletTestSkin/container/logout.html/@@login.html?nextURL=http%3A//localhost/%2B%2Bskin%2B%2BPageletTestSkin/container/%40%40logout.html">Login</a>
    <div>
  <h1>Logout successful!</h1>
  <p style="font-size: 200%">
    You are now logged out.
  </p>
  <a href=".">Back to the main page.</a>
</div>
  </body>
</html>

CHANGES

1.5.0 (2009-05-28)

  • Removed dependency on zope.app.exception by using zope.browser>=1.2 and by implementing the exception view classes directly instead of inheriting them (Quite nothing of the base classes was in use here.)

  • Removed not necessary test dependency on zope.app.twisted.

  • Removed no longer necessary test dependency on zope.app.component.

1.4.0 (2009-03-16)

  • Removed direct dependency on zope.app.security by using the new packages zope.authentication and zope.principalregistry.

  • Removed not needed test-dependency on zope.app.zcmlfiles.

  • Fixed namespace package declaration in setup.py.

1.3.0 (2009-03-13)

  • Implemented login and logout using pagelets resp. viewlets.

  • Updated tests to use new zope.configuration which containts the exclude directive.

1.2.1 (2009-02-21)

  • Release 1.2.0 was missing the test file for the security issue.

1.2.0 (2009-02-21)

  • Security issue: The traverser defined for IPageletBrowserLayer was a trusted adapter, so the security proxy got removed from each traversed object. Thus all sub-objects were publically accessable, too.

1.1.0 (2009-02-14)

  • Bugfix: use IContentTemplate instead of IPageTemplate which avoids to get the layout template if no IPageTemplate is registered.

  • Using zope.location.interfaces.ISite instead of zope.app.component.interfaces.ISite.

  • Using zope.container instead of zope.app.container.

  • Cleaned up dependencies.

1.0.1 (2008-01-24)

  • Bug: Update meta data.

1.0.0 (2008-01-21)

  • Restructure: Move z3c.layer.pagelet package to it’s own top level package form z3c.layer to z3c.layer.pagelet.

  • Restructure: Removed zope.app.form support from pagelet layer.

0.2.3 (2007-11-07)

  • Forward-Bug: Due to a bug in mechanize, the testbrowser throws httperror_seek_wrapper instead of HTTPError errors. Thanks to RE normalizers, the code will now work whether the bug is fixed or not in mechanize.

0.2.2 (2007-10-31)

  • Bug: Fixed package meta-data.

  • Bug: Fixed test failures due to depency updates.

  • Restructure: Fixed deprecation warninf for ZopeSecurityPolicy.

0.2.1 (2007-??-??)

  • Changes unknown.

0.2.0 (2007-??-??)

  • Initial release.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

z3c.layer.pagelet-1.5.0.tar.gz (27.1 kB view details)

Uploaded Source

File details

Details for the file z3c.layer.pagelet-1.5.0.tar.gz.

File metadata

File hashes

Hashes for z3c.layer.pagelet-1.5.0.tar.gz
Algorithm Hash digest
SHA256 d21f748ac0cb80311dc94e5f1b6b72613d2cc3551bc7c59c7497edf638cd36dc
MD5 b57cb7d9c0e9a34728f509dbee774fcd
BLAKE2b-256 7aff3176633fab3471e41264c968e4459db6b369ee1771892d0034ed10454b91

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page