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

1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
1
# IVLE - Informatics Virtual Learning Environment
2
# Copyright (C) 2007-2009 The University of Melbourne
3
#
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18
# Author: Nick Chadwick
19
20
import inspect
21
import os.path
1099.1.120 by William Grant
Move the login machinery to the new framework.
22
import urllib
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
23
24
import genshi.template
25
1099.1.60 by William Grant
Add support in XHTMLView for plugin styles and scripts.
26
from ivle.webapp.media import media_url
1092.1.24 by William Grant
Convince the main XHTML template to use versioned styles/scripts, and move the
27
from ivle.webapp.core import Plugin as CorePlugin
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
28
from ivle.webapp.base.views import BaseView
1099.1.115 by William Grant
Add tabs to the new framework. Move the app icons into the apps themselves.
29
from ivle.webapp.base.plugins import ViewPlugin, OverlayPlugin
1099.1.96 by William Grant
Add an XHTMLUnauthorizedView which redirects unauthenticated users to the
30
from ivle.webapp.errors import HTTPError, Unauthorized
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
31
32
class XHTMLView(BaseView):
33
    """
34
    A view which provides a base class for views which need to return XHTML
35
    It is expected that apps which use this view will be written using Genshi
36
    templates.
37
    """
1099.1.60 by William Grant
Add support in XHTMLView for plugin styles and scripts.
38
39
    template = 'template.html'
40
    plugin_scripts = {}
41
    plugin_styles = {}
1099.1.129 by William Grant
Allow XHTML views to specify that they cannot have overlays.
42
    allow_overlays = True
1099.1.74 by Nick Chadwick
Added overlay system and console overlay. Note that the console overlay
43
    overlay_blacklist = []
1099.1.60 by William Grant
Add support in XHTMLView for plugin styles and scripts.
44
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
45
    def __init__(self, req, **kwargs):
46
        for key in kwargs:
1099.1.46 by Nick Chadwick
Fixed a slight issue in the indentation of xhtml.py
47
            setattr(self, key, kwargs[key])
1099.1.38 by William Grant
ivle.webapp.base.xhtml.XHTMLView: Split the global and view contexts.
48
1148 by William Grant
Allow XHTMLView subclasses to apply filters to the generated app XML stream.
49
    def filter(self, stream, ctx):
50
        return stream
51
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
52
    def render(self, req):
53
        req.content_type = 'text/html' # TODO: Detect application/xhtml+xml
1099.1.38 by William Grant
ivle.webapp.base.xhtml.XHTMLView: Split the global and view contexts.
54
55
        # View template
56
        viewctx = genshi.template.Context()
57
        self.populate(req, viewctx)
58
59
        # The template is found in the directory of the module containing the
60
        # view.
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
61
        app_template = os.path.join(os.path.dirname(
1099.1.35 by William Grant
ivle.webapp.base.xhtml#XHTMLView: Rename app_template to template (the things
62
                        inspect.getmodule(self).__file__), self.template) 
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
63
        loader = genshi.template.TemplateLoader(".", auto_reload=True)
64
        tmpl = loader.load(app_template)
1148 by William Grant
Allow XHTMLView subclasses to apply filters to the generated app XML stream.
65
        app = self.filter(tmpl.generate(viewctx), viewctx)
1099.1.38 by William Grant
ivle.webapp.base.xhtml.XHTMLView: Split the global and view contexts.
66
1099.1.60 by William Grant
Add support in XHTMLView for plugin styles and scripts.
67
        for plugin in self.plugin_scripts:
68
            for path in self.plugin_scripts[plugin]:
69
                req.scripts.append(media_url(req, plugin, path))
70
71
        for plugin in self.plugin_styles:
72
            for path in self.plugin_styles[plugin]:
73
                req.styles.append(media_url(req, plugin, path))
74
1099.1.38 by William Grant
ivle.webapp.base.xhtml.XHTMLView: Split the global and view contexts.
75
        # Global template
76
        ctx = genshi.template.Context()
1099.1.74 by Nick Chadwick
Added overlay system and console overlay. Note that the console overlay
77
        # XXX: Leave this here!! (Before req.styles is read)
1099.1.206 by William Grant
Only display tabs and overlays when we are logged in, and JavaScript settings
78
        ctx['overlays'] = self.render_overlays(req) if req.user else []
