Implemented basic user account settings. Now you can change your email
address.
This commit is contained in:
parent
11263d65fa
commit
18982dc129
6
NEWS
6
NEWS
|
@ -1,3 +1,9 @@
|
||||||
|
1.3.17: May 7, 2008
|
||||||
|
* Implemented basic user account settings. Now you can change your email
|
||||||
|
address.
|
||||||
|
* Fixed a bug where if you load a particular note in its own window, and
|
||||||
|
that note is a startup note, it shows up in the note tree twice.
|
||||||
|
|
||||||
1.3.16: May 6, 2008
|
1.3.16: May 6, 2008
|
||||||
* Fixed a bug where an invite sent for a notebook with an accented unicode
|
* Fixed a bug where an invite sent for a notebook with an accented unicode
|
||||||
name would cause a UnicodeEncodeError upon sending the invite email. Now
|
name would cause a UnicodeEncodeError upon sending the invite email. Now
|
||||||
|
|
|
@ -1208,3 +1208,46 @@ class Users( object ):
|
||||||
|
|
||||||
def rate_plan( self, plan_index ):
|
def rate_plan( self, plan_index ):
|
||||||
return self.__rate_plans[ plan_index ]
|
return self.__rate_plans[ plan_index ]
|
||||||
|
|
||||||
|
@expose( view = Json )
|
||||||
|
@end_transaction
|
||||||
|
@grab_user_id
|
||||||
|
@validate(
|
||||||
|
email_address = ( Valid_string( min = 0, max = 60 ) ),
|
||||||
|
settings_button = unicode,
|
||||||
|
user_id = Valid_id( none_okay = True ),
|
||||||
|
)
|
||||||
|
def update_settings( self, email_address, settings_button, user_id ):
|
||||||
|
"""
|
||||||
|
Update the settings for a particular user.
|
||||||
|
|
||||||
|
@type email_address: unicode
|
||||||
|
@param email_address: new email address
|
||||||
|
@type settings_button: unicode
|
||||||
|
@param settings_button: ignored
|
||||||
|
@type user_id: unicode
|
||||||
|
@param user_id: id of current logged-in user (if any), determined by @grab_user_id
|
||||||
|
@rtype: json dict
|
||||||
|
@return: { "email_address": new_email_address }
|
||||||
|
@raise Validation_error: one of the arguments is invalid
|
||||||
|
@raise Access_error: the given user id is unknown
|
||||||
|
"""
|
||||||
|
if len( email_address ) > 0:
|
||||||
|
try:
|
||||||
|
email_address = valid_email_address( email_address )
|
||||||
|
except ValueError:
|
||||||
|
raise Validation_error( "email_address", email_address, valid_email_address )
|
||||||
|
else:
|
||||||
|
email_address = None
|
||||||
|
|
||||||
|
user = self.__database.load( User, user_id )
|
||||||
|
if not user:
|
||||||
|
raise Access_error()
|
||||||
|
|
||||||
|
if email_address != user.email_address:
|
||||||
|
user.email_address = email_address
|
||||||
|
self.__database.save( user )
|
||||||
|
|
||||||
|
return dict(
|
||||||
|
email_address = email_address,
|
||||||
|
)
|
||||||
|
|
|
@ -3630,6 +3630,79 @@ class Test_users( Test_controller ):
|
||||||
assert rate_plan
|
assert rate_plan
|
||||||
assert rate_plan == self.settings[ u"global" ][ u"luminotes.rate_plans" ][ plan_index ]
|
assert rate_plan == self.settings[ u"global" ][ u"luminotes.rate_plans" ][ plan_index ]
|
||||||
|
|
||||||
|
def test_update_settings( self ):
|
||||||
|
self.login()
|
||||||
|
previous_revision = self.user.revision
|
||||||
|
|
||||||
|
result = self.http_post( "/users/update_settings", dict(
|
||||||
|
email_address = self.new_email_address,
|
||||||
|
settings_button = u"save settings",
|
||||||
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
assert result[ u"email_address" ] == self.new_email_address
|
||||||
|
|
||||||
|
user = self.database.load( User, self.user.object_id )
|
||||||
|
assert user.email_address == self.new_email_address
|
||||||
|
assert user.revision > previous_revision
|
||||||
|
|
||||||
|
def test_update_settings_without_login( self ):
|
||||||
|
original_revision = self.user.revision
|
||||||
|
|
||||||
|
result = self.http_post( "/users/update_settings", dict(
|
||||||
|
email_address = self.new_email_address,
|
||||||
|
settings_button = u"save settings",
|
||||||
|
) )
|
||||||
|
|
||||||
|
assert u"access" in result[ u"error" ]
|
||||||
|
|
||||||
|
user = self.database.load( User, self.user.object_id )
|
||||||
|
assert user.email_address == self.email_address
|
||||||
|
assert user.revision == original_revision
|
||||||
|
|
||||||
|
def test_update_settings_with_same_email_address( self ):
|
||||||
|
self.login()
|
||||||
|
original_revision = self.user.revision
|
||||||
|
|
||||||
|
result = self.http_post( "/users/update_settings", dict(
|
||||||
|
email_address = self.email_address,
|
||||||
|
settings_button = u"save settings",
|
||||||
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
assert result[ u"email_address" ] == self.email_address
|
||||||
|
|
||||||
|
user = self.database.load( User, self.user.object_id )
|
||||||
|
assert user.email_address == self.email_address
|
||||||
|
assert user.revision == original_revision
|
||||||
|
|
||||||
|
def test_update_settings_with_invalid_email_address( self ):
|
||||||
|
original_revision = self.user.revision
|
||||||
|
|
||||||
|
result = self.http_post( "/users/update_settings", dict(
|
||||||
|
email_address = u"foo@bar@com",
|
||||||
|
settings_button = u"save settings",
|
||||||
|
) )
|
||||||
|
|
||||||
|
assert u"invalid" in result[ u"error" ]
|
||||||
|
|
||||||
|
user = self.database.load( User, self.user.object_id )
|
||||||
|
assert user.email_address == self.email_address
|
||||||
|
assert user.revision == original_revision
|
||||||
|
|
||||||
|
def test_update_settings_with_blank_email_address( self ):
|
||||||
|
self.login()
|
||||||
|
previous_revision = self.user.revision
|
||||||
|
|
||||||
|
result = self.http_post( "/users/update_settings", dict(
|
||||||
|
email_address = u"",
|
||||||
|
settings_button = u"save settings",
|
||||||
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
assert result[ u"email_address" ] == None
|
||||||
|
|
||||||
|
user = self.database.load( User, self.user.object_id )
|
||||||
|
assert user.email_address == None
|
||||||
|
assert user.revision > previous_revision
|
||||||
|
|
||||||
def login( self ):
|
def login( self ):
|
||||||
result = self.http_post( "/users/login", dict(
|
result = self.http_post( "/users/login", dict(
|
||||||
username = self.username,
|
username = self.username,
|
||||||
|
|
|
@ -281,6 +281,10 @@ class User( Persistent ):
|
||||||
|
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
def __set_email_address( self, email_address ):
|
||||||
|
self.update_revision()
|
||||||
|
self.__email_address = email_address
|
||||||
|
|
||||||
def __set_password( self, password ):
|
def __set_password( self, password ):
|
||||||
self.update_revision()
|
self.update_revision()
|
||||||
self.__salt = User.__create_salt()
|
self.__salt = User.__create_salt()
|
||||||
|
@ -295,7 +299,7 @@ class User( Persistent ):
|
||||||
self.__rate_plan = rate_plan
|
self.__rate_plan = rate_plan
|
||||||
|
|
||||||
username = property( lambda self: self.__username )
|
username = property( lambda self: self.__username )
|
||||||
email_address = property( lambda self: self.__email_address )
|
email_address = property( lambda self: self.__email_address, __set_email_address )
|
||||||
password = property( None, __set_password )
|
password = property( None, __set_password )
|
||||||
storage_bytes = property( lambda self: self.__storage_bytes, __set_storage_bytes )
|
storage_bytes = property( lambda self: self.__storage_bytes, __set_storage_bytes )
|
||||||
rate_plan = property( lambda self: self.__rate_plan, __set_rate_plan )
|
rate_plan = property( lambda self: self.__rate_plan, __set_rate_plan )
|
||||||
|
|
|
@ -27,6 +27,22 @@ class Test_user( object ):
|
||||||
def test_check_incorrect_password( self ):
|
def test_check_incorrect_password( self ):
|
||||||
assert self.user.check_password( u"wrong" ) == False
|
assert self.user.check_password( u"wrong" ) == False
|
||||||
|
|
||||||
|
def test_set_email_address( self ):
|
||||||
|
previous_revision = self.user.revision
|
||||||
|
email_address = u"alice@example.com"
|
||||||
|
self.user.email_address = email_address
|
||||||
|
|
||||||
|
assert self.user.email_address == email_address
|
||||||
|
assert self.user.revision > previous_revision
|
||||||
|
|
||||||
|
def test_set_none_email_address( self ):
|
||||||
|
previous_revision = self.user.revision
|
||||||
|
email_address = None
|
||||||
|
self.user.email_address = email_address
|
||||||
|
|
||||||
|
assert self.user.email_address == email_address
|
||||||
|
assert self.user.revision > previous_revision
|
||||||
|
|
||||||
def test_set_password( self ):
|
def test_set_password( self ):
|
||||||
previous_revision = self.user.revision
|
previous_revision = self.user.revision
|
||||||
new_password = u"newpass"
|
new_password = u"newpass"
|
||||||
|
|
|
@ -213,6 +213,17 @@ Editor.prototype.finish_init = function () {
|
||||||
connect_button( revoke_button, invite_id );
|
connect_button( revoke_button, invite_id );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var settings_button = getElement( "settings_button" );
|
||||||
|
if ( settings_button ) {
|
||||||
|
var settings_form = getElement( "settings_form" );
|
||||||
|
connect( settings_button, "onclick", function ( event ) {
|
||||||
|
signal( self, "submit_form", "/users/update_settings", settings_form, function ( result ) {
|
||||||
|
signal( self, "settings_updated", result );
|
||||||
|
} );
|
||||||
|
event.stop();
|
||||||
|
} );
|
||||||
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// browsers such as Firefox, but not Opera
|
// browsers such as Firefox, but not Opera
|
||||||
|
|
|
@ -17,6 +17,7 @@ function Wiki( invoker ) {
|
||||||
this.invite_id = getElement( "invite_id" ).value;
|
this.invite_id = getElement( "invite_id" ).value;
|
||||||
this.after_login = getElement( "after_login" ).value;
|
this.after_login = getElement( "after_login" ).value;
|
||||||
this.signup_plan = getElement( "signup_plan" ).value;
|
this.signup_plan = getElement( "signup_plan" ).value;
|
||||||
|
this.email_address = getElement( "email_address" ).value || "";
|
||||||
this.font_size = null;
|
this.font_size = null;
|
||||||
|
|
||||||
var total_notes_count_node = getElement( "total_notes_count" );
|
var total_notes_count_node = getElement( "total_notes_count" );
|
||||||
|
@ -361,6 +362,14 @@ Wiki.prototype.populate = function ( startup_notes, current_notes, note_read_wri
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var settings_link = getElement( "settings_link" );
|
||||||
|
if ( settings_link ) {
|
||||||
|
connect( settings_link, "onclick", function ( event ) {
|
||||||
|
self.load_editor( "account settings", "null", null, null, null, getElement( "notes_top" ) );
|
||||||
|
event.stop();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
var declutter_link = getElement( "declutter_link" );
|
var declutter_link = getElement( "declutter_link" );
|
||||||
if ( declutter_link ) {
|
if ( declutter_link ) {
|
||||||
connect( declutter_link, "onclick", function ( event ) {
|
connect( declutter_link, "onclick", function ( event ) {
|
||||||
|
@ -468,6 +477,16 @@ Wiki.prototype.load_editor = function ( note_title, note_id, revision, previous_
|
||||||
this.share_notebook();
|
this.share_notebook();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if ( note_title == "account settings" ) {
|
||||||
|
var editor = this.open_editors[ note_title ];
|
||||||
|
if ( editor ) {
|
||||||
|
editor.highlight();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.display_settings();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// but if the note corresponding to the link's title is already open, highlight it and bail
|
// but if the note corresponding to the link's title is already open, highlight it and bail
|
||||||
if ( !revision ) {
|
if ( !revision ) {
|
||||||
|
@ -512,7 +531,7 @@ Wiki.prototype.resolve_link = function ( note_title, link, callback ) {
|
||||||
if ( link && link.target )
|
if ( link && link.target )
|
||||||
link.removeAttribute( "target" );
|
link.removeAttribute( "target" );
|
||||||
|
|
||||||
if ( note_title == "search results" || note_title == "share this notebook" ) {
|
if ( note_title == "search results" || note_title == "share this notebook" || note_title == "account settings" ) {
|
||||||
link.href = "/notebooks/" + this.notebook_id + "?" + queryString(
|
link.href = "/notebooks/" + this.notebook_id + "?" + queryString(
|
||||||
[ "title", "note_id" ],
|
[ "title", "note_id" ],
|
||||||
[ note_title, "null" ]
|
[ note_title, "null" ]
|
||||||
|
@ -520,8 +539,10 @@ Wiki.prototype.resolve_link = function ( note_title, link, callback ) {
|
||||||
if ( callback ) {
|
if ( callback ) {
|
||||||
if ( note_title == "search results" )
|
if ( note_title == "search results" )
|
||||||
callback( "current search results" );
|
callback( "current search results" );
|
||||||
else
|
else if ( note_title == "share this notebook" )
|
||||||
callback( "share this notebook with others" );
|
callback( "share this notebook with others" );
|
||||||
|
else
|
||||||
|
callback( "account settings" );
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -694,6 +715,11 @@ Wiki.prototype.create_editor = function ( id, note_text, deleted_from_id, revisi
|
||||||
connect( editor, "load_editor", this, "load_editor" );
|
connect( editor, "load_editor", this, "load_editor" );
|
||||||
connect( editor, "hide_clicked", function ( event ) { self.hide_editor( event, editor ) } );
|
connect( editor, "hide_clicked", function ( event ) { self.hide_editor( event, editor ) } );
|
||||||
connect( editor, "invites_updated", function ( invites ) { self.invites = invites; self.share_notebook(); } );
|
connect( editor, "invites_updated", function ( invites ) { self.invites = invites; self.share_notebook(); } );
|
||||||
|
connect( editor, "settings_updated", function ( result ) {
|
||||||
|
self.email_address = result.email_address || "";
|
||||||
|
self.display_message( "Your account settings have been updated." );
|
||||||
|
} );
|
||||||
|
|
||||||
connect( editor, "submit_form", function ( url, form, callback ) {
|
connect( editor, "submit_form", function ( url, form, callback ) {
|
||||||
var args = {}
|
var args = {}
|
||||||
if ( url == "/users/signup" ) {
|
if ( url == "/users/signup" ) {
|
||||||
|
@ -1556,6 +1582,41 @@ Wiki.prototype.display_invites = function ( invite_area ) {
|
||||||
replaceChildNodes( invite_area, div );
|
replaceChildNodes( invite_area, div );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Wiki.prototype.display_settings = function () {
|
||||||
|
this.clear_pulldowns();
|
||||||
|
|
||||||
|
var settings_frame = getElement( "note_settings" );
|
||||||
|
if ( settings_frame ) {
|
||||||
|
settings_frame.editor.highlight();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var div = createDOM( "div", {},
|
||||||
|
createDOM( "form", { "id": "settings_form" },
|
||||||
|
createDOM( "p", {},
|
||||||
|
createDOM( "b", {}, "email address" ),
|
||||||
|
createDOM( "br", {} ),
|
||||||
|
createDOM( "input",
|
||||||
|
{ "type": "text", "name": "email_address", "id": "email_address", "class": "text_field",
|
||||||
|
"size": "30", "maxlength": "60", "value": this.email_address || "" }
|
||||||
|
)
|
||||||
|
),
|
||||||
|
createDOM( "p", {},
|
||||||
|
createDOM( "input",
|
||||||
|
{ "type": "submit", "name": "settings_button", "id": "settings_button", "class": "button", "value": "save settings" }
|
||||||
|
)
|
||||||
|
),
|
||||||
|
createDOM( "p", {},
|
||||||
|
"Your email address will ",
|
||||||
|
createDOM( "a", { "href": "/privacy", "target": "_new" }, "never be shared" ),
|
||||||
|
". It will only be used for password resets, contacting you about account problems, and the from address in any invite emails you send."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.create_editor( "settings", "<h3>account settings</h3>" + div.innerHTML, undefined, undefined, undefined, false, true, true, getElement( "notes_top" ) );
|
||||||
|
}
|
||||||
|
|
||||||
Wiki.prototype.declutter_clicked = function () {
|
Wiki.prototype.declutter_clicked = function () {
|
||||||
var header = getElement( "header" );
|
var header = getElement( "header" );
|
||||||
if ( header )
|
if ( header )
|
||||||
|
@ -2269,6 +2330,12 @@ function Link_pulldown( wiki, notebook_id, invoker, editor, link ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( title == "account settings" ) {
|
||||||
|
this.title_field.value = title;
|
||||||
|
this.display_summary( title, "account settings" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.invoker.invoke(
|
this.invoker.invoke(
|
||||||
"/notebooks/load_note_by_title", "GET", {
|
"/notebooks/load_note_by_title", "GET", {
|
||||||
"notebook_id": this.notebook_id,
|
"notebook_id": this.notebook_id,
|
||||||
|
|
|
@ -32,6 +32,15 @@ class Header( Div ):
|
||||||
),
|
),
|
||||||
u" | ",
|
u" | ",
|
||||||
) or None,
|
) or None,
|
||||||
|
user.username and Span(
|
||||||
|
A(
|
||||||
|
u"settings",
|
||||||
|
href = u"#",
|
||||||
|
title = u"Update your account settings.",
|
||||||
|
id = u"settings_link",
|
||||||
|
),
|
||||||
|
" | ",
|
||||||
|
) or None,
|
||||||
user.username and Span(
|
user.username and Span(
|
||||||
A(
|
A(
|
||||||
u"upgrade",
|
u"upgrade",
|
||||||
|
|
|
@ -141,6 +141,7 @@ class Main_page( Page ):
|
||||||
Input( type = u"hidden", name = u"invite_id", id = u"invite_id", value = invite_id ),
|
Input( type = u"hidden", name = u"invite_id", id = u"invite_id", value = invite_id ),
|
||||||
Input( type = u"hidden", name = u"after_login", id = u"after_login", value = after_login ),
|
Input( type = u"hidden", name = u"after_login", id = u"after_login", value = after_login ),
|
||||||
Input( type = u"hidden", name = u"signup_plan", id = u"signup_plan", value = signup_plan ),
|
Input( type = u"hidden", name = u"signup_plan", id = u"signup_plan", value = signup_plan ),
|
||||||
|
Input( type = u"hidden", name = u"email_address", id = u"email_address", value = user.email_address ),
|
||||||
Div(
|
Div(
|
||||||
id = u"status_area",
|
id = u"status_area",
|
||||||
),
|
),
|
||||||
|
|
Reference in New Issue