summaryrefslogtreecommitdiff
path: root/docs/narr/hooks.rst
blob: 086dc16ad91a504ce399895028c92d623f12edc6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
.. _hooks_chapter:

Using ZCML Hooks
================

ZCML "hooks" can be used to influence the behavior of the
:mod:`repoze.bfg` framework in various ways.

Changing the Not Found View
---------------------------

When :mod:`repoze.bfg` can't map a URL to view code, it invokes a
notfound :term:`view`. The view it invokes can be customized by
placing something like the following ZCML in your ``configure.zcml``
file.

.. code-block:: xml
   :linenos:

   <notfound 
       view="helloworld.views.notfound_view"/>

Replace ``helloworld.views.notfound_view`` with the Python dotted name
to the notfound view you want to use.  Here's some sample code that
implements a minimal NotFound view:

.. code-block:: python

   from webob.exc import HTTPNotFound

   def notfound_view(context, request):
       return HTTPNotFound()

.. note:: When a NotFound view is invoked, it is passed a request.
   The ``environ`` attribute of the request is the WSGI environment.
   Within the WSGI environ will be a key named ``repoze.bfg.message``
   that has a value explaining why the not found error was raised.
   This error will be different when the ``debug_notfound``
   environment setting is true than it is when it is false.

Changing the Forbidden View
---------------------------

When :mod:`repoze.bfg` can't authorize execution of a view based on
the authorization policy in use, it invokes a "forbidden view".  The
default forbidden response has a 401 status code and is very plain,
but it can be overridden as necessary by placing something like the
following ZCML in your ``configure.zcml`` file.

.. code-block:: xml
   :linenos:

   <forbidden
       view="helloworld.views.forbidden_view"/>

Replace ``helloworld.views.forbidden_view`` with the Python
dotted name to the forbidden view you want to use.  Like any other
view, the forbidden view must accept two parameters: ``context`` and
``request`` .  The ``context`` is the context found by the router when
the view invocation was denied.  The ``request`` is the current
:term:`request` representing the denied action.  Here's some sample
code that implements a minimal forbidden view:

.. code-block:: python

   from repoze.bfg.chameleon_zpt import render_template_to_response

   def forbidden_view(context, request):
       return render_template_to_response('templates/login_form.pt')

.. note:: When an forbidden view is invoked, it is passed
   the request as the second argument.  An attribute of the request is
   ``environ``, which is the WSGI environment.  Within the WSGI
   environ will be a key named ``repoze.bfg.message`` that has a value
   explaining why the current view invocation was forbidden.  This
   error will be different when the ``debug_authorization``
   environment setting is true than it is when it is false.

.. warning:: the default forbidden view sends a response with a ``401
   Unauthorized`` status code for backwards compatibility reasons.
   You can influence the status code of Forbidden responses by using
   an alterate forbidden view.  For example, it would make sense to
   return a response with a ``403 Forbidden`` status code.

Changing the response factory
-----------------------------

You may change the class used as the "response factory" from within
the :mod:`repoze.bfg` ``chameleon_zpt``, ``chameleon_genshi``,
``chameleon_text`` (the ``render_template_to_response`` function used
within each) and other various places where a Response object is
constructed by :mod:`repoze.bfg`.  The default "response factory" is
the class ``webob.Response``.  You may change it by placing the
following ZCML in your ``configure.zcml`` file.

.. code-block:: xml
   :linenos:

   <utility provides="repoze.bfg.interfaces.IResponseFactory"
            component="helloworld.factories.response_factory"/>

Replace ``helloworld.factories.response_factory`` with the Python
dotted name to the response factory you want to use.  Here's some
sample code that implements a minimal response factory:

.. code-block:: python

   from webob import Response

   class MyResponse(Response):
      pass

   def response_factory():
       return MyResponse

Unlike a request factory, a response factory does not need to return
an object that implements any particular interface; it simply needs
have a ``status`` attribute, a ``headerlist`` attribute, and and
``app_iter`` attribute.