173 lines
5.0 KiB
Python
173 lines
5.0 KiB
Python
from sqlalchemy import or_
|
|
from typing import List
|
|
from uuid import UUID
|
|
|
|
from atat.database import db
|
|
from atat.domain.permission_sets import PermissionSets
|
|
from atat.domain.authz import Authorization
|
|
from atat.domain.portfolio_roles import PortfolioRoles
|
|
|
|
from atat.domain.invitations import PortfolioInvitations
|
|
from atat.models import (
|
|
Portfolio,
|
|
PortfolioStateMachine,
|
|
FSMStates,
|
|
Permissions,
|
|
PortfolioRole,
|
|
PortfolioRoleStatus,
|
|
TaskOrder,
|
|
CLIN,
|
|
)
|
|
|
|
from .query import PortfoliosQuery, PortfolioStateMachinesQuery
|
|
from .scopes import ScopedPortfolio
|
|
|
|
|
|
class PortfolioError(Exception):
|
|
pass
|
|
|
|
|
|
class PortfolioDeletionApplicationsExistError(Exception):
|
|
pass
|
|
|
|
|
|
class PortfolioStateMachines(object):
|
|
@classmethod
|
|
def create(cls, portfolio, **sm_attrs):
|
|
sm_attrs.update({"portfolio": portfolio})
|
|
sm = PortfolioStateMachinesQuery.create(**sm_attrs)
|
|
return sm
|
|
|
|
|
|
class Portfolios(object):
|
|
@classmethod
|
|
def get_or_create_state_machine(cls, portfolio):
|
|
"""
|
|
get or create Portfolio State Machine for a Portfolio
|
|
"""
|
|
return portfolio.state_machine or PortfolioStateMachines.create(portfolio)
|
|
|
|
@classmethod
|
|
def create(cls, user, portfolio_attrs):
|
|
portfolio = PortfoliosQuery.create(**portfolio_attrs)
|
|
perms_sets = PermissionSets.get_many(PortfolioRoles.PORTFOLIO_PERMISSION_SETS)
|
|
Portfolios._create_portfolio_role(
|
|
user,
|
|
portfolio,
|
|
status=PortfolioRoleStatus.ACTIVE,
|
|
permission_sets=perms_sets,
|
|
)
|
|
PortfoliosQuery.add_and_commit(portfolio)
|
|
return portfolio
|
|
|
|
@classmethod
|
|
def get(cls, user, portfolio_id):
|
|
portfolio = PortfoliosQuery.get(portfolio_id)
|
|
return ScopedPortfolio(user, portfolio)
|
|
|
|
@classmethod
|
|
def delete(cls, portfolio):
|
|
if len(portfolio.applications) != 0:
|
|
raise PortfolioDeletionApplicationsExistError()
|
|
|
|
for portfolio_role in portfolio.roles:
|
|
PortfolioRoles.disable(portfolio_role=portfolio_role, commit=False)
|
|
|
|
portfolio.deleted = True
|
|
|
|
db.session.add(portfolio)
|
|
db.session.commit()
|
|
|
|
return portfolio
|
|
|
|
@classmethod
|
|
def get_for_update(cls, portfolio_id):
|
|
portfolio = PortfoliosQuery.get(portfolio_id)
|
|
|
|
return portfolio
|
|
|
|
@classmethod
|
|
def for_user(cls, user):
|
|
if Authorization.has_atat_permission(user, Permissions.VIEW_PORTFOLIO):
|
|
portfolios = PortfoliosQuery.get_all()
|
|
else:
|
|
portfolios = PortfoliosQuery.get_for_user(user)
|
|
return portfolios
|
|
|
|
@classmethod
|
|
def add_member(cls, portfolio, member, permission_sets=None):
|
|
portfolio_role = PortfolioRoles.add(member, portfolio.id, permission_sets)
|
|
return portfolio_role
|
|
|
|
@classmethod
|
|
def invite(cls, portfolio, inviter, member_data):
|
|
permission_sets = PortfolioRoles._permission_sets_for_names(
|
|
member_data.get("permission_sets", [])
|
|
)
|
|
role = PortfolioRole(portfolio=portfolio, permission_sets=permission_sets)
|
|
|
|
invitation = PortfolioInvitations.create(
|
|
inviter=inviter, role=role, member_data=member_data["user_data"]
|
|
)
|
|
|
|
PortfoliosQuery.add_and_commit(role)
|
|
|
|
return invitation
|
|
|
|
@classmethod
|
|
def update_member(cls, member, permission_sets):
|
|
return PortfolioRoles.update(member, permission_sets)
|
|
|
|
@classmethod
|
|
def _create_portfolio_role(
|
|
cls, user, portfolio, status=PortfolioRoleStatus.PENDING, permission_sets=None
|
|
):
|
|
if permission_sets is None:
|
|
permission_sets = []
|
|
|
|
portfolio_role = PortfoliosQuery.create_portfolio_role(
|
|
user, portfolio, status=status, permission_sets=permission_sets
|
|
)
|
|
PortfoliosQuery.add_and_commit(portfolio_role)
|
|
return portfolio_role
|
|
|
|
@classmethod
|
|
def update(cls, portfolio, new_data):
|
|
if "name" in new_data:
|
|
portfolio.name = new_data["name"]
|
|
|
|
if "description" in new_data:
|
|
portfolio.description = new_data["description"]
|
|
|
|
PortfoliosQuery.add_and_commit(portfolio)
|
|
|
|
@classmethod
|
|
def base_provision_query(cls):
|
|
return db.session.query(Portfolio.id)
|
|
|
|
@classmethod
|
|
def get_portfolios_pending_provisioning(cls, now) -> List[UUID]:
|
|
"""
|
|
Any portfolio with a corresponding State Machine that is either:
|
|
not started yet,
|
|
failed in creating a tenant
|
|
failed
|
|
"""
|
|
|
|
results = (
|
|
db.session.query(Portfolio.id)
|
|
.join(PortfolioStateMachine)
|
|
.join(TaskOrder)
|
|
.join(CLIN)
|
|
.filter(Portfolio.deleted == False)
|
|
.filter(CLIN.start_date <= now)
|
|
.filter(CLIN.end_date > now)
|
|
.filter(
|
|
or_(
|
|
PortfolioStateMachine.state == FSMStates.UNSTARTED,
|
|
PortfolioStateMachine.state.like("%CREATED"),
|
|
)
|
|
)
|
|
)
|
|
return [id_ for id_, in results]
|