~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to ivle/webapp/base/xhtml.py

Port the forum app to the new framework. With it also comes new cookie
infrastructure.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 
20
20
import inspect
21
21
import os.path
22
 
import urllib
23
22
 
24
23
import genshi.template
25
24
 
26
25
from ivle.webapp.media import media_url
27
 
from ivle.webapp.core import Plugin as CorePlugin
28
26
from ivle.webapp.base.views import BaseView
29
 
from ivle.webapp.base.plugins import ViewPlugin, OverlayPlugin
30
 
from ivle.webapp.errors import HTTPError, Unauthorized
31
 
from ivle.webapp.publisher import NoPath
32
 
from ivle.webapp.breadcrumbs import Breadcrumber
 
27
from ivle.webapp.base.plugins import OverlayPlugin
 
28
import ivle.conf
 
29
import ivle.util
33
30
 
34
31
class XHTMLView(BaseView):
35
32
    """
39
36
    """
40
37
 
41
38
    template = 'template.html'
42
 
    allow_overlays = True
43
 
    breadcrumb_text = None
44
 
 
45
 
    def __init__(self, *args, **kwargs):
46
 
        super(XHTMLView, self).__init__(*args, **kwargs)
47
 
 
48
 
        self.overlay_blacklist = []
49
 
 
50
 
        self.plugin_scripts = {}
51
 
        self.plugin_styles = {}
52
 
        self.scripts_init = []
53
 
 
54
 
        self.extra_breadcrumbs = []
55
 
        self.overlay_blacklist = []
56
 
 
57
 
    def get_context_ancestry(self, req):
58
 
        return req.publisher.get_ancestors(self.context)
59
 
 
60
 
    def filter(self, stream, ctx):
61
 
        return stream
 
39
    plugin_scripts = {}
 
40
    plugin_styles = {}
 
41
    overlay_blacklist = []
 
42
 
 
43
    def __init__(self, req, **kwargs):
 
44
        for key in kwargs:
 
45
            setattr(self, key, kwargs[key])
62
46
 
63
47
    def render(self, req):
64
48
        req.content_type = 'text/html' # TODO: Detect application/xhtml+xml
71
55
        # view.
72
56
        app_template = os.path.join(os.path.dirname(
73
57
                        inspect.getmodule(self).__file__), self.template) 
 
58
        req.write_html_head_foot = False
74
59
        loader = genshi.template.TemplateLoader(".", auto_reload=True)
75
60
        tmpl = loader.load(app_template)
76
 
        app = self.filter(tmpl.generate(viewctx), viewctx)
 
61
        app = tmpl.generate(viewctx)
77
62
 
78
 
        view_scripts = []
79
63
        for plugin in self.plugin_scripts:
80
64
            for path in self.plugin_scripts[plugin]:
81
 
                view_scripts.append(media_url(req, plugin, path))
 
65
                req.scripts.append(media_url(req, plugin, path))
82
66
 
83
 
        view_styles = []
84
67
        for plugin in self.plugin_styles:
85
68
            for path in self.plugin_styles[plugin]:
86
 
                view_styles.append(media_url(req, plugin, path))
 
69
                req.styles.append(media_url(req, plugin, path))
87
70
 
88
71
        # Global template
89
72
        ctx = genshi.template.Context()
90
 
 
91
 
        overlay_bits = self.render_overlays(req) if req.user else [[]]*4
92
 
        ctx['overlays'] = overlay_bits[0]
93
 
 
94
 
        ctx['styles'] = [media_url(req, CorePlugin, 'ivle.css')]
95
 
        ctx['styles'] += view_styles
96
 
        ctx['styles'] += overlay_bits[1]
97
 
 
98
 
        ctx['scripts'] = [media_url(req, CorePlugin, path) for path in
99
 
                           ('util.js', 'json2.js', 'md5.js')]
100
 
        ctx['scripts'].append(media_url(req, '+external/jquery', 'jquery.js'))
101
 
        ctx['scripts'] += view_scripts
102
 
        ctx['scripts'] += overlay_bits[2]
103
 
 
104
 
        ctx['scripts_init'] = self.scripts_init + overlay_bits[3]
 
73
        # XXX: Leave this here!! (Before req.styles is read)
 
74
        ctx['overlays'] = self.render_overlays(req)
 
75
        ctx['app_styles'] = req.styles
 
76
        ctx['scripts'] = req.scripts
 
