witten
/
luminotes
Archived
1
0
Fork 0

Implemented basic user account settings. Now you can change your email

address.
This commit is contained in:
Dan Helfman 2008-05-08 03:05:35 +00:00
parent 11263d65fa
commit 18982dc129
9 changed files with 233 additions and 3 deletions

6
NEWS
View File

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

View File

@ -1208,3 +1208,46 @@ class Users( object ):
def rate_plan( self, 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,
)

View File

@ -3630,6 +3630,79 @@ class Test_users( Test_controller ):
assert rate_plan
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 ):
result = self.http_post( "/users/login", dict(
username = self.username,

View File

@ -281,6 +281,10 @@ class User( Persistent ):
return d
def __set_email_address( self, email_address ):
self.update_revision()
self.__email_address = email_address
def __set_password( self, password ):
self.update_revision()
self.__salt = User.__create_salt()
@ -295,7 +299,7 @@ class User( Persistent ):
self.__rate_plan = rate_plan
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 )
storage_bytes = property( lambda self: self.__storage_bytes, __set_storage_bytes )
rate_plan = property( lambda self: self.__rate_plan, __set_rate_plan )

View File

@ -27,6 +27,22 @@ class Test_user( object ):
def test_check_incorrect_password( self ):
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 ):
previous_revision = self.user.revision
new_password = u"newpass"

View File

@ -213,6 +213,17 @@ Editor.prototype.finish_init = function () {
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

View File

@ -17,6 +17,7 @@ function Wiki( invoker ) {
this.invite_id = getElement( "invite_id" ).value;
this.after_login = getElement( "after_login" ).value;
this.signup_plan = getElement( "signup_plan" ).value;
this.email_address = getElement( "email_address" ).value || "";
this.font_size = null;
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" );
if ( declutter_link ) {
connect( declutter_link, "onclick", function ( event ) {
@ -468,6 +477,16 @@ Wiki.prototype.load_editor = function ( note_title, note_id, revision, previous_
this.share_notebook();
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
if ( !revision ) {
@ -512,7 +531,7 @@ Wiki.prototype.resolve_link = function ( note_title, link, callback ) {
if ( link && link.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(
[ "title", "note_id" ],
[ note_title, "null" ]
@ -520,8 +539,10 @@ Wiki.prototype.resolve_link = function ( note_title, link, callback ) {
if ( callback ) {
if ( note_title == "search results" )
callback( "current search results" );
else
else if ( note_title == "share this notebook" )
callback( "share this notebook with others" );
else
callback( "account settings" );
}
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, "hide_clicked", function ( event ) { self.hide_editor( event, editor ) } );
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 ) {
var args = {}
if ( url == "/users/signup" ) {
@ -1556,6 +1582,41 @@ Wiki.prototype.display_invites = function ( invite_area ) {
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 () {
var header = getElement( "header" );
if ( header )
@ -2269,6 +2330,12 @@ function Link_pulldown( wiki, notebook_id, invoker, editor, link ) {
return;
}
if ( title == "account settings" ) {
this.title_field.value = title;
this.display_summary( title, "account settings" );
return;
}
this.invoker.invoke(
"/notebooks/load_note_by_title", "GET", {
"notebook_id": this.notebook_id,

View File

@ -32,6 +32,15 @@ class Header( Div ):
),
u" | ",
) 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(
A(
u"upgrade",

View File

@ -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"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"email_address", id = u"email_address", value = user.email_address ),
Div(
id = u"status_area",
),