diff --git a/controller/Notebooks.py b/controller/Notebooks.py index b2b7529..b1c778d 100644 --- a/controller/Notebooks.py +++ b/controller/Notebooks.py @@ -780,6 +780,9 @@ class Notebooks( object ): note = self.__database.load( Note, note_id ) + if not note: + raise Access_error() + # check whether the provided note contents have been changed since the previous revision def update_note( current_notebook, old_note, user ): # if the revision to revert to is already the newest revision, bail without updating the note diff --git a/controller/test/Test_notebooks.py b/controller/test/Test_notebooks.py index 16be830..6bef94e 100644 --- a/controller/test/Test_notebooks.py +++ b/controller/test/Test_notebooks.py @@ -2294,6 +2294,327 @@ class Test_notebooks( Test_controller ): def test_save_two_new_startup_notes( self ): self.test_save_two_new_notes( startup = True ) + def test_revert_note( self ): + self.login() + + # save over an existing note, supplying new contents and a new title + first_revision = self.note.revision + original_contents = self.note.contents + new_note_contents = u"

new title

new blah" + result = self.http_post( "/notebooks/save_note/", dict( + notebook_id = self.notebook.object_id, + note_id = self.note.object_id, + contents = new_note_contents, + startup = False, + previous_revision = first_revision, + ), session_id = self.session_id ) + + second_revision = result[ "new_revision" ].revision + + # revert the note to the earlier revision + result = self.http_post( "/notebooks/revert_note/", dict( + notebook_id = self.notebook.object_id, + note_id = self.note.object_id, + revision = first_revision, + ), session_id = self.session_id ) + + assert result[ "new_revision" ] + assert result[ "new_revision" ].revision != first_revision + assert result[ "new_revision" ].revision != second_revision + assert result[ "new_revision" ].user_id == self.user.object_id + assert result[ "new_revision" ].username == self.username + current_revision = result[ "new_revision" ].revision + assert result[ "previous_revision" ].revision == second_revision + assert result[ "previous_revision" ].user_id == self.user.object_id + assert result[ "previous_revision" ].username == self.username + user = self.database.load( User, self.user.object_id ) + assert user.storage_bytes > 0 + assert result[ "storage_bytes" ] == user.storage_bytes + assert result[ "contents" ] == original_contents + + # make sure that the correct revisions are returned and are in chronological order + result = self.http_post( "/notebooks/load_note_revisions/", dict( + notebook_id = self.notebook.object_id, + note_id = self.note.object_id, + ), session_id = self.session_id ) + + revisions = result[ "revisions" ] + assert revisions != None + assert len( revisions ) == 3 + assert revisions[ 0 ].revision == first_revision + assert revisions[ 0 ].user_id == self.user.object_id + assert revisions[ 0 ].username == self.username + assert revisions[ 1 ].revision == second_revision + assert revisions[ 1 ].user_id == self.user.object_id + assert revisions[ 1 ].username == self.username + assert revisions[ 2 ].revision == current_revision + assert revisions[ 2 ].user_id == self.user.object_id + assert revisions[ 2 ].username == self.username + + def test_revert_note_by_different_user( self ): + self.login() + + # save over an existing note, supplying new contents and a new title + first_revision = self.note.revision + original_contents = self.note.contents + new_note_contents = u"

new title

