From 6f6d3720bce8a846b26e840974c883f8e22e338d Mon Sep 17 00:00:00 2001 From: Philip Kalinsky Date: Fri, 7 Feb 2020 12:05:02 -0500 Subject: [PATCH 1/4] class method to export portfolio data as dictionary as an arg to state machine --- atst/jobs.py | 2 +- atst/models/portfolio.py | 45 ++++++++++++++++++++++++++ atst/models/portfolio_state_machine.py | 2 ++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/atst/jobs.py b/atst/jobs.py index 6a12d423..46575a3d 100644 --- a/atst/jobs.py +++ b/atst/jobs.py @@ -145,7 +145,7 @@ def do_work(fn, task, csp, **kwargs): def do_provision_portfolio(csp: CloudProviderInterface, portfolio_id=None): portfolio = Portfolios.get_for_update(portfolio_id) fsm = Portfolios.get_or_create_state_machine(portfolio) - fsm.trigger_next_transition() + fsm.trigger_next_transition(csp_data=portfolio.to_dictionary()) @celery.task(bind=True, base=RecordFailure) diff --git a/atst/models/portfolio.py b/atst/models/portfolio.py index 5a8f0f1e..caef5b1b 100644 --- a/atst/models/portfolio.py +++ b/atst/models/portfolio.py @@ -1,3 +1,5 @@ +import re + from sqlalchemy import Column, String from sqlalchemy.orm import relationship from sqlalchemy.types import ARRAY @@ -6,6 +8,7 @@ from itertools import chain from atst.models.base import Base import atst.models.types as types import atst.models.mixins as mixins +from atst.models.task_order import TaskOrder from atst.models.portfolio_role import PortfolioRole, Status as PortfolioRoleStatus from atst.domain.permission_sets import PermissionSets from atst.utils import first_or_none @@ -153,6 +156,48 @@ class Portfolio( def application_id(self): return None + def to_dictionary(self): + ppoc = self.owner + user_id = f"{ppoc.first_name[0]}{ppoc.last_name}".lower() + domain_name = re.sub("[^0-9a-zA-Z]+", "", self.name).lower() + portfolio_data = { + "user_id": user_id, + "password": "jklfsdNCVD83nklds2#202", # pragma: allowlist secret + "domain_name": domain_name, + "first_name": ppoc.first_name, + "last_name": ppoc.last_name, + "country_code": "US", + "password_recovery_email_address": ppoc.email, + "address": { # TODO: TBD if we're sourcing this from data or config + "company_name": "", + "address_line_1": "", + "city": "", + "region": "", + "country": "", + "postal_code": "", + }, + "billing_profile_display_name": "My Billing Profile", + } + + try: + initial_task_order: TaskOrder = self.task_orders[0] + initial_clin = initial_task_order.sorted_clins[0] + portfolio_data.update( + { + "initial_clin_amount": initial_clin.obligated_amount, + "initial_clin_start_date": initial_clin.start_date.strftime( + "%Y/%m/%d" + ), + "initial_clin_end_date": initial_clin.end_date.strftime("%Y/%m/%d"), + "initial_clin_type": initial_clin.number, + "initial_task_order_id": initial_task_order.number, + } + ) + except IndexError: + pass + + return portfolio_data + def __repr__(self): return "".format( self.name, self.user_count, self.id diff --git a/atst/models/portfolio_state_machine.py b/atst/models/portfolio_state_machine.py index f5c1a461..e154b71a 100644 --- a/atst/models/portfolio_state_machine.py +++ b/atst/models/portfolio_state_machine.py @@ -99,6 +99,8 @@ class PortfolioStateMachine( def trigger_next_transition(self, **kwargs): state_obj = self.machine.get_state(self.state) + csp_data = kwargs.get("csp_data", {}) + if state_obj.is_system: if self.current_state in (FSMStates.UNSTARTED, FSMStates.STARTING): # call the first trigger availabe for these two system states From a2201a0edf06e43c1e7abc6ede89612470255b15 Mon Sep 17 00:00:00 2001 From: Philip Kalinsky Date: Fri, 7 Feb 2020 14:00:16 -0500 Subject: [PATCH 2/4] portfolio data dict. domain name uses random string suffix. do not set the password --- atst/models/portfolio.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/atst/models/portfolio.py b/atst/models/portfolio.py index caef5b1b..2d4f8d80 100644 --- a/atst/models/portfolio.py +++ b/atst/models/portfolio.py @@ -1,9 +1,11 @@ import re +from string import ascii_lowercase, digits +from random import choices +from itertools import chain from sqlalchemy import Column, String from sqlalchemy.orm import relationship from sqlalchemy.types import ARRAY -from itertools import chain from atst.models.base import Base import atst.models.types as types @@ -159,10 +161,12 @@ class Portfolio( def to_dictionary(self): ppoc = self.owner user_id = f"{ppoc.first_name[0]}{ppoc.last_name}".lower() - domain_name = re.sub("[^0-9a-zA-Z]+", "", self.name).lower() + + domain_name = re.sub("[^0-9a-zA-Z]+", "", self.name).lower() + \ + ''.join(choices(ascii_lowercase + digits, k=4)) portfolio_data = { "user_id": user_id, - "password": "jklfsdNCVD83nklds2#202", # pragma: allowlist secret + "password": "", "domain_name": domain_name, "first_name": ppoc.first_name, "last_name": ppoc.last_name, @@ -176,7 +180,7 @@ class Portfolio( "country": "", "postal_code": "", }, - "billing_profile_display_name": "My Billing Profile", + "billing_profile_display_name": "ATAT Billing Profile", } try: From 91d3795a92ae6827710c8583cb76130c3000ccee Mon Sep 17 00:00:00 2001 From: tomdds Date: Tue, 11 Feb 2020 13:21:53 -0500 Subject: [PATCH 3/4] Fix formatting issue --- atst/models/portfolio.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/atst/models/portfolio.py b/atst/models/portfolio.py index 8c9694a6..ffa674c3 100644 --- a/atst/models/portfolio.py +++ b/atst/models/portfolio.py @@ -1,5 +1,5 @@ import re -from string import ascii_lowercase, digits +from string import ascii_lowercase, digits from random import choices from itertools import chain @@ -168,8 +168,9 @@ class Portfolio( ppoc = self.owner user_id = f"{ppoc.first_name[0]}{ppoc.last_name}".lower() - domain_name = re.sub("[^0-9a-zA-Z]+", "", self.name).lower() + \ - ''.join(choices(ascii_lowercase + digits, k=4)) + domain_name = re.sub("[^0-9a-zA-Z]+", "", self.name).lower() + "".join( + choices(ascii_lowercase + digits, k=4) + ) portfolio_data = { "user_id": user_id, "password": "", From 6079e01fb074a9df1988540f0749b990572ca27b Mon Sep 17 00:00:00 2001 From: tomdds Date: Tue, 11 Feb 2020 13:23:11 -0500 Subject: [PATCH 4/4] Ensure non-none value for csp_data state machine arg --- atst/models/portfolio_state_machine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atst/models/portfolio_state_machine.py b/atst/models/portfolio_state_machine.py index 96192d18..24a3fefc 100644 --- a/atst/models/portfolio_state_machine.py +++ b/atst/models/portfolio_state_machine.py @@ -99,7 +99,7 @@ class PortfolioStateMachine( def trigger_next_transition(self, **kwargs): state_obj = self.machine.get_state(self.state) - csp_data = kwargs.get("csp_data", {}) + kwargs["csp_data"] = kwargs.get("csp_data", {}) if state_obj.is_system: if self.current_state in (FSMStates.UNSTARTED, FSMStates.STARTING):