Fixed a bug in Luminotes Desktop in which a backslash within a note was duplicated each time the note was saved.
This commit is contained in:
parent
e4104adb81
commit
d37422b592
2
NEWS
2
NEWS
|
@ -3,6 +3,8 @@
|
||||||
* Added a "start a new discussion" link to each discussion forum page.
|
* Added a "start a new discussion" link to each discussion forum page.
|
||||||
* Updated Luminotes Server INSTALL file with instructions for setting the
|
* Updated Luminotes Server INSTALL file with instructions for setting the
|
||||||
http_url configuration setting.
|
http_url configuration setting.
|
||||||
|
* Fixed a bug in Luminotes Desktop in which a backslash within a note was
|
||||||
|
duplicated each time the note was saved.
|
||||||
* Fixed a bug in which special characters in a customer's name prevented
|
* Fixed a bug in which special characters in a customer's name prevented
|
||||||
PayPal payments from going through properly.
|
PayPal payments from going through properly.
|
||||||
|
|
||||||
|
|
|
@ -174,6 +174,15 @@ class Database( object ):
|
||||||
except ImportError:
|
except ImportError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def unescape( self, sql_command ):
|
||||||
|
"""
|
||||||
|
For backends that don't treat backslashes specially, un-double all backslashes in the given
|
||||||
|
sql_command.
|
||||||
|
"""
|
||||||
|
if self.__backend == Persistent.SQLITE_BACKEND:
|
||||||
|
return sql_command.replace( "\\\\", "\\" )
|
||||||
|
return sql_command
|
||||||
|
|
||||||
@synchronized
|
@synchronized
|
||||||
def save( self, obj, commit = True ):
|
def save( self, obj, commit = True ):
|
||||||
"""
|
"""
|
||||||
|
@ -187,11 +196,11 @@ class Database( object ):
|
||||||
connection = self.get_connection()
|
connection = self.get_connection()
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
|
|
||||||
cursor.execute( obj.sql_exists() )
|
cursor.execute( self.unescape( obj.sql_exists() ) )
|
||||||
if cursor.fetchone():
|
if cursor.fetchone():
|
||||||
cursor.execute( obj.sql_update() )
|
cursor.execute( self.unescape( obj.sql_update() ) )
|
||||||
else:
|
else:
|
||||||
cursor.execute( obj.sql_create() )
|
cursor.execute( self.unescape( obj.sql_create() ) )
|
||||||
|
|
||||||
if isinstance( obj, self.CLASSES_NOT_TO_CACHE ):
|
if isinstance( obj, self.CLASSES_NOT_TO_CACHE ):
|
||||||
cache = None
|
cache = None
|
||||||
|
@ -285,7 +294,7 @@ class Database( object ):
|
||||||
connection = self.get_connection()
|
connection = self.get_connection()
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
|
|
||||||
cursor.execute( sql_command )
|
cursor.execute( self.unescape( sql_command ) )
|
||||||
|
|
||||||
row = self.__row_to_unicode( cursor.fetchone() )
|
row = self.__row_to_unicode( cursor.fetchone() )
|
||||||
if not row:
|
if not row:
|
||||||
|
@ -317,7 +326,7 @@ class Database( object ):
|
||||||
connection = self.get_connection()
|
connection = self.get_connection()
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
|
|
||||||
cursor.execute( sql_command )
|
cursor.execute( self.unescape( sql_command ) )
|
||||||
|
|
||||||
objects = []
|
objects = []
|
||||||
row = self.__row_to_unicode( cursor.fetchone() )
|
row = self.__row_to_unicode( cursor.fetchone() )
|
||||||
|
@ -352,7 +361,7 @@ class Database( object ):
|
||||||
connection = self.get_connection()
|
connection = self.get_connection()
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
|
|
||||||
cursor.execute( sql_command )
|
cursor.execute( self.unescape( sql_command ) )
|
||||||
|
|
||||||
if commit:
|
if commit:
|
||||||
connection.commit()
|
connection.commit()
|
||||||
|
@ -373,7 +382,7 @@ class Database( object ):
|
||||||
if self.__backend == Persistent.SQLITE_BACKEND:
|
if self.__backend == Persistent.SQLITE_BACKEND:
|
||||||
cursor.executescript( sql_commands )
|
cursor.executescript( sql_commands )
|
||||||
else:
|
else:
|
||||||
cursor.execute( sql_commands )
|
cursor.execute( self.unescape( sql_commands ) )
|
||||||
|
|
||||||
if commit:
|
if commit:
|
||||||
connection.commit()
|
connection.commit()
|
||||||
|
@ -430,15 +439,15 @@ class Database( object ):
|
||||||
# generate a random id, but on the off-chance that it collides with something else already in
|
# generate a random id, but on the off-chance that it collides with something else already in
|
||||||
# the database, try again
|
# the database, try again
|
||||||
next_id = Database.generate_id()
|
next_id = Database.generate_id()
|
||||||
cursor.execute( Object_type.sql_id_exists( next_id ) )
|
cursor.execute( self.unescape( Object_type.sql_id_exists( next_id ) ) )
|
||||||
|
|
||||||
while cursor.fetchone() is not None:
|
while cursor.fetchone() is not None:
|
||||||
next_id = Database.generate_id()
|
next_id = Database.generate_id()
|
||||||
cursor.execute( Object_type.sql_id_exists( next_id ) )
|
cursor.execute( self.unescape( Object_type.sql_id_exists( next_id ) ) )
|
||||||
|
|
||||||
# save a new object with the next_id to the database
|
# save a new object with the next_id to the database
|
||||||
obj = Object_type( next_id )
|
obj = Object_type( next_id )
|
||||||
cursor.execute( obj.sql_create() )
|
cursor.execute( self.unescape( obj.sql_create() ) )
|
||||||
|
|
||||||
if commit:
|
if commit:
|
||||||
connection.commit()
|
connection.commit()
|
||||||
|
|
|
@ -3363,6 +3363,44 @@ class Test_notebooks( Test_controller ):
|
||||||
assert note.contents == contents + " bar"
|
assert note.contents == contents + " bar"
|
||||||
assert note.user_id == self.user.object_id
|
assert note.user_id == self.user.object_id
|
||||||
|
|
||||||
|
def test_save_new_note_with_backslashes( self ):
|
||||||
|
self.login()
|
||||||
|
|
||||||
|
# save a completely new note
|
||||||
|
contents = r"<h3>newest title</h3>c:\windows\foo\bar\baz.exe"
|
||||||
|
new_note = Note.create( "55", contents )
|
||||||
|
previous_revision = new_note.revision
|
||||||
|
result = self.http_post( "/notebooks/save_note/", dict(
|
||||||
|
notebook_id = self.notebook.object_id,
|
||||||
|
note_id = new_note.object_id,
|
||||||
|
contents = new_note.contents,
|
||||||
|
startup = False,
|
||||||
|
previous_revision = None,
|
||||||
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
assert result[ "new_revision" ]
|
||||||
|
assert result[ "new_revision" ] != previous_revision
|
||||||
|
assert result[ "new_revision" ].user_id == self.user.object_id
|
||||||
|
assert result[ "new_revision" ].username == self.username
|
||||||
|
assert result[ "previous_revision" ] == None
|
||||||
|
user = self.database.load( User, self.user.object_id )
|
||||||
|
assert user.storage_bytes > 0
|
||||||
|
assert result[ "storage_bytes" ] == user.storage_bytes
|
||||||
|
assert result[ "rank" ] == 0.0
|
||||||
|
|
||||||
|
# make sure the new title is now loadable
|
||||||
|
result = self.http_post( "/notebooks/load_note_by_title/", dict(
|
||||||
|
notebook_id = self.notebook.object_id,
|
||||||
|
note_title = new_note.title,
|
||||||
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
note = result[ "note" ]
|
||||||
|
|
||||||
|
assert note.object_id == new_note.object_id
|
||||||
|
assert note.title == new_note.title
|
||||||
|
assert note.contents == contents
|
||||||
|
assert note.user_id == self.user.object_id
|
||||||
|
|
||||||
def test_save_two_new_notes( self, startup = False ):
|
def test_save_two_new_notes( self, startup = False ):
|
||||||
self.login()
|
self.login()
|
||||||
|
|
||||||
|
|
Reference in New Issue