Make portfolio invitation specific to portfolio

- add a base domain class
- extract shared model code to mixin
- rename invitation classes
- invitation model relationship to portfolio_role name is now more
  generic "role"
This commit is contained in:
dandds
2019-04-22 14:54:37 -04:00
parent ac36e34c13
commit c4ad7b4378
20 changed files with 228 additions and 203 deletions

View File

@@ -2,7 +2,7 @@ import datetime
from sqlalchemy.orm.exc import NoResultFound
from atst.database import db
from atst.models.invitation import Invitation, Status as InvitationStatus
from atst.models import InvitationStatus, PortfolioInvitation
from atst.domain.portfolio_roles import PortfolioRoles
from .exceptions import NotFoundError
@@ -38,27 +38,29 @@ class InvitationError(Exception):
return "{} has a status of {}".format(self.invite.id, self.invite.status.value)
class Invitations(object):
class BaseInvitations(object):
model = None
# number of minutes a given invitation is considered valid
EXPIRATION_LIMIT_MINUTES = 360
@classmethod
def _get(cls, token):
try:
invite = db.session.query(Invitation).filter_by(token=token).one()
invite = db.session.query(cls.model).filter_by(token=token).one()
except NoResultFound:
raise NotFoundError("invite")
return invite
@classmethod
def create(cls, inviter, portfolio_role, email):
invite = Invitation(
portfolio_role=portfolio_role,
def create(cls, inviter, role, email):
# pylint: disable=not-callable
invite = cls.model(
role=role,
inviter=inviter,
user=portfolio_role.user,
user=role.user,
status=InvitationStatus.PENDING,
expiration_time=Invitations.current_expiration_time(),
expiration_time=cls.current_expiration_time(),
email=email,
)
db.session.add(invite)
@@ -68,29 +70,29 @@ class Invitations(object):
@classmethod
def accept(cls, user, token):
invite = Invitations._get(token)
invite = cls._get(token)
if invite.user.dod_id != user.dod_id:
if invite.is_pending:
Invitations._update_status(invite, InvitationStatus.REJECTED_WRONG_USER)
cls._update_status(invite, InvitationStatus.REJECTED_WRONG_USER)
raise WrongUserError(user, invite)
elif invite.is_expired:
Invitations._update_status(invite, InvitationStatus.REJECTED_EXPIRED)
cls._update_status(invite, InvitationStatus.REJECTED_EXPIRED)
raise ExpiredError(invite)
elif invite.is_accepted or invite.is_revoked or invite.is_rejected:
raise InvitationError(invite)
elif invite.is_pending: # pragma: no branch
Invitations._update_status(invite, InvitationStatus.ACCEPTED)
PortfolioRoles.enable(invite.portfolio_role)
cls._update_status(invite, InvitationStatus.ACCEPTED)
PortfolioRoles.enable(invite.role)
return invite
@classmethod
def current_expiration_time(cls):
return datetime.datetime.now() + datetime.timedelta(
minutes=Invitations.EXPIRATION_LIMIT_MINUTES
minutes=cls.EXPIRATION_LIMIT_MINUTES
)
@classmethod
@@ -103,23 +105,25 @@ class Invitations(object):
@classmethod
def revoke(cls, token):
invite = Invitations._get(token)
return Invitations._update_status(invite, InvitationStatus.REVOKED)
invite = cls._get(token)
return cls._update_status(invite, InvitationStatus.REVOKED)
@classmethod
def lookup_by_portfolio_and_user(cls, portfolio, user):
portfolio_role = PortfolioRoles.get(portfolio.id, user.id)
role = PortfolioRoles.get(portfolio.id, user.id)
if portfolio_role.latest_invitation is None:
if role.latest_invitation is None:
raise NotFoundError("invitation")
return portfolio_role.latest_invitation
return role.latest_invitation
@classmethod
def resend(cls, user, token):
previous_invitation = Invitations._get(token)
Invitations._update_status(previous_invitation, InvitationStatus.REVOKED)
previous_invitation = cls._get(token)
cls._update_status(previous_invitation, InvitationStatus.REVOKED)
return Invitations.create(
user, previous_invitation.portfolio_role, previous_invitation.email
)
return cls.create(user, previous_invitation.role, previous_invitation.email)
class PortfolioInvitations(BaseInvitations):
model = PortfolioInvitation