new blah" + result = self.http_post( "/notebooks/save_note/", dict( + notebook_id = self.notebook.object_id, + note_id = self.note.object_id, + contents = new_note_contents, + startup = False, + previous_revision = first_revision, + ), session_id = self.session_id ) + + second_revision = result[ "new_revision" ].revision + + self.login2() + + # as a different user, revert the note to the earlier revision + result = self.http_post( "/notebooks/revert_note/", dict( + notebook_id = self.notebook.object_id, + note_id = self.note.object_id, + revision = first_revision, + ), session_id = self.session_id ) + + assert result[ "new_revision" ] + assert result[ "new_revision" ].revision != first_revision + assert result[ "new_revision" ].revision != second_revision + assert result[ "new_revision" ].user_id == self.user2.object_id + assert result[ "new_revision" ].username == self.username2 + current_revision = result[ "new_revision" ].revision + assert result[ "previous_revision" ].revision == second_revision + assert result[ "previous_revision" ].user_id == self.user.object_id + assert result[ "previous_revision" ].username == self.username + user = self.database.load( User, self.user.object_id ) + assert user.storage_bytes > 0 + assert result[ "storage_bytes" ] == user.storage_bytes + assert result[ "contents" ] == original_contents + + # make sure that the correct revisions are returned and are in chronological order + result = self.http_post( "/notebooks/load_note_revisions/", dict( + notebook_id = self.notebook.object_id, + note_id = self.note.object_id, + ), session_id = self.session_id ) + + revisions = result[ "revisions" ] + assert revisions != None + assert len( revisions ) == 3 + assert revisions[ 0 ].revision == first_revision + assert revisions[ 0 ].user_id == self.user.object_id + assert revisions[ 0 ].username == self.username + assert revisions[ 1 ].revision == second_revision + assert revisions[ 1 ].user_id == self.user.object_id + assert revisions[ 1 ].username == self.username + assert revisions[ 2 ].revision == current_revision + assert revisions[ 2 ].user_id == self.user2.object_id + assert revisions[ 2 ].username == self.username2 + + def test_revert_note_without_login( self ): + self.login() + + # save over an existing note, supplying new contents and a new title + first_revision = self.note.revision + original_contents = self.note.contents + new_note_contents = u"

new title

new blah" + result = self.http_post( "/notebooks/save_note/", dict( + notebook_id = self.notebook.object_id, + note_id = self.note.object_id, + contents = new_note_contents, + startup = False, + previous_revision = first_revision, + ), session_id = self.session_id ) + + second_revision = result[ "new_revision" ].revision + + # revert the note to the earlier revision, but without logging in + result = self.http_post( "/notebooks/revert_note/", dict( + notebook_id = self.notebook.object_id, + note_id = self.note.object_id, + revision = first_revision, + ) ) + + assert result.get( "error" ) + + # make sure that a new revision wasn't saved + result = self.http_post( "/notebooks/load_note_revisions/", dict( + notebook_id = self.notebook.object_id, + note_id = self.note.object_id, + ), session_id = self.session_id ) + + revisions = result[ "revisions" ] + assert revisions != None + assert len( revisions ) == 2 + assert revisions[ 0 ].revision == first_revision + assert revisions[ 0 ].user_id == self.user.object_id + assert revisions[ 0 ].username == self.username + assert revisions[ 1 ].revision == second_revision + assert revisions[ 1 ].user_id == self.user.object_id + assert revisions[ 1 ].username == self.username + + def test_revert_deleted_note( self ): + self.login() + + # delete an existing note + first_revision = self.note.revision + result = self.http_post( "/notebooks/delete_note/", dict( + notebook_id = self.notebook.object_id, + note_id = self.note.object_id, + ), session_id = self.session_id ) + + note = self.database.load( Note, self.note.object_id ) + second_revision = note.revision + + # revert the note to the earlier, non-deleted revision + result = self.http_post( "/notebooks/revert_note/", dict( + notebook_id = self.notebook.object_id, + note_id = self.note.object_id, + revision = first_revision, + ), session_id = self.session_id ) + + assert result[ "new_revision" ] + assert result[ "new_revision" ].revision != first_revision + assert result[ "new_revision" ].revision != second_revision + assert result[ "new_revision" ].user_id == self.user.object_id + assert result[ "new_revision" ].username == self.username + current_revision = result[ "new_revision" ].revision + assert result[ "previous_revision" ].revision == second_revision + assert result[ "previous_revision" ].user_id == self.user.object_id + assert result[ "previous_revision" ].username == self.username + user = self.database.load( User, self.user.object_id ) + assert user.storage_bytes > 0 + assert result[ "storage_bytes" ] == user.storage_bytes + assert result[ "contents" ] == self.note.contents + + # make sure that the reverted note is not in the trash anymore + note = self.database.load( Note, self.note.object_id ) + assert note.notebook_id == self.note.notebook_id + + # make sure that the correct revisions are returned and are in chronological order + result = self.http_post( "/notebooks/load_note_revisions/", dict( + notebook_id = self.notebook.object_id, + note_id = self.note.object_id, + ), session_id = self.session_id ) + + revisions = result[ "revisions" ] + assert revisions != None + assert len( revisions ) == 3 + assert revisions[ 0 ].revision == first_revision + assert revisions[ 0 ].user_id == self.user.object_id + assert revisions[ 0 ].username == self.username + assert revisions[ 1 ].revision == second_revision + assert revisions[ 1 ].user_id == self.user.object_id + assert revisions[ 1 ].username == self.username + assert revisions[ 2 ].revision == current_revision + assert revisions[ 2 ].user_id == self.user.object_id + assert revisions[ 2 ].username == self.username + + def test_revert_note_with_unknown_notebook( self ): + self.login() + + # save over an existing note, supplying new contents and a new title + first_revision = self.note.revision + original_contents = self.note.contents + new_note_contents = u"

