New backend flow for application invitations.
Like portfolio invitations, now a user is not associated with an application role until they accept the associated invitation. - domain method for inviting user to application - change application route for inviting a member - ApplicationRole model knows user name from invitation
This commit is contained in:
@@ -1,13 +1,20 @@
|
||||
from sqlalchemy.orm.exc import NoResultFound
|
||||
|
||||
from atst.database import db
|
||||
from . import BaseDomainClass
|
||||
from atst.database import db
|
||||
from atst.domain.application_roles import ApplicationRoles
|
||||
from atst.domain.environment_roles import EnvironmentRoles
|
||||
from atst.domain.environments import Environments
|
||||
from atst.domain.exceptions import NotFoundError
|
||||
from atst.domain.invitations import ApplicationInvitations
|
||||
from atst.domain.users import Users
|
||||
from atst.models import Application, ApplicationRole, ApplicationRoleStatus
|
||||
from atst.models import (
|
||||
Application,
|
||||
ApplicationRole,
|
||||
ApplicationRoleStatus,
|
||||
EnvironmentRole,
|
||||
)
|
||||
from atst.utils import first_or_none
|
||||
|
||||
|
||||
class Applications(BaseDomainClass):
|
||||
@@ -104,6 +111,52 @@ class Applications(BaseDomainClass):
|
||||
|
||||
return application_role
|
||||
|
||||
@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 remove_member(cls, application, user_id):
|
||||
application_role = ApplicationRoles.get(
|
||||
|
@@ -59,12 +59,17 @@ class ApplicationRole(
|
||||
),
|
||||
)
|
||||
|
||||
@property
|
||||
def latest_invitation(self):
|
||||
if self.invitations:
|
||||
return self.invitations[-1]
|
||||
|
||||
@property
|
||||
def user_name(self):
|
||||
if self.user:
|
||||
return self.user.full_name
|
||||
else:
|
||||
return None
|
||||
elif self.latest_invitation:
|
||||
return self.latest_invitation.user_name
|
||||
|
||||
def __repr__(self):
|
||||
return "<ApplicationRole(application='{}', user_id='{}', id='{}', permissions={})>".format(
|
||||
|
@@ -13,8 +13,8 @@ from atst.domain.users import Users
|
||||
from atst.forms.application_member import NewForm as NewMemberForm
|
||||
from atst.forms.team import TeamForm
|
||||
from atst.models import Permissions
|
||||
from atst.services.invitation import Invitation as InvitationService
|
||||
from atst.utils.flash import formatted_flash as flash
|
||||
from atst.queue import queue
|
||||
|
||||
|
||||
def get_form_permission_value(member, edit_perm_set):
|
||||
@@ -125,6 +125,17 @@ def update_team(application_id):
|
||||
return (render_team_page(application), 400)
|
||||
|
||||
|
||||
def send_application_invitation(invitee_email, inviter_name, token):
|
||||
body = render_template(
|
||||
"emails/application/invitation.txt", owner=inviter_name, token=token
|
||||
)
|
||||
queue.send_mail(
|
||||
[invitee_email],
|
||||
"{} has invited you to a JEDI cloud application".format(inviter_name),
|
||||
body,
|
||||
)
|
||||
|
||||
|
||||
@applications_bp.route("/application/<application_id>/members/new", methods=["POST"])
|
||||
@user_can(
|
||||
Permissions.CREATE_APPLICATION_MEMBER, message="create new application member"
|
||||
@@ -135,19 +146,19 @@ def create_member(application_id):
|
||||
|
||||
if form.validate():
|
||||
try:
|
||||
member = Applications.create_member(
|
||||
application,
|
||||
form.user_data.data,
|
||||
permission_sets=form.permission_sets.data,
|
||||
invite = Applications.invite(
|
||||
application=application,
|
||||
inviter=g.current_user,
|
||||
user_data=form.user_data.data,
|
||||
permission_sets_names=form.permission_sets.data,
|
||||
environment_roles_data=form.environment_roles.data,
|
||||
)
|
||||
|
||||
invite_service = InvitationService(
|
||||
g.current_user, member, form.user_data.data.get("email")
|
||||
send_application_invitation(
|
||||
invite.email, g.current_user.full_name, invite.token
|
||||
)
|
||||
invite_service.invite()
|
||||
|
||||
flash("new_portfolio_member", new_member=member)
|
||||
flash("new_application_member", user_name=invite.user_name)
|
||||
|
||||
except AlreadyExistsError:
|
||||
return render_template(
|
||||
|
@@ -67,7 +67,7 @@ MESSAGES = {
|
||||
"new_application_member": {
|
||||
"title_template": translate("flash.success"),
|
||||
"message_template": """
|
||||
<p>{{ "flash.new_application_member" | translate({ "user_name": new_member.user_name }) }}</p>
|
||||
<p>{{ "flash.new_application_member" | translate({ "user_name": user_name }) }}</p>
|
||||
""",
|
||||
"category": "success",
|
||||
},
|
||||
@@ -179,7 +179,7 @@ MESSAGES = {
|
||||
"update_portfolio_members": {
|
||||
"title_template": "Success!",
|
||||
"message_template": """
|
||||
<p>You have successfully updated access permissions for members of {{ portfolio.name }}.</p>
|
||||
<p>You have successfully updated access permissions for members of {{ portfolio.name }}.</p>
|
||||
""",
|
||||
"category": "success",
|
||||
},
|
||||
|
Reference in New Issue
Block a user