77
        ctx['scripts_init'] = req.scripts_init
105
78
        ctx['app_template'] = app
106
 
        ctx['title_img'] = media_url(req, CorePlugin,
107
 
                                     "images/chrome/root-breadcrumb.png")
108
 
        try:
109
 
            ancestry = self.get_context_ancestry(req)
110
 
        except NoPath:
111
 
            ancestry = []
112
 
 
113
 
        crumber = Breadcrumber(req)
114
 
 
115
 
        ctx['breadcrumbs'] = []
116
 
        if not req.publicmode:
117
 
            for ancestor in ancestry:
118
 
                crumb = crumber.crumb(ancestor)
119
 
                if crumb is None:
120
 
                    continue
121
 
 
122
 
                if hasattr(crumb, 'extra_breadcrumbs_before'):
123
 
                    ctx['breadcrumbs'].extend(crumb.extra_breadcrumbs_before)
124
 
                ctx['breadcrumbs'].append(crumb)
125
 
                if hasattr(crumb, 'extra_breadcrumbs_after'):
126
 
                    ctx['breadcrumbs'].extend(crumb.extra_breadcrumbs_after)
127
 
 
128
 
            # If the view has specified text for a breadcrumb, add one.
129
 
            if self.breadcrumb_text:
130
 
                ctx['breadcrumbs'].append(ViewBreadcrumb(req, self))
131
 
 
132
 
            # Allow the view to add its own fake breadcrumbs.
133
 
            ctx['breadcrumbs'].extend(self.extra_breadcrumbs)
134
 
 
135
79
        self.populate_headings(req, ctx)
136
80
        tmpl = loader.load(os.path.join(os.path.dirname(__file__), 
137
81
                                                        'ivle-headings.html'))
142
86
 
143
87
    def populate_headings(self, req, ctx):
144
88
        ctx['favicon'] = None
145
 
        ctx['root_dir'] = req.config['urls']['root']
146
 
        ctx['public_host'] = req.config['urls']['public_host']
147
 
        ctx['svn_base'] = req.config['urls']['svn_addr']
 
89
        ctx['root_dir'] = ivle.conf.root_dir
 
90
        ctx['public_host'] = ivle.conf.public_host
148
91
        ctx['write_javascript_settings'] = req.write_javascript_settings
149
92
        if req.user:
150
93
            ctx['login'] = req.user.login
152
95
            ctx['nick'] = req.user.nick
153
96
        else:
154
97
            ctx['login'] = None
155
 
            ctx['logged_in'] = False
156
98
        ctx['publicmode'] = req.publicmode
157
 
        if hasattr(self, 'help'):
158
 
            ctx['help_path'] = self.help
159
 
 
160
99
        ctx['apps_in_tabs'] = []
161
 
        for plugin in req.config.plugin_index[ViewPlugin]:
162
 
            if not hasattr(plugin, 'tabs'):
163
 
                continue
164
 
 
165
 
            for tab in plugin.tabs:
166
 
                # tab is a tuple: name, title, desc, icon, path, weight, admin
167
 
                # (Admin is optional, defaults to false)
168
 
                new_app = {}
169
 
                new_app['this_app'] = hasattr(self, 'tab') \
170
 
                                      and tab[0] == self.tab
171
 
 
172
 
                # Icon name
173
 
                if tab[3] is not None:
174
 
                    new_app['has_icon'] = True
175
 
                    icon_url = media_url(req, plugin, tab[3])
176
 
                    new_app['icon_url'] = icon_url
177
 
                    if new_app['this_app']:
178
 
                        ctx['favicon'] = icon_url
179
 
                else:
180
 
                    new_app['has_icon'] = False
181
 
                # The following check is here, so it is AFTER setting the
182
 
                # icon, but BEFORE actually installing the tab in the menu
183
 
                if len(tab) > 6 and tab[6]:
184
 
                    # Admin-only tab
185
 
                    if not (req.user and req.user.admin):
186
 
                        break
187
 
                new_app['path'] = req.make_path(tab[4])
188
 
                new_app['desc'] = tab[2]
189
 
                new_app['name'] = tab[1]
190
 
                new_app['weight'] = tab[5]
191
 
                ctx['apps_in_tabs'].append(new_app)
192
 
 
193
 
        ctx['apps_in_tabs'].sort(key=lambda tab: tab['weight'])
194
 
 
 
100
        for urlname in ivle.conf.apps.apps_in_tabs:
 
