Non-paying users can now invite people to their notebook, but only as viewers.
Paying users can invite them as viewers, collaborators, or owners.
This commit is contained in:
parent
5554b1df17
commit
52c111895a
3
NEWS
3
NEWS
|
@ -1,4 +1,5 @@
|
|||
1.0.4: December ??, 2007
|
||||
1.1.0: December ??, 2007
|
||||
* Ability to invite people to your notebook.
|
||||
* When the web browser is resized, all notes are automatically resized as well.
|
||||
* Fixed note focusing in Safari.
|
||||
* Fixed note state detection (bold, italic, etc.) in Safari.
|
||||
|
|
|
@ -27,22 +27,22 @@ settings = {
|
|||
{
|
||||
"name": "free",
|
||||
"storage_quota_bytes": 30 * MEGABYTE,
|
||||
"notebook_sharing": False,
|
||||
"notebook_collaboration": False,
|
||||
},
|
||||
{
|
||||
"name": "basic",
|
||||
"storage_quota_bytes": 250 * MEGABYTE,
|
||||
"notebook_sharing": True,
|
||||
"notebook_collaboration": True,
|
||||
},
|
||||
{
|
||||
"name": "standard",
|
||||
"storage_quota_bytes": 500 * MEGABYTE,
|
||||
"notebook_sharing": True,
|
||||
"notebook_collaboration": True,
|
||||
},
|
||||
{
|
||||
"name": "premium",
|
||||
"storage_quota_bytes": 1000 * MEGABYTE,
|
||||
"notebook_sharing": True,
|
||||
"notebook_collaboration": True,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -668,7 +668,8 @@ class Users( object ):
|
|||
@type email_addresses: unicode
|
||||
@param email_addresses: a string containing whitespace- or comma-separated email addresses
|
||||
@type access: unicode
|
||||
@param access: type of access to grant, either "collaborator", "viewer", or "owner"
|
||||
@param access: type of access to grant, either "collaborator", "viewer", or "owner". with
|
||||
certain rate plans, only "viewer" is allowed
|
||||
@type invite_button: unicode
|
||||
@param invite_button: ignored
|
||||
@type user_id: unicode
|
||||
|
@ -677,13 +678,22 @@ class Users( object ):
|
|||
@return: { 'message': message }
|
||||
@raise Password_reset_error: an error occured when sending the password reset email
|
||||
@raise Validation_error: one of the arguments is invalid
|
||||
@raise Access_error: user_id doesn't have owner-level notebook access to send an invite
|
||||
@raise Access_error: user_id doesn't have owner-level notebook access to send an invite or
|
||||
doesn't have a rate plan supporting notebook collaboration
|
||||
"""
|
||||
if len( email_addresses ) < 5:
|
||||
raise Invite_error( u"Please enter at least one valid email address." )
|
||||
if len( email_addresses ) > 5000:
|
||||
raise Invite_error( u"Please enter fewer email addresses." )
|
||||
|
||||
if not self.check_access( user_id, notebook_id, read_write = True, owner = True ):
|
||||
raise Access_error()
|
||||
|
||||
# this feature requires a rate plan above basic
|
||||
user = self.__database.load( User, user_id )
|
||||
if user is None or ( user.rate_plan == 0 and access != u"viewer" ):
|
||||
raise Access_error()
|
||||
|
||||
if access == u"collaborator":
|
||||
read_write = True
|
||||
owner = False
|
||||
|
@ -696,14 +706,6 @@ class Users( object ):
|
|||
else:
|
||||
raise Access_error()
|
||||
|
||||
if not self.check_access( user_id, notebook_id, read_write = True, owner = True ):
|
||||
raise Access_error()
|
||||
|
||||
# this feature requires a rate plan above basic
|
||||
user = self.__database.load( User, user_id )
|
||||
if user is None or user.rate_plan == 0:
|
||||
raise Access_error()
|
||||
|
||||
notebook = self.__database.load( Notebook, notebook_id )
|
||||
if notebook is None:
|
||||
raise Access_error()
|
||||
|
|
|
@ -1180,7 +1180,7 @@ class Test_users( Test_controller ):
|
|||
assert result[ u"error" ]
|
||||
assert "access" in result[ u"error" ]
|
||||
|
||||
def test_send_invites_without_sufficient_rate_plan( self ):
|
||||
def test_send_invites_viewer_with_lowest_rate_plan( self ):
|
||||
Stub_smtp.reset()
|
||||
smtplib.SMTP = Stub_smtp
|
||||
self.login()
|
||||
|
@ -1196,6 +1196,51 @@ class Test_users( Test_controller ):
|
|||
), session_id = self.session_id )
|
||||
session_id = result[ u"session_id" ]
|
||||
|
||||
assert u"An invitation has been sent." in result[ u"message" ]
|
||||
assert smtplib.SMTP.connected == False
|
||||
assert len( smtplib.SMTP.emails ) == 1
|
||||
|
||||
( from_address, to_addresses, message ) = smtplib.SMTP.emails[ 0 ]
|
||||
assert self.email_address in from_address
|
||||
assert to_addresses == email_addresses_list
|
||||
assert self.notebooks[ 0 ].name in message
|
||||
assert self.INVITE_LINK_PATTERN.search( message )
|
||||
|
||||
def test_send_invites_collaborator_with_lowest_rate_plan( self ):
|
||||
Stub_smtp.reset()
|
||||
smtplib.SMTP = Stub_smtp
|
||||
self.login()
|
||||
|
||||
email_addresses_list = [ u"foo@example.com" ]
|
||||
email_addresses = email_addresses_list[ 0 ]
|
||||
|
||||
result = self.http_post( "/users/send_invites", dict(
|
||||
notebook_id = self.notebooks[ 0 ].object_id,
|
||||
email_addresses = email_addresses,
|
||||
access = u"collaborator",
|
||||
invite_button = u"send invites",
|
||||
), session_id = self.session_id )
|
||||
session_id = result[ u"session_id" ]
|
||||
|
||||
assert result[ u"error" ]
|
||||
assert "access" in result[ u"error" ]
|
||||
|
||||
def test_send_invites_owner_with_lowest_rate_plan( self ):
|
||||
Stub_smtp.reset()
|
||||
smtplib.SMTP = Stub_smtp
|
||||
self.login()
|
||||
|
||||
email_addresses_list = [ u"foo@example.com" ]
|
||||
email_addresses = email_addresses_list[ 0 ]
|
||||
|
||||
result = self.http_post( "/users/send_invites", dict(
|
||||
notebook_id = self.notebooks[ 0 ].object_id,
|
||||
email_addresses = email_addresses,
|
||||
access = u"owner",
|
||||
invite_button = u"send invites",
|
||||
), session_id = self.session_id )
|
||||
session_id = result[ u"session_id" ]
|
||||
|
||||
assert result[ u"error" ]
|
||||
assert "access" in result[ u"error" ]
|
||||
|
||||
|
|
|
@ -185,23 +185,25 @@ Editor.prototype.finish_init = function () {
|
|||
|
||||
var invite_button = getElement( "invite_button" );
|
||||
if ( invite_button ) {
|
||||
var collaborators_radio = getElement( "collaborators_radio" );
|
||||
connect( "collaborators_link", "onclick", function ( event ) {
|
||||
collaborators_radio.checked = true;
|
||||
event.stop();
|
||||
} );
|
||||
if ( getElement( "access_choices" ) ) {
|
||||
var collaborators_radio = getElement( "collaborators_radio" );
|
||||
connect( "collaborators_link", "onclick", function ( event ) {
|
||||
collaborators_radio.checked = true;
|
||||
event.stop();
|
||||
} );
|
||||
|
||||
var viewers_radio = getElement( "viewers_radio" );
|
||||
connect( "viewers_link", "onclick", function ( event ) {
|
||||
viewers_radio.checked = true;
|
||||
event.stop();
|
||||
} );
|
||||
var viewers_radio = getElement( "viewers_radio" );
|
||||
connect( "viewers_link", "onclick", function ( event ) {
|
||||
viewers_radio.checked = true;
|
||||
event.stop();
|
||||
} );
|
||||
|
||||
var owners_radio = getElement( "owners_radio" );
|
||||
connect( "owners_link", "onclick", function ( event ) {
|
||||
owners_radio.checked = true;
|
||||
event.stop();
|
||||
} );
|
||||
var owners_radio = getElement( "owners_radio" );
|
||||
connect( "owners_link", "onclick", function ( event ) {
|
||||
owners_radio.checked = true;
|
||||
event.stop();
|
||||
} );
|
||||
}
|
||||
|
||||
var invite_form = getElement( "invite_form" );
|
||||
connect( invite_button, "onclick", function ( event ) {
|
||||
|
|
|
@ -1250,15 +1250,6 @@ Wiki.prototype.share_notebook = function () {
|
|||
return;
|
||||
}
|
||||
|
||||
if ( !this.rate_plan.notebook_sharing ) {
|
||||
this.display_message(
|
||||
"If you'd like to share your notebook, please ",
|
||||
[ createDOM( "a", { "href": "/upgrade", "target": "_new" }, "upgrade" ),
|
||||
" your account first." ]
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
var collaborators_link = createDOM( "a",
|
||||
{ "href": "#", "id": "collaborators_link", "class": "radio_link", "title": "Collaborators may view and edit this notebook." },
|
||||
"collaborators"
|
||||
|
@ -1282,6 +1273,28 @@ Wiki.prototype.share_notebook = function () {
|
|||
{ "type": "radio", "id": "owners_radio", "name": "access", "value": "owner" }
|
||||
)
|
||||
|
||||
if ( this.rate_plan.notebook_collaboration ) {
|
||||
var access_area = createDOM( "p", { "id": "access_choices" },
|
||||
createDOM( "p", {}, "Invite these people as:" ),
|
||||
createDOM( "table" , { "id": "access_table" },
|
||||
createDOM( "tr", {},
|
||||
createDOM( "td", {}, collaborators_radio, collaborators_link ),
|
||||
createDOM( "td", {}, viewers_radio, viewers_link ),
|
||||
createDOM( "td", {}, owners_radio, owners_link )
|
||||
)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
var access_area = createDOM( "p", {},
|
||||
createDOM( "b", {}, "Note: " ),
|
||||
"These people will only be able to view your notebook. If you'd like them to be able to edit ",
|
||||
"your notebook as well, please ",
|
||||
createDOM( "a", { "href": "/upgrade", "target": "_new" }, "upgrade" ),
|
||||
" your account.",
|
||||
createDOM( "input", { "type": "hidden", "name": "access", "value": "viewer" } )
|
||||
);
|
||||
}
|
||||
|
||||
var div = createDOM( "div", {},
|
||||
createDOM( "form", { "id": "invite_form" },
|
||||
createDOM( "input", { "type": "hidden", "name": "notebook_id", "value": this.notebook_id } ),
|
||||
|
@ -1293,16 +1306,7 @@ Wiki.prototype.share_notebook = function () {
|
|||
)
|
||||
),
|
||||
createDOM( "p", {}, "Please separate email addresses with commas, spaces, or the enter key." ),
|
||||
createDOM( "p", {},
|
||||
createDOM( "p", {}, "Invite these people as:" ),
|
||||
createDOM( "table" , { "id": "access_table" },
|
||||
createDOM( "tr", {},
|
||||
createDOM( "td", {}, collaborators_radio, collaborators_link ),
|
||||
createDOM( "td", {}, viewers_radio, viewers_link ),
|
||||
createDOM( "td", {}, owners_radio, owners_link )
|
||||
)
|
||||
)
|
||||
),
|
||||
access_area,
|
||||
createDOM( "p", {},
|
||||
createDOM( "input",
|
||||
{ "type": "submit", "name": "invite_button", "id": "invite_button", "class": "button", "value": "send invites" }
|
||||
|
|
Reference in New Issue