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

« back to all changes in this revision

Viewing changes to ivle/webapp/filesystem/browser/__init__.py

  • Committer: William Grant
  • Date: 2009-02-23 23:47:02 UTC
  • mfrom: (1099.1.211 new-dispatch)
  • Revision ID: grantw@unimelb.edu.au-20090223234702-db4b1llly46ignwo
Merge from lp:~ivle-dev/ivle/new-dispatch.

Pretty much everything changes. Reread the setup docs. Backup your databases.
Every file is now in a different installed location, the configuration system
is rewritten, the dispatch system is rewritten, URLs are different, the
database is different, worksheets and exercises are no longer on the
filesystem, we use a templating engine, jail service protocols are rewritten,
we don't repeat ourselves, we have authorization rewritten, phpBB is gone,
and probably lots of other things that I cannot remember.

This is certainly the biggest commit I have ever made, and hopefully
the largest I ever will.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# IVLE
2
 
# Copyright (C) 2007-2008 The University of Melbourne
 
1
# IVLE - Informatics Virtual Learning Environment
 
2
# Copyright (C) 2007-2009 The University of Melbourne
3
3
#
4
4
# This program is free software; you can redistribute it and/or modify
5
5
# it under the terms of the GNU General Public License as published by
15
15
# along with this program; if not, write to the Free Software
16
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
17
 
18
 
# App: File Browser
19
 
# Author: Matt Giuca
20
 
# Date: 9/1/2008
21
 
 
22
 
# The file browser application. Presents an Ajax-based interface to the
23
 
# student's subversion workspace.
24
 
# Note that there is virtually no server-side code for this application. It
25
 
# simply presents static HTML and JavaScript, and all server-side activities
26
 
# take place in the FileService app (for handling Ajax requests).
 
18
# Author: Matt Giuca, Nick Chadwick
 
19
 
 
20
"""
 
21
The file browser application. Presents an Ajax-based interface to the
 
22
student's subversion workspace.
 
23
 
 
24
Note that there is virtually no server-side code for this application. It
 
25
simply presents static HTML and JavaScript, and all server-side activities
 
26
take place in the FileService app (for handling Ajax requests).
 
27
"""
 
28
 
 
29
from ivle.webapp.base.plugins import ViewPlugin, CookiePlugin, MediaPlugin
 
30
from ivle.webapp.base.xhtml import XHTMLView
27
31
 
28
32
import os.path
29
33
import cgi
31
35
from ivle import (util, studpath)
32
36
import ivle.svn
33
37
 
34
 
import genshi
35
 
import genshi.core
36
 
import genshi.template
37
 
 
38
 
# url path for this app
39
 
THIS_APP = "files"
40
 
 
41
 
def handle(req):
42
 
    """Handler for the File Browser application."""
43
 
 
44
 
    # Work out where we are browsing
45
 
    browsepath = req.path
46
 
    if len(browsepath) == 0:
47
 
        # If no path specified, default to the user's home directory
48
 
        redirectPath = util.make_path(os.path.join(THIS_APP,req.user.login))
49
 
        req.throw_redirect(util.make_path(redirectPath))
50
 
 
51
 
    ctx = genshi.template.Context()
52
 
 
53
 
    # Set request attributes
54
 
    req.content_type = "text/html"
55
 
    req.styles = [
56
 
        "media/browser/browser.css",
57
 
        "media/browser/listing.css",
58
 
        "media/browser/editor.css",
59
 
    ]
60
 
    req.scripts = [
61
 
        "media/common/json2.js",
62
 
        "media/common/codepress/codepress.js",
63
 
        "media/common/util.js",
64
 
        "media/browser/browser.js",
65
 
        "media/browser/listing.js",
66
 
        "media/browser/editor.js",
67
 
        "media/browser/specialhome.js",
68
 
    ]
69
 
    req.scripts_init = [
70
 
        "browser_init",
71
 
    ]
72
 
 
73
 
    req.write_html_head_foot = True     # Have dispatch print head and foot
74
 
    # The page title should contain the name of the file being browsed
