witten
/
luminotes
Archived
1
0
Fork 0

* 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:
Dan Helfman 2008-01-04 04:45:43 +00:00
parent e086114478
commit 5520fe5892
13 changed files with 263 additions and 80 deletions

4
NEWS
View File

@ -1,5 +1,7 @@
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
* Ability to invite people to view your notebook.

View File

@ -11,6 +11,7 @@ from model.Notebook import Notebook
from model.Note import Note
from model.Invite import Invite
from model.User import User
from model.User_revision import User_revision
from view.Main_page import Main_page
from view.Json import Json
from view.Html_file import Html_file
@ -374,7 +375,7 @@ class Notebooks( object ):
@type user_id: unicode or NoneType
@param user_id: id of current logged-in user (if any), determined by @grab_user_id
@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 Validation_error: one of the arguments is invalid
"""
@ -398,7 +399,7 @@ class Notebooks( object ):
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:
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
@rtype: json dict
@return: {
'new_revision': new revision of saved note, or None if nothing was saved,
'previous_revision': revision immediately before new_revision, or None if the note is new
'new_revision': User_revision of saved note, or None if nothing was saved
'previous_revision': User_revision immediately before new_revision, or None if the note is new
'storage_bytes': current storage usage by user,
}
@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 ):
raise Access_error()
user = self.__database.load( User, user_id )
notebook = self.__database.load( Notebook, notebook_id )
if not notebook:
if not user or not notebook:
raise Access_error()
note = self.__database.load( Note, note_id )
# 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
if contents.replace( u"\n", u"" ) == old_note.contents.replace( u"\n", "" ) and startup == old_note.startup:
new_revision = None
@ -469,9 +471,9 @@ class Notebooks( object ):
note.rank = self.__database.select_one( float, notebook.sql_highest_rank() ) + 1
else:
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
@ -479,19 +481,21 @@ class Notebooks( object ):
if note and note.notebook_id == notebook.object_id:
old_note = self.__database.load( Note, note_id, previous_revision )
previous_revision = note.revision
new_revision = update_note( notebook, old_note, startup, user_id )
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 )
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
elif note and notebook.trash_id and note.notebook_id == notebook.trash_id:
old_note = self.__database.load( Note, note_id, previous_revision )
# 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.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
else:
if startup:
@ -501,7 +505,7 @@ class Notebooks( object ):
previous_revision = None
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:
self.__database.save( note, commit = False )

View File

@ -13,6 +13,7 @@ class Test_controller( object ):
from model.Notebook import Notebook
from model.Note import Note
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
# 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 ):
note_list = database.objects.get( self.object_id )
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
Note.sql_load_revisions = lambda self: \

View File

@ -686,7 +686,9 @@ class Test_notebooks( Test_controller ):
revisions = result[ "revisions" ]
assert revisions != None
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 ):
self.login()
@ -702,9 +704,14 @@ class Test_notebooks( Test_controller ):
previous_revision = previous_revision,
), session_id = self.session_id )
assert result[ "new_revision" ] and result[ "new_revision" ] != previous_revision
current_revision = result[ "new_revision" ]
assert result[ "previous_revision" ] == previous_revision
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
@ -746,8 +753,12 @@ class Test_notebooks( Test_controller ):
revisions = result[ "revisions" ]
assert revisions != None
assert len( revisions ) == 2
assert revisions[ 0 ] == previous_revision
assert revisions[ 1 ] == current_revision
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_startup_note( self ):
self.test_save_note( startup = True )
@ -790,8 +801,13 @@ class Test_notebooks( Test_controller ):
previous_revision = previous_revision,
), session_id = self.session_id )
assert result[ "new_revision" ] and result[ "new_revision" ] != previous_revision
assert result[ "previous_revision" ] == previous_revision
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
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
@ -851,7 +867,7 @@ class Test_notebooks( Test_controller ):
# now attempt to save over that note again without changing the contents
user = self.database.load( User, self.user.object_id )
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(
notebook_id = self.notebook.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 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 )
assert user.storage_bytes == previous_storage_bytes
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
user = self.database.load( User, self.user.object_id )
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(
notebook_id = self.notebook.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 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 )
assert user.storage_bytes == previous_storage_bytes
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
# to its startup flag
previous_revision = result[ "new_revision" ]
previous_revision = result[ "new_revision" ].revision
result = self.http_post( "/notebooks/save_note/", dict(
notebook_id = self.notebook.object_id,
note_id = self.note.object_id,
@ -966,8 +986,13 @@ class Test_notebooks( Test_controller ):
), session_id = self.session_id )
# assert that the note was updated the second time
assert result[ "new_revision" ] and result[ "new_revision" ] != previous_revision
assert result[ "previous_revision" ] == previous_revision
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
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
@ -1009,7 +1034,7 @@ class Test_notebooks( Test_controller ):
# except for adding a newline
user = self.database.load( User, self.user.object_id )
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(
notebook_id = self.notebook.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 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 )
assert user.storage_bytes == previous_storage_bytes
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
# 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"
result = self.http_post( "/notebooks/save_note/", dict(
notebook_id = self.notebook.object_id,
@ -1066,8 +1093,12 @@ class Test_notebooks( Test_controller ):
# make sure the second save actually caused an update
assert result[ "new_revision" ]
assert result[ "new_revision" ] not in ( first_revision, second_revision )
assert result[ "previous_revision" ] == second_revision
assert result[ "new_revision" ].revision not in ( first_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 )
assert user.storage_bytes > 0
assert result[ "storage_bytes" ] == user.storage_bytes
@ -1133,7 +1164,10 @@ class Test_notebooks( Test_controller ):
previous_revision = None,
), 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
user = self.database.load( User, self.user.object_id )
assert user.storage_bytes > 0
@ -1179,7 +1213,10 @@ class Test_notebooks( Test_controller ):
previous_revision = None,
), 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
user = self.database.load( User, self.user.object_id )
assert user.storage_bytes > 0
@ -1216,7 +1253,10 @@ class Test_notebooks( Test_controller ):
previous_revision = None,
), 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
user = self.database.load( User, self.user.object_id )
assert user.storage_bytes > 0
@ -1263,7 +1303,10 @@ class Test_notebooks( Test_controller ):
previous_revision = None,
), 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
user = self.database.load( User, self.user.object_id )
assert user.storage_bytes > 0

View File

@ -6,7 +6,8 @@ class Invite( Persistent ):
An invitiation to view or edit a notebook.
"""
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.
@ -26,6 +27,8 @@ class Invite( Persistent ):
@param owner: whether the invitation is for owner-level access (optional, defaults to False)
@type redeemed_user_id: unicode or NoneType
@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
@return: newly constructed notebook invitation
"""
@ -36,6 +39,7 @@ class Invite( Persistent ):
self.__read_write = read_write
self.__owner = owner
self.__redeemed_user_id = redeemed_user_id
self.__redeemed_username = redeemed_username
@staticmethod
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:
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
def sql_id_exists( object_id, revision = None ):
@ -92,16 +107,36 @@ class Invite( Persistent ):
def sql_load_similar( self ):
# 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 " + \
"where notebook_id = %s and email_address = %s and id != %s;" % \
( quote( self.__notebook_id ), quote( self.__email_address ), quote( self.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.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
def sql_load_notebook_invites( notebook_id ):
# select a list of invites to the given notebook. if there are multiple invites for a given
# email_address, arbitrarily pick one of them
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 a list of invites to the given notebook
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.notebook_id = %s
order by
invite.email_address, invite.redeemed_user_id;
""" % quote( notebook_id )
def sql_revoke_invites( self ):
return "delete from invite where notebook_id = %s and email_address = %s;" % \
@ -116,6 +151,7 @@ class Invite( Persistent ):
read_write = self.__read_write,
owner = self.__owner,
redeemed_user_id = self.__redeemed_user_id,
redeemed_username = self.__redeemed_username,
) )
return d
@ -141,3 +177,4 @@ class Invite( Persistent ):
read_write = property( lambda self: self.__read_write, __set_read_write )
owner = property( lambda self: self.__owner, __set_owner )
redeemed_user_id = property( lambda self: self.__redeemed_user_id, __set_redeemed_user_id )
redeemed_username = property( lambda self: self.__redeemed_username )

