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

« back to all changes in this revision

Viewing changes to www/apps/fileservice/action.py

  • Committer: mattgiuca
  • Date: 2008-01-10 07:04:53 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:165
fileservice: Added cut, copy and paste actions. All working.
    Abstracted action_move's code into movefile, which is now shared by
    action_move and action_paste.

Show diffs side-by-side

added added

removed removed

Lines of Context:
171
171
        raise ActionError("Invalid path")
172
172
    return r
173
173
 
 
174
def movefile(req, frompath, topath, copy=False):
 
175
    """Performs a file move, resolving filenames, checking for any errors,
 
176
    and throwing ActionErrors if necessary. Can also be used to do a copy
 
177
    operation instead.
 
178
 
 
179
    frompath and topath are straight paths from the client. Will be checked.
 
180
    """
 
181
    # TODO: Do an SVN mv if the file is versioned.
 
182
    # TODO: Disallow tampering with student's home directory
 
183
    if frompath is None or topath is None:
 
184
        raise ActionError("Required field missing")
 
185
    frompath = actionpath_to_local(req, frompath)
 
186
    topath = actionpath_to_local(req, topath)
 
187
    if not os.path.exists(frompath):
 
188
        raise ActionError("The source file does not exist")
 
189
    if os.path.exists(topath):
 
190
        if frompath == topath:
 
191
            raise ActionError("Source and destination are the same")
 
192
        raise ActionError("Another file already exists with that name")
 
193
 
 
194
    try:
 
195
        if copy:
 
196
            if os.path.isdir(frompath):
 
197
                shutil.copytree(frompath, topath)
 
198
            else:
 
199
                shutil.copy2(frompath, topath)
 
200
        else:
 
201
            shutil.move(frompath, topath)
 
202
    except OSError:
 
203
        raise ActionError("Could not move the file specified")
 
204
    except shutil.Error:
 
205
        raise ActionError("Could not move the file specified")
 
206
 
174
207
### ACTIONS ###
175
208
 
176
209
def action_remove(req, fields):
209
242
    """
210
243
    frompath = fields.getfirst('from')
211
244
    topath = fields.getfirst('to')
212
 
    if frompath is None or topath is None:
213
 
        raise ActionError("Required field missing")
214
 
    frompath = actionpath_to_local(req, frompath)
215
 
    topath = actionpath_to_local(req, topath)
216
 
    if not os.path.exists(frompath):
217
 
        raise ActionError("The source file does not exist")
218
 
    if os.path.exists(topath):
219
 
        raise ActionError("Another file already exists with that name")
220
 
 
221
 
    try:
222
 
        shutil.move(frompath, topath)
223
 
    except OSError:
224
 
        raise ActionError("Could not move the file specified")
225
 
    except shutil.Error:
226
 
        raise ActionError("Could not move the file specified")
 
245
    movefile(req, frompath, topath)
227
246
 
228
247
def action_putfile(req, fields):
229
248
    """Writes data to a file, overwriting it if it exists and creating it if
245
264
    except OSError:
246
265
        raise ActionError("Could not write to target file")
247
266
 
 
267
def action_copy_or_cut(req, fields, mode):
 
268
    """Marks specified files on the clipboard, stored in the
 
269
    browser session. Sets clipboard for either a cut or copy operation
 
270
    as specified.
 
271
 
 
272
    Reads fields: 'path'
 
273
    """
 
274
    # The clipboard object created conforms to the JSON clipboard
 
275
    # specification given at the top of listing.py.
 
276
    # Note that we do not check for the existence of files here. That is done
 
277
    # in the paste operation.
 
278
    files = fields.getlist('path')
 
279
    files = map(lambda field: field.value, files)
 
280
    clipboard = { "mode" : mode, "base" : req.path, "files" : files }
 
281
    session = req.get_session()
 
282
    session['clipboard'] = clipboard
 
283
    session.save()
 
284
 
 
285
def action_copy(req, fields):
 
286
    """Marks specified files on the clipboard, stored in the
 
287
    browser session. Sets clipboard for a "copy" action.
 
288
 
 
289
    Reads fields: 'path'
 
290
    """
 
291
    action_copy_or_cut(req, fields, "copy")
 
292
 
 
293
def action_cut(req, fields):
 
294
    """Marks specified files on the clipboard, stored in the
 
295
    browser session. Sets clipboard for a "cut" action.
 
296
 
 
297
    Reads fields: 'path'
 
298
    """
 
299
    action_copy_or_cut(req, fields, "cut")
 
300
 
 
301
def action_paste(req, fields):
 
302
    """Performs the copy or move action with the files stored on
 
303
    the clipboard in the browser session. Copies/moves the files
 
304
    to the specified directory. Clears the clipboard.
 
305
 
 
306
    Reads fields: 'path'
 
307
    """
 
308
    errormsg = None
 
309
 
 
310
    todir = fields.getfirst('path')
 
311
    if todir is None:
 
312
        raise ActionError("Required field missing")
 
313
    todir_local = actionpath_to_local(req, todir)
 
314
    if not os.path.isdir(todir_local):
 
315
        raise ActionError("Target is not a directory")
 
316
 
 
317
    session = req.get_session()
 
318
    try:
 
319
        clipboard = session['clipboard']
 
320
        files = clipboard['files']
 
321
        base = clipboard['base']
 
322
        if clipboard['mode'] == "copy":
 
323
            copy = True
 
324
        else:
 
325
            copy = False
 
326
    except KeyError:
 
327
        raise ActionError("Clipboard was empty")
 
328
 
 
329
    errorfiles = []
 
330
    for file in files:
 
331
        # The source must not be interpreted as relative to req.path
 
332
        # Add a slash (relative to top-level)
 
333
        frompath = os.sep + os.path.join(base, file)
 
334
        # The destination is found by taking just the basename of the file
 
335
        topath = os.path.join(todir, os.path.basename(file))
 
336
        try:
 
337
            movefile(req, frompath, topath, copy)
 
338
        except ActionError, message:
 
339
            # Store the error for later; we want to copy as many as possible
 
340
            if errormsg is None:
 
341
                errormsg = message
 
342
            else:
 
343
                # Multiple errors; generic message
 
344
                errormsg = "One or more files could not be pasted"
 
345
            # Add this file to errorfiles; it will be put back on the
 
346
            # clipboard for possible future pasting.
 
347
            errorfiles.append(file)
 
348
    # If errors occured, augment the clipboard and raise ActionError
 
349
    if len(errorfiles) > 0:
 
350
        clipboard['files'] = errorfiles
 
351
        session['clipboard'] = clipboard
 
352
        session.save()
 
353
        raise ActionError(errormsg)
 
354
 
 
355
    # Success: Clear the clipboard
 
356
    del session['clipboard']
 
357
    session.save()
 
358
 
248
359
# Table of all action functions #
249
360
# Each function has the interface f(req, fields).
250
361
 
252
363
    "remove" : action_remove,
253
364
    "move" : action_move,
254
365
    "putfile" : action_putfile,
 
366
 
 
367
    "copy" : action_copy,
 
368
    "cut" : action_cut,
 
369
    "paste" : action_paste,
255
370
}