new title

new blah" + result = self.http_post( "/notebooks/save_note/", dict( + notebook_id = self.notebook.object_id, + note_id = self.note.object_id, + contents = new_note_contents, + startup = False, + previous_revision = first_revision, + ), session_id = self.session_id ) + + second_revision = result[ "new_revision" ].revision + + # revert the note to the earlier revision, but with an unknown notebook + result = self.http_post( "/notebooks/revert_note/", dict( + notebook_id = self.unknown_notebook_id, + note_id = self.note.object_id, + revision = first_revision, + ), session_id = self.session_id ) + + assert result.get( "error" ) + + # make sure that a new revision wasn't saved + result = self.http_post( "/notebooks/load_note_revisions/", dict( + notebook_id = self.notebook.object_id, + note_id = self.note.object_id, + ), session_id = self.session_id ) + + revisions = result[ "revisions" ] + assert revisions != None + assert len( revisions ) == 2 + assert revisions[ 0 ].revision == first_revision + assert revisions[ 0 ].user_id == self.user.object_id + assert revisions[ 0 ].username == self.username + assert revisions[ 1 ].revision == second_revision + assert revisions[ 1 ].user_id == self.user.object_id + assert revisions[ 1 ].username == self.username + + def test_revert_unknown_note( self ): + self.login() + + # revert a new (unsaved) note + new_note = Note.create( "55", u"

newest title

foo" ) + result = self.http_post( "/notebooks/revert_note/", dict( + notebook_id = self.notebook.object_id, + note_id = new_note.object_id, + revision = new_note.revision, + ), session_id = self.session_id ) + + assert "access" in result.get( "error" ) + + note = self.database.load( Note, new_note.object_id ) + assert note == None + + def test_revert_note_to_newest_revision( self ): + self.login() + + # save over an existing note, supplying new contents and a new title + first_revision = self.note.revision + original_contents = self.note.contents + new_note_contents = u"

new title

new blah" + result = self.http_post( "/notebooks/save_note/", dict( + notebook_id = self.notebook.object_id, + note_id = self.note.object_id, + contents = new_note_contents, + startup = False, + previous_revision = first_revision, + ), session_id = self.session_id ) + + second_revision = result[ "new_revision" ].revision + + # "revert" the note to the most recent revision + result = self.http_post( "/notebooks/revert_note/", dict( + notebook_id = self.notebook.object_id, + note_id = self.note.object_id, + revision = second_revision, + ), session_id = self.session_id ) + + assert result[ "new_revision" ] is None + assert result[ "previous_revision" ].revision == second_revision + assert result[ "previous_revision" ].user_id == self.user.object_id + assert result[ "previous_revision" ].username == self.username + user = self.database.load( User, self.user.object_id ) + assert user.storage_bytes > 0 + assert result[ "contents" ] == new_note_contents + + # make sure that the correct revisions are returned and are in chronological order + result = self.http_post( "/notebooks/load_note_revisions/", dict( + notebook_id = self.notebook.object_id, + note_id = self.note.object_id, + ), session_id = self.session_id ) + + revisions = result[ "revisions" ] + assert revisions != None + assert len( revisions ) == 2 + assert revisions[ 0 ].revision == first_revision + assert revisions[ 0 ].user_id == self.user.object_id + assert revisions[ 0 ].username == self.username + assert revisions[ 1 ].revision == second_revision + assert revisions[ 1 ].user_id == self.user.object_id + assert revisions[ 1 ].username == self.username + def test_delete_note( self ): self.login()