View File

@ -152,7 +152,16 @@ class Note( Persistent ):
return self.sql_create()
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 ):
d = Persistent.to_dict( self )

30
model/User_revision.py Normal file
View File

@ -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 )

View File

@ -1,11 +1,6 @@
update notebook set user_id = (
select user_notebook.user_id
from user_notebook
where notebook_id = notebook.id and read_write = 't' and owner = 't'
limit 1
);
update note set user_id = (
select notebook_current.user_id
from notebook_current
where note.notebook_id = notebook_current.id
);
update notebook set user_id = user_notebook.user_id
from user_notebook
where user_notebook.notebook_id = notebook.id and read_write = 't' and owner = 't';
update note set user_id = notebook_current.user_id
from notebook_current
where note.notebook_id = notebook_current.id;

View File

@ -25,6 +25,7 @@ class Test_invite( object ):
assert self.invite.read_write == self.read_write
assert self.invite.owner == self.owner
assert self.invite.redeemed_user_id == None
assert self.invite.redeemed_username == None
def test_redeem( self ):
previous_revision = self.invite.revision
@ -53,3 +54,4 @@ class Test_invite( object ):
assert d.get( "read_write" ) == self.read_write
assert d.get( "owner" ) == self.owner
assert d.get( "redeemed_user_id" ) == None
assert d.get( "redeemed_username" ) == None