75
 
    req.title = browsepath.rsplit('/', 1)[-1]
76
 
 
77
 
    _, localpath = studpath.url_to_local(browsepath)
78
 
    if localpath is None:
79
 
        req.throw_error(req.HTTP_NOT_FOUND,
80
 
            "The path specified is invalid.")
81
 
 
82
 
    # Start writing data
83
 
 
84
 
    # FIXME: This isn't completely reliable! We're not inside the jail, so we
85
 
    # can't know the type for sure. This is now only used for adding a / to the
86
 
    # end of displayed paths, so I'm leaving this although it will often break.
87
 
    isdir = os.path.isdir(localpath)
88
 
    ctx['isdir'] = isdir
89
 
    gen_path(req, browsepath, ctx)
90
 
    gen_actions(req, ctx)
91
 
    
92
 
    ctx['fileservice_action'] = util.make_path(os.path.join("fileservice", req.path))
93
 
    ctx['filename'] = cgi.escape(req.path)
94
 
 
95
 
    loader = genshi.template.TemplateLoader(".", auto_reload=True)
96
 
    tmpl = loader.load(util.make_local_path("apps/browser/template.html"))
97
 
    
98
 
    req.write(tmpl.generate(ctx).render('html')) #'xhtml', doctype='xhtml'))
99
 
 
100
 
#TODO: Move all this logic into the template
101
 
def gen_path(req, path, ctx):
102
 
 
103
 
    href_path = util.make_path(THIS_APP)
104
 
    nav_path = ""
105
 
    revision = ivle.svn.revision_from_string(
106
 
                     req.get_fieldstorage().getfirst('r'))
107
 
    try: 
108
 
        revno = revision.number
109
 
    except:
110
 
        revno = None
111
 
      
112
 
    ctx['revno'] = revno
113
 
    
114
 
    # Create all of the paths
115
 
    pathlist = path.split("/")
116
 
    ctx['paths'] = []
117
 
    for path_seg in pathlist:
118
 
        if path_seg == "":
119
 
            continue
120
 
        new_seg = {}
121
 
        
122
 
        nav_path = nav_path + path_seg
123
 
        href_path = href_path + '/' + path_seg
124
 
        
125
 
        new_seg['path'] = path_seg        
126
 
        new_seg['nav_path'] = nav_path
127
 
        new_seg['href_path'] = href_path
128
 
        if revno is not None:
129
 
            new_seg['href_path'] += '?r=%d' % revno
130
 
        
131
 
        ctx['paths'].append(new_seg)
132
 
 
133
 
 
134
 
def gen_actions(req, ctx):
135
 
    """
136
 
    Presents a set of links/buttons for the "actions1" row of the top bar.
137
 
    This is always exactly the same - the JavaScript will customize it later.
138
 
    """
139
 
    # Set up our actions. The second field of each group is whether to disable
140
 
    # the items by default.
141
 
    ctx['moreactions'] = [
142
 
      ('Publishing', True, [
143
 
        ('publish', ['Publish',          'Make it so this directory can be seen by anyone on the web']),
144
 
        ('share',   ['Share this file',  'Get a link to this published file, to give to friends']),
145
 
        ('submit',  ['Submit', 'Submit the selected files for an assignment'])
146
 
      ]),
147
 
      ('File actions', True, [
148
 
        ('rename',  ['Rename',           'Change the name of this file']),
149
 
        ('delete',  ['Delete',           'Delete the selected files']),
150
 
        ('copy',    ['Copy',             'Prepare to copy the selected files to another directory']),
151
 
        ('cut',     ['Cut',              'Prepare to move the selected files to another directory'])
152
 
      ]),
153
 
      ('Directory actions', False, [
154
 
        ('paste',   ['Paste',            'Paste the copied or cut files into the current directory']),
155
 
        ('newfile', ['New File',         'Open a new file for editing in the current directory']),
156
 
        ('mkdir',   ['New Directory',    'Make a new subdirectory in the current directory']),
157
 
        ('upload',  ['Upload File',      'Upload a file to the current directory'])
158
 
      ]),
159
 
      ('Subversion', True, [
160
 
        ('svncut',      ['Svn Cut',      'Prepare to move the selected files to another directory, maintaining history']),
161
 
        ('svncopy',     ['Svn Copy',     'Prepare to copy the selected files to another directory, maintaining history']),
162
 
        ('svnadd',      ['Add',            'Schedule the selected temporary files to be added permanently']),
163
 
        ('svnremove',   ['Remove',         'Schedule the selected permanent files to be removed']),
164
 
        ('svndiff',     ['Diff',           'View any changes to the selected file since its last committed state']),
165
 
        ('svnrevert',   ['Revert',         'Restore the selected files back to their last committed state']),
166
 
        ('svnupdate',   ['Update',         'Update your files with changes from the permanent repository']),
167
 
        ('svncommit',   ['Commit',         'Commit any changes to the permanent repository']),
168
 
        ('svnresolved', ['Mark Resolved',  'Mark a conflicted file as being resolved']),
169
 
        ('svnlog',      ['View Log',       'View the log of commits of the selected file']),
170
 
      ])
171
 
    ]
 
