Password reset now stores and uses a revision timestamp, which helps when testing for expiry.
This commit is contained in:
parent
bbebad528e
commit
322134cba6
|
@ -487,7 +487,7 @@ class Users( object ):
|
||||||
|
|
||||||
# record the sending of this reset email
|
# record the sending of this reset email
|
||||||
password_reset_id = self.__database.next_id( Password_reset, commit = False )
|
password_reset_id = self.__database.next_id( Password_reset, commit = False )
|
||||||
password_reset = Password_reset( password_reset_id, email_address )
|
password_reset = Password_reset.create( password_reset_id, email_address )
|
||||||
self.__database.save( password_reset )
|
self.__database.save( password_reset )
|
||||||
|
|
||||||
# create an email message with a unique link
|
# create an email message with a unique link
|
||||||
|
|
|
@ -5,12 +5,14 @@ class Password_reset( Persistent ):
|
||||||
"""
|
"""
|
||||||
A request for a password reset.
|
A request for a password reset.
|
||||||
"""
|
"""
|
||||||
def __init__( self, object_id, email_address = None, redeemed = False ):
|
def __init__( self, object_id, revision = None, email_address = None, redeemed = False ):
|
||||||
"""
|
"""
|
||||||
Create a password reset request with the given id.
|
Create a password reset request with the given id.
|
||||||
|
|
||||||
@type object_id: unicode
|
@type object_id: unicode
|
||||||
@param object_id: id of the password reset
|
@param object_id: id of the password reset
|
||||||
|
@type revision: datetime or NoneType
|
||||||
|
@param revision: revision timestamp of the object (optional, defaults to now)
|
||||||
@type email_address: unicode
|
@type email_address: unicode
|
||||||
@param email_address: where the reset confirmation was emailed
|
@param email_address: where the reset confirmation was emailed
|
||||||
@type redeemed: bool or NoneType
|
@type redeemed: bool or NoneType
|
||||||
|
@ -18,17 +20,29 @@ class Password_reset( Persistent ):
|
||||||
@rtype: Password_reset
|
@rtype: Password_reset
|
||||||
@return: newly constructed password reset
|
@return: newly constructed password reset
|
||||||
"""
|
"""
|
||||||
Persistent.__init__( self, object_id )
|
Persistent.__init__( self, object_id, revision )
|
||||||
self.__email_address = email_address
|
self.__email_address = email_address
|
||||||
self.__redeemed = redeemed
|
self.__redeemed = redeemed
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create( object_id, email_address = None ):
|
||||||
|
"""
|
||||||
|
Convenience constructor for creating a new note.
|
||||||
|
|
||||||
|
@type email_address: unicode
|
||||||
|
@param email_address: where the reset confirmation was emailed
|
||||||
|
@rtype: Password_reset
|
||||||
|
@return: newly constructed password reset
|
||||||
|
"""
|
||||||
|
return Password_reset( object_id, email_address = email_address )
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def sql_load( object_id, revision = None ):
|
def sql_load( object_id, revision = None ):
|
||||||
# password resets don't track revisions
|
# password resets don't track revisions
|
||||||
if revision:
|
if revision:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
return "select * from password_reset where id = %s;" % quote( object_id )
|
return "select id, revision, email_address, redeemed from password_reset where id = %s;" % quote( object_id )
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def sql_id_exists( object_id, revision = None ):
|
def sql_id_exists( object_id, revision = None ):
|
||||||
|
@ -41,12 +55,12 @@ class Password_reset( Persistent ):
|
||||||
return Password_reset.sql_id_exists( self.object_id )
|
return Password_reset.sql_id_exists( self.object_id )
|
||||||
|
|
||||||
def sql_create( self ):
|
def sql_create( self ):
|
||||||
return "insert into password_reset ( id, email_address, redeemed ) values ( %s, %s, %s );" % \
|
return "insert into password_reset ( id, revision, email_address, redeemed ) values ( %s, %s, %s, %s );" % \
|
||||||
( quote( self.object_id ), quote( self.__email_address ), quote( self.__redeemed and "t" or "f" ) )
|
( quote( self.object_id ), quote( self.revision ), quote( self.__email_address ), quote( self.__redeemed and "t" or "f" ) )
|
||||||
|
|
||||||
def sql_update( self ):
|
def sql_update( self ):
|
||||||
return "update password_reset set email_address = %s, redeemed = %s where id = %s;" % \
|
return "update password_reset set revision = %s, email_address = %s, redeemed = %s where id = %s;" % \
|
||||||
( quote( self.__email_address ), quote( self.__redeemed and "t" or "f" ), quote( self.object_id ) )
|
( quote( self.revision ), quote( self.__email_address ), quote( self.__redeemed and "t" or "f" ), quote( self.object_id ) )
|
||||||
|
|
||||||
def __set_redeemed( self, redeemed ):
|
def __set_redeemed( self, redeemed ):
|
||||||
if redeemed != self.__redeemed:
|
if redeemed != self.__redeemed:
|
||||||
|
|
|
@ -98,6 +98,7 @@ ALTER TABLE public.notebook_current OWNER TO luminotes;
|
||||||
|
|
||||||
CREATE TABLE password_reset (
|
CREATE TABLE password_reset (
|
||||||
id text NOT NULL,
|
id text NOT NULL,
|
||||||
|
revision timestamp with time zone NOT NULL,
|
||||||
email_address text,
|
email_address text,
|
||||||
redeemed boolean
|
redeemed boolean
|
||||||
);
|
);
|
||||||
|
|
|
@ -7,7 +7,7 @@ class Test_password_reset( object ):
|
||||||
self.object_id = u"17"
|
self.object_id = u"17"
|
||||||
self.email_address = u"bob@example.com"
|
self.email_address = u"bob@example.com"
|
||||||
|
|
||||||
self.password_reset = Password_reset( self.object_id, self.email_address )
|
self.password_reset = Password_reset.create( self.object_id, self.email_address )
|
||||||
|
|
||||||
def test_create( self ):
|
def test_create( self ):
|
||||||
assert self.password_reset.object_id == self.object_id
|
assert self.password_reset.object_id == self.object_id
|
||||||
|
|
Reference in New Issue