diff --git a/NEWS b/NEWS
index a7d58e8..4d676c2 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,8 @@
+1.4.23:
+ * Enforcing maximum note length after stripping the note of any disallowed
+ HTML tags instead of before. This makes Luminotes work better when cutting
+ and pasting lots of text from MS Word.
+
1.4.22: August 1, 2008:
* Skipping clearing of messages/errors if they haven't been open long enough
to read.
diff --git a/controller/Validate.py b/controller/Validate.py
index 3030f46..1831d4e 100644
--- a/controller/Validate.py
+++ b/controller/Validate.py
@@ -94,17 +94,21 @@ class Valid_string( object ):
else:
self.message = u"must be at least %s characters long" % self.min
raise ValueError()
- elif self.max is not None and len( value ) > self.max:
- self.message = u"must be no longer than %s characters" % self.max
- raise ValueError()
# either escape all html completely or just clean up the html, stripping out everything that's
# not on a tag/attribute whitelist
if self.escape_html:
- return escape( value, quote = True )
+ value = escape( value, quote = True )
else:
cleaner = Html_cleaner()
- return cleaner.strip( value )
+ value = cleaner.strip( value )
+
+ # check for max length after cleaning html, as cleaning can reduce the html's size
+ if self.max is not None and len( value ) > self.max:
+ self.message = u"must be no longer than %s characters" % self.max
+ raise ValueError()
+
+ return value
def __demoronize( self, value ):
"""
diff --git a/controller/test/Test_notebooks.py b/controller/test/Test_notebooks.py
index 6bef94e..d37f20c 100644
--- a/controller/test/Test_notebooks.py
+++ b/controller/test/Test_notebooks.py
@@ -1725,12 +1725,14 @@ class Test_notebooks( Test_controller ):
def test_save_note_without_login( self, startup = False ):
# save over an existing note supplying new contents and a new title
+ previous_revision = self.note.revision
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 = startup,
+ previous_revision = previous_revision,
), session_id = self.session_id )
assert result.get( "error" )
@@ -1740,6 +1742,95 @@ class Test_notebooks( Test_controller ):
def test_save_startup_note_without_login( self ):
self.test_save_note_without_login( startup = True )
+ def test_save_note_too_long( self, startup = False ):
+ self.login()
+
+ # save over an existing note supplying new (too long) contents and a new title
+ previous_revision = self.note.revision
+ new_note_contents = u"new title
new blah" * 962
+ 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 = startup,
+ previous_revision = previous_revision,
+ ), session_id = self.session_id )
+
+ assert result.get( "error" )
+ user = self.database.load( User, self.user.object_id )
+ assert user.storage_bytes == 0
+
+ def test_save_note_too_long_before_cleaning( self, startup = False ):
+ self.login()
+
+ # save over an existing note supplying new contents and a new title. the contents
+ # should be too long before they're cleaned/stripped, but short enough after
+ previous_revision = self.note.revision
+ new_note_contents = u"new title
ha" * 962
+ 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 = startup,
+ previous_revision = previous_revision,
+ ), session_id = self.session_id )
+
+ assert result[ "new_revision" ]
+ assert result[ "new_revision" ].revision != previous_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 == previous_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
+
+ # make sure the old title can no longer be loaded
+ result = self.http_post( "/notebooks/load_note_by_title/", dict(
+ notebook_id = self.notebook.object_id,
+ note_title = "my title",
+ ), session_id = self.session_id )
+
+ note = result[ "note" ]
+ assert note == None
+
+ # 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 title",
+ ), session_id = self.session_id )
+
+ note = result[ "note" ]
+
+ assert note.object_id == self.note.object_id
+ assert note.title == "new title"
+ assert note.contents == new_note_contents.replace( u"", "" )
+ assert note.startup == startup
+ assert note.user_id == self.user.object_id
+
+ if startup:
+ assert note.rank == 0
+ else:
+ assert note.rank is None
+
+ # 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 == previous_revision
+ assert revisions[ 0 ].user_id == self.user.object_id
+ assert revisions[ 0 ].username == self.username
+ assert revisions[ 1 ].revision == current_revision
+ assert revisions[ 1 ].user_id == self.user.object_id
+ assert revisions[ 1 ].username == self.username
+
def test_save_deleted_note( self ):
self.login()
@@ -2098,12 +2189,14 @@ class Test_notebooks( Test_controller ):
self.login()
# save over an existing note supplying new contents and a new title
+ previous_revision = self.note.revision
new_note_contents = u"new title
new blah"
result = self.http_post( "/notebooks/save_note/", dict(
notebook_id = self.unknown_notebook_id,
note_id = self.note.object_id,
contents = new_note_contents,
startup = False,
+ previous_revision = previous_revision,
), session_id = self.session_id )
assert result.get( "error" )