38
class BrowserView(XHTMLView):
 
39
    """
 
40
    The view for the browser
 
41
    """
 
42
    template = 'template.html'
 
43
    appname = 'files'
 
44
    help = 'Filesystem/Browser'
 
45
 
 
46
    def authorize(self, req):
 
47
        return req.user is not None
 
48
 
 
49
    def populate(self, req, ctx):
 
50
        if not hasattr(self, 'path'):
 
51
            # If no path specified, default to the user's home directory
 
52
            redirectPath = util.make_path(os.path.join('files', req.user.login))
 
53
            req.throw_redirect(util.make_path(redirectPath))
 
54
 
 
55
        # Set request attributes
 
56
        self.plugin_styles[Plugin] = ['browser.css',
 
57
                                      'listing.css',
 
58
                                      'editor.css']
 
59
        self.plugin_scripts[Plugin] = ['browser.js',
 
60
                                       'listing.js',
 
61
                                       'editor.js',
 
62
                                       'specialhome.js',
 
63
                                       'codepress/codepress.js']
 
64
        req.scripts_init = ["browser_init"]
 
65
 
 
66
        _, localpath = studpath.url_to_local(self.path)
 
67
        if localpath is None:
 
68
            raise NotFound()
 
69
 
 
70
        # Start writing data
 
71
 
 
72
        # FIXME: This isn't completely reliable! We're not inside the jail, so we
 
73
        # can't know the type for sure. This is now only used for adding a / to the
 
74
        # end of displayed paths, so I'm leaving this although it will often break.
 
75
        isdir = os.path.isdir(localpath)
 
76
        ctx['isdir'] = isdir
 
77
        self.gen_path(req, ctx)
 
78
        self.gen_actions(req, ctx)
 
79
 
 
80
        # The page title should contain the name of the file being browsed
 
81
        ctx['title'] = self.path.rsplit('/', 1)[-1]
 
82
 
 
83
        ctx['fileservice_action'] = util.make_path(os.path.join("fileservice", req.path))
 
84
        ctx['filename'] = cgi.escape(req.path)
 
85
 
 
86
    #TODO: Move all this logic into the template
 
87
    def gen_path(self, req, ctx):
 
88
 
 
89
        href_path = util.make_path('files')
 
90
        nav_path = ""
 
91
        revision = ivle.svn.revision_from_string(
 
92
                         req.get_fieldstorage().getfirst('r'))
 
93
        try:
 
94
            revno = revision.number
 
95
        except:
 
96
            revno = None
 
97
 
 
98
        ctx['revno'] = revno
 
99
 
 
100
        # Create all of the paths
 
101
        pathlist = self.path.split("/")
 
102
        ctx['paths'] = []
 
103
        for path_seg in pathlist:
 
104
            if path_seg == "":
 
105
                continue
 
106
            new_seg = {}
 
107
 
 
108
            nav_path = nav_path + path_seg
 
