Merge pull request #1435 from dod-ccpo/email-new-env-role

Email new env role
This commit is contained in:
leigh-mil 2020-02-26 13:25:02 -05:00 committed by GitHub
commit 658e2cb9f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 71 additions and 26 deletions

View File

@ -4,9 +4,12 @@ from typing import Dict, List, Optional
from uuid import uuid4 from uuid import uuid4
import re import re
from flask import current_app as app
from pydantic import BaseModel, validator, root_validator from pydantic import BaseModel, validator, root_validator
from .utils import (
generate_mail_nickname,
generate_user_principal_name,
)
from atst.utils import snake_to_camel from atst.utils import snake_to_camel
@ -527,11 +530,11 @@ class UserMixin(BaseModel):
@property @property
def user_principal_name(self): def user_principal_name(self):
return f"{self.mail_nickname}@{self.tenant_host_name}.{app.config.get('OFFICE_365_DOMAIN')}" return generate_user_principal_name(self.display_name, self.tenant_host_name)
@property @property
def mail_nickname(self): def mail_nickname(self):
return self.display_name.replace(" ", ".").lower() return generate_mail_nickname(self.display_name)
@validator("password", pre=True, always=True) @validator("password", pre=True, always=True)
def supply_password_default(cls, password): def supply_password_default(cls, password):

View File

@ -0,0 +1,10 @@
from flask import current_app as app
def generate_user_principal_name(name, domain_name):
mail_name = generate_mail_nickname(name)
return f"{mail_name}@{domain_name}.{app.config.get('OFFICE_365_DOMAIN')}"
def generate_mail_nickname(name):
return name.replace(" ", ".").lower()

View File

