record expiration time on the invitation
This commit is contained in:
parent
d5998ed370
commit
5c5f9c6c9c
@ -0,0 +1,28 @@
|
|||||||
|
"""add expiration_time to invitation
|
||||||
|
|
||||||
|
Revision ID: e62bcc460c26
|
||||||
|
Revises: 03654d08f5ff
|
||||||
|
Create Date: 2018-10-26 13:37:39.015003
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'e62bcc460c26'
|
||||||
|
down_revision = '03654d08f5ff'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column('invitations', sa.Column('expiration_time', sa.TIMESTAMP(timezone=True), nullable=True))
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_column('invitations', 'expiration_time')
|
||||||
|
# ### end Alembic commands ###
|
@ -36,6 +36,7 @@ class Invitations(object):
|
|||||||
inviter=inviter,
|
inviter=inviter,
|
||||||
user=user,
|
user=user,
|
||||||
status=InvitationStatus.PENDING,
|
status=InvitationStatus.PENDING,
|
||||||
|
expiration_time=Invitations.current_expiration_time(),
|
||||||
)
|
)
|
||||||
db.session.add(invite)
|
db.session.add(invite)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
@ -46,7 +47,7 @@ class Invitations(object):
|
|||||||
def accept(cls, invite_id):
|
def accept(cls, invite_id):
|
||||||
invite = Invitations._get(invite_id)
|
invite = Invitations._get(invite_id)
|
||||||
|
|
||||||
if Invitations._is_expired(invite):
|
if invite.is_expired:
|
||||||
invite.status = InvitationStatus.REJECTED
|
invite.status = InvitationStatus.REJECTED
|
||||||
elif invite.is_pending:
|
elif invite.is_pending:
|
||||||
invite.status = InvitationStatus.ACCEPTED
|
invite.status = InvitationStatus.ACCEPTED
|
||||||
@ -60,9 +61,7 @@ class Invitations(object):
|
|||||||
return invite
|
return invite
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _is_expired(cls, invite):
|
def current_expiration_time(cls):
|
||||||
time_created = invite.time_created
|
return datetime.datetime.now() + datetime.timedelta(
|
||||||
expiration = datetime.datetime.now(time_created.tzinfo) - datetime.timedelta(
|
|
||||||
minutes=Invitations.EXPIRATION_LIMIT_MINUTES
|
minutes=Invitations.EXPIRATION_LIMIT_MINUTES
|
||||||
)
|
)
|
||||||
return invite.time_created < expiration
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
|
import datetime
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
from sqlalchemy import Column, ForeignKey, Enum as SQLAEnum
|
from sqlalchemy import Column, ForeignKey, Enum as SQLAEnum, TIMESTAMP
|
||||||
from sqlalchemy.dialects.postgresql import UUID
|
from sqlalchemy.dialects.postgresql import UUID
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
|
||||||
@ -31,6 +32,8 @@ class Invitation(Base, TimestampsMixin):
|
|||||||
|
|
||||||
status = Column(SQLAEnum(Status, native_enum=False, default=Status.PENDING))
|
status = Column(SQLAEnum(Status, native_enum=False, default=Status.PENDING))
|
||||||
|
|
||||||
|
expiration_time = Column(TIMESTAMP(timezone=True))
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<Invitation(user='{}', workspace='{}', id='{}')>".format(
|
return "<Invitation(user='{}', workspace='{}', id='{}')>".format(
|
||||||
self.user.id, self.workspace.id, self.id
|
self.user.id, self.workspace.id, self.id
|
||||||
@ -51,3 +54,7 @@ class Invitation(Base, TimestampsMixin):
|
|||||||
@property
|
@property
|
||||||
def is_rejected(self):
|
def is_rejected(self):
|
||||||
return self.status == Status.REJECTED
|
return self.status == Status.REJECTED
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_expired(self):
|
||||||
|
return datetime.datetime.now(self.expiration_time.tzinfo) > self.expiration_time
|
||||||
|
@ -30,11 +30,11 @@ def test_accept_expired_invitation():
|
|||||||
workspace = WorkspaceFactory.create()
|
workspace = WorkspaceFactory.create()
|
||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
increment = Invitations.EXPIRATION_LIMIT_MINUTES + 1
|
increment = Invitations.EXPIRATION_LIMIT_MINUTES + 1
|
||||||
created_at = datetime.datetime.now() - datetime.timedelta(minutes=increment)
|
expiration_time = datetime.datetime.now() - datetime.timedelta(minutes=increment)
|
||||||
invite = InvitationFactory.create(
|
invite = InvitationFactory.create(
|
||||||
workspace_id=workspace.id,
|
workspace_id=workspace.id,
|
||||||
user_id=user.id,
|
user_id=user.id,
|
||||||
time_created=created_at,
|
expiration_time=expiration_time,
|
||||||
status=Status.PENDING,
|
status=Status.PENDING,
|
||||||
)
|
)
|
||||||
with pytest.raises(InvitationError):
|
with pytest.raises(InvitationError):
|
||||||
|
@ -22,6 +22,7 @@ from atst.models.workspace_role import WorkspaceRole
|
|||||||
from atst.models.environment_role import EnvironmentRole
|
from atst.models.environment_role import EnvironmentRole
|
||||||
from atst.models.invitation import Invitation, Status as InvitationStatus
|
from atst.models.invitation import Invitation, Status as InvitationStatus
|
||||||
from atst.domain.workspaces import Workspaces
|
from atst.domain.workspaces import Workspaces
|
||||||
|
from atst.domain.invitations import Invitations
|
||||||
|
|
||||||
|
|
||||||
class Base(factory.alchemy.SQLAlchemyModelFactory):
|
class Base(factory.alchemy.SQLAlchemyModelFactory):
|
||||||
@ -341,3 +342,4 @@ class InvitationFactory(Base):
|
|||||||
model = Invitation
|
model = Invitation
|
||||||
|
|
||||||
status = InvitationStatus.PENDING
|
status = InvitationStatus.PENDING
|
||||||
|
expiration_time = Invitations.current_expiration_time()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user