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

« back to all changes in this revision

Viewing changes to lib/fileservice_lib/action.py

  • Committer: mattgiuca
  • Date: 2008-02-19 06:10:53 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:503
user.py: Added acct_expired and pass_expired methods.
login.py: Removed has_expired function (now we put it inside the class)
    and called those methods instead.

Show diffs side-by-side

added added

removed removed

Lines of Context:
62
62
#               will create a directory instead and unpack the ZIP file
63
63
#               into it.
64
64
#
65
 
# action=mkdir: Create a directory. The parent dir must exist.
66
 
#       path:   The path to a file which does not exist, but whose parent
67
 
#               does. The dir will be made with this name.
68
 
#
69
65
# The differences between putfile and putfiles are:
70
66
# * putfile can only accept a single file.
71
67
# * putfile can accept string data, doesn't have to be a file upload.
72
68
# * putfile ignores the upload filename, the entire filename is specified on
73
69
#       path. putfiles calls files after the name on the user's machine.
74
70
#
75
 
# action=paste: Copy or move the files to a specified dir.
76
 
#       src:    The path to the DIRECTORY to get the files from (relative).
77
 
#       dst:    The path to the DIRECTORY to paste the files to. Must not
 
71
# Clipboard-based actions. Cut/copy/paste work in the same way as modern
 
72
# file browsers, by keeping a server-side clipboard of files that have been
 
73
# cut and copied. The clipboard is stored in the session data, so it persists
 
74
# across navigation, tabs and browser windows, but not across browser
 
75
# sessions.
 
76
 
77
# action=copy: Write file(s) to the session-based clipboard. Overrides any
 
78
#               existing clipboard data. Does not actually copy the file.
 
79
#               The files are physically copied when the clipboard is pasted.
 
80
#       path:   The path to the file or directory to copy. Can be specified
 
81
#               multiple times.
 
82
 
83
# action=cut: Write file(s) to the session-based clipboard. Overrides any
 
84
#               existing clipboard data. Does not actually move the file.
 
85
#               The files are physically moved when the clipboard is pasted.
 
86
#       path:   The path to the file or directory to cut. Can be specified
 
87
#               multiple times.
 
88
 
89
# action=paste: Copy or move the files stored in the clipboard. Clears the
 
90
#               clipboard. The files are copied or moved to a specified dir.
 
91
#       path:   The path to the DIRECTORY to paste the files to. Must not
78
92
#               be a file.
79
 
#       mode:   'copy' or 'move'
80
 
#       file:   File to be copied or moved, relative to src, to a destination
81
 
#               relative to dst. Can be specified multiple times.
82
93
#
83
94
# Subversion actions.
84
95
# action=svnadd: Add an existing file(s) to version control.
108
119
#               recursively.
109
120
#       logmsg: Text of the log message. Optional. There is a default log
110
121
#               message if unspecified.
111
 
# action=svncheckout: Checkout a file/directory from the repository.
112
 
#       path:   The [repository] path to the file or directory to be
113
 
#               checked out.
114
122
115
123
# TODO: Implement the following actions:
116
124
#   putfiles, svnrevert, svnupdate, svncommit
128
136
import pysvn
129
137
 
130
138
from common import (util, studpath, zip)
131
 
import conf
132
 
 
133
 
def get_login(_realm, _username, _may_save):
134
 
    """Return the subversion credentials for the user."""
135
 
    return (True, conf.login, conf.svn_pass, True)
136
139
 
137
140
# Make a Subversion client object
138
141
svnclient = pysvn.Client()
139
 
svnclient.callback_get_login = get_login
140
142
 
141
143
DEFAULT_LOGMESSAGE = "No log message supplied."
142
144
 
285
287
    topath = fields.getfirst('to')
286
288
    movefile(req, frompath, topath)
287
289
 
288
 
def action_mkdir(req, fields):
289
 
    """Creates a directory with the given path.
290
 
    Reads fields: 'path'
291
 
    """
