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:
parent
ac36e34c13
commit
c4ad7b4378
@ -6,8 +6,8 @@ from . import user_can_access
|
|||||||
from atst.domain.portfolios import Portfolios
|
from atst.domain.portfolios import Portfolios
|
||||||
from atst.domain.task_orders import TaskOrders
|
from atst.domain.task_orders import TaskOrders
|
||||||
from atst.domain.applications import Applications
|
from atst.domain.applications import Applications
|
||||||
from atst.domain.invitations import Invitations
|
|
||||||
from atst.domain.environments import Environments
|
from atst.domain.environments import Environments
|
||||||
|
from atst.domain.invitations import PortfolioInvitations
|
||||||
from atst.domain.exceptions import UnauthorizedError
|
from atst.domain.exceptions import UnauthorizedError
|
||||||
|
|
||||||
|
|
||||||
@ -24,8 +24,8 @@ def check_access(permission, message, override, *args, **kwargs):
|
|||||||
access_args["portfolio"] = task_order.portfolio
|
access_args["portfolio"] = task_order.portfolio
|
||||||
|
|
||||||
elif "token" in kwargs:
|
elif "token" in kwargs:
|
||||||
invite = Invitations._get(kwargs["token"])
|
invite = PortfolioInvitations._get(kwargs["token"])
|
||||||
access_args["portfolio"] = invite.portfolio_role.portfolio
|
access_args["portfolio"] = invite.role.portfolio
|
||||||
|
|
||||||
elif "portfolio_id" in kwargs:
|
elif "portfolio_id" in kwargs:
|
||||||
access_args["portfolio"] = Portfolios.get(
|
access_args["portfolio"] = Portfolios.get(
|
||||||
|
@ -2,7 +2,7 @@ import datetime
|
|||||||
from sqlalchemy.orm.exc import NoResultFound
|
from sqlalchemy.orm.exc import NoResultFound
|
||||||
|
|
||||||
from atst.database import db
|
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 atst.domain.portfolio_roles import PortfolioRoles
|
||||||
|
|
||||||
from .exceptions import NotFoundError
|
from .exceptions import NotFoundError
|
||||||
@ -38,27 +38,29 @@ class InvitationError(Exception):
|
|||||||
return "{} has a status of {}".format(self.invite.id, self.invite.status.value)
|
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
|
# number of minutes a given invitation is considered valid
|
||||||
EXPIRATION_LIMIT_MINUTES = 360
|
EXPIRATION_LIMIT_MINUTES = 360
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get(cls, token):
|
def _get(cls, token):
|
||||||
try:
|
try:
|
||||||
invite = db.session.query(Invitation).filter_by(token=token).one()
|
invite = db.session.query(cls.model).filter_by(token=token).one()
|
||||||
except NoResultFound:
|
except NoResultFound:
|
||||||
raise NotFoundError("invite")
|
raise NotFoundError("invite")
|
||||||
|
|
||||||
return invite
|
return invite
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, inviter, portfolio_role, email):
|
def create(cls, inviter, role, email):
|
||||||
invite = Invitation(
|
# pylint: disable=not-callable
|
||||||
portfolio_role=portfolio_role,
|
invite = cls.model(
|
||||||
|
role=role,
|
||||||
inviter=inviter,
|
inviter=inviter,
|
||||||
user=portfolio_role.user,
|
user=role.user,
|
||||||
status=InvitationStatus.PENDING,
|
status=InvitationStatus.PENDING,
|
||||||
expiration_time=Invitations.current_expiration_time(),
|
expiration_time=cls.current_expiration_time(),
|
||||||
email=email,
|
email=email,
|
||||||
)
|
)
|
||||||
db.session.add(invite)
|
db.session.add(invite)
|
||||||
@ -68,29 +70,29 @@ class Invitations(object):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def accept(cls, user, token):
|
def accept(cls, user, token):
|
||||||
invite = Invitations._get(token)
|
invite = cls._get(token)
|
||||||
|
|
||||||
if invite.user.dod_id != user.dod_id:
|
if invite.user.dod_id != user.dod_id:
|
||||||
if invite.is_pending:
|
if invite.is_pending:
|
||||||
Invitations._update_status(invite, InvitationStatus.REJECTED_WRONG_USER)
|
cls._update_status(invite, InvitationStatus.REJECTED_WRONG_USER)
|
||||||
raise WrongUserError(user, invite)
|
raise WrongUserError(user, invite)
|
||||||
|
|
||||||
elif invite.is_expired:
|
elif invite.is_expired:
|
||||||
Invitations._update_status(invite, InvitationStatus.REJECTED_EXPIRED)
|
cls._update_status(invite, InvitationStatus.REJECTED_EXPIRED)
|
||||||
raise ExpiredError(invite)
|
raise ExpiredError(invite)
|
||||||
|
|
||||||
elif invite.is_accepted or invite.is_revoked or invite.is_rejected:
|
elif invite.is_accepted or invite.is_revoked or invite.is_rejected:
|
||||||
raise InvitationError(invite)
|
raise InvitationError(invite)
|
||||||
|
|
||||||
elif invite.is_pending: # pragma: no branch
|
elif invite.is_pending: # pragma: no branch
|
||||||
Invitations._update_status(invite, InvitationStatus.ACCEPTED)
|
cls._update_status(invite, InvitationStatus.ACCEPTED)
|
||||||
PortfolioRoles.enable(invite.portfolio_role)
|
PortfolioRoles.enable(invite.role)
|
||||||
return invite
|
return invite
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def current_expiration_time(cls):
|
def current_expiration_time(cls):
|
||||||
return datetime.datetime.now() + datetime.timedelta(
|
return datetime.datetime.now() + datetime.timedelta(
|
||||||
minutes=Invitations.EXPIRATION_LIMIT_MINUTES
|
minutes=cls.EXPIRATION_LIMIT_MINUTES
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -103,23 +105,25 @@ class Invitations(object):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def revoke(cls, token):
|
def revoke(cls, token):
|
||||||
invite = Invitations._get(token)
|
invite = cls._get(token)
|
||||||
return Invitations._update_status(invite, InvitationStatus.REVOKED)
|
return cls._update_status(invite, InvitationStatus.REVOKED)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def lookup_by_portfolio_and_user(cls, portfolio, user):
|
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")
|
raise NotFoundError("invitation")
|
||||||
|
|
||||||
return portfolio_role.latest_invitation
|
return role.latest_invitation
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def resend(cls, user, token):
|
def resend(cls, user, token):
|
||||||
previous_invitation = Invitations._get(token)
|
previous_invitation = cls._get(token)
|
||||||
Invitations._update_status(previous_invitation, InvitationStatus.REVOKED)
|
cls._update_status(previous_invitation, InvitationStatus.REVOKED)
|
||||||
|
|
||||||
return Invitations.create(
|
return cls.create(user, previous_invitation.role, previous_invitation.email)
|
||||||
user, previous_invitation.portfolio_role, previous_invitation.email
|
|
||||||
)
|
|
||||||
|
class PortfolioInvitations(BaseInvitations):
|
||||||
|
model = PortfolioInvitation
|
||||||
|
@ -5,14 +5,16 @@ Base = declarative_base()
|
|||||||
from .permissions import Permissions
|
from .permissions import Permissions
|
||||||
from .permission_set import PermissionSet
|
from .permission_set import PermissionSet
|
||||||
from .user import User
|
from .user import User
|
||||||
from .portfolio_role import PortfolioRole
|
from .portfolio_role import PortfolioRole, Status as PortfolioRoleStatus
|
||||||
from .application_role import ApplicationRole
|
from .application_role import ApplicationRole, Status as ApplicationRoleStatus
|
||||||
from .environment_role import EnvironmentRole
|
from .environment_role import EnvironmentRole
|
||||||
from .portfolio import Portfolio
|
from .portfolio import Portfolio
|
||||||
from .application import Application
|
from .application import Application
|
||||||
from .environment import Environment
|
from .environment import Environment
|
||||||
from .attachment import Attachment
|
from .attachment import Attachment
|
||||||
from .audit_event import AuditEvent
|
from .audit_event import AuditEvent
|
||||||
from .invitation import Invitation
|
from .portfolio_invitation import PortfolioInvitation
|
||||||
from .task_order import TaskOrder
|
from .task_order import TaskOrder
|
||||||
from .dd_254 import DD254
|
from .dd_254 import DD254
|
||||||
|
|
||||||
|
from .mixins.invites import Status as InvitationStatus
|
||||||
|
@ -2,3 +2,4 @@ from .timestamps import TimestampsMixin
|
|||||||
from .auditable import AuditableMixin
|
from .auditable import AuditableMixin
|
||||||
from .permissions import PermissionsMixin
|
from .permissions import PermissionsMixin
|
||||||
from .deletable import DeletableMixin
|
from .deletable import DeletableMixin
|
||||||
|
from .invites import InvitesMixin
|
||||||
|
@ -3,12 +3,11 @@ from enum import Enum
|
|||||||
import secrets
|
import secrets
|
||||||
|
|
||||||
from sqlalchemy import Column, ForeignKey, Enum as SQLAEnum, TIMESTAMP, String
|
from sqlalchemy import Column, ForeignKey, Enum as SQLAEnum, TIMESTAMP, String
|
||||||
|
from sqlalchemy.ext.declarative import declared_attr
|
||||||
from sqlalchemy.dialects.postgresql import UUID
|
from sqlalchemy.dialects.postgresql import UUID
|
||||||
from sqlalchemy.orm import relationship, backref
|
from sqlalchemy.orm import relationship
|
||||||
|
|
||||||
from atst.models import Base, types
|
from atst.models import types
|
||||||
from atst.models.mixins.timestamps import TimestampsMixin
|
|
||||||
from atst.models.mixins.auditable import AuditableMixin
|
|
||||||
|
|
||||||
|
|
||||||
class Status(Enum):
|
class Status(Enum):
|
||||||
@ -19,24 +18,24 @@ class Status(Enum):
|
|||||||
REJECTED_EXPIRED = "rejected_expired"
|
REJECTED_EXPIRED = "rejected_expired"
|
||||||
|
|
||||||
|
|
||||||
class Invitation(Base, TimestampsMixin, AuditableMixin):
|
class InvitesMixin(object):
|
||||||
__tablename__ = "invitations"
|
|
||||||
|
|
||||||
id = types.Id()
|
id = types.Id()
|
||||||
|
|
||||||
user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), index=True)
|
@declared_attr
|
||||||
user = relationship("User", backref="invitations", foreign_keys=[user_id])
|
def user_id(cls):
|
||||||
|
return Column(UUID(as_uuid=True), ForeignKey("users.id"), index=True)
|
||||||
|
|
||||||
portfolio_role_id = Column(
|
@declared_attr
|
||||||
UUID(as_uuid=True), ForeignKey("portfolio_roles.id"), index=True
|
def user(cls):
|
||||||
)
|
return relationship("User", foreign_keys=[cls.user_id])
|
||||||
portfolio_role = relationship(
|
|
||||||
"PortfolioRole",
|
|
||||||
backref=backref("invitations", order_by="Invitation.time_created"),
|
|
||||||
)
|
|
||||||
|
|
||||||
inviter_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), index=True)
|
@declared_attr
|
||||||
inviter = relationship("User", backref="sent_invites", foreign_keys=[inviter_id])
|
def inviter_id(cls):
|
||||||
|
return Column(UUID(as_uuid=True), ForeignKey("users.id"), index=True)
|
||||||
|
|
||||||
|
@declared_attr
|
||||||
|
def inviter(cls):
|
||||||
|
return relationship("User", foreign_keys=[cls.inviter_id])
|
||||||
|
|
||||||
status = Column(SQLAEnum(Status, native_enum=False, default=Status.PENDING))
|
status = Column(SQLAEnum(Status, native_enum=False, default=Status.PENDING))
|
||||||
|
|
||||||
@ -47,8 +46,9 @@ class Invitation(Base, TimestampsMixin, AuditableMixin):
|
|||||||
email = Column(String, nullable=False)
|
email = Column(String, nullable=False)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<Invitation(user='{}', portfolio_role='{}', id='{}', email='{}')>".format(
|
role_id = self.role.id if self.role else None
|
||||||
self.user_id, self.portfolio_role_id, self.id, self.email
|
return "<{}(user='{}', role='{}', id='{}', email='{}')>".format(
|
||||||
|
self.__class__.__name__, self.user_id, role_id, self.id, self.email
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -90,14 +90,9 @@ class Invitation(Base, TimestampsMixin, AuditableMixin):
|
|||||||
Status.REVOKED,
|
Status.REVOKED,
|
||||||
]
|
]
|
||||||
|
|
||||||
@property
|
|
||||||
def portfolio(self):
|
|
||||||
if self.portfolio_role: # pragma: no branch
|
|
||||||
return self.portfolio_role.portfolio
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def user_name(self):
|
def user_name(self):
|
||||||
return self.portfolio_role.user.full_name
|
return self.role.user.full_name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_revokable(self):
|
def is_revokable(self):
|
||||||
@ -110,21 +105,3 @@ class Invitation(Base, TimestampsMixin, AuditableMixin):
|
|||||||
@property
|
@property
|
||||||
def user_dod_id(self):
|
def user_dod_id(self):
|
||||||
return self.user.dod_id if self.user is not None else None
|
return self.user.dod_id if self.user is not None else None
|
||||||
|
|
||||||
@property
|
|
||||||
def event_details(self):
|
|
||||||
return {"email": self.email, "dod_id": self.user_dod_id}
|
|
||||||
|
|
||||||
@property
|
|
||||||
def history(self):
|
|
||||||
changes = self.get_changes()
|
|
||||||
change_set = {}
|
|
||||||
|
|
||||||
if "status" in changes:
|
|
||||||
change_set["status"] = [s.name for s in changes["status"]]
|
|
||||||
|
|
||||||
return change_set
|
|
||||||
|
|
||||||
@property
|
|
||||||
def portfolio_id(self):
|
|
||||||
return self.portfolio_role.portfolio_id
|
|
41
atst/models/portfolio_invitation.py
Normal file
41
atst/models/portfolio_invitation.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
from sqlalchemy import Column, ForeignKey
|
||||||
|
from sqlalchemy.dialects.postgresql import UUID
|
||||||
|
from sqlalchemy.orm import relationship, backref
|
||||||
|
|
||||||
|
from atst.models import Base
|
||||||
|
from atst.models.mixins import TimestampsMixin, AuditableMixin, InvitesMixin
|
||||||
|
|
||||||
|
|
||||||
|
class PortfolioInvitation(Base, TimestampsMixin, AuditableMixin, InvitesMixin):
|
||||||
|
__tablename__ = "invitations"
|
||||||
|
|
||||||
|
portfolio_role_id = Column(
|
||||||
|
UUID(as_uuid=True), ForeignKey("portfolio_roles.id"), index=True
|
||||||
|
)
|
||||||
|
role = relationship(
|
||||||
|
"PortfolioRole",
|
||||||
|
backref=backref("invitations", order_by="PortfolioInvitation.time_created"),
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def portfolio(self):
|
||||||
|
if self.role: # pragma: no branch
|
||||||
|
return self.role.portfolio
|
||||||
|
|
||||||
|
@property
|
||||||
|
def portfolio_id(self):
|
||||||
|
return self.role.portfolio_id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def event_details(self):
|
||||||
|
return {"email": self.email, "dod_id": self.user_dod_id}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def history(self):
|
||||||
|
changes = self.get_changes()
|
||||||
|
change_set = {}
|
||||||
|
|
||||||
|
if "status" in changes:
|
||||||
|
change_set["status"] = [s.name for s in changes["status"]]
|
||||||
|
|
||||||
|
return change_set
|
@ -4,6 +4,7 @@ from sqlalchemy.dialects.postgresql import UUID
|
|||||||
|
|
||||||
from atst.models import Base, types, mixins
|
from atst.models import Base, types, mixins
|
||||||
from atst.models.permissions import Permissions
|
from atst.models.permissions import Permissions
|
||||||
|
from atst.models.portfolio_invitation import PortfolioInvitation
|
||||||
|
|
||||||
|
|
||||||
users_permission_sets = Table(
|
users_permission_sets = Table(
|
||||||
@ -31,6 +32,13 @@ class User(
|
|||||||
primaryjoin="and_(ApplicationRole.user_id==User.id, ApplicationRole.deleted==False)",
|
primaryjoin="and_(ApplicationRole.user_id==User.id, ApplicationRole.deleted==False)",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
portfolio_invitations = relationship(
|
||||||
|
"PortfolioInvitation", foreign_keys=PortfolioInvitation.user_id
|
||||||
|
)
|
||||||
|
sent_portfolio_invitations = relationship(
|
||||||
|
"PortfolioInvitation", foreign_keys=PortfolioInvitation.inviter_id
|
||||||
|
)
|
||||||
|
|
||||||
email = Column(String)
|
email = Column(String)
|
||||||
dod_id = Column(String, unique=True, nullable=False)
|
dod_id = Column(String, unique=True, nullable=False)
|
||||||
first_name = Column(String)
|
first_name = Column(String)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from flask import g, redirect, url_for, render_template
|
from flask import g, redirect, url_for, render_template
|
||||||
|
|
||||||
from . import portfolios_bp
|
from . import portfolios_bp
|
||||||
from atst.domain.invitations import Invitations
|
from atst.domain.invitations import PortfolioInvitations
|
||||||
from atst.queue import queue
|
from atst.queue import queue
|
||||||
from atst.utils.flash import formatted_flash as flash
|
from atst.utils.flash import formatted_flash as flash
|
||||||
from atst.domain.authz.decorator import user_can_access_decorator as user_can
|
from atst.domain.authz.decorator import user_can_access_decorator as user_can
|
||||||
@ -19,7 +19,7 @@ def send_invite_email(owner_name, token, new_member_email):
|
|||||||
|
|
||||||
@portfolios_bp.route("/portfolios/invitations/<token>", methods=["GET"])
|
@portfolios_bp.route("/portfolios/invitations/<token>", methods=["GET"])
|
||||||
def accept_invitation(token):
|
def accept_invitation(token):
|
||||||
invite = Invitations.accept(g.current_user, token)
|
invite = PortfolioInvitations.accept(g.current_user, token)
|
||||||
|
|
||||||
for task_order in invite.portfolio.task_orders:
|
for task_order in invite.portfolio.task_orders:
|
||||||
if g.current_user in task_order.officers:
|
if g.current_user in task_order.officers:
|
||||||
@ -37,7 +37,7 @@ def accept_invitation(token):
|
|||||||
)
|
)
|
||||||
@user_can(Permissions.EDIT_PORTFOLIO_USERS, message="revoke invitation")
|
@user_can(Permissions.EDIT_PORTFOLIO_USERS, message="revoke invitation")
|
||||||
def revoke_invitation(portfolio_id, token):
|
def revoke_invitation(portfolio_id, token):
|
||||||
Invitations.revoke(token)
|
PortfolioInvitations.revoke(token)
|
||||||
|
|
||||||
return redirect(
|
return redirect(
|
||||||
url_for(
|
url_for(
|
||||||
@ -54,7 +54,7 @@ def revoke_invitation(portfolio_id, token):
|
|||||||
)
|
)
|
||||||
@user_can(Permissions.EDIT_PORTFOLIO_USERS, message="resend invitation")
|
@user_can(Permissions.EDIT_PORTFOLIO_USERS, message="resend invitation")
|
||||||
def resend_invitation(portfolio_id, token):
|
def resend_invitation(portfolio_id, token):
|
||||||
invite = Invitations.resend(g.current_user, token)
|
invite = PortfolioInvitations.resend(g.current_user, token)
|
||||||
send_invite_email(g.current_user.full_name, invite.token, invite.email)
|
send_invite_email(g.current_user.full_name, invite.token, invite.email)
|
||||||
flash("resend_portfolio_invitation", user_name=invite.user_name)
|
flash("resend_portfolio_invitation", user_name=invite.user_name)
|
||||||
return redirect(
|
return redirect(
|
||||||
|
@ -7,7 +7,7 @@ from atst.domain.authz.decorator import user_can_access_decorator as user_can
|
|||||||
from atst.models.permissions import Permissions
|
from atst.models.permissions import Permissions
|
||||||
from atst.database import db
|
from atst.database import db
|
||||||
from atst.domain.exceptions import NotFoundError, NoAccessError
|
from atst.domain.exceptions import NotFoundError, NoAccessError
|
||||||
from atst.domain.invitations import Invitations
|
from atst.domain.invitations import PortfolioInvitations
|
||||||
from atst.domain.portfolios import Portfolios
|
from atst.domain.portfolios import Portfolios
|
||||||
from atst.utils.localization import translate
|
from atst.utils.localization import translate
|
||||||
from atst.forms.officers import EditTaskOrderOfficersForm
|
from atst.forms.officers import EditTaskOrderOfficersForm
|
||||||
@ -57,7 +57,7 @@ def resend_invite(task_order_id):
|
|||||||
if not officer:
|
if not officer:
|
||||||
raise NotFoundError("officer")
|
raise NotFoundError("officer")
|
||||||
|
|
||||||
invitation = Invitations.lookup_by_portfolio_and_user(portfolio, officer)
|
invitation = PortfolioInvitations.lookup_by_portfolio_and_user(portfolio, officer)
|
||||||
|
|
||||||
if not invitation:
|
if not invitation:
|
||||||
raise NotFoundError("invitation")
|
raise NotFoundError("invitation")
|
||||||
@ -65,11 +65,11 @@ def resend_invite(task_order_id):
|
|||||||
if not invitation.can_resend:
|
if not invitation.can_resend:
|
||||||
raise NoAccessError("invitation")
|
raise NoAccessError("invitation")
|
||||||
|
|
||||||
Invitations.revoke(token=invitation.token)
|
PortfolioInvitations.revoke(token=invitation.token)
|
||||||
|
|
||||||
invite_service = InvitationService(
|
invite_service = InvitationService(
|
||||||
g.current_user,
|
g.current_user,
|
||||||
invitation.portfolio_role,
|
invitation.role,
|
||||||
invitation.email,
|
invitation.email,
|
||||||
subject=invite_type_info["subject"],
|
subject=invite_type_info["subject"],
|
||||||
email_template=invite_type_info["template"],
|
email_template=invite_type_info["template"],
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from flask import render_template
|
from flask import render_template
|
||||||
|
|
||||||
from atst.domain.invitations import Invitations
|
from atst.domain.invitations import PortfolioInvitations
|
||||||
from atst.queue import queue
|
from atst.queue import queue
|
||||||
from atst.domain.task_orders import TaskOrders
|
from atst.domain.task_orders import TaskOrders
|
||||||
from atst.domain.portfolio_roles import PortfolioRoles
|
from atst.domain.portfolio_roles import PortfolioRoles
|
||||||
@ -68,7 +68,7 @@ class Invitation:
|
|||||||
return invite
|
return invite
|
||||||
|
|
||||||
def _create_invite(self):
|
def _create_invite(self):
|
||||||
return Invitations.create(self.inviter, self.member, self.email)
|
return PortfolioInvitations.create(self.inviter, self.member, self.email)
|
||||||
|
|
||||||
def _send_invite_email(self, token):
|
def _send_invite_email(self, token):
|
||||||
body = render_template(
|
body = render_template(
|
||||||
|
@ -3,33 +3,32 @@ import pytest
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from atst.domain.invitations import (
|
from atst.domain.invitations import (
|
||||||
Invitations,
|
PortfolioInvitations,
|
||||||
InvitationError,
|
InvitationError,
|
||||||
WrongUserError,
|
WrongUserError,
|
||||||
ExpiredError,
|
ExpiredError,
|
||||||
NotFoundError,
|
NotFoundError,
|
||||||
)
|
)
|
||||||
from atst.models.invitation import Status
|
from atst.domain.audit_log import AuditLog
|
||||||
|
from atst.models import InvitationStatus
|
||||||
|
|
||||||
from tests.factories import (
|
from tests.factories import (
|
||||||
PortfolioFactory,
|
PortfolioFactory,
|
||||||
PortfolioRoleFactory,
|
PortfolioRoleFactory,
|
||||||
UserFactory,
|
UserFactory,
|
||||||
InvitationFactory,
|
PortfolioInvitationFactory,
|
||||||
)
|
)
|
||||||
|
|
||||||
from atst.domain.audit_log import AuditLog
|
|
||||||
|
|
||||||
|
|
||||||
def test_create_invitation():
|
def test_create_invitation():
|
||||||
portfolio = PortfolioFactory.create()
|
portfolio = PortfolioFactory.create()
|
||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
||||||
invite = Invitations.create(portfolio.owner, ws_role, user.email)
|
invite = PortfolioInvitations.create(portfolio.owner, ws_role, user.email)
|
||||||
assert invite.user == user
|
assert invite.user == user
|
||||||
assert invite.portfolio_role == ws_role
|
assert invite.role == ws_role
|
||||||
assert invite.inviter == portfolio.owner
|
assert invite.inviter == portfolio.owner
|
||||||
assert invite.status == Status.PENDING
|
assert invite.status == InvitationStatus.PENDING
|
||||||
assert re.match(r"^[\w\-_]+$", invite.token)
|
assert re.match(r"^[\w\-_]+$", invite.token)
|
||||||
|
|
||||||
|
|
||||||
@ -37,9 +36,9 @@ def test_accept_invitation():
|
|||||||
portfolio = PortfolioFactory.create()
|
portfolio = PortfolioFactory.create()
|
||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
||||||
invite = Invitations.create(portfolio.owner, ws_role, user.email)
|
invite = PortfolioInvitations.create(portfolio.owner, ws_role, user.email)
|
||||||
assert invite.is_pending
|
assert invite.is_pending
|
||||||
accepted_invite = Invitations.accept(user, invite.token)
|
accepted_invite = PortfolioInvitations.accept(user, invite.token)
|
||||||
assert accepted_invite.is_accepted
|
assert accepted_invite.is_accepted
|
||||||
|
|
||||||
|
|
||||||
@ -47,16 +46,16 @@ def test_accept_expired_invitation():
|
|||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
portfolio = PortfolioFactory.create()
|
portfolio = PortfolioFactory.create()
|
||||||
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
||||||
increment = Invitations.EXPIRATION_LIMIT_MINUTES + 1
|
increment = PortfolioInvitations.EXPIRATION_LIMIT_MINUTES + 1
|
||||||
expiration_time = datetime.datetime.now() - datetime.timedelta(minutes=increment)
|
expiration_time = datetime.datetime.now() - datetime.timedelta(minutes=increment)
|
||||||
invite = InvitationFactory.create(
|
invite = PortfolioInvitationFactory.create(
|
||||||
user=user,
|
user=user,
|
||||||
expiration_time=expiration_time,
|
expiration_time=expiration_time,
|
||||||
status=Status.PENDING,
|
status=InvitationStatus.PENDING,
|
||||||
portfolio_role=ws_role,
|
role=ws_role,
|
||||||
)
|
)
|
||||||
with pytest.raises(ExpiredError):
|
with pytest.raises(ExpiredError):
|
||||||
Invitations.accept(user, invite.token)
|
PortfolioInvitations.accept(user, invite.token)
|
||||||
|
|
||||||
assert invite.is_rejected
|
assert invite.is_rejected
|
||||||
|
|
||||||
@ -65,22 +64,22 @@ def test_accept_rejected_invite():
|
|||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
portfolio = PortfolioFactory.create()
|
portfolio = PortfolioFactory.create()
|
||||||
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
||||||
invite = InvitationFactory.create(
|
invite = PortfolioInvitationFactory.create(
|
||||||
user=user, status=Status.REJECTED_EXPIRED, portfolio_role=ws_role
|
user=user, status=InvitationStatus.REJECTED_EXPIRED, role=ws_role
|
||||||
)
|
)
|
||||||
with pytest.raises(InvitationError):
|
with pytest.raises(InvitationError):
|
||||||
Invitations.accept(user, invite.token)
|
PortfolioInvitations.accept(user, invite.token)
|
||||||
|
|
||||||
|
|
||||||
def test_accept_revoked_invite():
|
def test_accept_revoked_invite():
|
||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
portfolio = PortfolioFactory.create()
|
portfolio = PortfolioFactory.create()
|
||||||
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
||||||
invite = InvitationFactory.create(
|
invite = PortfolioInvitationFactory.create(
|
||||||
user=user, status=Status.REVOKED, portfolio_role=ws_role
|
user=user, status=InvitationStatus.REVOKED, role=ws_role
|
||||||
)
|
)
|
||||||
with pytest.raises(InvitationError):
|
with pytest.raises(InvitationError):
|
||||||
Invitations.accept(user, invite.token)
|
PortfolioInvitations.accept(user, invite.token)
|
||||||
|
|
||||||
|
|
||||||
def test_wrong_user_accepts_invitation():
|
def test_wrong_user_accepts_invitation():
|
||||||
@ -88,9 +87,9 @@ def test_wrong_user_accepts_invitation():
|
|||||||
portfolio = PortfolioFactory.create()
|
portfolio = PortfolioFactory.create()
|
||||||
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
||||||
wrong_user = UserFactory.create()
|
wrong_user = UserFactory.create()
|
||||||
invite = InvitationFactory.create(user=user, portfolio_role=ws_role)
|
invite = PortfolioInvitationFactory.create(user=user, role=ws_role)
|
||||||
with pytest.raises(WrongUserError):
|
with pytest.raises(WrongUserError):
|
||||||
Invitations.accept(wrong_user, invite.token)
|
PortfolioInvitations.accept(wrong_user, invite.token)
|
||||||
|
|
||||||
|
|
||||||
def test_user_cannot_accept_invitation_accepted_by_wrong_user():
|
def test_user_cannot_accept_invitation_accepted_by_wrong_user():
|
||||||
@ -98,30 +97,30 @@ def test_user_cannot_accept_invitation_accepted_by_wrong_user():
|
|||||||
portfolio = PortfolioFactory.create()
|
portfolio = PortfolioFactory.create()
|
||||||
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
||||||
wrong_user = UserFactory.create()
|
wrong_user = UserFactory.create()
|
||||||
invite = InvitationFactory.create(user=user, portfolio_role=ws_role)
|
invite = PortfolioInvitationFactory.create(user=user, role=ws_role)
|
||||||
with pytest.raises(WrongUserError):
|
with pytest.raises(WrongUserError):
|
||||||
Invitations.accept(wrong_user, invite.token)
|
PortfolioInvitations.accept(wrong_user, invite.token)
|
||||||
with pytest.raises(InvitationError):
|
with pytest.raises(InvitationError):
|
||||||
Invitations.accept(user, invite.token)
|
PortfolioInvitations.accept(user, invite.token)
|
||||||
|
|
||||||
|
|
||||||
def test_accept_invitation_twice():
|
def test_accept_invitation_twice():
|
||||||
portfolio = PortfolioFactory.create()
|
portfolio = PortfolioFactory.create()
|
||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
||||||
invite = Invitations.create(portfolio.owner, ws_role, user.email)
|
invite = PortfolioInvitations.create(portfolio.owner, ws_role, user.email)
|
||||||
Invitations.accept(user, invite.token)
|
PortfolioInvitations.accept(user, invite.token)
|
||||||
with pytest.raises(InvitationError):
|
with pytest.raises(InvitationError):
|
||||||
Invitations.accept(user, invite.token)
|
PortfolioInvitations.accept(user, invite.token)
|
||||||
|
|
||||||
|
|
||||||
def test_revoke_invitation():
|
def test_revoke_invitation():
|
||||||
portfolio = PortfolioFactory.create()
|
portfolio = PortfolioFactory.create()
|
||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
||||||
invite = Invitations.create(portfolio.owner, ws_role, user.email)
|
invite = PortfolioInvitations.create(portfolio.owner, ws_role, user.email)
|
||||||
assert invite.is_pending
|
assert invite.is_pending
|
||||||
Invitations.revoke(invite.token)
|
PortfolioInvitations.revoke(invite.token)
|
||||||
assert invite.is_revoked
|
assert invite.is_revoked
|
||||||
|
|
||||||
|
|
||||||
@ -129,8 +128,8 @@ def test_resend_invitation():
|
|||||||
portfolio = PortfolioFactory.create()
|
portfolio = PortfolioFactory.create()
|
||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
||||||
invite = Invitations.create(portfolio.owner, ws_role, user.email)
|
invite = PortfolioInvitations.create(portfolio.owner, ws_role, user.email)
|
||||||
Invitations.resend(user, invite.token)
|
PortfolioInvitations.resend(user, invite.token)
|
||||||
assert ws_role.invitations[0].is_revoked
|
assert ws_role.invitations[0].is_revoked
|
||||||
assert ws_role.invitations[1].is_pending
|
assert ws_role.invitations[1].is_pending
|
||||||
|
|
||||||
@ -139,8 +138,8 @@ def test_audit_event_for_accepted_invite():
|
|||||||
portfolio = PortfolioFactory.create()
|
portfolio = PortfolioFactory.create()
|
||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
||||||
invite = Invitations.create(portfolio.owner, ws_role, user.email)
|
invite = PortfolioInvitations.create(portfolio.owner, ws_role, user.email)
|
||||||
invite = Invitations.accept(user, invite.token)
|
invite = PortfolioInvitations.accept(user, invite.token)
|
||||||
|
|
||||||
accepted_event = AuditLog.get_by_resource(invite.id)[0]
|
accepted_event = AuditLog.get_by_resource(invite.id)[0]
|
||||||
assert "email" in accepted_event.event_details
|
assert "email" in accepted_event.event_details
|
||||||
@ -151,9 +150,11 @@ def test_lookup_by_user_and_portfolio():
|
|||||||
portfolio = PortfolioFactory.create()
|
portfolio = PortfolioFactory.create()
|
||||||
user = UserFactory.create()
|
user = UserFactory.create()
|
||||||
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
ws_role = PortfolioRoleFactory.create(user=user, portfolio=portfolio)
|
||||||
invite = Invitations.create(portfolio.owner, ws_role, user.email)
|
invite = PortfolioInvitations.create(portfolio.owner, ws_role, user.email)
|
||||||
|
|
||||||
assert Invitations.lookup_by_portfolio_and_user(portfolio, user) == invite
|
assert PortfolioInvitations.lookup_by_portfolio_and_user(portfolio, user) == invite
|
||||||
|
|
||||||
with pytest.raises(NotFoundError):
|
with pytest.raises(NotFoundError):
|
||||||
Invitations.lookup_by_portfolio_and_user(portfolio, UserFactory.create())
|
PortfolioInvitations.lookup_by_portfolio_and_user(
|
||||||
|
portfolio, UserFactory.create()
|
||||||
|
)
|
||||||
|
@ -7,7 +7,7 @@ from atst.models.portfolio_role import Status as PortfolioRoleStatus
|
|||||||
from tests.factories import (
|
from tests.factories import (
|
||||||
PortfolioFactory,
|
PortfolioFactory,
|
||||||
UserFactory,
|
UserFactory,
|
||||||
InvitationFactory,
|
PortfolioInvitationFactory,
|
||||||
PortfolioRoleFactory,
|
PortfolioRoleFactory,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -7,11 +7,8 @@ import datetime
|
|||||||
|
|
||||||
from atst.forms import data
|
from atst.forms import data
|
||||||
from atst.models import *
|
from atst.models import *
|
||||||
from atst.models.portfolio_role import Status as PortfolioRoleStatus
|
|
||||||
from atst.models.application_role import Status as ApplicationRoleStatus
|
from atst.domain.invitations import PortfolioInvitations
|
||||||
from atst.models.invitation import Status as InvitationStatus
|
|
||||||
from atst.models.environment_role import CSPRole
|
|
||||||
from atst.domain.invitations import Invitations
|
|
||||||
from atst.domain.permission_sets import PermissionSets
|
from atst.domain.permission_sets import PermissionSets
|
||||||
from atst.domain.portfolio_roles import PortfolioRoles
|
from atst.domain.portfolio_roles import PortfolioRoles
|
||||||
|
|
||||||
@ -240,13 +237,13 @@ class EnvironmentRoleFactory(Base):
|
|||||||
user = factory.SubFactory(UserFactory)
|
user = factory.SubFactory(UserFactory)
|
||||||
|
|
||||||
|
|
||||||
class InvitationFactory(Base):
|
class PortfolioInvitationFactory(Base):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Invitation
|
model = PortfolioInvitation
|
||||||
|
|
||||||
email = factory.Faker("email")
|
email = factory.Faker("email")
|
||||||
status = InvitationStatus.PENDING
|
status = InvitationStatus.PENDING
|
||||||
expiration_time = Invitations.current_expiration_time()
|
expiration_time = PortfolioInvitations.current_expiration_time()
|
||||||
|
|
||||||
|
|
||||||
class AttachmentFactory(Base):
|
class AttachmentFactory(Base):
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
import pytest
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from atst.models.invitation import Invitation, Status
|
from atst.models import InvitationStatus, PortfolioRoleStatus
|
||||||
from atst.models.portfolio_role import Status as PortfolioRoleStatus
|
|
||||||
|
|
||||||
from tests.factories import (
|
from tests.factories import (
|
||||||
InvitationFactory,
|
PortfolioInvitationFactory,
|
||||||
PortfolioFactory,
|
PortfolioFactory,
|
||||||
UserFactory,
|
UserFactory,
|
||||||
PortfolioRoleFactory,
|
PortfolioRoleFactory,
|
||||||
@ -18,9 +16,9 @@ def test_expired_invite_is_not_revokable():
|
|||||||
portfolio_role = PortfolioRoleFactory.create(
|
portfolio_role = PortfolioRoleFactory.create(
|
||||||
portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING
|
portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING
|
||||||
)
|
)
|
||||||
invite = InvitationFactory.create(
|
invite = PortfolioInvitationFactory.create(
|
||||||
expiration_time=datetime.datetime.now() - datetime.timedelta(minutes=60),
|
expiration_time=datetime.datetime.now() - datetime.timedelta(minutes=60),
|
||||||
portfolio_role=portfolio_role,
|
role=portfolio_role,
|
||||||
)
|
)
|
||||||
assert not invite.is_revokable
|
assert not invite.is_revokable
|
||||||
|
|
||||||
@ -31,7 +29,7 @@ def test_unexpired_invite_is_revokable():
|
|||||||
portfolio_role = PortfolioRoleFactory.create(
|
portfolio_role = PortfolioRoleFactory.create(
|
||||||
portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING
|
portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING
|
||||||
)
|
)
|
||||||
invite = InvitationFactory.create(portfolio_role=portfolio_role)
|
invite = PortfolioInvitationFactory.create(role=portfolio_role)
|
||||||
assert invite.is_revokable
|
assert invite.is_revokable
|
||||||
|
|
||||||
|
|
||||||
@ -41,7 +39,7 @@ def test_invite_is_not_revokable_if_invite_is_not_pending():
|
|||||||
portfolio_role = PortfolioRoleFactory.create(
|
portfolio_role = PortfolioRoleFactory.create(
|
||||||
portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING
|
portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING
|
||||||
)
|
)
|
||||||
invite = InvitationFactory.create(
|
invite = PortfolioInvitationFactory.create(
|
||||||
portfolio_role=portfolio_role, status=Status.ACCEPTED
|
role=portfolio_role, status=InvitationStatus.ACCEPTED
|
||||||
)
|
)
|
||||||
assert not invite.is_revokable
|
assert not invite.is_revokable
|
@ -6,14 +6,11 @@ from atst.domain.portfolios import Portfolios
|
|||||||
from atst.domain.portfolio_roles import PortfolioRoles
|
from atst.domain.portfolio_roles import PortfolioRoles
|
||||||
from atst.domain.applications import Applications
|
from atst.domain.applications import Applications
|
||||||
from atst.domain.permission_sets import PermissionSets
|
from atst.domain.permission_sets import PermissionSets
|
||||||
from atst.models.portfolio_role import Status
|
from atst.models import AuditEvent, InvitationStatus, PortfolioRoleStatus, CSPRole
|
||||||
from atst.models.invitation import Status as InvitationStatus
|
|
||||||
from atst.models.audit_event import AuditEvent
|
|
||||||
from atst.models.portfolio_role import Status as PortfolioRoleStatus
|
|
||||||
from atst.models.environment_role import CSPRole
|
|
||||||
from tests.factories import (
|
from tests.factories import (
|
||||||
UserFactory,
|
UserFactory,
|
||||||
InvitationFactory,
|
PortfolioInvitationFactory,
|
||||||
PortfolioRoleFactory,
|
PortfolioRoleFactory,
|
||||||
EnvironmentFactory,
|
EnvironmentFactory,
|
||||||
EnvironmentRoleFactory,
|
EnvironmentRoleFactory,
|
||||||
@ -189,12 +186,12 @@ def test_has_environment_roles():
|
|||||||
|
|
||||||
|
|
||||||
def test_status_when_member_is_active():
|
def test_status_when_member_is_active():
|
||||||
portfolio_role = PortfolioRoleFactory.create(status=Status.ACTIVE)
|
portfolio_role = PortfolioRoleFactory.create(status=PortfolioRoleStatus.ACTIVE)
|
||||||
assert portfolio_role.display_status == "Active"
|
assert portfolio_role.display_status == "Active"
|
||||||
|
|
||||||
|
|
||||||
def test_status_when_member_is_disabled():
|
def test_status_when_member_is_disabled():
|
||||||
portfolio_role = PortfolioRoleFactory.create(status=Status.DISABLED)
|
portfolio_role = PortfolioRoleFactory.create(status=PortfolioRoleStatus.DISABLED)
|
||||||
assert portfolio_role.display_status == "Disabled"
|
assert portfolio_role.display_status == "Disabled"
|
||||||
|
|
||||||
|
|
||||||
@ -204,8 +201,8 @@ def test_status_when_invitation_has_been_rejected_for_expirations():
|
|||||||
portfolio_role = PortfolioRoleFactory.create(
|
portfolio_role = PortfolioRoleFactory.create(
|
||||||
portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING
|
portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING
|
||||||
)
|
)
|
||||||
invitation = InvitationFactory.create(
|
PortfolioInvitationFactory.create(
|
||||||
portfolio_role=portfolio_role, status=InvitationStatus.REJECTED_EXPIRED
|
role=portfolio_role, status=InvitationStatus.REJECTED_EXPIRED
|
||||||
)
|
)
|
||||||
assert portfolio_role.display_status == "Invite expired"
|
assert portfolio_role.display_status == "Invite expired"
|
||||||
|
|
||||||
@ -216,8 +213,8 @@ def test_status_when_invitation_has_been_rejected_for_wrong_user():
|
|||||||
portfolio_role = PortfolioRoleFactory.create(
|
portfolio_role = PortfolioRoleFactory.create(
|
||||||
portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING
|
portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING
|
||||||
)
|
)
|
||||||
invitation = InvitationFactory.create(
|
PortfolioInvitationFactory.create(
|
||||||
portfolio_role=portfolio_role, status=InvitationStatus.REJECTED_WRONG_USER
|
role=portfolio_role, status=InvitationStatus.REJECTED_WRONG_USER
|
||||||
)
|
)
|
||||||
assert portfolio_role.display_status == "Error on invite"
|
assert portfolio_role.display_status == "Error on invite"
|
||||||
|
|
||||||
@ -228,8 +225,8 @@ def test_status_when_invitation_has_been_revoked():
|
|||||||
portfolio_role = PortfolioRoleFactory.create(
|
portfolio_role = PortfolioRoleFactory.create(
|
||||||
portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING
|
portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING
|
||||||
)
|
)
|
||||||
invitation = InvitationFactory.create(
|
PortfolioInvitationFactory.create(
|
||||||
portfolio_role=portfolio_role, status=InvitationStatus.REVOKED
|
role=portfolio_role, status=InvitationStatus.REVOKED
|
||||||
)
|
)
|
||||||
assert portfolio_role.display_status == "Invite revoked"
|
assert portfolio_role.display_status == "Invite revoked"
|
||||||
|
|
||||||
@ -240,8 +237,8 @@ def test_status_when_invitation_is_expired():
|
|||||||
portfolio_role = PortfolioRoleFactory.create(
|
portfolio_role = PortfolioRoleFactory.create(
|
||||||
portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING
|
portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING
|
||||||
)
|
)
|
||||||
invitation = InvitationFactory.create(
|
PortfolioInvitationFactory.create(
|
||||||
portfolio_role=portfolio_role,
|
role=portfolio_role,
|
||||||
status=InvitationStatus.PENDING,
|
status=InvitationStatus.PENDING,
|
||||||
expiration_time=datetime.datetime.now() - datetime.timedelta(seconds=1),
|
expiration_time=datetime.datetime.now() - datetime.timedelta(seconds=1),
|
||||||
)
|
)
|
||||||
@ -254,8 +251,8 @@ def test_can_not_resend_invitation_if_active():
|
|||||||
portfolio_role = PortfolioRoleFactory.create(
|
portfolio_role = PortfolioRoleFactory.create(
|
||||||
portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING
|
portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING
|
||||||
)
|
)
|
||||||
invitation = InvitationFactory.create(
|
PortfolioInvitationFactory.create(
|
||||||
portfolio_role=portfolio_role, status=InvitationStatus.ACCEPTED
|
role=portfolio_role, status=InvitationStatus.ACCEPTED
|
||||||
)
|
)
|
||||||
assert not portfolio_role.can_resend_invitation
|
assert not portfolio_role.can_resend_invitation
|
||||||
|
|
||||||
@ -266,8 +263,8 @@ def test_can_resend_invitation_if_expired():
|
|||||||
portfolio_role = PortfolioRoleFactory.create(
|
portfolio_role = PortfolioRoleFactory.create(
|
||||||
portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING
|
portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING
|
||||||
)
|
)
|
||||||
invitation = InvitationFactory.create(
|
PortfolioInvitationFactory.create(
|
||||||
portfolio_role=portfolio_role, status=InvitationStatus.REJECTED_EXPIRED
|
role=portfolio_role, status=InvitationStatus.REJECTED_EXPIRED
|
||||||
)
|
)
|
||||||
assert portfolio_role.can_resend_invitation
|
assert portfolio_role.can_resend_invitation
|
||||||
|
|
||||||
|
@ -6,12 +6,11 @@ from tests.factories import (
|
|||||||
UserFactory,
|
UserFactory,
|
||||||
PortfolioFactory,
|
PortfolioFactory,
|
||||||
PortfolioRoleFactory,
|
PortfolioRoleFactory,
|
||||||
InvitationFactory,
|
PortfolioInvitationFactory,
|
||||||
TaskOrderFactory,
|
TaskOrderFactory,
|
||||||
)
|
)
|
||||||
from atst.domain.portfolios import Portfolios
|
from atst.domain.portfolios import Portfolios
|
||||||
from atst.models.portfolio_role import Status as PortfolioRoleStatus
|
from atst.models import InvitationStatus, PortfolioRoleStatus
|
||||||
from atst.models.invitation import Status as InvitationStatus
|
|
||||||
from atst.domain.users import Users
|
from atst.domain.users import Users
|
||||||
from atst.domain.permission_sets import PermissionSets
|
from atst.domain.permission_sets import PermissionSets
|
||||||
|
|
||||||
@ -22,7 +21,7 @@ def test_existing_member_accepts_valid_invite(client, user_session):
|
|||||||
ws_role = PortfolioRoleFactory.create(
|
ws_role = PortfolioRoleFactory.create(
|
||||||
portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING
|
portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING
|
||||||
)
|
)
|
||||||
invite = InvitationFactory.create(user_id=user.id, portfolio_role=ws_role)
|
invite = PortfolioInvitationFactory.create(user_id=user.id, role=ws_role)
|
||||||
|
|
||||||
# the user does not have access to the portfolio before accepting the invite
|
# the user does not have access to the portfolio before accepting the invite
|
||||||
assert len(Portfolios.for_user(user)) == 0
|
assert len(Portfolios.for_user(user)) == 0
|
||||||
@ -60,7 +59,7 @@ def test_new_member_accepts_valid_invite(monkeypatch, client, user_session):
|
|||||||
|
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
user = Users.get_by_dod_id(user_info["dod_id"])
|
user = Users.get_by_dod_id(user_info["dod_id"])
|
||||||
token = user.invitations[0].token
|
token = user.portfolio_invitations[0].token
|
||||||
|
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
"atst.domain.auth.should_redirect_to_user_profile", lambda *args: False
|
"atst.domain.auth.should_redirect_to_user_profile", lambda *args: False
|
||||||
@ -84,10 +83,8 @@ def test_member_accepts_invalid_invite(client, user_session):
|
|||||||
ws_role = PortfolioRoleFactory.create(
|
ws_role = PortfolioRoleFactory.create(
|
||||||
user=user, portfolio=portfolio, status=PortfolioRoleStatus.PENDING
|
user=user, portfolio=portfolio, status=PortfolioRoleStatus.PENDING
|
||||||
)
|
)
|
||||||
invite = InvitationFactory.create(
|
invite = PortfolioInvitationFactory.create(
|
||||||
user_id=user.id,
|
user_id=user.id, role=ws_role, status=InvitationStatus.REJECTED_WRONG_USER
|
||||||
portfolio_role=ws_role,
|
|
||||||
status=InvitationStatus.REJECTED_WRONG_USER,
|
|
||||||
)
|
)
|
||||||
user_session(user)
|
user_session(user)
|
||||||
response = client.get(url_for("portfolios.accept_invitation", token=invite.token))
|
response = client.get(url_for("portfolios.accept_invitation", token=invite.token))
|
||||||
@ -119,7 +116,7 @@ def test_user_accepts_invite_with_wrong_dod_id(client, user_session):
|
|||||||
ws_role = PortfolioRoleFactory.create(
|
ws_role = PortfolioRoleFactory.create(
|
||||||
user=user, portfolio=portfolio, status=PortfolioRoleStatus.PENDING
|
user=user, portfolio=portfolio, status=PortfolioRoleStatus.PENDING
|
||||||
)
|
)
|
||||||
invite = InvitationFactory.create(user_id=user.id, portfolio_role=ws_role)
|
invite = PortfolioInvitationFactory.create(user_id=user.id, role=ws_role)
|
||||||
user_session(different_user)
|
user_session(different_user)
|
||||||
response = client.get(url_for("portfolios.accept_invitation", token=invite.token))
|
response = client.get(url_for("portfolios.accept_invitation", token=invite.token))
|
||||||
|
|
||||||
@ -132,9 +129,9 @@ def test_user_accepts_expired_invite(client, user_session):
|
|||||||
ws_role = PortfolioRoleFactory.create(
|
ws_role = PortfolioRoleFactory.create(
|
||||||
user=user, portfolio=portfolio, status=PortfolioRoleStatus.PENDING
|
user=user, portfolio=portfolio, status=PortfolioRoleStatus.PENDING
|
||||||
)
|
)
|
||||||
invite = InvitationFactory.create(
|
invite = PortfolioInvitationFactory.create(
|
||||||
user_id=user.id,
|
user_id=user.id,
|
||||||
portfolio_role=ws_role,
|
role=ws_role,
|
||||||
status=InvitationStatus.REJECTED_EXPIRED,
|
status=InvitationStatus.REJECTED_EXPIRED,
|
||||||
expiration_time=datetime.datetime.now() - datetime.timedelta(seconds=1),
|
expiration_time=datetime.datetime.now() - datetime.timedelta(seconds=1),
|
||||||
)
|
)
|
||||||
@ -150,9 +147,9 @@ def test_revoke_invitation(client, user_session):
|
|||||||
ws_role = PortfolioRoleFactory.create(
|
ws_role = PortfolioRoleFactory.create(
|
||||||
user=user, portfolio=portfolio, status=PortfolioRoleStatus.PENDING
|
user=user, portfolio=portfolio, status=PortfolioRoleStatus.PENDING
|
||||||
)
|
)
|
||||||
invite = InvitationFactory.create(
|
invite = PortfolioInvitationFactory.create(
|
||||||
user_id=user.id,
|
user_id=user.id,
|
||||||
portfolio_role=ws_role,
|
role=ws_role,
|
||||||
status=InvitationStatus.REJECTED_EXPIRED,
|
status=InvitationStatus.REJECTED_EXPIRED,
|
||||||
expiration_time=datetime.datetime.now() - datetime.timedelta(seconds=1),
|
expiration_time=datetime.datetime.now() - datetime.timedelta(seconds=1),
|
||||||
)
|
)
|
||||||
@ -176,9 +173,9 @@ def test_user_can_only_revoke_invites_in_their_portfolio(client, user_session):
|
|||||||
portfolio_role = PortfolioRoleFactory.create(
|
portfolio_role = PortfolioRoleFactory.create(
|
||||||
user=user, portfolio=other_portfolio, status=PortfolioRoleStatus.PENDING
|
user=user, portfolio=other_portfolio, status=PortfolioRoleStatus.PENDING
|
||||||
)
|
)
|
||||||
invite = InvitationFactory.create(
|
invite = PortfolioInvitationFactory.create(
|
||||||
user_id=user.id,
|
user_id=user.id,
|
||||||
portfolio_role=portfolio_role,
|
role=portfolio_role,
|
||||||
status=InvitationStatus.REJECTED_EXPIRED,
|
status=InvitationStatus.REJECTED_EXPIRED,
|
||||||
expiration_time=datetime.datetime.now() - datetime.timedelta(seconds=1),
|
expiration_time=datetime.datetime.now() - datetime.timedelta(seconds=1),
|
||||||
)
|
)
|
||||||
@ -202,9 +199,9 @@ def test_user_can_only_resend_invites_in_their_portfolio(client, user_session, q
|
|||||||
portfolio_role = PortfolioRoleFactory.create(
|
portfolio_role = PortfolioRoleFactory.create(
|
||||||
user=user, portfolio=other_portfolio, status=PortfolioRoleStatus.PENDING
|
user=user, portfolio=other_portfolio, status=PortfolioRoleStatus.PENDING
|
||||||
)
|
)
|
||||||
invite = InvitationFactory.create(
|
invite = PortfolioInvitationFactory.create(
|
||||||
user_id=user.id,
|
user_id=user.id,
|
||||||
portfolio_role=portfolio_role,
|
role=portfolio_role,
|
||||||
status=InvitationStatus.REJECTED_EXPIRED,
|
status=InvitationStatus.REJECTED_EXPIRED,
|
||||||
expiration_time=datetime.datetime.now() - datetime.timedelta(seconds=1),
|
expiration_time=datetime.datetime.now() - datetime.timedelta(seconds=1),
|
||||||
)
|
)
|
||||||
@ -227,8 +224,8 @@ def test_resend_invitation_sends_email(client, user_session, queue):
|
|||||||
ws_role = PortfolioRoleFactory.create(
|
ws_role = PortfolioRoleFactory.create(
|
||||||
user=user, portfolio=portfolio, status=PortfolioRoleStatus.PENDING
|
user=user, portfolio=portfolio, status=PortfolioRoleStatus.PENDING
|
||||||
)
|
)
|
||||||
invite = InvitationFactory.create(
|
invite = PortfolioInvitationFactory.create(
|
||||||
user_id=user.id, portfolio_role=ws_role, status=InvitationStatus.PENDING
|
user_id=user.id, role=ws_role, status=InvitationStatus.PENDING
|
||||||
)
|
)
|
||||||
user_session(portfolio.owner)
|
user_session(portfolio.owner)
|
||||||
client.post(
|
client.post(
|
||||||
@ -250,9 +247,9 @@ def test_existing_member_invite_resent_to_email_submitted_in_form(
|
|||||||
ws_role = PortfolioRoleFactory.create(
|
ws_role = PortfolioRoleFactory.create(
|
||||||
user=user, portfolio=portfolio, status=PortfolioRoleStatus.PENDING
|
user=user, portfolio=portfolio, status=PortfolioRoleStatus.PENDING
|
||||||
)
|
)
|
||||||
invite = InvitationFactory.create(
|
invite = PortfolioInvitationFactory.create(
|
||||||
user_id=user.id,
|
user_id=user.id,
|
||||||
portfolio_role=ws_role,
|
role=ws_role,
|
||||||
status=InvitationStatus.PENDING,
|
status=InvitationStatus.PENDING,
|
||||||
email="example@example.com",
|
email="example@example.com",
|
||||||
)
|
)
|
||||||
@ -290,7 +287,7 @@ def test_contracting_officer_accepts_invite(monkeypatch, client, user_session):
|
|||||||
|
|
||||||
# contracting officer accepts invitation
|
# contracting officer accepts invitation
|
||||||
user = Users.get_by_dod_id(user_info["dod_id"])
|
user = Users.get_by_dod_id(user_info["dod_id"])
|
||||||
token = user.invitations[0].token
|
token = user.portfolio_invitations[0].token
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
"atst.domain.auth.should_redirect_to_user_profile", lambda *args: False
|
"atst.domain.auth.should_redirect_to_user_profile", lambda *args: False
|
||||||
)
|
)
|
||||||
@ -324,7 +321,7 @@ def test_cor_accepts_invite(monkeypatch, client, user_session):
|
|||||||
|
|
||||||
# contracting officer representative accepts invitation
|
# contracting officer representative accepts invitation
|
||||||
user = Users.get_by_dod_id(user_info["dod_id"])
|
user = Users.get_by_dod_id(user_info["dod_id"])
|
||||||
token = user.invitations[0].token
|
token = user.portfolio_invitations[0].token
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
"atst.domain.auth.should_redirect_to_user_profile", lambda *args: False
|
"atst.domain.auth.should_redirect_to_user_profile", lambda *args: False
|
||||||
)
|
)
|
||||||
@ -358,7 +355,7 @@ def test_so_accepts_invite(monkeypatch, client, user_session):
|
|||||||
|
|
||||||
# security officer accepts invitation
|
# security officer accepts invitation
|
||||||
user = Users.get_by_dod_id(user_info["dod_id"])
|
user = Users.get_by_dod_id(user_info["dod_id"])
|
||||||
token = user.invitations[0].token
|
token = user.portfolio_invitations[0].token
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
"atst.domain.auth.should_redirect_to_user_profile", lambda *args: False
|
"atst.domain.auth.should_redirect_to_user_profile", lambda *args: False
|
||||||
)
|
)
|
||||||
|
@ -45,7 +45,7 @@ def test_create_member(client, user_session):
|
|||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert user.full_name in response.data.decode()
|
assert user.full_name in response.data.decode()
|
||||||
assert user.has_portfolios
|
assert user.has_portfolios
|
||||||
assert user.invitations
|
assert user.portfolio_invitations
|
||||||
assert len(queue.get_queue()) == queue_length + 1
|
assert len(queue.get_queue()) == queue_length + 1
|
||||||
portfolio_role = user.portfolio_roles[0]
|
portfolio_role = user.portfolio_roles[0]
|
||||||
assert len(portfolio_role.permission_sets) == 5
|
assert len(portfolio_role.permission_sets) == 5
|
||||||
|
@ -4,7 +4,7 @@ from flask import url_for
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from atst.domain.task_orders import TaskOrders
|
from atst.domain.task_orders import TaskOrders
|
||||||
from atst.models.invitation import Status as InvitationStatus
|
from atst.models import InvitationStatus
|
||||||
from atst.models.portfolio_role import Status as PortfolioStatus
|
from atst.models.portfolio_role import Status as PortfolioStatus
|
||||||
from atst.queue import queue
|
from atst.queue import queue
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ from tests.factories import (
|
|||||||
TaskOrderFactory,
|
TaskOrderFactory,
|
||||||
UserFactory,
|
UserFactory,
|
||||||
PortfolioRoleFactory,
|
PortfolioRoleFactory,
|
||||||
InvitationFactory,
|
PortfolioInvitationFactory,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ def test_does_not_resend_officer_invitation(client, user_session):
|
|||||||
user_session(user)
|
user_session(user)
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
client.post(url_for("task_orders.invite", task_order_id=task_order.id))
|
client.post(url_for("task_orders.invite", task_order_id=task_order.id))
|
||||||
assert len(contracting_officer.invitations) == 1
|
assert len(contracting_officer.portfolio_invitations) == 1
|
||||||
|
|
||||||
|
|
||||||
def test_does_not_invite_if_task_order_incomplete(client, user_session, queue):
|
def test_does_not_invite_if_task_order_incomplete(client, user_session, queue):
|
||||||
@ -272,9 +272,9 @@ class TestTaskOrderInvitations:
|
|||||||
cor_invite=True,
|
cor_invite=True,
|
||||||
)
|
)
|
||||||
portfolio_role = PortfolioRoleFactory.create(portfolio=self.portfolio, user=cor)
|
portfolio_role = PortfolioRoleFactory.create(portfolio=self.portfolio, user=cor)
|
||||||
invitation = InvitationFactory.create(
|
PortfolioInvitationFactory.create(
|
||||||
inviter=self.portfolio.owner,
|
inviter=self.portfolio.owner,
|
||||||
portfolio_role=portfolio_role,
|
role=portfolio_role,
|
||||||
user=cor,
|
user=cor,
|
||||||
status=InvitationStatus.PENDING,
|
status=InvitationStatus.PENDING,
|
||||||
)
|
)
|
||||||
@ -369,9 +369,9 @@ def test_resend_invite_when_not_pending(app, client, user_session, portfolio, us
|
|||||||
portfolio=portfolio, user=user, status=PortfolioStatus.ACTIVE
|
portfolio=portfolio, user=user, status=PortfolioStatus.ACTIVE
|
||||||
)
|
)
|
||||||
|
|
||||||
original_invitation = InvitationFactory.create(
|
original_invitation = PortfolioInvitationFactory.create(
|
||||||
inviter=user,
|
inviter=user,
|
||||||
portfolio_role=portfolio_role,
|
role=portfolio_role,
|
||||||
email=user.email,
|
email=user.email,
|
||||||
status=InvitationStatus.ACCEPTED,
|
status=InvitationStatus.ACCEPTED,
|
||||||
)
|
)
|
||||||
@ -397,9 +397,9 @@ def test_resending_revoked_invite(app, client, user_session, portfolio, user):
|
|||||||
|
|
||||||
portfolio_role = PortfolioRoleFactory.create(portfolio=portfolio, user=user)
|
portfolio_role = PortfolioRoleFactory.create(portfolio=portfolio, user=user)
|
||||||
|
|
||||||
invite = InvitationFactory.create(
|
invite = PortfolioInvitationFactory.create(
|
||||||
inviter=user,
|
inviter=user,
|
||||||
portfolio_role=portfolio_role,
|
role=portfolio_role,
|
||||||
email=user.email,
|
email=user.email,
|
||||||
status=InvitationStatus.REVOKED,
|
status=InvitationStatus.REVOKED,
|
||||||
)
|
)
|
||||||
@ -427,9 +427,9 @@ def test_resending_expired_invite(app, client, user_session, portfolio):
|
|||||||
portfolio=portfolio, contracting_officer=ko, ko_invite=True
|
portfolio=portfolio, contracting_officer=ko, ko_invite=True
|
||||||
)
|
)
|
||||||
portfolio_role = PortfolioRoleFactory.create(portfolio=portfolio, user=ko)
|
portfolio_role = PortfolioRoleFactory.create(portfolio=portfolio, user=ko)
|
||||||
invite = InvitationFactory.create(
|
invite = PortfolioInvitationFactory.create(
|
||||||
inviter=portfolio.owner,
|
inviter=portfolio.owner,
|
||||||
portfolio_role=portfolio_role,
|
role=portfolio_role,
|
||||||
email=ko.email,
|
email=ko.email,
|
||||||
expiration_time=datetime.now() - timedelta(days=1),
|
expiration_time=datetime.now() - timedelta(days=1),
|
||||||
)
|
)
|
||||||
|
@ -10,5 +10,5 @@ def test_invite_member(queue):
|
|||||||
ws_member = PortfolioRoleFactory.create(user=new_member, portfolio=portfolio)
|
ws_member = PortfolioRoleFactory.create(user=new_member, portfolio=portfolio)
|
||||||
invite_service = Invitation(inviter, ws_member, new_member.email)
|
invite_service = Invitation(inviter, ws_member, new_member.email)
|
||||||
new_invitation = invite_service.invite()
|
new_invitation = invite_service.invite()
|
||||||
assert new_invitation == new_member.invitations[0]
|
assert new_invitation == new_member.portfolio_invitations[0]
|
||||||
assert len(queue.get_queue()) == 1
|
assert len(queue.get_queue()) == 1
|
||||||
|
@ -17,7 +17,7 @@ from tests.factories import (
|
|||||||
ApplicationRoleFactory,
|
ApplicationRoleFactory,
|
||||||
EnvironmentFactory,
|
EnvironmentFactory,
|
||||||
EnvironmentRoleFactory,
|
EnvironmentRoleFactory,
|
||||||
InvitationFactory,
|
PortfolioInvitationFactory,
|
||||||
PortfolioFactory,
|
PortfolioFactory,
|
||||||
PortfolioRoleFactory,
|
PortfolioRoleFactory,
|
||||||
TaskOrderFactory,
|
TaskOrderFactory,
|
||||||
@ -75,7 +75,9 @@ def test_all_protected_routes_have_access_control(
|
|||||||
monkeypatch.setattr("atst.domain.portfolios.Portfolios.get", lambda *a: None)
|
monkeypatch.setattr("atst.domain.portfolios.Portfolios.get", lambda *a: None)
|
||||||
monkeypatch.setattr("atst.domain.task_orders.TaskOrders.get", lambda *a: Mock())
|
monkeypatch.setattr("atst.domain.task_orders.TaskOrders.get", lambda *a: Mock())
|
||||||
monkeypatch.setattr("atst.domain.applications.Applications.get", lambda *a: Mock())
|
monkeypatch.setattr("atst.domain.applications.Applications.get", lambda *a: Mock())
|
||||||
monkeypatch.setattr("atst.domain.invitations.Invitations._get", lambda *a: Mock())
|
monkeypatch.setattr(
|
||||||
|
"atst.domain.invitations.PortfolioInvitations._get", lambda *a: Mock()
|
||||||
|
)
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
"atst.utils.context_processors.get_portfolio_from_context", lambda *a: None
|
"atst.utils.context_processors.get_portfolio_from_context", lambda *a: None
|
||||||
)
|
)
|
||||||
@ -402,7 +404,7 @@ def test_portfolios_resend_invitation_access(post_url_assert_status):
|
|||||||
|
|
||||||
portfolio = PortfolioFactory.create(owner=owner)
|
portfolio = PortfolioFactory.create(owner=owner)
|
||||||
prr = PortfolioRoleFactory.create(user=invitee, portfolio=portfolio)
|
prr = PortfolioRoleFactory.create(user=invitee, portfolio=portfolio)
|
||||||
invite = InvitationFactory.create(user=UserFactory.create(), portfolio_role=prr)
|
invite = PortfolioInvitationFactory.create(user=UserFactory.create(), role=prr)
|
||||||
|
|
||||||
url = url_for(
|
url = url_for(
|
||||||
"portfolios.resend_invitation", portfolio_id=portfolio.id, token=invite.token
|
"portfolios.resend_invitation", portfolio_id=portfolio.id, token=invite.token
|
||||||
@ -423,7 +425,7 @@ def test_task_orders_resend_invite_access(post_url_assert_status):
|
|||||||
portfolio = PortfolioFactory.create(owner=owner)
|
portfolio = PortfolioFactory.create(owner=owner)
|
||||||
task_order = TaskOrderFactory.create(portfolio=portfolio, contracting_officer=ko)
|
task_order = TaskOrderFactory.create(portfolio=portfolio, contracting_officer=ko)
|
||||||
prr = PortfolioRoleFactory.create(user=ko, portfolio=portfolio)
|
prr = PortfolioRoleFactory.create(user=ko, portfolio=portfolio)
|
||||||
invite = InvitationFactory.create(user=UserFactory.create(), portfolio_role=prr)
|
PortfolioInvitationFactory.create(user=UserFactory.create(), role=prr)
|
||||||
|
|
||||||
url = url_for(
|
url = url_for(
|
||||||
"task_orders.resend_invite",
|
"task_orders.resend_invite",
|
||||||
@ -449,7 +451,7 @@ def test_portfolios_revoke_invitation_access(post_url_assert_status):
|
|||||||
prr = PortfolioRoleFactory.create(
|
prr = PortfolioRoleFactory.create(
|
||||||
user=prt_member, portfolio=portfolio, status=PortfolioRoleStatus.ACTIVE
|
user=prt_member, portfolio=portfolio, status=PortfolioRoleStatus.ACTIVE
|
||||||
)
|
)
|
||||||
invite = InvitationFactory.create(user=prt_member, portfolio_role=prr)
|
invite = PortfolioInvitationFactory.create(user=prt_member, role=prr)
|
||||||
url = url_for(
|
url = url_for(
|
||||||
"portfolios.revoke_invitation",
|
"portfolios.revoke_invitation",
|
||||||
portfolio_id=portfolio.id,
|
portfolio_id=portfolio.id,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user