109
            href_path = href_path + '/' + path_seg
 
110
 
 
111
            new_seg['path'] = path_seg
 
112
            new_seg['nav_path'] = nav_path
 
113
            new_seg['href_path'] = href_path
 
114
            if revno is not None:
 
115
                new_seg['href_path'] += '?r=%d' % revno
 
116
 
 
117
            ctx['paths'].append(new_seg)
 
118
 
 
119
    def gen_actions(self, req, ctx):
 
120
        """
 
121
        Presents a set of links/buttons for the "actions1" row of the top bar.
 
122
        This is always exactly the same - the JavaScript will customize it later.
 
123
        """
 
124
        # Set up our actions. The second field of each group is whether to disable
 
125
        # the items by default.
 
126
        ctx['moreactions'] = [
 
127
          ('Publishing', True, [
 
128
            ('publish', ['Publish',          'Make it so this directory can be seen by anyone on the web']),
 
129
            ('share',   ['Share this file',  'Get a link to this published file, to give to friends']),
 
130
            ('submit',  ['Submit', 'Submit the selected files for an assignment'])
 
131
          ]),
 
132
          ('File actions', True, [
 
133
            ('rename',  ['Rename',           'Change the name of this file']),
 
134
            ('delete',  ['Delete',           'Delete the selected files']),
 
135
            ('copy',    ['Copy',             'Prepare to copy the selected files to another directory']),
 
136
            ('cut',     ['Cut',              'Prepare to move the selected files to another directory'])
 
137
          ]),
 
138
          ('Directory actions', False, [
 
139
            ('paste',   ['Paste',            'Paste the copied or cut files into the current directory']),
 
140
            ('newfile', ['New File',         'Open a new file for editing in the current directory']),
 
141
            ('mkdir',   ['New Directory',    'Make a new subdirectory in the current directory']),
 
142
            ('upload',  ['Upload File',      'Upload a file to the current directory'])
 
143
          ]),
 
144
          ('Subversion', True, [
 
145
            ('svncut',      ['Svn Cut',      'Prepare to move the selected files to another directory, maintaining history']),
 
146
            ('svncopy',     ['Svn Copy',     'Prepare to copy the selected files to another directory, maintaining history']),
 
147
            ('svnadd',      ['Add',            'Schedule the selected temporary files to be added permanently']),
 
148
            ('svnremove',   ['Remove',         'Schedule the selected permanent files to be removed']),
 
149
            ('svndiff',     ['Diff',           'View any changes to the selected file since its last committed state']),
 
150
            ('svnrevert',   ['Revert',         'Restore the selected files back to their last committed state']),
 
151
            ('svnupdate',   ['Update',         'Update your files with changes from the permanent repository']),
 
152
            ('svncommit',   ['Commit',         'Commit any changes to the permanent repository']),
 
153
            ('svnresolved', ['Mark Resolved',  'Mark a conflicted file as being resolved']),
 
154
            ('svnlog',      ['View Log',       'View the log of commits of the selected file']),
 
155
          ])
 
156
        ]
 
157
 
 
158
class Plugin(ViewPlugin, CookiePlugin, MediaPlugin):
 
159
    """
 
160
    The Plugin class for the user plugin.
 
161
    """
 
162
    # Magic attribute: urls
 
163
    # Sequence of pairs/triples of
 
164
    # (regex str, handler class, kwargs dict)
 
165
    # The kwargs dict is passed to the __init__ of the view object
 
166
    urls = [
 
167
        ('files/*(path)', BrowserView),
 
168
        ('files/', BrowserView),
 
169
        ('/', BrowserView),
 
170
    ]
 
171
 
 
172
    tabs = [
 
173
        ('files', 'Files', 'Gives you access to all of your files and lets '
 
174
         'you download, upload, edit and run them.', 'browser.png', 'files', 1)
 
175
    ]
 
176
 
 
177
    cookies = {'clipboard': None}
 
178
 
 
179
    help = {'Filesystem': {'Browser': 'help.html'}}
 
180
 
 
181
    media = 'media'