View File

@ -36,6 +36,15 @@ class Test_user( object ):
assert self.user.check_password( new_password ) == True
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 ):
previous_revision = self.user.revision
new_password = None

View File

@ -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

View File

@ -4,7 +4,7 @@ function Editor( id, notebook_id, note_text, deleted_from_id, revision, read_wri
this.initial_text = note_text;
this.deleted_from_id = deleted_from_id || null;
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.startup = startup || false; // whether this Editor is for a startup note
this.init_highlight = highlight || false;

View File

@ -1135,11 +1135,11 @@ Wiki.prototype.update_editor_revisions = function ( result, editor ) {
return;
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
// 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", {
"type": "button",
"class": "message_button",
@ -1150,18 +1150,18 @@ Wiki.prototype.update_editor_revisions = function ( result, editor ) {
var self = this;
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;
editor.revisions_list.push( result.previous_revision );
editor.user_revisions.push( result.previous_revision );
}
// 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;
editor.revisions_list.push( result.new_revision );
editor.user_revisions.push( result.new_revision );
}
Wiki.prototype.search = function ( event ) {
@ -1341,8 +1341,15 @@ Wiki.prototype.display_invites = function ( invite_area ) {
var owners = createDOM( "div", { "id": "owners" } );
var self = this;
var addresses = new Array();
for ( var i in this.invites ) {
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", {
"type": "button",
"id": "revoke_" + invite.object_id,
@ -1363,8 +1370,12 @@ Wiki.prototype.display_invites = function ( invite_area ) {
appendChildNodes(
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" );
@ -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
// 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 );
return;
}
@ -1794,7 +1805,7 @@ Wiki.prototype.toggle_editor_changes = function ( event, editor ) {
"note_id": editor.id
},
function ( result ) {
editor.revisions_list = result.revisions;
editor.user_revisions = result.revisions;
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.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." ) );
return;
}
// display list of revision timestamps in reverse chronological order
var revisions_list = clone( editor.revisions_list );
revisions_list.reverse();
var user_revisions = clone( editor.user_revisions );
user_revisions.reverse();
var self = this;
for ( var i = 0; i < revisions_list.length - 1; ++i ) { // -1 to skip the oldest revision
var revision = revisions_list[ i ];
var short_revision = this.wiki.brief_revision( revision );
for ( var i = 0; i < user_revisions.length - 1; ++i ) { // -1 to skip the oldest revision
var user_revision = user_revisions[ i ];
var short_revision = this.wiki.brief_revision( user_revision.revision );
var href = "/notebooks/" + this.notebook_id + "?" + queryString(
[ "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 );
link.revision = revision;
link.revision = user_revision.revision;
connect( link, "onclick", function ( event ) { self.link_clicked( event, self.editor.id ); } );
appendChildNodes( this.div, link );
appendChildNodes( this.div, createDOM( "br" ) );