* make a User_revision object containing a revision timestamp, user_id, username
* change controller.Notebooks.load_note_revisions() to select and return User_revision objects * change controller.Notebooks.save_note() to use User_revision objects for new_revision and previous_revision as well * update client to deal with new load_note_revisions() return values (make sure all uses of revisions_list are updated) * update client to deal with new new_revision/previous_revision * update changes pulldown to show username along with each timestamp * update model.Invite to load redeemed_username along with redeemed_user_id * display the redeemed username next to each email address in the "share this notebook" note
This commit is contained in:
parent
e086114478
commit
5520fe5892
4
NEWS
4
NEWS
|
@ -1,5 +1,7 @@
|
||||||
1.1.0: January ??, 2007
|
1.1.0: January ??, 2007
|
||||||
*
|
* Ability to invite people to your notebook as a collaborator or owner.
|
||||||
|
* Fixed bug where passwords with special characters broke password hashing.
|
||||||
|
* Fixed bug where link info box summaries sometimes contained HTML tags.
|
||||||
|
|
||||||
1.0.4: December 30, 2007
|
1.0.4: December 30, 2007
|
||||||
* Ability to invite people to view your notebook.
|
* Ability to invite people to view your notebook.
|
||||||
|
|
|
@ -11,6 +11,7 @@ from model.Notebook import Notebook
|
||||||
from model.Note import Note
|
from model.Note import Note
|
||||||
from model.Invite import Invite
|
from model.Invite import Invite
|
||||||
from model.User import User
|
from model.User import User
|
||||||
|
from model.User_revision import User_revision
|
||||||
from view.Main_page import Main_page
|
from view.Main_page import Main_page
|
||||||
from view.Json import Json
|
from view.Json import Json
|
||||||
from view.Html_file import Html_file
|
from view.Html_file import Html_file
|
||||||
|
@ -374,7 +375,7 @@ class Notebooks( object ):
|
||||||
@type user_id: unicode or NoneType
|
@type user_id: unicode or NoneType
|
||||||
@param user_id: id of current logged-in user (if any), determined by @grab_user_id
|
@param user_id: id of current logged-in user (if any), determined by @grab_user_id
|
||||||
@rtype: json dict
|
@rtype: json dict
|
||||||
@return: { 'revisions': revisionslist or None }
|
@return: { 'revisions': userrevisionlist or None }
|
||||||
@raise Access_error: the current user doesn't have access to the given notebook or note
|
@raise Access_error: the current user doesn't have access to the given notebook or note
|
||||||
@raise Validation_error: one of the arguments is invalid
|
@raise Validation_error: one of the arguments is invalid
|
||||||
"""
|
"""
|
||||||
|
@ -398,7 +399,7 @@ class Notebooks( object ):
|
||||||
|
|
||||||
raise Access_error()
|
raise Access_error()
|
||||||
|
|
||||||
revisions = self.__database.select_many( unicode, note.sql_load_revisions() )
|
revisions = self.__database.select_many( User_revision, note.sql_load_revisions() )
|
||||||
else:
|
else:
|
||||||
revisions = None
|
revisions = None
|
||||||
|
|
||||||
|
@ -438,8 +439,8 @@ class Notebooks( object ):
|
||||||
@param user_id: id of current logged-in user (if any), determined by @grab_user_id
|
@param user_id: id of current logged-in user (if any), determined by @grab_user_id
|
||||||
@rtype: json dict
|
@rtype: json dict
|
||||||
@return: {
|
@return: {
|
||||||
'new_revision': new revision of saved note, or None if nothing was saved,
|
'new_revision': User_revision of saved note, or None if nothing was saved
|
||||||
'previous_revision': revision immediately before new_revision, or None if the note is new
|
'previous_revision': User_revision immediately before new_revision, or None if the note is new
|
||||||
'storage_bytes': current storage usage by user,
|
'storage_bytes': current storage usage by user,
|
||||||
}
|
}
|
||||||
@raise Access_error: the current user doesn't have access to the given notebook
|
@raise Access_error: the current user doesn't have access to the given notebook
|
||||||
|
@ -448,15 +449,16 @@ class Notebooks( object ):
|
||||||
if not self.__users.check_access( user_id, notebook_id, read_write = True ):
|
if not self.__users.check_access( user_id, notebook_id, read_write = True ):
|
||||||
raise Access_error()
|
raise Access_error()
|
||||||
|
|
||||||
|
user = self.__database.load( User, user_id )
|
||||||
notebook = self.__database.load( Notebook, notebook_id )
|
notebook = self.__database.load( Notebook, notebook_id )
|
||||||
|
|
||||||
if not notebook:
|
if not user or not notebook:
|
||||||
raise Access_error()
|
raise Access_error()
|
||||||
|
|
||||||
note = self.__database.load( Note, note_id )
|
note = self.__database.load( Note, note_id )
|
||||||
|
|
||||||
# check whether the provided note contents have been changed since the previous revision
|
# check whether the provided note contents have been changed since the previous revision
|
||||||
def update_note( current_notebook, old_note, startup, user_id ):
|
def update_note( current_notebook, old_note, startup, user ):
|
||||||
# the note hasn't been changed, so bail without updating it
|
# the note hasn't been changed, so bail without updating it
|
||||||
if contents.replace( u"\n", u"" ) == old_note.contents.replace( u"\n", "" ) and startup == old_note.startup:
|
if contents.replace( u"\n", u"" ) == old_note.contents.replace( u"\n", "" ) and startup == old_note.startup:
|
||||||
new_revision = None
|
new_revision = None
|
||||||
|
@ -469,9 +471,9 @@ class Notebooks( object ):
|
||||||
note.rank = self.__database.select_one( float, notebook.sql_highest_rank() ) + 1
|
note.rank = self.__database.select_one( float, notebook.sql_highest_rank() ) + 1
|
||||||
else:
|
else:
|
||||||
note.rank = None
|
note.rank = None
|
||||||
note.user_id = user_id
|
note.user_id = user.object_id
|
||||||
|
|
||||||
new_revision = note.revision
|
new_revision = User_revision( note.revision, note.user_id, user.username )
|
||||||
|
|
||||||
return new_revision
|
return new_revision
|
||||||
|
|
||||||
|
@ -479,19 +481,21 @@ class Notebooks( object ):
|
||||||
if note and note.notebook_id == notebook.object_id:
|
if note and note.notebook_id == notebook.object_id:
|
||||||
old_note = self.__database.load( Note, note_id, previous_revision )
|
old_note = self.__database.load( Note, note_id, previous_revision )
|
||||||
|
|
||||||
previous_revision = note.revision
|
previous_user = self.__database.load( User, note.user_id )
|
||||||
new_revision = update_note( notebook, old_note, startup, user_id )
|
previous_revision = User_revision( note.revision, note.user_id, previous_user and previous_user.username or None )
|
||||||
|
new_revision = update_note( notebook, old_note, startup, user )
|
||||||
|
|
||||||
# the note is not already in the given notebook, so look for it in the trash
|
# the note is not already in the given notebook, so look for it in the trash
|
||||||
elif note and notebook.trash_id and note.notebook_id == notebook.trash_id:
|
elif note and notebook.trash_id and note.notebook_id == notebook.trash_id:
|
||||||
old_note = self.__database.load( Note, note_id, previous_revision )
|
old_note = self.__database.load( Note, note_id, previous_revision )
|
||||||
|
|
||||||
# undelete the note, putting it back in the given notebook
|
# undelete the note, putting it back in the given notebook
|
||||||
previous_revision = note.revision
|
previous_user = self.__database.load( User, note.user_id )
|
||||||
|
previous_revision = User_revision( note.revision, note.user_id, previous_user and previous_user.username or None )
|
||||||
note.notebook_id = notebook.object_id
|
note.notebook_id = notebook.object_id
|
||||||
note.deleted_from_id = None
|
note.deleted_from_id = None
|
||||||
|
|
||||||
new_revision = update_note( notebook, old_note, startup, user_id )
|
new_revision = update_note( notebook, old_note, startup, user )
|
||||||
# otherwise, create a new note
|
# otherwise, create a new note
|
||||||
else:
|
else:
|
||||||
if startup:
|
if startup:
|
||||||
|
@ -501,7 +505,7 @@ class Notebooks( object ):
|
||||||
|
|
||||||
previous_revision = None
|
previous_revision = None
|
||||||
note = Note.create( note_id, contents, notebook_id = notebook.object_id, startup = startup, rank = rank, user_id = user_id )
|
note = Note.create( note_id, contents, notebook_id = notebook.object_id, startup = startup, rank = rank, user_id = user_id )
|
||||||
new_revision = note.revision
|
new_revision = User_revision( note.revision, note.user_id, user.username )
|
||||||
|
|
||||||
if new_revision:
|
if new_revision:
|
||||||
self.__database.save( note, commit = False )
|
self.__database.save( note, commit = False )
|
||||||
|
|
|
@ -13,6 +13,7 @@ class Test_controller( object ):
|
||||||
from model.Notebook import Notebook
|
from model.Notebook import Notebook
|
||||||
from model.Note import Note
|
from model.Note import Note
|
||||||
from model.Invite import Invite
|
from model.Invite import Invite
|
||||||
|
from model.User_revision import User_revision
|
||||||
|
|
||||||
# Since Stub_database isn't a real database and doesn't know SQL, replace some of the
|
# Since Stub_database isn't a real database and doesn't know SQL, replace some of the
|
||||||
# SQL-returning methods in User, Note, and Notebook to return functions that manipulate data in
|
# SQL-returning methods in User, Note, and Notebook to return functions that manipulate data in
|
||||||
|
@ -141,8 +142,19 @@ class Test_controller( object ):
|
||||||
def sql_load_revisions( self, database ):
|
def sql_load_revisions( self, database ):
|
||||||
note_list = database.objects.get( self.object_id )
|
note_list = database.objects.get( self.object_id )
|
||||||
if not note_list: return None
|
if not note_list: return None
|
||||||
|
revisions = []
|
||||||
|
|
||||||
|
for note in note_list:
|
||||||
|
user_list = database.objects.get( note.user_id )
|
||||||
|
user_id = None
|
||||||
|
username = None
|
||||||
|
|
||||||
|
if user_list:
|
||||||
|
user_id = user_list[ -1 ].object_id
|
||||||
|
username = user_list[ -1 ].username
|
||||||
|
|
||||||
|
revisions.append( User_revision( note.revision, user_id, username ) )
|
||||||
|
|
||||||
revisions = [ note.revision for note in note_list ]
|
|
||||||
return revisions
|
return revisions
|
||||||
|
|
||||||
Note.sql_load_revisions = lambda self: \
|
Note.sql_load_revisions = lambda self: \
|
||||||
|
|
|
@ -686,7 +686,9 @@ class Test_notebooks( Test_controller ):
|
||||||
revisions = result[ "revisions" ]
|
revisions = result[ "revisions" ]
|
||||||
assert revisions != None
|
assert revisions != None
|
||||||
assert len( revisions ) == 1
|
assert len( revisions ) == 1
|
||||||
assert revisions[ 0 ] == self.note.revision
|
assert revisions[ 0 ].revision == self.note.revision
|
||||||
|
assert revisions[ 0 ].user_id == self.user.object_id
|
||||||
|
assert revisions[ 0 ].username == self.username
|
||||||
|
|
||||||
def test_save_note( self, startup = False ):
|
def test_save_note( self, startup = False ):
|
||||||
self.login()
|
self.login()
|
||||||
|
@ -702,9 +704,14 @@ class Test_notebooks( Test_controller ):
|
||||||
previous_revision = previous_revision,
|
previous_revision = previous_revision,
|
||||||
), session_id = self.session_id )
|
), session_id = self.session_id )
|
||||||
|
|
||||||
assert result[ "new_revision" ] and result[ "new_revision" ] != previous_revision
|
assert result[ "new_revision" ]
|
||||||
current_revision = result[ "new_revision" ]
|
assert result[ "new_revision" ].revision != previous_revision
|
||||||
assert result[ "previous_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 )
|
user = self.database.load( User, self.user.object_id )
|
||||||
assert user.storage_bytes > 0
|
assert user.storage_bytes > 0
|
||||||
assert result[ "storage_bytes" ] == user.storage_bytes
|
assert result[ "storage_bytes" ] == user.storage_bytes
|
||||||
|
@ -746,8 +753,12 @@ class Test_notebooks( Test_controller ):
|
||||||
revisions = result[ "revisions" ]
|
revisions = result[ "revisions" ]
|
||||||
assert revisions != None
|
assert revisions != None
|
||||||
assert len( revisions ) == 2
|
assert len( revisions ) == 2
|
||||||
assert revisions[ 0 ] == previous_revision
|
assert revisions[ 0 ].revision == previous_revision
|
||||||
assert revisions[ 1 ] == current_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_startup_note( self ):
|
def test_save_startup_note( self ):
|
||||||
self.test_save_note( startup = True )
|
self.test_save_note( startup = True )
|
||||||
|
@ -790,8 +801,13 @@ class Test_notebooks( Test_controller ):
|
||||||
previous_revision = previous_revision,
|
previous_revision = previous_revision,
|
||||||
), session_id = self.session_id )
|
), session_id = self.session_id )
|
||||||
|
|
||||||
assert result[ "new_revision" ] and result[ "new_revision" ] != previous_revision
|
assert result[ "new_revision" ]
|
||||||
assert result[ "previous_revision" ] == previous_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
|
||||||
|
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 )
|
user = self.database.load( User, self.user.object_id )
|
||||||
assert user.storage_bytes > 0
|
assert user.storage_bytes > 0
|
||||||
assert result[ "storage_bytes" ] == user.storage_bytes
|
assert result[ "storage_bytes" ] == user.storage_bytes
|
||||||
|
@ -851,7 +867,7 @@ class Test_notebooks( Test_controller ):
|
||||||
# now attempt to save over that note again without changing the contents
|
# now attempt to save over that note again without changing the contents
|
||||||
user = self.database.load( User, self.user.object_id )
|
user = self.database.load( User, self.user.object_id )
|
||||||
previous_storage_bytes = user.storage_bytes
|
previous_storage_bytes = user.storage_bytes
|
||||||
previous_revision = result[ "new_revision" ]
|
previous_revision = result[ "new_revision" ].revision
|
||||||
result = self.http_post( "/notebooks/save_note/", dict(
|
result = self.http_post( "/notebooks/save_note/", dict(
|
||||||
notebook_id = self.notebook.object_id,
|
notebook_id = self.notebook.object_id,
|
||||||
note_id = self.note.object_id,
|
note_id = self.note.object_id,
|
||||||
|
@ -862,7 +878,9 @@ class Test_notebooks( Test_controller ):
|
||||||
|
|
||||||
# assert that the note wasn't actually updated the second time
|
# assert that the note wasn't actually updated the second time
|
||||||
assert result[ "new_revision" ] == None
|
assert result[ "new_revision" ] == None
|
||||||
assert result[ "previous_revision" ] == previous_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 )
|
user = self.database.load( User, self.user.object_id )
|
||||||
assert user.storage_bytes == previous_storage_bytes
|
assert user.storage_bytes == previous_storage_bytes
|
||||||
assert result[ "storage_bytes" ] == 0
|
assert result[ "storage_bytes" ] == 0
|
||||||
|
@ -902,7 +920,7 @@ class Test_notebooks( Test_controller ):
|
||||||
# now attempt to save over that note again without changing the contents
|
# now attempt to save over that note again without changing the contents
|
||||||
user = self.database.load( User, self.user.object_id )
|
user = self.database.load( User, self.user.object_id )
|
||||||
previous_storage_bytes = user.storage_bytes
|
previous_storage_bytes = user.storage_bytes
|
||||||
previous_revision = result[ "new_revision" ]
|
previous_revision = result[ "new_revision" ].revision
|
||||||
result = self.http_post( "/notebooks/save_note/", dict(
|
result = self.http_post( "/notebooks/save_note/", dict(
|
||||||
notebook_id = self.notebook.object_id,
|
notebook_id = self.notebook.object_id,
|
||||||
note_id = self.note.object_id,
|
note_id = self.note.object_id,
|
||||||
|
@ -913,7 +931,9 @@ class Test_notebooks( Test_controller ):
|
||||||
|
|
||||||
# assert that the note wasn't actually updated the second time
|
# assert that the note wasn't actually updated the second time
|
||||||
assert result[ "new_revision" ] == None
|
assert result[ "new_revision" ] == None
|
||||||
assert result[ "previous_revision" ] == previous_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 )
|
user = self.database.load( User, self.user.object_id )
|
||||||
assert user.storage_bytes == previous_storage_bytes
|
assert user.storage_bytes == previous_storage_bytes
|
||||||
assert result[ "storage_bytes" ] == 0
|
assert result[ "storage_bytes" ] == 0
|
||||||
|
@ -956,7 +976,7 @@ class Test_notebooks( Test_controller ):
|
||||||
|
|
||||||
# now attempt to save over that note again without changing the contents, but with a change
|
# now attempt to save over that note again without changing the contents, but with a change
|
||||||
# to its startup flag
|
# to its startup flag
|
||||||
previous_revision = result[ "new_revision" ]
|
previous_revision = result[ "new_revision" ].revision
|
||||||
result = self.http_post( "/notebooks/save_note/", dict(
|
result = self.http_post( "/notebooks/save_note/", dict(
|
||||||
notebook_id = self.notebook.object_id,
|
notebook_id = self.notebook.object_id,
|
||||||
note_id = self.note.object_id,
|
note_id = self.note.object_id,
|
||||||
|
@ -966,8 +986,13 @@ class Test_notebooks( Test_controller ):
|
||||||
), session_id = self.session_id )
|
), session_id = self.session_id )
|
||||||
|
|
||||||
# assert that the note was updated the second time
|
# assert that the note was updated the second time
|
||||||
assert result[ "new_revision" ] and result[ "new_revision" ] != previous_revision
|
assert result[ "new_revision" ]
|
||||||
assert result[ "previous_revision" ] == previous_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
|
||||||
|
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 )
|
user = self.database.load( User, self.user.object_id )
|
||||||
assert user.storage_bytes > 0
|
assert user.storage_bytes > 0
|
||||||
assert result[ "storage_bytes" ] == user.storage_bytes
|
assert result[ "storage_bytes" ] == user.storage_bytes
|
||||||
|
@ -1009,7 +1034,7 @@ class Test_notebooks( Test_controller ):
|
||||||
# except for adding a newline
|
# except for adding a newline
|
||||||
user = self.database.load( User, self.user.object_id )
|
user = self.database.load( User, self.user.object_id )
|
||||||
previous_storage_bytes = user.storage_bytes
|
previous_storage_bytes = user.storage_bytes
|
||||||
previous_revision = result[ "new_revision" ]
|
previous_revision = result[ "new_revision" ].revision
|
||||||
result = self.http_post( "/notebooks/save_note/", dict(
|
result = self.http_post( "/notebooks/save_note/", dict(
|
||||||
notebook_id = self.notebook.object_id,
|
notebook_id = self.notebook.object_id,
|
||||||
note_id = self.note.object_id,
|
note_id = self.note.object_id,
|
||||||
|
@ -1020,7 +1045,9 @@ class Test_notebooks( Test_controller ):
|
||||||
|
|
||||||
# assert that the note wasn't actually updated the second time
|
# assert that the note wasn't actually updated the second time
|
||||||
assert result[ "new_revision" ] == None
|
assert result[ "new_revision" ] == None
|
||||||
assert result[ "previous_revision" ] == previous_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 )
|
user = self.database.load( User, self.user.object_id )
|
||||||
assert user.storage_bytes == previous_storage_bytes
|
assert user.storage_bytes == previous_storage_bytes
|
||||||
assert result[ "storage_bytes" ] == 0
|
assert result[ "storage_bytes" ] == 0
|
||||||
|
@ -1054,7 +1081,7 @@ class Test_notebooks( Test_controller ):
|
||||||
|
|
||||||
# save over that note again with new contents, providing the original
|
# save over that note again with new contents, providing the original
|
||||||
# revision as the previous known revision
|
# revision as the previous known revision
|
||||||
second_revision = result[ "new_revision" ]
|
second_revision = result[ "new_revision" ].revision
|
||||||
new_note_contents = u"<h3>new new title</h3>new new blah"
|
new_note_contents = u"<h3>new new title</h3>new new blah"
|
||||||
result = self.http_post( "/notebooks/save_note/", dict(
|
result = self.http_post( "/notebooks/save_note/", dict(
|
||||||
notebook_id = self.notebook.object_id,
|
notebook_id = self.notebook.object_id,
|
||||||
|
@ -1066,8 +1093,12 @@ class Test_notebooks( Test_controller ):
|
||||||
|
|
||||||
# make sure the second save actually caused an update
|
# make sure the second save actually caused an update
|
||||||
assert result[ "new_revision" ]
|
assert result[ "new_revision" ]
|
||||||
assert result[ "new_revision" ] not in ( first_revision, second_revision )
|
assert result[ "new_revision" ].revision not in ( first_revision, second_revision )
|
||||||
assert result[ "previous_revision" ] == second_revision
|
assert result[ "new_revision" ].user_id == self.user.object_id
|
||||||
|
assert result[ "new_revision" ].username == self.username
|
||||||
|
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 )
|
user = self.database.load( User, self.user.object_id )
|
||||||
assert user.storage_bytes > 0
|
assert user.storage_bytes > 0
|
||||||
assert result[ "storage_bytes" ] == user.storage_bytes
|
assert result[ "storage_bytes" ] == user.storage_bytes
|
||||||
|
@ -1133,7 +1164,10 @@ class Test_notebooks( Test_controller ):
|
||||||
previous_revision = None,
|
previous_revision = None,
|
||||||
), session_id = self.session_id )
|
), session_id = self.session_id )
|
||||||
|
|
||||||
assert result[ "new_revision" ] and result[ "new_revision" ] != previous_revision
|
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
|
assert result[ "previous_revision" ] == None
|
||||||
user = self.database.load( User, self.user.object_id )
|
user = self.database.load( User, self.user.object_id )
|
||||||
assert user.storage_bytes > 0
|
assert user.storage_bytes > 0
|
||||||
|
@ -1179,7 +1213,10 @@ class Test_notebooks( Test_controller ):
|
||||||
previous_revision = None,
|
previous_revision = None,
|
||||||
), session_id = self.session_id )
|
), session_id = self.session_id )
|
||||||
|
|
||||||
assert result[ "new_revision" ] and result[ "new_revision" ] != previous_revision
|
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
|
assert result[ "previous_revision" ] == None
|
||||||
user = self.database.load( User, self.user.object_id )
|
user = self.database.load( User, self.user.object_id )
|
||||||
assert user.storage_bytes > 0
|
assert user.storage_bytes > 0
|
||||||
|
@ -1216,7 +1253,10 @@ class Test_notebooks( Test_controller ):
|
||||||
previous_revision = None,
|
previous_revision = None,
|
||||||
), session_id = self.session_id )
|
), session_id = self.session_id )
|
||||||
|
|
||||||
assert result[ "new_revision" ] and result[ "new_revision" ] != previous_revision
|
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
|
assert result[ "previous_revision" ] == None
|
||||||
user = self.database.load( User, self.user.object_id )
|
user = self.database.load( User, self.user.object_id )
|
||||||
assert user.storage_bytes > 0
|
assert user.storage_bytes > 0
|
||||||
|
@ -1263,7 +1303,10 @@ class Test_notebooks( Test_controller ):
|
||||||
previous_revision = None,
|
previous_revision = None,
|
||||||
), session_id = self.session_id )
|
), session_id = self.session_id )
|
||||||
|
|
||||||
assert result[ "new_revision" ] and result[ "new_revision" ] != previous_revision
|
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
|
assert result[ "previous_revision" ] == None
|
||||||
user = self.database.load( User, self.user.object_id )
|
user = self.database.load( User, self.user.object_id )
|
||||||
assert user.storage_bytes > 0
|
assert user.storage_bytes > 0
|
||||||
|
|
|
@ -6,7 +6,8 @@ class Invite( Persistent ):
|
||||||
An invitiation to view or edit a notebook.
|
An invitiation to view or edit a notebook.
|
||||||
"""
|
"""
|
||||||
def __init__( self, object_id, revision = None, from_user_id = None, notebook_id = None,
|
def __init__( self, object_id, revision = None, from_user_id = None, notebook_id = None,
|
||||||
email_address = None, read_write = False, owner = False, redeemed_user_id = None ):
|
email_address = None, read_write = False, owner = False, redeemed_user_id = None,
|
||||||
|
redeemed_username = None ):
|
||||||
"""
|
"""
|
||||||
Create an invitation with the given id.
|
Create an invitation with the given id.
|
||||||
|
|
||||||
|
@ -26,6 +27,8 @@ class Invite( Persistent ):
|
||||||
@param owner: whether the invitation is for owner-level access (optional, defaults to False)
|
@param owner: whether the invitation is for owner-level access (optional, defaults to False)
|
||||||
@type redeemed_user_id: unicode or NoneType
|
@type redeemed_user_id: unicode or NoneType
|
||||||
@param redeemed_user_id: id of the user who has redeemed this invitation, if any (optional)
|
@param redeemed_user_id: id of the user who has redeemed this invitation, if any (optional)
|
||||||
|
@type redeemed_username: unicode or NoneType
|
||||||
|
@param redeemed_username: username of the user who has redeemed this invitation, if any (optional)
|
||||||
@rtype: Invite
|
@rtype: Invite
|
||||||
@return: newly constructed notebook invitation
|
@return: newly constructed notebook invitation
|
||||||
"""
|
"""
|
||||||
|
@ -36,6 +39,7 @@ class Invite( Persistent ):
|
||||||
self.__read_write = read_write
|
self.__read_write = read_write
|
||||||
self.__owner = owner
|
self.__owner = owner
|
||||||
self.__redeemed_user_id = redeemed_user_id
|
self.__redeemed_user_id = redeemed_user_id
|
||||||
|
self.__redeemed_username = redeemed_username
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create( object_id, from_user_id = None, notebook_id = None, email_address = None, read_write = False, owner = False ):
|
def create( object_id, from_user_id = None, notebook_id = None, email_address = None, read_write = False, owner = False ):
|
||||||
|
@ -66,7 +70,18 @@ class Invite( Persistent ):
|
||||||
if revision:
|
if revision:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
return "select id, revision, from_user_id, notebook_id, email_address, read_write, owner, redeemed_user_id from invite where id = %s;" % quote( object_id )
|
return \
|
||||||
|
"""
|
||||||
|
select
|
||||||
|
invite.id, invite.revision, invite.from_user_id, invite.notebook_id, invite.email_address,
|
||||||
|
invite.read_write, invite.owner, invite.redeemed_user_id, luminotes_user_current.username
|
||||||
|
from
|
||||||
|
invite left outer join luminotes_user_current
|
||||||
|
on
|
||||||
|
( invite.redeemed_user_id = luminotes_user_current.id )
|
||||||
|
where
|
||||||
|
invite.id = %s;
|
||||||
|
""" % quote( object_id )
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def sql_id_exists( object_id, revision = None ):
|
def sql_id_exists( object_id, revision = None ):
|
||||||
|
@ -92,16 +107,36 @@ class Invite( Persistent ):
|
||||||
|
|
||||||
def sql_load_similar( self ):
|
def sql_load_similar( self ):
|
||||||
# select invites with the same notebook_id, and email_address as this invite
|
# select invites with the same notebook_id, and email_address as this invite
|
||||||
return "select id, revision, from_user_id, notebook_id, email_address, read_write, owner, redeemed_user_id from invite " + \
|
return \
|
||||||
"where notebook_id = %s and email_address = %s and id != %s;" % \
|
"""
|
||||||
( quote( self.__notebook_id ), quote( self.__email_address ), quote( self.object_id ) )
|
select
|
||||||
|
invite.id, invite.revision, invite.from_user_id, invite.notebook_id, invite.email_address,
|
||||||
|
invite.read_write, invite.owner, invite.redeemed_user_id, luminotes_user_current.username
|
||||||
|
from
|
||||||
|
invite left outer join luminotes_user_current
|
||||||
|
on
|
||||||
|
( invite.redeemed_user_id = luminotes_user_current.id )
|
||||||
|
where
|
||||||
|
invite.notebook_id = %s and invite.email_address = %s and invite.id != %s;
|
||||||
|
""" % ( quote( self.__notebook_id ), quote( self.__email_address ), quote( self.object_id ) )
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def sql_load_notebook_invites( notebook_id ):
|
def sql_load_notebook_invites( notebook_id ):
|
||||||
# select a list of invites to the given notebook. if there are multiple invites for a given
|
# select a list of invites to the given notebook
|
||||||
# email_address, arbitrarily pick one of them
|
return \
|
||||||
return "select id, revision, from_user_id, notebook_id, email_address, read_write, owner, redeemed_user_id from invite " + \
|
"""
|
||||||
"where id in ( select max( id ) from invite where notebook_id = %s group by email_address ) order by email_address;" % quote( notebook_id )
|
select
|
||||||
|
invite.id, invite.revision, invite.from_user_id, invite.notebook_id, invite.email_address,
|
||||||
|
invite.read_write, invite.owner, invite.redeemed_user_id, luminotes_user_current.username
|
||||||
|
from
|
||||||
|
invite left outer join luminotes_user_current
|
||||||
|
on
|
||||||
|
( invite.redeemed_user_id = luminotes_user_current.id )
|
||||||
|
where
|
||||||
|
invite.notebook_id = %s
|
||||||
|
order by
|
||||||
|
invite.email_address, invite.redeemed_user_id;
|
||||||
|
""" % quote( notebook_id )
|
||||||
|
|
||||||
def sql_revoke_invites( self ):
|
def sql_revoke_invites( self ):
|
||||||
return "delete from invite where notebook_id = %s and email_address = %s;" % \
|
return "delete from invite where notebook_id = %s and email_address = %s;" % \
|
||||||
|
@ -116,6 +151,7 @@ class Invite( Persistent ):
|
||||||
read_write = self.__read_write,
|
read_write = self.__read_write,
|
||||||
owner = self.__owner,
|
owner = self.__owner,
|
||||||
redeemed_user_id = self.__redeemed_user_id,
|
redeemed_user_id = self.__redeemed_user_id,
|
||||||
|
redeemed_username = self.__redeemed_username,
|
||||||
) )
|
) )
|
||||||
|
|
||||||
return d
|
return d
|
||||||
|
@ -141,3 +177,4 @@ class Invite( Persistent ):
|
||||||
read_write = property( lambda self: self.__read_write, __set_read_write )
|
read_write = property( lambda self: self.__read_write, __set_read_write )
|
||||||
owner = property( lambda self: self.__owner, __set_owner )
|
owner = property( lambda self: self.__owner, __set_owner )
|
||||||
redeemed_user_id = property( lambda self: self.__redeemed_user_id, __set_redeemed_user_id )
|
redeemed_user_id = property( lambda self: self.__redeemed_user_id, __set_redeemed_user_id )
|
||||||
|
redeemed_username = property( lambda self: self.__redeemed_username )
|
||||||
|
|
|
@ -152,7 +152,16 @@ class Note( Persistent ):
|
||||||
return self.sql_create()
|
return self.sql_create()
|
||||||
|
|
||||||
def sql_load_revisions( self ):
|
def sql_load_revisions( self ):
|
||||||
return "select revision from note where id = %s order by revision;" % quote( self.object_id )
|
return """ \
|
||||||
|
select
|
||||||
|
note.revision, luminotes_user_current.id, username
|
||||||
|
from
|
||||||
|
note left outer join luminotes_user_current
|
||||||
|
on
|
||||||
|
( note.user_id = luminotes_user_current.id )
|
||||||
|
where
|
||||||
|
note.id = %s order by note.revision;
|
||||||
|
""" % quote( self.object_id )
|
||||||
|
|
||||||
def to_dict( self ):
|
def to_dict( self ):
|
||||||
d = Persistent.to_dict( self )
|
d = Persistent.to_dict( self )
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
class User_revision( object ):
|
||||||
|
"""
|
||||||
|
A revision timestamp along with information on the user that made that revision.
|
||||||
|
"""
|
||||||
|
def __init__( self, revision, user_id = None, username = None ):
|
||||||
|
"""
|
||||||
|
Create a User_revision with the given timestamp and user information.
|
||||||
|
|
||||||
|
@type revision: datetime
|
||||||
|
@param revision: revision timestamp
|
||||||
|
@type user_id: unicode or NoneType
|
||||||
|
@param user_id: id of user who made this revision (optional, defaults to None)
|
||||||
|
@type username: username of user who made this revision (optional, defaults to None)
|
||||||
|
@rtype: User_revision
|
||||||
|
@return: newly constructed User_revision object
|
||||||
|
"""
|
||||||
|
self.__revision = revision
|
||||||
|
self.__user_id = user_id
|
||||||
|
self.__username = username
|
||||||
|
|
||||||
|
def to_dict( self ):
|
||||||
|
return dict(
|
||||||
|
revision = self.__revision,
|
||||||
|
user_id = self.__user_id,
|
||||||
|
username = self.__username,
|
||||||
|
)
|
||||||
|
|
||||||
|
revision = property( lambda self: self.__revision )
|
||||||
|
user_id = property( lambda self: self.__user_id )
|
||||||
|
username = property( lambda self: self.__username )
|
|
@ -1,11 +1,6 @@
|
||||||
update notebook set user_id = (
|
update notebook set user_id = user_notebook.user_id
|
||||||
select user_notebook.user_id
|
from user_notebook
|
||||||
from user_notebook
|
where user_notebook.notebook_id = notebook.id and read_write = 't' and owner = 't';
|
||||||
where notebook_id = notebook.id and read_write = 't' and owner = 't'
|
update note set user_id = notebook_current.user_id
|
||||||
limit 1
|
from notebook_current
|
||||||
);
|
where note.notebook_id = notebook_current.id;
|
||||||
update note set user_id = (
|
|
||||||
select notebook_current.user_id
|
|
||||||
from notebook_current
|
|
||||||
where note.notebook_id = notebook_current.id
|
|
||||||
);
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ class Test_invite( object ):
|
||||||
assert self.invite.read_write == self.read_write
|
assert self.invite.read_write == self.read_write
|
||||||
assert self.invite.owner == self.owner
|
assert self.invite.owner == self.owner
|
||||||
assert self.invite.redeemed_user_id == None
|
assert self.invite.redeemed_user_id == None
|
||||||
|
assert self.invite.redeemed_username == None
|
||||||
|
|
||||||
def test_redeem( self ):
|
def test_redeem( self ):
|
||||||
previous_revision = self.invite.revision
|
previous_revision = self.invite.revision
|
||||||
|
@ -53,3 +54,4 @@ class Test_invite( object ):
|
||||||
assert d.get( "read_write" ) == self.read_write
|
assert d.get( "read_write" ) == self.read_write
|
||||||
assert d.get( "owner" ) == self.owner
|
assert d.get( "owner" ) == self.owner
|
||||||
assert d.get( "redeemed_user_id" ) == None
|
assert d.get( "redeemed_user_id" ) == None
|
||||||
|
assert d.get( "redeemed_username" ) == None
|
||||||
|
|
|
@ -36,6 +36,15 @@ class Test_user( object ):
|
||||||
assert self.user.check_password( new_password ) == True
|
assert self.user.check_password( new_password ) == True
|
||||||
assert self.user.revision > previous_revision
|
assert self.user.revision > previous_revision
|
||||||
|
|
||||||
|
def test_set_password_with_special_characters( self ):
|
||||||
|
previous_revision = self.user.revision
|
||||||
|
new_password = u"newpass\xe4"
|
||||||
|
self.user.password = new_password
|
||||||
|
|
||||||
|
assert self.user.check_password( self.password ) == False
|
||||||
|
assert self.user.check_password( new_password ) == True
|
||||||
|
assert self.user.revision > previous_revision
|
||||||
|
|
||||||
def test_set_none_password( self ):
|
def test_set_none_password( self ):
|
||||||
previous_revision = self.user.revision
|
previous_revision = self.user.revision
|
||||||
new_password = None
|
new_password = None
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
from datetime import datetime
|
||||||
|
from model.User_revision import User_revision
|
||||||
|
|
||||||
|
|
||||||
|
class Test_user_revision( object ):
|
||||||
|
def setUp( self ):
|
||||||
|
self.revision = datetime.now()
|
||||||
|
self.user_id = u"77"
|
||||||
|
self.username = u"bob"
|
||||||
|
|
||||||
|
self.user_revision = User_revision( self.revision, self.user_id, self.username )
|
||||||
|
|
||||||
|
def test_create( self ):
|
||||||
|
assert self.user_revision.revision == self.revision
|
||||||
|
assert self.user_revision.user_id == self.user_id
|
||||||
|
assert self.user_revision.username == self.username
|
||||||
|
|
||||||
|
def test_to_dict( self ):
|
||||||
|
d = self.user_revision.to_dict()
|
||||||
|
|
||||||
|
assert d.get( "revision" ) == self.revision
|
||||||
|
assert d.get( "user_id" ) == self.user_id
|
||||||
|
assert d.get( "username" ) == self.username
|
|
@ -4,7 +4,7 @@ function Editor( id, notebook_id, note_text, deleted_from_id, revision, read_wri
|
||||||
this.initial_text = note_text;
|
this.initial_text = note_text;
|
||||||
this.deleted_from_id = deleted_from_id || null;
|
this.deleted_from_id = deleted_from_id || null;
|
||||||
this.revision = revision;
|
this.revision = revision;
|
||||||
this.revisions_list = new Array(); // cache for this note's list of revisions, loaded from the server on-demand
|
this.user_revisions = new Array(); // cache for this note's list of revisions, loaded from the server on-demand
|
||||||
this.read_write = read_write;
|
this.read_write = read_write;
|
||||||
this.startup = startup || false; // whether this Editor is for a startup note
|
this.startup = startup || false; // whether this Editor is for a startup note
|
||||||
this.init_highlight = highlight || false;
|
this.init_highlight = highlight || false;
|
||||||
|
|
|
@ -1135,11 +1135,11 @@ Wiki.prototype.update_editor_revisions = function ( result, editor ) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var client_previous_revision = editor.revision;
|
var client_previous_revision = editor.revision;
|
||||||
editor.revision = result.new_revision;
|
editor.revision = result.new_revision.revision;
|
||||||
|
|
||||||
// if the server's idea of the previous revision doesn't match the client's, then someone has
|
// if the server's idea of the previous revision doesn't match the client's, then someone has
|
||||||
// gone behind our back and saved the editor's note from another window
|
// gone behind our back and saved the editor's note from another window
|
||||||
if ( result.previous_revision != client_previous_revision ) {
|
if ( result.previous_revision.revision != client_previous_revision ) {
|
||||||
var compare_button = createDOM( "input", {
|
var compare_button = createDOM( "input", {
|
||||||
"type": "button",
|
"type": "button",
|
||||||
"class": "message_button",
|
"class": "message_button",
|
||||||
|
@ -1150,18 +1150,18 @@ Wiki.prototype.update_editor_revisions = function ( result, editor ) {
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
connect( compare_button, "onclick", function ( event ) {
|
connect( compare_button, "onclick", function ( event ) {
|
||||||
self.compare_versions( event, editor, result.previous_revision );
|
self.compare_versions( event, editor, result.previous_revision.revision );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
if ( !editor.revisions_list || editor.revisions_list.length == 0 )
|
if ( !editor.user_revisions || editor.user_revisions.length == 0 )
|
||||||
return;
|
return;
|
||||||
editor.revisions_list.push( result.previous_revision );
|
editor.user_revisions.push( result.previous_revision );
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the new revision to the editor's revisions list
|
// add the new revision to the editor's revisions list
|
||||||
if ( !editor.revisions_list || editor.revisions_list.length == 0 )
|
if ( !editor.user_revisions || editor.user_revisions.length == 0 )
|
||||||
return;
|
return;
|
||||||
editor.revisions_list.push( result.new_revision );
|
editor.user_revisions.push( result.new_revision );
|
||||||
}
|
}
|
||||||
|
|
||||||
Wiki.prototype.search = function ( event ) {
|
Wiki.prototype.search = function ( event ) {
|
||||||
|
@ -1341,8 +1341,15 @@ Wiki.prototype.display_invites = function ( invite_area ) {
|
||||||
var owners = createDOM( "div", { "id": "owners" } );
|
var owners = createDOM( "div", { "id": "owners" } );
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
var addresses = new Array();
|
||||||
|
|
||||||
for ( var i in this.invites ) {
|
for ( var i in this.invites ) {
|
||||||
var invite = this.invites[ i ];
|
var invite = this.invites[ i ];
|
||||||
|
|
||||||
|
// only display the first invite for a given email address
|
||||||
|
if ( addresses[ invite.email_address ] == true )
|
||||||
|
continue;
|
||||||
|
|
||||||
var revoke_button = createDOM( "input", {
|
var revoke_button = createDOM( "input", {
|
||||||
"type": "button",
|
"type": "button",
|
||||||
"id": "revoke_" + invite.object_id,
|
"id": "revoke_" + invite.object_id,
|
||||||
|
@ -1363,8 +1370,12 @@ Wiki.prototype.display_invites = function ( invite_area ) {
|
||||||
|
|
||||||
appendChildNodes(
|
appendChildNodes(
|
||||||
add_invite_to, createDOM( "div", { "class": "invite" },
|
add_invite_to, createDOM( "div", { "class": "invite" },
|
||||||
invite.email_address, " ", revoke_button )
|
invite.email_address, " ",
|
||||||
|
( invite.redeemed_username ? "(" + invite.redeemed_username + ")" : "" ),
|
||||||
|
" ", revoke_button )
|
||||||
);
|
);
|
||||||
|
|
||||||
|
addresses[ invite.email_address ] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var div = createDOM( "div" );
|
var div = createDOM( "div" );
|
||||||
|
@ -1781,7 +1792,7 @@ Wiki.prototype.toggle_editor_changes = function ( event, editor ) {
|
||||||
|
|
||||||
// if there's already a cached revision list, or the editor doesn't have a revision yet, then
|
// if there's already a cached revision list, or the editor doesn't have a revision yet, then
|
||||||
// display the changes pulldown and bail
|
// display the changes pulldown and bail
|
||||||
if ( ( editor.revisions_list && editor.revisions_list.length > 0 ) || !editor.revision ) {
|
if ( ( editor.user_revisions && editor.user_revisions.length > 0 ) || !editor.revision ) {
|
||||||
new Changes_pulldown( this, this.notebook_id, this.invoker, editor );
|
new Changes_pulldown( this, this.notebook_id, this.invoker, editor );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1794,7 +1805,7 @@ Wiki.prototype.toggle_editor_changes = function ( event, editor ) {
|
||||||
"note_id": editor.id
|
"note_id": editor.id
|
||||||
},
|
},
|
||||||
function ( result ) {
|
function ( result ) {
|
||||||
editor.revisions_list = result.revisions;
|
editor.user_revisions = result.revisions;
|
||||||
new Changes_pulldown( self, self.notebook_id, self.invoker, editor );
|
new Changes_pulldown( self, self.notebook_id, self.invoker, editor );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -1920,26 +1931,32 @@ function Changes_pulldown( wiki, notebook_id, invoker, editor ) {
|
||||||
this.editor = editor;
|
this.editor = editor;
|
||||||
this.links = new Array();
|
this.links = new Array();
|
||||||
|
|
||||||
if ( !editor.revisions_list || editor.revisions_list.length == 0 ) {
|
if ( !editor.user_revisions || editor.user_revisions.length == 0 ) {
|
||||||
appendChildNodes( this.div, createDOM( "span", "This note has no previous changes." ) );
|
appendChildNodes( this.div, createDOM( "span", "This note has no previous changes." ) );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// display list of revision timestamps in reverse chronological order
|
// display list of revision timestamps in reverse chronological order
|
||||||
var revisions_list = clone( editor.revisions_list );
|
var user_revisions = clone( editor.user_revisions );
|
||||||
revisions_list.reverse();
|
user_revisions.reverse();
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
for ( var i = 0; i < revisions_list.length - 1; ++i ) { // -1 to skip the oldest revision
|
for ( var i = 0; i < user_revisions.length - 1; ++i ) { // -1 to skip the oldest revision
|
||||||
var revision = revisions_list[ i ];
|
var user_revision = user_revisions[ i ];
|
||||||
var short_revision = this.wiki.brief_revision( revision );
|
var short_revision = this.wiki.brief_revision( user_revision.revision );
|
||||||
var href = "/notebooks/" + this.notebook_id + "?" + queryString(
|
var href = "/notebooks/" + this.notebook_id + "?" + queryString(
|
||||||
[ "note_id", "revision" ],
|
[ "note_id", "revision" ],
|
||||||
[ this.editor.id, revision ]
|
[ this.editor.id, user_revision.revision ]
|
||||||
);
|
);
|
||||||
var link = createDOM( "a", { "href": href, "class": "pulldown_link" }, short_revision );
|
|
||||||
|
var link = createDOM(
|
||||||
|
"a",
|
||||||
|
{ "href": href, "class": "pulldown_link" },
|
||||||
|
short_revision + ( user_revision.username ? " by " + user_revision.username : "" )
|
||||||
|
);
|
||||||
|
|
||||||
this.links.push( link );
|
this.links.push( link );
|
||||||
link.revision = revision;
|
link.revision = user_revision.revision;
|
||||||
connect( link, "onclick", function ( event ) { self.link_clicked( event, self.editor.id ); } );
|
connect( link, "onclick", function ( event ) { self.link_clicked( event, self.editor.id ); } );
|
||||||
appendChildNodes( this.div, link );
|
appendChildNodes( this.div, link );
|
||||||
appendChildNodes( this.div, createDOM( "br" ) );
|
appendChildNodes( this.div, createDOM( "br" ) );
|
||||||
|
|
Reference in New Issue