1092.1.24 by William Grant
Convince the main XHTML template to use versioned styles/scripts, and move the
79
80
        ctx['styles'] = [media_url(req, CorePlugin, 'ivle.css')]
81
        ctx['styles'] += req.styles
82
83
        ctx['scripts'] = [media_url(req, CorePlugin, path) for path in
1092.1.28 by William Grant
Only load tos.js on /+tos.
84
                           ('util.js', 'json2.js', 'md5.js')]
1160 by William Grant
Swap the version and +external in media URLs, and use media_url for jQuery.
85
        ctx['scripts'].append(media_url(req, '+external/jquery', 'jquery.js'))
1092.1.24 by William Grant
Convince the main XHTML template to use versioned styles/scripts, and move the
86
        ctx['scripts'] += req.scripts
87
1099.1.38 by William Grant
ivle.webapp.base.xhtml.XHTMLView: Split the global and view contexts.
88
        ctx['scripts_init'] = req.scripts_init
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
89
        ctx['app_template'] = app
1100.1.9 by Matt Giuca
The IVLE logo is now an <img> element, rather than a CSS background.
90
        ctx['title_img'] = media_url(req, CorePlugin,
91
                                     "images/chrome/title.png")
1099.1.38 by William Grant
ivle.webapp.base.xhtml.XHTMLView: Split the global and view contexts.
92
        self.populate_headings(req, ctx)
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
93
        tmpl = loader.load(os.path.join(os.path.dirname(__file__), 
94
                                                        'ivle-headings.html'))
95
        req.write(tmpl.generate(ctx).render('xhtml', doctype='xhtml'))
1099.1.74 by Nick Chadwick
Added overlay system and console overlay. Note that the console overlay
96
        
97
    def populate(self, req, ctx):
98
        raise NotImplementedError()
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
99
100
    def populate_headings(self, req, ctx):
101
        ctx['favicon'] = None
1202 by William Grant
XHTMLView no longer uses ivle.conf.
102
        ctx['root_dir'] = req.config['urls']['root']
103
        ctx['public_host'] = req.config['urls']['public_host']
104
        ctx['svn_base'] = req.config['urls']['svn_addr']
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
105
        ctx['write_javascript_settings'] = req.write_javascript_settings
106
        if req.user:
107
            ctx['login'] = req.user.login
108
            ctx['logged_in'] = True
109
            ctx['nick'] = req.user.nick
110
        else:
111
            ctx['login'] = None
1099.1.92 by William Grant
Fix the XHTML base template to not crash when not logged in.
112
            ctx['logged_in'] = False
1099.1.34 by William Grant
Split up ivle.webapp.base.views into ivle.webapp.base.{rest,xhtml}, as it was
113
        ctx['publicmode'] = req.publicmode
1099.1.100 by Nick Chadwick
Created a new help system.
114
        if hasattr(self, 'help'):
115
            ctx['help_path'] = self.help
1099.1.115 by William Grant
Add tabs to the new framework. Move the app icons into the apps themselves.
116
117
        ctx['apps_in_tabs'] = []
1092.1.59 by William Grant
Move the plugin loading/indexing logic into ivle.config.Config.
118
        for plugin in req.config.plugin_index[ViewPlugin]:
1099.1.115 by William Grant
Add tabs to the new framework. Move the app icons into the apps themselves.
119
            if not hasattr(plugin, 'tabs'):
120
                continue
121
122
            for tab in plugin.tabs:
123
                # tab is a tuple: name, title, desc, icon, path
124
                new_app = {}
1116 by William Grant
Move the old tutorial views into the 'subjects' tab, so they get the right
125
                new_app['this_app'] = hasattr(self, 'tab') \
126
                                      and tab[0] == self.tab
1099.1.115 by William Grant
Add tabs to the new framework. Move the app icons into the apps themselves.
127
128
                # Icon name
129
                if tab[3] is not None:
130
                    new_app['has_icon'] = True
131
                    icon_url = media_url(req, plugin, tab[3])
132
                    new_app['icon_url'] = icon_url
133
                    if new_app['this_app']:
134
                        ctx['favicon'] = icon_url
135
                else:
136
                    new_app['has_icon'] = False
1210 by William Grant
Use Request.make_path everywhere.
137
                new_app['path'] = req.make_path(tab[4])