292
 
    path = fields.getfirst('path')
293
 
    if path is None:
294
 
        raise ActionError("Required field missing")
295
 
    path = actionpath_to_local(req, path)
296
 
 
297
 
    # Create the directory
298
 
    try:
299
 
        os.mkdir(path)
300
 
    except OSError:
301
 
        raise ActionError("Could not create directory")
302
 
 
303
290
def action_putfile(req, fields):
304
291
    """Writes data to a file, overwriting it if it exists and creating it if
305
292
    it doesn't.
310
297
    # Important: Data is "None" if the file submitted is empty.
311
298
    path = fields.getfirst('path')
312
299
    data = fields.getfirst('data')
313
 
    if path is None:
 
300
    if path is None or data is None:
314
301
        raise ActionError("Required field missing")
315
 
    if data is None:
316
 
        # Workaround - field reader treats "" as None, so this is the only
317
 
        # way to allow blank file uploads
318
 
        data = ""
319
302
    path = actionpath_to_local(req, path)
320
303
 
321
304
    if data is not None:
355
338
    for datum in data:
356
339
        # Each of the uploaded files
357
340
        filepath = os.path.join(path, datum.filename)
358
 
        filedata = datum.file
 
341
        filedata = datum.value
359
342
 
360
343
        if unpack and datum.filename.lower().endswith(".zip"):
361
344
            # A zip file - unpack it instead of just copying
363
346
            # Note: Just unzip into the current directory (ignore the
364
347
            # filename)
365
348
            try:
366
 
                # First get the entire path (within jail)
367
 
                _, _, abspath = studpath.url_to_jailpaths(path)
368
 
                abspath = os.path.join(os.sep, abspath)
369
 
                zip.unzip(abspath, filedata)
 
349
                zip.unzip(path, filedata)
370
350
            except (OSError, IOError):
371
351
                goterror = True
372
352
        else:
390
370
            raise ActionError(
391
371
                "Could not write to one or more of the target files")
392
372
 
 
373
def action_copy_or_cut(req, fields, mode):
 
374
    """Marks specified files on the clipboard, stored in the
 
375
    browser session. Sets clipboard for either a cut or copy operation
 
376
    as specified.
 
377
 
 
378
    Reads fields: 'path'
 
379
    """
 
380
    # The clipboard object created conforms to the JSON clipboard
 
381
    # specification given at the top of listing.py.
 
382
    # Note that we do not check for the existence of files here. That is done
 
383
    # in the paste operation.
 
384
    files = fields.getlist('path')
 
385
    clipboard = { "mode" : mode, "base" : req.path, "files" : files }
 
386
    session = req.get_session()
 
387
    session['clipboard'] = clipboard
 
388
    session.save()
 
389
 
 
390
def action_copy(req, fields):
 
391
    """Marks specified files on the clipboard, stored in the
 
392
    browser session. Sets clipboard for a "copy" action.
 
393
 
 
394
    Reads fields: 'path'
 
395
    """
 
396
    action_copy_or_cut(req, fields, "copy")
 
397
 
 
398
def action_cut(req, fields):
 
399
    """Marks specified files on the clipboard, stored in the
 
400
    browser session. Sets clipboard for a "cut" action.
 
401
 
 
402
    Reads fields: 'path'
 
403
    """
 
404
    action_copy_or_cut(req, fields, "cut")
 
405
 
393
406
def action_paste(req, fields):
394
 
    """Performs the copy or move action with the files specified.
395
 
    Copies/moves the files to the specified directory.
 
407
    """Performs the copy or move action with the files stored on
 
408
    the clipboard in the browser session. Copies/moves the files
 
409
    to the specified directory. Clears the clipboard.
396
410
 
397
 
    Reads fields: 'src', 'dst', 'mode', 'file' (multiple).
398
 
    src: Base path that all the files are relative to (source).
399
 
    dst: Destination path to paste into.
400
 
    mode: 'copy' or 'move'.
401
 
    file: (Multiple) Files relative to base, which will be copied
402
 
        or moved to new locations relative to path.
 
411
    Reads fields: 'path'
403
412
    """
