atst/atat/domain/applications.py
2020-03-04 11:51:15 -05:00

148 lines
4.7 KiB
Python

from flask import g
from sqlalchemy import func, or_, and_
from typing import List
from uuid import UUID
from . import BaseDomainClass
from atat.database import db
from atat.domain.application_roles import ApplicationRoles
from atat.domain.environments import Environments
from atat.domain.exceptions import NotFoundError
from atat.domain.invitations import ApplicationInvitations
from atat.models import (
Application,
ApplicationRole,
ApplicationRoleStatus,
EnvironmentRole,
Portfolio,
PortfolioStateMachine,
)
from atat.models.mixins.state_machines import FSMStates
from atat.utils import first_or_none, commit_or_raise_already_exists_error
class Applications(BaseDomainClass):
model = Application
resource_name = "application"
@classmethod
def create(cls, user, portfolio, name, description, environment_names=None):
application = Application(
portfolio=portfolio, name=name, description=description
)
db.session.add(application)
if environment_names:
Environments.create_many(user, application, environment_names)
commit_or_raise_already_exists_error(message="application")
return application
@classmethod
def for_user(self, user, portfolio):
return (
db.session.query(Application)
.join(ApplicationRole)
.filter(Application.portfolio_id == portfolio.id)
.filter(ApplicationRole.application_id == Application.id)
.filter(ApplicationRole.user_id == user.id)
.filter(ApplicationRole.status == ApplicationRoleStatus.ACTIVE)
.all()
)
@classmethod
def update(cls, application, new_data):
if "name" in new_data:
application.name = new_data["name"]
if "description" in new_data:
application.description = new_data["description"]
if "environment_names" in new_data:
Environments.create_many(
g.current_user, application, new_data["environment_names"]
)
db.session.add(application)
commit_or_raise_already_exists_error(message="application")
return application
@classmethod
def delete(cls, application):
for env in application.environments:
Environments.delete(env)
application.deleted = True
for role in application.roles:
role.deleted = True
role.status = ApplicationRoleStatus.DISABLED
db.session.add(role)
db.session.add(application)
db.session.commit()
@classmethod
def invite(
cls,
application,
inviter,
user_data,
permission_sets_names=None,
environment_roles_data=None,
):
permission_sets_names = permission_sets_names or []
permission_sets = ApplicationRoles._permission_sets_for_names(
permission_sets_names
)
app_role = ApplicationRole(
application=application, permission_sets=permission_sets
)
db.session.add(app_role)
for env_role_data in environment_roles_data:
env_role_name = env_role_data.get("role")
environment_id = env_role_data.get("environment_id")
if env_role_name is not None:
# pylint: disable=cell-var-from-loop
environment = first_or_none(
lambda e: str(e.id) == str(environment_id), application.environments
)
if environment is None:
raise NotFoundError("environment")
else:
env_role = EnvironmentRole(
application_role=app_role,
environment=environment,
role=env_role_name,
)
db.session.add(env_role)
invitation = ApplicationInvitations.create(
inviter=inviter, role=app_role, member_data=user_data
)
db.session.add(invitation)
db.session.commit()
return invitation
@classmethod
def get_applications_pending_creation(cls) -> List[UUID]:
results = (
db.session.query(Application.id)
.join(Portfolio)
.join(PortfolioStateMachine)
.filter(
and_(
PortfolioStateMachine.state == FSMStates.COMPLETED,
Application.deleted == False,
Application.cloud_id.is_(None),
or_(
Application.claimed_until.is_(None),
Application.claimed_until <= func.now(),
),
)
)
).all()
return [id_ for id_, in results]