witten
/
luminotes
Archived
1
0
Fork 0

File renaming works. Unit tests still pending.

File deleting implemented. Testing and unit tests still pending.
Now releasing session lock at top of download() to prevent session deadlocks.
This commit is contained in:
Dan Helfman 2008-02-20 23:25:13 +00:00
parent 1f223089df
commit eb18b6020d
3 changed files with 113 additions and 13 deletions

View File

@ -232,6 +232,10 @@ class Files( object ):
@return: file data
@raise Access_error: the current user doesn't have access to the notebook that the file is in
"""
# release the session lock before beginning to stream the download. otherwise, if the
# upload is cancelled before it's done, the lock won't be released
cherrypy.session.release_lock()
db_file = self.__database.load( File, file_id )
if not db_file or not self.__users.check_access( user_id, db_file.notebook_id ):
@ -431,8 +435,8 @@ class Files( object ):
)
def stats( self, file_id, user_id = None ):
"""
Return information on a file that has been completely uploaded and is stored in the database.
Also return the user's current storage utilization in bytes.
Return information on a file that has been completely uploaded with its metadata stored in the
database. Also return the user's current storage utilization in bytes.
@type file_id: unicode
@param file_id: id of the file to report on
@ -442,7 +446,7 @@ class Files( object ):
@return: {
'filename': filename,
'size_bytes': filesize,
'storage_bytes': current sturage usage by user
'storage_bytes': current storage usage by user
}
@raise Access_error: the current user doesn't have access to the notebook that the file is in
"""
@ -461,8 +465,70 @@ class Files( object ):
storage_bytes = user.storage_bytes,
)
def delete( self, file_id ):
pass # TODO
@expose( view = Json )
@grab_user_id
@validate(
file_id = Valid_id(),
user_id = Valid_id( none_okay = True ),
)
def delete( self, file_id, user_id = None ):
"""
Delete a file that has been completely uploaded, removing both its metadata from the database
and its data from the filesystem. Return the user's current storage utilization in bytes.
def rename( self, file_id, filename ):
pass # TODO
@type file_id: unicode
@param file_id: id of the file to delete
@type user_id: unicode or NoneType
@param user_id: id of current logged-in user (if any)
@rtype: dict
@return: {
'storage_bytes': current storage usage by user
}
@raise Access_error: the current user doesn't have access to the notebook that the file is in
"""
db_file = self.__database.load( File, file_id )
if not db_file or not self.__users.check_access( user_id, db_file.notebook_id, read_write = True ):
raise Access_error()
user = self.__database.load( User, user_id )
if not user:
raise Access_error()
self.__database.execute( db_file.sql_delete() )
os.remove( Upload_file.make_server_filename( file_id ) )
return dict(
storage_bytes = user.storage_bytes,
)
@expose( view = Json )
@grab_user_id
@validate(
file_id = Valid_id(),
filename = unicode,
user_id = Valid_id( none_okay = True ),
)
def rename( self, file_id, filename, user_id = None ):
"""
Rename a file that has been completely uploaded.
@type file_id: unicode
@param file_id: id of the file to delete
@type filename: unicode
@param filename: new name for the file
@type user_id: unicode or NoneType
@param user_id: id of current logged-in user (if any)
@rtype: dict
@return: {}
@raise Access_error: the current user doesn't have access to the notebook that the file is in
"""
db_file = self.__database.load( File, file_id )
if not db_file or not self.__users.check_access( user_id, db_file.notebook_id, read_write = True ):
raise Access_error()
db_file.filename = filename
self.__database.save( db_file )
return dict()

View File

@ -95,6 +95,9 @@ class File( Persistent ):
( quote( self.revision ), quote( self.__notebook_id ), quote( self.__note_id ), quote( self.__filename ),
self.__size_bytes or 'null', quote( self.__content_type ), quote( self.object_id ) )
def sql_delete( self ):
return "delete from file where file_id = %s;" % quote( self.object_id )
def to_dict( self ):
d = Persistent.to_dict( self )
d.update( dict(
@ -107,8 +110,11 @@ class File( Persistent ):
return d
def __set_filename( self, filename ):
self.__filename = filename
notebook_id = property( lambda self: self.__notebook_id )
note_id = property( lambda self: self.__note_id )
filename = property( lambda self: self.__filename )
filename = property( lambda self: self.__filename, __set_filename )
size_bytes = property( lambda self: self.__size_bytes )
content_type = property( lambda self: self.__content_type )

View File

@ -2395,27 +2395,40 @@ function File_link_pulldown( wiki, notebook_id, invoker, editor, link ) {
connect( this.filename_field, "onblur", function ( event ) { self.filename_field_changed( event ); } );
connect( this.filename_field, "onkeydown", function ( event ) { self.filename_field_key_pressed( event ); } );
var delete_button = createDOM( "input", {
"type": "button",
"class": "button",
"value": "delete",
"title": "delete file"
} );
appendChildNodes( this.div, createDOM( "span", { "class": "field_label" }, "filename: " ) );
appendChildNodes( this.div, this.filename_field );
appendChildNodes( this.div, this.file_size );
appendChildNodes( this.div, " " );
appendChildNodes( this.div, delete_button );
var query = parse_query( link );
var file_id = query.file_id;
this.file_id = query.file_id;
// get the file's name and size from the server
this.invoker.invoke(
"/files/stats", "GET", {
"file_id": file_id
"file_id": this.file_id
},
function ( result ) {
// if the user has already started typing something, don't overwrite it
if ( self.filename_field.value.length == 0 )
if ( self.filename_field.value.length == 0 ) {
self.filename_field.value = result.filename;
self.previous_filename = result.filename;
}
replaceChildNodes( self.file_size, bytes_to_megabytes( result.size_bytes, true ) );
self.wiki.display_storage_usage( result.storage_bytes );
}
);
connect( delete_button, "onclick", function ( event ) { self.delete_button_clicked( event ); } );
// FIXME: when this is called, the text cursor moves to an unexpected location
editor.focus();
}
@ -2437,11 +2450,15 @@ File_link_pulldown.prototype.filename_field_changed = function ( event ) {
if ( filename == this.previous_filename )
return;
var title = link_title( this.link );
if ( title == this.previous_filename )
replaceChildNodes( this.link, this.editor.document.createTextNode( filename ) );
this.previous_filename = filename;
this.invoker.invoke(
"/files/rename", "GET", {
"file_id": file_id,
"/files/rename", "POST", {
"file_id": this.file_id,
"filename": filename
}
);
@ -2456,6 +2473,17 @@ File_link_pulldown.prototype.filename_field_key_pressed = function ( event ) {
}
}
File_link_pulldown.prototype.delete_button_clicked = function ( event ) {
var self = this;
this.invoker.invoke(
"/files/delete", "POST", {
"file_id": this.file_id
},
function ( result ) { self.wiki.display_storage_usage( result.storage_bytes ); }
);
}
File_link_pulldown.prototype.update_position = function ( anchor, relative_to ) {
Pulldown.prototype.update_position.call( this, anchor, relative_to );
}