404
413
    errormsg = None
405
414
 
406
 
    dst = fields.getfirst('dst')
407
 
    src = fields.getfirst('src')
408
 
    mode = fields.getfirst('mode')
409
 
    files = fields.getlist('file')
410
 
    if dst is None or src is None or mode is None:
 
415
    todir = fields.getfirst('path')
 
416
    if todir is None:
411
417
        raise ActionError("Required field missing")
412
 
    if mode == "copy":
413
 
        copy = True
414
 
    elif mode == "move":
415
 
        copy = False
416
 
    else:
417
 
        raise ActionError("Invalid mode (must be 'copy' or 'move')")
418
 
    dst_local = actionpath_to_local(req, dst)
419
 
    if not os.path.isdir(dst_local):
420
 
        raise ActionError("dst is not a directory")
 
418
    todir_local = actionpath_to_local(req, todir)
 
419
    if not os.path.isdir(todir_local):
 
420
        raise ActionError("Target is not a directory")
 
421
 
 
422
    session = req.get_session()
 
423
    try:
 
424
        clipboard = session['clipboard']
 
425
        files = clipboard['files']
 
426
        base = clipboard['base']
 
427
        if clipboard['mode'] == "copy":
 
428
            copy = True
 
429
        else:
 
430
            copy = False
 
431
    except KeyError:
 
432
        raise ActionError("Clipboard was empty")
421
433
 
422
434
    errorfiles = []
423
435
    for file in files:
424
436
        # The source must not be interpreted as relative to req.path
425
437
        # Add a slash (relative to top-level)
426
 
        if src[:1] != '/':
427
 
            src = '/' + src
428
 
        frompath = os.path.join(src, file)
 
438
        frompath = os.sep + os.path.join(base, file)
429
439
        # The destination is found by taking just the basename of the file
430
 
        topath = os.path.join(dst, os.path.basename(file))
 
440
        topath = os.path.join(todir, os.path.basename(file))
431
441
        try:
432
442
            movefile(req, frompath, topath, copy)
433
443
        except ActionError, message:
440
450
            # Add this file to errorfiles; it will be put back on the
441
451
            # clipboard for possible future pasting.
442
452
            errorfiles.append(file)
443
 
    if errormsg is not None:
 
453
    # If errors occured, augment the clipboard and raise ActionError
 
454
    if len(errorfiles) > 0:
 
455
        clipboard['files'] = errorfiles
 
456
        session['clipboard'] = clipboard
 
457
        session.save()
444
458
        raise ActionError(errormsg)
445
459
 
446
 
    # XXX errorfiles contains a list of files that couldn't be pasted.
447
 
    # we currently do nothing with this.
448
 
 
449
 
def action_publish(req,fields):
450
 
    """Marks the folder as published by adding a '.published' file to the 
451
 
    directory and ensuring that the parent directory permissions are correct
452
 
 
453
 
    Reads fields: 'path'
454
 
    """
455
 
    paths = fields.getlist('path')
456
 
    user = studpath.url_to_local(req.path)[0]
457
 
    homedir = "/home/%s" % user
458
 
    if len(paths):
459
 
        paths = map(lambda path: actionpath_to_local(req, path), paths)
460
 
    else:
461
 
        paths = [studpath.url_to_jailpaths(req.path)[2]]
462
 
 
463
 
    # Set all the dirs in home dir world browsable (o+r,o+x)
464
 
    #FIXME: Should really only do those in the direct path not all of the 
465
 
    # folders in a students home directory
466
 
    for root,dirs,files in os.walk(homedir):
467
 
        os.chmod(root, os.stat(root).st_mode|0005)
468
 
 
469
 
    try:
