Implemented delete forever for notebooks. And unit tests!
This commit is contained in:
parent
7bd83199a1
commit
eec5ef6411
|
@ -835,7 +835,6 @@ class Notebooks( object ):
|
||||||
|
|
||||||
notebook = self.__database.load( Notebook, notebook_id )
|
notebook = self.__database.load( Notebook, notebook_id )
|
||||||
|
|
||||||
# TODO: maybe if notebook.deleted is already True, then the notebook should be "deleted forever"
|
|
||||||
if not notebook:
|
if not notebook:
|
||||||
raise Access_error()
|
raise Access_error()
|
||||||
|
|
||||||
|
@ -857,6 +856,47 @@ class Notebooks( object ):
|
||||||
redirect = u"/notebooks/%s?deleted_id=%s" % ( remaining_notebook.object_id, notebook.object_id ),
|
redirect = u"/notebooks/%s?deleted_id=%s" % ( remaining_notebook.object_id, notebook.object_id ),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@expose( view = Json )
|
||||||
|
@grab_user_id
|
||||||
|
@validate(
|
||||||
|
notebook_id = Valid_id(),
|
||||||
|
user_id = Valid_id( none_okay = True ),
|
||||||
|
)
|
||||||
|
def delete_forever( self, notebook_id, user_id ):
|
||||||
|
"""
|
||||||
|
Delete the given notebook permanently (by simply revoking the user's access to it).
|
||||||
|
|
||||||
|
@type notebook_id: unicode
|
||||||
|
@param notebook_id: id of notebook to delete
|
||||||
|
@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 given notebook
|
||||||
|
@raise Validation_error: one of the arguments is invalid
|
||||||
|
"""
|
||||||
|
if user_id is None:
|
||||||
|
raise Access_error()
|
||||||
|
|
||||||
|
user = self.__database.load( User, user_id )
|
||||||
|
|
||||||
|
if not self.__users.check_access( user_id, notebook_id, read_write = True ):
|
||||||
|
raise Access_error()
|
||||||
|
|
||||||
|
notebook = self.__database.load( Notebook, notebook_id )
|
||||||
|
|
||||||
|
if not notebook:
|
||||||
|
raise Access_error()
|
||||||
|
|
||||||
|
# prevent deletion of a trash notebook directly
|
||||||
|
if notebook.name == u"trash":
|
||||||
|
raise Access_error()
|
||||||
|
|
||||||
|
self.__database.execute( user.sql_remove_notebook( notebook_id ), commit = False )
|
||||||
|
self.__database.commit()
|
||||||
|
|
||||||
|
return dict()
|
||||||
|
|
||||||
@expose( view = Json )
|
@expose( view = Json )
|
||||||
@grab_user_id
|
@grab_user_id
|
||||||
@validate(
|
@validate(
|
||||||
|
|
|
@ -26,6 +26,15 @@ class Test_controller( object ):
|
||||||
User.sql_save_notebook = lambda self, notebook_id, read_write = False: \
|
User.sql_save_notebook = lambda self, notebook_id, read_write = False: \
|
||||||
lambda database: sql_save_notebook( self, notebook_id, read_write, database )
|
lambda database: sql_save_notebook( self, notebook_id, read_write, database )
|
||||||
|
|
||||||
|
def sql_remove_notebook( self, notebook_id, database ):
|
||||||
|
if self.object_id in database.user_notebook:
|
||||||
|
for access_tuple in database.user_notebook[ self.object_id ]:
|
||||||
|
if access_tuple[ 0 ] == notebook_id:
|
||||||
|
database.user_notebook[ self.object_id ].remove( access_tuple )
|
||||||
|
|
||||||
|
User.sql_remove_notebook = lambda self, notebook_id: \
|
||||||
|
lambda database: sql_remove_notebook( self, notebook_id, database )
|
||||||
|
|
||||||
def sql_load_notebooks( self, parents_only, undeleted_only, database ):
|
def sql_load_notebooks( self, parents_only, undeleted_only, database ):
|
||||||
notebooks = []
|
notebooks = []
|
||||||
notebook_tuples = database.user_notebook.get( self.object_id )
|
notebook_tuples = database.user_notebook.get( self.object_id )
|
||||||
|
|
|
@ -1805,7 +1805,26 @@ class Test_notebooks( Test_controller ):
|
||||||
def test_contents_after_delete( self ):
|
def test_contents_after_delete( self ):
|
||||||
self.login()
|
self.login()
|
||||||
|
|
||||||
result = self.http_post( "/notebooks/delete", dict(
|
self.http_post( "/notebooks/delete", dict(
|
||||||
|
notebook_id = self.notebook.object_id,
|
||||||
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
result = cherrypy.root.notebooks.contents(
|
||||||
|
notebook_id = self.notebook.object_id,
|
||||||
|
user_id = self.user.object_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
notebook = result[ "notebook" ]
|
||||||
|
assert notebook.deleted == True
|
||||||
|
|
||||||
|
def test_contents_after_delete_twice( self ):
|
||||||
|
self.login()
|
||||||
|
|
||||||
|
self.http_post( "/notebooks/delete", dict(
|
||||||
|
notebook_id = self.notebook.object_id,
|
||||||
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
self.http_post( "/notebooks/delete", dict(
|
||||||
notebook_id = self.notebook.object_id,
|
notebook_id = self.notebook.object_id,
|
||||||
), session_id = self.session_id )
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
@ -1833,6 +1852,74 @@ class Test_notebooks( Test_controller ):
|
||||||
|
|
||||||
assert u"error" in result
|
assert u"error" in result
|
||||||
|
|
||||||
|
def test_delete_forever( self ):
|
||||||
|
self.login()
|
||||||
|
|
||||||
|
result = self.http_post( "/notebooks/delete_forever", dict(
|
||||||
|
notebook_id = self.notebook.object_id,
|
||||||
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
assert u"error" not in result
|
||||||
|
|
||||||
|
@raises( Access_error )
|
||||||
|
def test_contents_after_delete_forever( self ):
|
||||||
|
self.login()
|
||||||
|
|
||||||
|
self.http_post( "/notebooks/delete_forever", dict(
|
||||||
|
notebook_id = self.notebook.object_id,
|
||||||
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
result = cherrypy.root.notebooks.contents(
|
||||||
|
notebook_id = self.notebook.object_id,
|
||||||
|
user_id = self.user.object_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_delete_then_delete_forever( self ):
|
||||||
|
self.login()
|
||||||
|
|
||||||
|
result = self.http_post( "/notebooks/delete", dict(
|
||||||
|
notebook_id = self.notebook.object_id,
|
||||||
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
result = self.http_post( "/notebooks/delete_forever", dict(
|
||||||
|
notebook_id = self.notebook.object_id,
|
||||||
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
assert u"error" not in result
|
||||||
|
|
||||||
|
@raises( Access_error )
|
||||||
|
def test_contents_after_delete_then_delete_forever( self ):
|
||||||
|
self.login()
|
||||||
|
|
||||||
|
self.http_post( "/notebooks/delete", dict(
|
||||||
|
notebook_id = self.notebook.object_id,
|
||||||
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
self.http_post( "/notebooks/delete_forever", dict(
|
||||||
|
notebook_id = self.notebook.object_id,
|
||||||
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
result = cherrypy.root.notebooks.contents(
|
||||||
|
notebook_id = self.notebook.object_id,
|
||||||
|
user_id = self.user.object_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_delete_forever_without_login( self ):
|
||||||
|
result = self.http_post( "/notebooks/delete_forever", dict(
|
||||||
|
notebook_id = self.notebook.object_id,
|
||||||
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
assert result[ u"error" ]
|
||||||
|
|
||||||
|
def test_delete_forever_trash( self ):
|
||||||
|
self.login()
|
||||||
|
|
||||||
|
result = self.http_post( "/notebooks/delete_forever", dict(
|
||||||
|
notebook_id = self.notebook.trash_id,
|
||||||
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
assert u"error" in result
|
||||||
|
|
||||||
def test_undelete( self ):
|
def test_undelete( self ):
|
||||||
self.login()
|
self.login()
|
||||||
|
|
||||||
|
|
|
@ -156,6 +156,13 @@ class User( Persistent ):
|
||||||
"insert into user_notebook ( user_id, notebook_id, read_write ) values " + \
|
"insert into user_notebook ( user_id, notebook_id, read_write ) values " + \
|
||||||
"( %s, %s, %s );" % ( quote( self.object_id ), quote( notebook_id ), quote( read_write and 't' or 'f' ) )
|
"( %s, %s, %s );" % ( quote( self.object_id ), quote( notebook_id ), quote( read_write and 't' or 'f' ) )
|
||||||
|
|
||||||
|
def sql_remove_notebook( self, notebook_id ):
|
||||||
|
"""
|
||||||
|
Return a SQL string to remove this user's access to a particular notebook.
|
||||||
|
"""
|
||||||
|
return \
|
||||||
|
"delete from user_notebook where user_id = %s and notebook_id = %s;" % ( quote( self.object_id ), quote( notebook_id ) )
|
||||||
|
|
||||||
def sql_has_access( self, notebook_id, read_write = False ):
|
def sql_has_access( self, notebook_id, read_write = False ):
|
||||||
"""
|
"""
|
||||||
Return a SQL string to determine whether this user has access to the given notebook.
|
Return a SQL string to determine whether this user has access to the given notebook.
|
||||||
|
|
|
@ -185,7 +185,7 @@ Wiki.prototype.populate = function ( startup_notes, current_notes, note_read_wri
|
||||||
connect_undelete( notebook.object_id );
|
connect_undelete( notebook.object_id );
|
||||||
|
|
||||||
appendChildNodes( deleted_notebooks, createDOM( "div",
|
appendChildNodes( deleted_notebooks, createDOM( "div",
|
||||||
{ "id": "deleted_notebook_" + notebook.object_id },
|
{ "id": "deleted_notebook_" + notebook.object_id, "class": "deleted_notebook_item" },
|
||||||
createDOM( "span", {}, delete_button ),
|
createDOM( "span", {}, delete_button ),
|
||||||
createDOM( "span", {}, undelete_button ),
|
createDOM( "span", {}, undelete_button ),
|
||||||
createDOM( "span", {}, notebook.name )
|
createDOM( "span", {}, notebook.name )
|
||||||
|
@ -304,9 +304,9 @@ Wiki.prototype.populate = function ( startup_notes, current_notes, note_read_wri
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
var rename_notebook_link = getElement( "delete_notebook_link" );
|
var delete_notebook_link = getElement( "delete_notebook_link" );
|
||||||
if ( rename_notebook_link ) {
|
if ( delete_notebook_link ) {
|
||||||
connect( rename_notebook_link, "onclick", function ( event ) {
|
connect( delete_notebook_link, "onclick", function ( event ) {
|
||||||
self.delete_notebook();
|
self.delete_notebook();
|
||||||
event.stop();
|
event.stop();
|
||||||
} );
|
} );
|
||||||
|
@ -1425,7 +1425,6 @@ Wiki.prototype.create_all_notes_link = function ( note_id, note_title ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Wiki.prototype.start_notebook_rename = function () {
|
Wiki.prototype.start_notebook_rename = function () {
|
||||||
this.clear_messages();
|
|
||||||
this.clear_pulldowns();
|
this.clear_pulldowns();
|
||||||
|
|
||||||
// if a renaming is already in progress, end the renaming instead of starting one
|
// if a renaming is already in progress, end the renaming instead of starting one
|
||||||
|
@ -1539,7 +1538,11 @@ Wiki.prototype.delete_notebook_forever = function ( event, notebook_id ) {
|
||||||
|
|
||||||
removeElement( deleted_notebook_node );
|
removeElement( deleted_notebook_node );
|
||||||
|
|
||||||
this.invoker.invoke( "/notebooks/delete", "POST", {
|
var items = getElementsByTagAndClassName( "div", "deleted_notebook_item" );
|
||||||
|
if ( items.length == 0 )
|
||||||
|
removeElement( "deleted_notebooks" );
|
||||||
|
|
||||||
|
this.invoker.invoke( "/notebooks/delete_forever", "POST", {
|
||||||
"notebook_id": notebook_id
|
"notebook_id": notebook_id
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
|
Reference in New Issue
Block a user