1099.1.115 by William Grant
Add tabs to the new framework. Move the app icons into the apps themselves.
138
                new_app['desc'] = tab[2]
139
                new_app['name'] = tab[1]
140
                new_app['weight'] = tab[5]
141
                ctx['apps_in_tabs'].append(new_app)
142
143
        ctx['apps_in_tabs'].sort(key=lambda tab: tab['weight'])
144
1099.1.74 by Nick Chadwick
Added overlay system and console overlay. Note that the console overlay
145
    def render_overlays(self, req):
146
        """Generate XML streams for the overlays.
147
        
148
        Returns a list of streams. Populates the scripts, styles, and 
149
        scripts_init.
150
        """
151
        overlays = []
1099.1.129 by William Grant
Allow XHTML views to specify that they cannot have overlays.
152
        if not self.allow_overlays:
153
            return overlays
154
1092.1.59 by William Grant
Move the plugin loading/indexing logic into ivle.config.Config.
155
        for plugin in req.config.plugin_index[OverlayPlugin]:
1099.1.74 by Nick Chadwick
Added overlay system and console overlay. Note that the console overlay
156
            for overclass in plugin.overlays:
157
                if overclass in self.overlay_blacklist:
158
                    continue
159
                overlay = overclass(req)
160
                #TODO: Re-factor this to look nicer
161
                for mplugin in overlay.plugin_scripts:
162
                    for path in overlay.plugin_scripts[mplugin]:
163
                        req.scripts.append(media_url(req, mplugin, path))
164
165
                for mplugin in overlay.plugin_styles:
166
                    for path in overlay.plugin_styles[mplugin]:
167
                        req.styles.append(media_url(req, mplugin, path))
1099.1.91 by William Grant
Add support for custom error views. Plugins can now declare that errors
168
1099.1.74 by Nick Chadwick
Added overlay system and console overlay. Note that the console overlay
169
                req.scripts_init += overlay.plugin_scripts_init
1099.1.91 by William Grant
Add support for custom error views. Plugins can now declare that errors
170
1099.1.74 by Nick Chadwick
Added overlay system and console overlay. Note that the console overlay
171
                overlays.append(overlay.render(req))
172
        return overlays
1099.1.91 by William Grant
Add support for custom error views. Plugins can now declare that errors
173
1099.1.95 by William Grant
Error views are now retrieved from a class method of the view, not the plugin
174
    @classmethod
175
    def get_error_view(cls, e):
1099.1.96 by William Grant
Add an XHTMLUnauthorizedView which redirects unauthenticated users to the
176
        view_map = {HTTPError:    XHTMLErrorView,
177
                    Unauthorized: XHTMLUnauthorizedView}
1099.1.95 by William Grant
Error views are now retrieved from a class method of the view, not the plugin
178
        for exccls in inspect.getmro(type(e)):
179
            if exccls in view_map:
180
                return view_map[exccls]
181
1099.1.91 by William Grant
Add support for custom error views. Plugins can now declare that errors
182
class XHTMLErrorView(XHTMLView):
183
    template = 'xhtmlerror.html'
184
185
    def __init__(self, req, exception):
186
        self.context = exception
187
188
    def populate(self, req, ctx):
189
        ctx['exception'] = self.context
1099.1.96 by William Grant
Add an XHTMLUnauthorizedView which redirects unauthenticated users to the
190
191
class XHTMLUnauthorizedView(XHTMLErrorView):
192
    template = 'xhtmlunauthorized.html'
193
194
    def __init__(self, req, exception):
195
        super(XHTMLUnauthorizedView, self).__init__(req, exception)
1099.1.120 by William Grant
Move the login machinery to the new framework.
196
1099.1.96 by William Grant
Add an XHTMLUnauthorizedView which redirects unauthenticated users to the
197
        if req.user is None:
198
            # Not logged in. Redirect to login page.
1099.1.209 by William Grant
Don't escape / in paths when they are in +login/+tos URLs.
199
            if req.uri == '/':
200
                query_string = ''
201
            else:
202
                query_string = '?url=' + urllib.quote(req.uri, safe="/~")
203
            req.throw_redirect('/+login' + query_string)
1099.1.96 by William Grant
Add an XHTMLUnauthorizedView which redirects unauthenticated users to the
204
205
        req.status = 403