diff --git a/model/Invite.py b/model/Invite.py new file mode 100644 index 0000000..6c97207 --- /dev/null +++ b/model/Invite.py @@ -0,0 +1,103 @@ +from Persistent import Persistent, quote + + +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 ): + """ + Create an invitation with the given id. + + @type object_id: unicode + @param object_id: id of the invitation + @type revision: datetime or NoneType + @param revision: revision timestamp of the object (optional, defaults to now) + @type from_user_id: unicode or NoneType + @param from_user_id: id of the user who sent the invite (optional) + @type notebook_id: unicode or NoneType + @param notebook_id: id of the notebook that the invitation is to + @type email_address: unicode or NoneType + @param email_address: where the invitation was emailed (optional) + @type read_write: bool or NoneType + @param read_write: whether the invitation is for read-write access (optional, defaults to False) + @type owner: bool or NoneType + @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) + @rtype: Invite + @return: newly constructed notebook invitation + """ + Persistent.__init__( self, object_id, revision ) + self.__from_user_id = from_user_id + self.__notebook_id = notebook_id + self.__email_address = email_address + self.__read_write = read_write + self.__owner = owner + self.__redeemed_user_id = redeemed_user_id + + @staticmethod + def create( object_id, from_user_id = None, notebook_id = None, email_address = None, read_write = False, owner = False ): + """ + Convenience constructor for creating a new invitation. + + @type object_id: unicode + @param object_id: id of the invitation + @type from_user_id: unicode or NoneType + @param from_user_id: id of the user who sent the invite (optional) + @type notebook_id: unicode or NoneType + @param notebook_id: id of the notebook that the invitation is to + @type email_address: unicode or NoneType + @param email_address: where the invitation was emailed (optional) + @type read_write: bool or NoneType + @param read_write: whether the invitation is for read-write access (optional, defaults to False) + @type owner: bool or NoneType + @param owner: whether the invitation is for owner-level access (optional, defaults to False) + @rtype: Invite + @return: newly constructed notebook invitation + """ + return Invite( object_id, from_user_id = from_user_id, notebook_id = notebook_id, + email_address = email_address, read_write = read_write, owner = owner ) + + @staticmethod + def sql_load( object_id, revision = None ): + # password resets don't store old revisions + 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 ) + + @staticmethod + def sql_id_exists( object_id, revision = None ): + if revision: + raise NotImplementedError() + + return "select id from invite where id = %s;" % quote( object_id ) + + def sql_exists( self ): + return Invite.sql_id_exists( self.object_id ) + + def sql_create( self ): + return "insert into invite ( id, revision, from_user_id, notebook_id, email_address, read_write, owner, redeemed_user_id ) values ( %s, %s, %s, %s, %s, %s, %s, %s );" % \ + ( quote( self.object_id ), quote( self.revision ), quote( self.__from_user_id ), quote( self.__notebook_id ), + quote( self.__email_address ), quote( self.__read_write and "t" or "f" ), quote( self.__owner and "t" or "f" ), + quote( self.__redeemed_user_id ) ) + + def sql_update( self ): + return "update invite set revision = %s, from_user_id = %s, notebook_id = %s, email_address = %s, read_write = %s, owner = %s, redeemed_user_id = %s where id = %s;" % \ + ( quote( self.object_id ), quote( self.revision ), quote( self.__from_user_id ), quote( self.__notebook_id ), + quote( self.__email_address ), quote( self.__read_write and "t" or "f" ), quote( self.__owner and "t" or "f" ), + quote( self.__redeemed_user_id ) ) + + def __set_redeemed_user_id( self, redeemed_user_id ): + if redeemed_user_id != self.__redeemed_user_id: + self.update_revision() + self.__redeemed_user_id = redeemed_user_id + + from_user_id = property( lambda self: self.__from_user_id ) + notebook_id = property( lambda self: self.__notebook_id ) + email_address = property( lambda self: self.__email_address ) + read_write = property( lambda self: self.__read_write ) + owner = property( lambda self: self.__owner ) + redeemed_user_id = property( lambda self: self.__redeemed_user_id, __set_redeemed_user_id ) diff --git a/model/Password_reset.py b/model/Password_reset.py index 64bd6d2..730dafa 100644 --- a/model/Password_reset.py +++ b/model/Password_reset.py @@ -13,8 +13,8 @@ class Password_reset( Persistent ): @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 - @param email_address: where the reset confirmation was emailed + @type email_address: unicode or NoneType + @param email_address: where the reset confirmation was emailed (optional) @type redeemed: bool or NoneType @param redeemed: whether this password reset has been redeemed yet (optional, defaults to False) @rtype: Password_reset @@ -27,7 +27,7 @@ class Password_reset( Persistent ): @staticmethod def create( object_id, email_address = None ): """ - Convenience constructor for creating a new note. + Convenience constructor for creating a new password reset. @type email_address: unicode @param email_address: where the reset confirmation was emailed @@ -38,7 +38,7 @@ class Password_reset( Persistent ): @staticmethod def sql_load( object_id, revision = None ): - # password resets don't track revisions + # password resets don't store old revisions if revision: raise NotImplementedError() diff --git a/model/delta/1.0.4.sql b/model/delta/1.0.4.sql index 855899c..fb501dc 100644 --- a/model/delta/1.0.4.sql +++ b/model/delta/1.0.4.sql @@ -1,7 +1,7 @@ create table invite ( id text not null, revision timestamp with time zone not null, - sent_user_id text, + from_user_id text, notebook_id text, email_address text, read_write boolean, diff --git a/model/schema.sql b/model/schema.sql index 9ce81ad..7fd6987 100644 --- a/model/schema.sql +++ b/model/schema.sql @@ -38,7 +38,7 @@ ALTER FUNCTION public.drop_html_tags(text) OWNER TO luminotes; CREATE TABLE invite ( id text NOT NULL, revision timestamp with time zone NOT NULL, - sent_user_id text, + from_user_id text, notebook_id text, email_address text, read_write boolean, diff --git a/model/test/Test_invite.py b/model/test/Test_invite.py new file mode 100644 index 0000000..0392c47 --- /dev/null +++ b/model/test/Test_invite.py @@ -0,0 +1,41 @@ +from model.User import User +from model.Invite import Invite + + +class Test_invite( object ): + def setUp( self ): + self.object_id = u"17" + self.from_user_id = u"18" + self.notebook_id = u"19" + self.email_address = u"bob@example.com" + self.read_write = True + self.owner = False + + self.invite = Invite.create( self.object_id, self.from_user_id, self.notebook_id, + self.email_address, self.read_write, self.owner ) + + def test_create( self ): + assert self.invite.object_id == self.object_id + assert self.invite.from_user_id == self.from_user_id + assert self.invite.notebook_id == self.notebook_id + assert self.invite.email_address == self.email_address + assert self.invite.read_write == self.read_write + assert self.invite.owner == self.owner + assert self.invite.redeemed_user_id == None + + def test_redeem( self ): + previous_revision = self.invite.revision + redeemed_user_id = u"20" + self.invite.redeemed_user_id = redeemed_user_id + + assert self.invite.redeemed_user_id == redeemed_user_id + assert self.invite.revision > previous_revision + + def test_redeem_twice( self ): + redeemed_user_id = u"20" + self.invite.redeemed_user_id = redeemed_user_id + current_revision = self.invite.revision + self.invite.redeemed_user_id = redeemed_user_id + + assert self.invite.redeemed_user_id == redeemed_user_id + assert self.invite.revision == current_revision