@ -7,6 +7,7 @@ from atst.database import db
from atst.domain.application_roles import ApplicationRoles from atst.domain.application_roles import ApplicationRoles
from atst.domain.applications import Applications from atst.domain.applications import Applications
from atst.domain.csp.cloud import CloudProviderInterface from atst.domain.csp.cloud import CloudProviderInterface
from atst.domain.csp.cloud.utils import generate_user_principal_name
from atst.domain.csp.cloud.exceptions import GeneralCSPException from atst.domain.csp.cloud.exceptions import GeneralCSPException
from atst.domain.csp.cloud.models import ( from atst.domain.csp.cloud.models import (
ApplicationCSPPayload, ApplicationCSPPayload,
@ -177,7 +178,21 @@ def do_create_environment_role(csp: CloudProviderInterface, environment_role_id=
env_role.cloud_id = result.id env_role.cloud_id = result.id
db.session.add(env_role) db.session.add(env_role)
db.session.commit() db.session.commit()
# TODO: should send notification email to the user, maybe with their portal login name
user = env_role.application_role.user
domain_name = csp_details.get("domain_name")
username = generate_user_principal_name(user.full_name, domain_name,)
send_mail(
recipients=[user.email],
subject=translate("email.azure_account_update.subject"),
body=translate(
"email.azure_account_update.body",
{"url": app.config.get("AZURE_LOGIN_URL"), "username": username},
),
)
app.logger.info(
f"Notification email sent for environment role creation. User id: {user.id}"
)
def render_email(template_path, context): def render_email(template_path, context):
@ -195,7 +210,7 @@ def send_PPOC_email(portfolio_dict):
ppoc_email = portfolio_dict.get("password_recovery_email_address") ppoc_email = portfolio_dict.get("password_recovery_email_address")
user_id = portfolio_dict.get("user_id") user_id = portfolio_dict.get("user_id")
domain_name = portfolio_dict.get("domain_name") domain_name = portfolio_dict.get("domain_name")
username = generate_user_principal_name(user_id, domain_name)
send_mail( send_mail(
recipients=[ppoc_email], recipients=[ppoc_email],
subject=translate("email.portfolio_ready.subject"), subject=translate("email.portfolio_ready.subject"),
@ -203,7 +218,7 @@ def send_PPOC_email(portfolio_dict):
"email.portfolio_ready.body", "email.portfolio_ready.body",
{ {
"password_reset_address": app.config.get("AZURE_LOGIN_URL"), "password_reset_address": app.config.get("AZURE_LOGIN_URL"),
"username": f"{user_id}@{domain_name}.{app.config.get('OFFICE_365_DOMAIN')}", "username": username,
}, },
), ),
) )

View File

@ -12,10 +12,10 @@ from sqlalchemy_json import NestedMutableJson
from atst.database import db from atst.database import db
import atst.models.mixins as mixins import atst.models.mixins as mixins
import atst.models.types as types import atst.models.types as types
from atst.domain.csp.cloud.utils import generate_mail_nickname
from atst.domain.permission_sets import PermissionSets from atst.domain.permission_sets import PermissionSets
from atst.models.base import Base from atst.models.base import Base
from atst.models.portfolio_role import PortfolioRole from atst.models.portfolio_role import PortfolioRole, Status as PortfolioRoleStatus
from atst.models.portfolio_role import Status as PortfolioRoleStatus
from atst.utils import first_or_none from atst.utils import first_or_none
@ -205,7 +205,9 @@ class Portfolio(
def to_dictionary(self): def to_dictionary(self):
return { return {
"user_id": f"{self.owner.first_name[0]}{self.owner.last_name}".lower(), "user_id": generate_mail_nickname(
f"{self.owner.first_name[0]}{self.owner.last_name}"
),
"password": "", "password": "",
"domain_name": self.domain_name, "domain_name": self.domain_name,
"first_name": self.owner.first_name, "first_name": self.owner.first_name,

View File

@ -399,23 +399,35 @@ def test_dispatch_create_environment_role(monkeypatch):
mock.delay.assert_called_once_with(environment_role_id=env_role.id) mock.delay.assert_called_once_with(environment_role_id=env_role.id)
def test_create_environment_role(): class TestCreateEnvironmentRole:
portfolio = PortfolioFactory.create(csp_data={"tenant_id": "123"}) @pytest.fixture
app = ApplicationFactory.create(portfolio=portfolio) def env_role(self):
app_role = ApplicationRoleFactory.create( portfolio = PortfolioFactory.create(csp_data={"tenant_id": "123"})
application=app, status=ApplicationRoleStatus.ACTIVE, cloud_id="123", app = ApplicationFactory.create(portfolio=portfolio)
) app_role = ApplicationRoleFactory.create(
env = EnvironmentFactory.create(application=app, cloud_id="123") application=app, status=ApplicationRoleStatus.ACTIVE, cloud_id="123",
env_role = EnvironmentRoleFactory.create( )
environment=env, application_role=app_role, cloud_id=None env = EnvironmentFactory.create(application=app, cloud_id="123")
) return EnvironmentRoleFactory.create(
environment=env, application_role=app_role, cloud_id=None
)
csp = Mock() @pytest.fixture
result = UserRoleCSPResult(id="a-cloud-id") def csp(self):
csp.create_user_role = MagicMock(return_value=result) csp = Mock()
do_create_environment_role(csp, environment_role_id=env_role.id) result = UserRoleCSPResult(id="a-cloud-id")
csp.create_user_role = MagicMock(return_value=result)
return csp
assert env_role.cloud_id == "a-cloud-id" def test_success(self, env_role, csp):
do_create_environment_role(csp, environment_role_id=env_role.id)
assert env_role.cloud_id == "a-cloud-id"
def test_sends_email(self, monkeypatch, env_role, csp):
send_mail = Mock()
monkeypatch.setattr("atst.jobs.send_mail", send_mail)
do_create_environment_role(csp, environment_role_id=env_role.id)
assert send_mail.call_count == 1
class TestSendTaskOrderFiles: class TestSendTaskOrderFiles:

View File

@ -86,7 +86,10 @@ email:
app_role_created: app_role_created:
subject: Application Role Created subject: Application Role Created
body: "Your application role has been created.\nVisit {url}, and use your username, {username}, to log in." body: "Your application role has been created.\nVisit {url}, and use your username, {username}, to log in."
portfolio_invite: "{inviter_name} has invited you to a JEDI cloud portfolio." azure_account_update:
subject: Azure account update
body: "There has been an update to your Azure account. \nVisit {url}, and use your username, {username}, to log in."
portfolio_invite: "{inviter_name} has invited you to a JEDI cloud portfolio"
portfolio_ready: portfolio_ready:
subject: Portfolio Provisioned subject: Portfolio Provisioned
body: "Your portfolio has been provisioned.\nVisit {password_reset_address}, and use your username, {username}, to create a password." body: "Your portfolio has been provisioned.\nVisit {password_reset_address}, and use your username, {username}, to create a password."