470
 
        for path in paths:
471
 
            if os.path.isdir(path):
472
 
                pubfile = open(os.path.join(path,'.published'),'w')
473
 
                pubfile.write("This directory is published\n")
474
 
                pubfile.close()
475
 
            else:
476
 
                raise ActionError("Can only publish directories")
477
 
    except OSError, e:
478
 
        raise ActionError("Directory could not be published")
479
 
 
480
 
def action_unpublish(req,fields):
481
 
    """Marks the folder as unpublished by removing a '.published' file in the 
482
 
    directory (if it exits). It does not change the permissions of the parent 
483
 
    directories.
484
 
 
485
 
    Reads fields: 'path'
486
 
    """
487
 
    paths = fields.getlist('path')
488
 
    if len(paths):
489
 
        paths = map(lambda path: actionpath_to_local(req, path), paths)
490
 
    else:
491
 
        paths = [studpath.url_to_jailpaths(req.path)[2]]
492
 
 
493
 
    try:
494
 
        for path in paths:
495
 
            if os.path.isdir(path):
496
 
                pubfile = os.path.join(path,'.published')
497
 
                if os.path.isfile(pubfile):
498
 
                    os.remove(pubfile)
499
 
            else:
500
 
                raise ActionError("Can only unpublish directories")
501
 
    except OSError, e:
502
 
        raise ActionError("Directory could not be unpublished")
503
 
 
 
460
    # Success: Clear the clipboard
 
461
    del session['clipboard']
 
462
    session.save()
504
463
 
505
464
def action_svnadd(req, fields):
506
465
    """Performs a "svn add" to each file specified.
551
510
    Reads fields: 'path'
552
511
    """
553
512
    paths = fields.getlist('path')
554
 
    if len(paths):
555
 
        paths = map(lambda path: actionpath_to_local(req, path), paths)
556
 
    else:
557
 
        paths = [studpath.url_to_jailpaths(req.path)[2]]
 
513
    paths = map(lambda path: actionpath_to_local(req, path), paths)
558
514
 
559
515
    try:
560
516
        for path in paths:
592
548
    except pysvn.ClientError:
593
549
        raise ActionError("One or more files could not be committed")
594
550
 
595
 
def action_svncheckout(req, fields):
596
 
    """Performs a "svn checkout" of each path specified.
597
 
 
598
 
    Reads fields: 'path'    (multiple)
599
 
    """
600
 
    paths = fields.getlist('path')
601
 
    if len(paths) != 2:
602
 
        raise ActionError("usage: svncheckout url local-path")
603
 
    url = conf.svn_addr + "/" + login + "/" + paths[0]
604
 
    local_path = actionpath_to_local(req, str(paths[1]))
605
 
    try:
606
 
        svnclient.callback_get_login = get_login
607
 
        svnclient.checkout(url, local_path, recurse=True)
608
 
    except pysvn.ClientError:
609
 
        raise ActionError("One or more files could not be checked out")
610
 
 
611
551
# Table of all action functions #
612
552
# Each function has the interface f(req, fields).
613
553
 
614
554
actions_table = {
615
555
    "remove" : action_remove,
616
556
    "move" : action_move,
617
 
    "mkdir" : action_mkdir,
618
557
    "putfile" : action_putfile,
619
558
    "putfiles" : action_putfiles,
 
559
 
 
560
    "copy" : action_copy,
 
561
    "cut" : action_cut,
620
562
    "paste" : action_paste,
621
 
    "publish" : action_publish,
622
 
    "unpublish" : action_unpublish,
623
563
 
624
564
    "svnadd" : action_svnadd,
625
565
    "svnupdate" : action_svnupdate,
627
567
    "svnpublish" : action_svnpublish,
628
568
    "svnunpublish" : action_svnunpublish,
629
569
    "svncommit" : action_svncommit,
630
 
    "svncheckout" : action_svncheckout,
631
570
}