summaryrefslogtreecommitdiff
path: root/repoze/bfg/zcml.py
blob: dc05cca18a7bcf4863b53abdd7fee211cb402db5 (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
122
123
124
125
126
127
128
129
130
131
import inspect
import os
import new

from zope.component.zcml import handler
from zope.component.interface import provideInterface
from zope.configuration.exceptions import ConfigurationError
from zope.configuration.fields import GlobalObject
from zope.configuration.fields import Path

from zope.schema import TextLine
from zope.interface import Interface
from zope.interface import implements

from zope.security.zcml import Permission

from repoze.bfg.interfaces import IRequest
from repoze.bfg.interfaces import IViewFactory
from repoze.bfg.interfaces import IView

from repoze.bfg.template import Z3CPTTemplateFactory
from repoze.bfg.view import TemplateView

class TemplateViewFactory(object):
    """ Pickleable template view factory """

    implements(IViewFactory)

    def __init__(self, template, base=None):
        if base is not None:
            if not inspect.isclass(base):
                raise ValueError('Factory must be a class to be used '
                                 'with a template, but %s was supplied' % base)
        self.template = template
        self.base = base

    def __call__(self, context, request):
        if self.base and self.base is not TemplateView:
            if issubclass(self.base, TemplateView):
                bases = (self.base,)
            else:
                bases = (self.base, TemplateView)
            name = 'DynamicTemplateView_For_%s' % self.base.__name__
            factory = new.classobj(name, bases, {})
        else:
            factory = TemplateView(context, request)
        factory.template = self.template
        return factory
        
def view(_context,
         permission,
         for_=None,
         factory=None,
         name="",
         template=None,
         ):

    # XXX we do nothing yet with permission

    if not (template or factory):
        raise ConfigurationError(
            'One of template or factory (or both) must be specified')

    if template:
        template_abs = os.path.abspath(str(_context.path(template)))
        if not os.path.exists(template_abs):
            raise ConfigurationError('No template file named %s' % template_abs)
        utility = Z3CPTTemplateFactory(template_abs)
        _context.action(
            discriminator = ('utility', IView, template_abs),
            callable = handler,
            args = ('registerUtility', utility, IView, template_abs),
            )
        factory = TemplateViewFactory(template_abs, factory)

    if for_ is not None:
        _context.action(
            discriminator = None,
            callable = provideInterface,
            args = ('', for_)
            )

    _context.action(
        discriminator = ('view', for_, name, IRequest, IViewFactory),
        callable = handler,
        args = ('registerAdapter',
                factory, (for_, IRequest), IViewFactory, name,
                _context.info),
        )

class IViewDirective(Interface):
    """
    The page directive is used to create views that provide a single
    url or page.

    The page directive creates a new view class from a given template
    and/or class and registers it.
    """

    for_ = GlobalObject(
        title=u"The interface or class this view is for.",
        required=False
        )

    permission = Permission(
        title=u"Permission",
        description=u"The permission needed to use the view.",
        required=True
        )

    factory = GlobalObject(
        title=u"Class",
        description=u"A class that provides a __call__ used by the view.",
        required=False,
        )

    name = TextLine(
        title=u"The name of the page (view)",
        description=u"""
        The name shows up in URLs/paths. For example 'foo' or
        'foo.html'.""",
        required=False,
        )

    template = Path(
        title=u"The name of a template that implements the page.",
        description=u"""Refers to a file containing a z3c.pt page template""",
        required=False
        )