101
            new_app = {}
 
102
            app = ivle.conf.apps.app_url[urlname]
 
103
            new_app['this_app'] = hasattr(self, 'appname') \
 
104
                                  and urlname == self.appname
 
105
            if app.icon:
 
106
                new_app['has_icon'] = True
 
107
                icon_dir = ivle.conf.apps.app_icon_dir
 
108
                icon_url = ivle.util.make_path(os.path.join(icon_dir, app.icon))
 
109
                new_app['icon_url'] = icon_url
 
110
                if new_app['this_app']:
 
111
                    ctx['favicon'] = icon_url
 
112
            else:
 
113
                new_app['has_icon'] = False
 
114
            new_app['path'] = ivle.util.make_path(urlname)
 
115
            new_app['desc'] = app.desc
 
116
            new_app['name'] = app.name
 
117
            ctx['apps_in_tabs'].append(new_app)
 
118
            
195
119
    def render_overlays(self, req):
196
120
        """Generate XML streams for the overlays.
197
121
        
199
123
        scripts_init.
200
124
        """
201
125
        overlays = []
202
 
        styles = []
203
 
        scripts = []
204
 
        scripts_init = []
205
 
        if not self.allow_overlays:
206
 
            return (overlays, styles, scripts, scripts_init)
207
 
 
208
 
        for plugin in req.config.plugin_index[OverlayPlugin]:
 
126
        for plugin in req.plugin_index[OverlayPlugin]:
209
127
            for overclass in plugin.overlays:
210
128
                if overclass in self.overlay_blacklist:
211
129
                    continue
213
131
                #TODO: Re-factor this to look nicer
214
132
                for mplugin in overlay.plugin_scripts:
215
133
                    for path in overlay.plugin_scripts[mplugin]:
216
 
                        scripts.append(media_url(req, mplugin, path))
 
134
                        req.scripts.append(media_url(req, mplugin, path))
217
135
 
218
136
                for mplugin in overlay.plugin_styles:
219
137
                    for path in overlay.plugin_styles[mplugin]:
220
 
                        styles.append(media_url(req, mplugin, path))
221
 
 
222
 
                scripts_init += overlay.plugin_scripts_init
223
 
 
 
138
                        req.styles.append(media_url(req, mplugin, path))
 
139
                
 
140
                req.scripts_init += overlay.plugin_scripts_init
 
141
                
224
142
                overlays.append(overlay.render(req))
225
 
        return (overlays, styles, scripts, scripts_init)
226
 
 
227
 
    @classmethod
228
 
    def get_error_view(cls, e):
229
 
        view_map = {HTTPError:    XHTMLErrorView,
230
 
                    Unauthorized: XHTMLUnauthorizedView}
231
 
        for exccls in inspect.getmro(type(e)):
232
 
            if exccls in view_map:
233
 
                return view_map[exccls]
234
 
 
235
 
class XHTMLErrorView(XHTMLView):
236
 
    template = 'xhtmlerror.html'
237
 
 
238
 
    def __init__(self, req, context, lastobj):
239
 
        super(XHTMLErrorView, self).__init__(req, context)
240
 
        self.lastobj = lastobj
241
 
 
242
 
    def get_context_ancestry(self, req):
243
 
        return req.publisher.get_ancestors(self.lastobj)
244
 
 
245
 
    def populate(self, req, ctx):
246
 
        ctx['req'] = req
247
 
        ctx['exception'] = self.context
248
 
 
249
 
class XHTMLUnauthorizedView(XHTMLErrorView):
250
 
    template = 'xhtmlunauthorized.html'
251
 
 
252
 
    def __init__(self, req, exception, lastobj):
253
 
        super(XHTMLUnauthorizedView, self).__init__(req, exception, lastobj)
254
 
 
255
 
        if not req.publicmode and req.user is None:
256
 
            # Not logged in. Redirect to login page.
257
 
            if req.uri == '/':
258
 
                query_string = ''
259
 
            else:
260
 
                query_string = '?url=' + urllib.quote(req.uri, safe="/~")
261
 
            req.throw_redirect('/+login' + query_string)
262
 
 
263
 
        req.status = 403
264
 
 
265
 
class ViewBreadcrumb(object):
266
 
    def __init__(self, req, context):
267
 
        self.req = req
268
 
        self.context = context
269
 
 
270
 
    @property
271
 
    def text(self):
272
 
        return self.context.breadcrumb_text
 
143
        return overlays