def update_org(self, org_info, bearer_token: str = None): """Update the passed organization with the new info.""" current_app.logger.debug('<update_org ') if self._model.type_code != OrgType.PREMIUM.value: existing_similar__org = OrgModel.find_similar_org_by_name( org_info['name'], self._model.id) if existing_similar__org is not None: raise BusinessException(Error.DATA_CONFLICT, None) bcol_credential = org_info.pop('bcOnlineCredential', None) mailing_address = org_info.pop('mailingAddress', None) # If the account is created using BCOL credential, verify its valid bc online account # If it's a valid account disable the current one and add a new one if bcol_credential: self.add_bcol_to_account(bcol_credential, bearer_token, org_info) # Update mailing address if mailing_address: contact = self._model.contacts[0].contact contact.update_from_dict(**camelback2snake(mailing_address)) contact.save() if self._model.type_code != OrgType.PREMIUM.value: self._model.update_org_from_dict(camelback2snake(org_info)) current_app.logger.debug('>update_org ') return self
def update_entity(business_identifier: str, entity_info: dict, **kwargs): """Update an entity from the given dictionary. Completely replaces the entity including the business identifier """ if not entity_info or not business_identifier: return None user_from_context: UserContext = kwargs['user_context'] # todo No memberhsip created at this point. check_auth wont work.ideally we shud put the logic in here # check_auth(token_info, one_of_roles=allowed_roles, business_identifier=business_identifier) entity = EntityModel.find_by_business_identifier(business_identifier) if entity is None or entity.corp_type_code is None: raise BusinessException(Error.DATA_NOT_FOUND, None) # if entity.corp_type_code != token_info.get('corp_type', None): # raise BusinessException(Error.INVALID_USER_CREDENTIALS, None) if user_from_context.is_system(): if entity_info.get('passCode') is not None: entity_info['passCode'] = passcode_hash(entity_info['passCode']) # Small mapping from state -> status. EX in LEAR: Business.State.HISTORICAL if 'state' in entity_info: entity_info['status'] = entity_info['state'] del entity_info['state'] entity.update_from_dict(**camelback2snake(entity_info)) entity.commit() entity = Entity(entity) return entity
def add_contact(token, contact_info: dict, throw_error_for_duplicates: bool = True): """Add contact information for an existing user.""" current_app.logger.debug('add_contact') user = UserModel.find_by_jwt_token(token) if user is None: raise BusinessException(Error.DATA_NOT_FOUND, None) # check for existing contact (we only want one contact per user) contact_link = ContactLinkModel.find_by_user_id(user.id) if contact_link is not None: if not throw_error_for_duplicates: # TODO may be throw whole object return None raise BusinessException(Error.DATA_ALREADY_EXISTS, None) contact = ContactModel(**camelback2snake(contact_info)) contact = contact.flush() contact_link = ContactLinkModel() contact_link.user = user contact_link.contact = contact contact_link.save() return ContactService(contact)
def update_entity(business_identifier: str, entity_info: dict, token_info: Dict = None): """Update an entity from the given dictionary. Completely replaces the entity including the business identifier """ if not entity_info or not business_identifier: return None # todo No memberhsip created at this point. check_auth wont work.ideally we shud put the logic in here # check_auth(token_info, one_of_roles=allowed_roles, business_identifier=business_identifier) entity = EntityModel.find_by_business_identifier(business_identifier) if entity is None or entity.corp_type_code is None: raise BusinessException(Error.DATA_NOT_FOUND, None) # if entity.corp_type_code != token_info.get('corp_type', None): # raise BusinessException(Error.INVALID_USER_CREDENTIALS, None) is_system = token_info and Role.SYSTEM.value in token_info.get( 'realm_access').get('roles') if is_system: if entity_info.get('passCode') is not None: entity_info['passCode'] = passcode_hash( entity_info['passCode']) entity.update_from_dict(**camelback2snake(entity_info)) entity.commit() entity = Entity(entity) return entity
def create_affidavit(token_info: Dict, affidavit_info: Dict): """Create a new affidavit record.""" current_app.logger.debug('<create_affidavit ') user = UserService.find_by_jwt_token(token=token_info) # If the user already have a pending affidavit, raise error existing_affidavit = AffidavitModel.find_pending_by_user_id( user_id=user.identifier) if existing_affidavit is not None: raise BusinessException(Error.ACTIVE_AFFIDAVIT_EXISTS, None) contact = affidavit_info.pop('contact') affidavit_model = AffidavitModel( issuer=affidavit_info.get('issuer'), document_id=affidavit_info.get('documentId'), status_code=AffidavitStatus.PENDING.value, user_id=user.identifier) affidavit_model.add_to_session() # Save contact for the affidavit if contact: contact = ContactModel(**camelback2snake(contact)) contact.add_to_session() contact_link = ContactLinkModel() contact_link.affidavit = affidavit_model contact_link.contact = contact contact_link.add_to_session() affidavit_model.save() return Affidavit(affidavit_model)
def change_org_ype(self, org_info, action=None): """Update the passed organization with the new info. if Upgrade: //TODO .Missing RULES 1.do bcol verification 2.attach mailing 3.change the org with bcol org name If downgrade: //TODO .Missing RULES 1.remove contact 2.deactivate payment settings 3.add new payment settings for cc 4.change the org with user passed org name """ if self._model.access_type == AccessType.ANONYMOUS.value: raise BusinessException(Error.INVALID_INPUT, None) bcol_credential = org_info.pop('bcOnlineCredential', None) mailing_address = org_info.pop('mailingAddress', None) current_app.logger.debug('<update_org ', action) if action == ChangeType.DOWNGRADE.value: if org_info.get('typeCode') != OrgType.BASIC.value: raise BusinessException(Error.INVALID_INPUT, None) # if they have not changed the name , they can claim the name. Dont check duplicate..or else check duplicate # TODO fix this # if org_info.get('name') != self._model.name: # Org.raise_error_if_duplicate_name(org_info['name']) # remove the bcol payment details from payment table org_info['bcol_account_id'] = '' org_info['bcol_user_id'] = '' org_info['bcol_account_name'] = '' payment_type = Org._get_default_payment_method_for_creditcard() # TODO Add the pay-api call here Org.__delete_contact(self._model) if action == ChangeType.UPGRADE.value: if org_info.get( 'typeCode' ) != OrgType.PREMIUM.value or bcol_credential is None: raise BusinessException(Error.INVALID_INPUT, None) bcol_response = Org.get_bcol_details(bcol_credential, self._model.id).json() Org._map_response_to_org(bcol_response, org_info) ProductService.create_subscription_from_bcol_profile( self._model.id, bcol_response.get('profileFlags')) payment_type = PaymentMethod.BCOL.value # If mailing address is provided, save it if mailing_address: self.add_contact_to_org(mailing_address, self._model) self._model.update_org_from_dict(camelback2snake(org_info), exclude=('status_code')) # TODO pass username instead of blanks Org._create_payment_settings(self._model, {}, payment_type, mailing_address, False) return self
def add_contact_to_org(mailing_address, org): """Update the passed organization with the mailing address.""" contact = ContactModel(**camelback2snake(mailing_address)) contact = contact.add_to_session() contact_link = ContactLinkModel() contact_link.contact = contact contact_link.org = org contact_link.add_to_session()
def create_from_dict(cls, entity_info: dict): """Create a new Entity from the provided dictionary.""" if entity_info: entity = Entity(**camelback2snake(entity_info)) current_app.logger.debug( 'Creating entity from dictionary {}'.format(entity_info)) entity.save() return entity return None
def create_from_dict(cls, entity_info: dict): """Create a new Entity from the provided dictionary.""" if entity_info: entity = Entity(**camelback2snake(entity_info)) entity.pass_code = passcode_hash(entity.pass_code) current_app.logger.debug( f'Creating entity from dictionary {entity_info}') entity.save() return entity return None
def create_task(task_info: dict, do_commit: bool = True): """Create a new task record.""" current_app.logger.debug('<create_task ') task_model = TaskModel(**camelback2snake(task_info)) task_model.flush() if do_commit: # Task mostly comes as a part of parent transaction.So do not commit unless asked. db.session.commit() current_app.logger.debug('>create_task ') return Task(task_model)
def update_org(self, org_info, bearer_token: str = None): """Update the passed organization with the new info.""" current_app.logger.debug('<update_org ') if self._model.type_code != OrgType.PREMIUM.value: existing_similar__org = OrgModel.find_similar_org_by_name( org_info['name'], self._model.id) if existing_similar__org is not None: raise BusinessException(Error.DATA_CONFLICT, None) is_premium = False bcol_credential = org_info.pop('bcOnlineCredential', None) mailing_address = org_info.pop('mailingAddress', None) selected_payment_method = org_info.pop('paymentMethod', None) # If the account is created using BCOL credential, verify its valid bc online account # If it's a valid account disable the current one and add a new one if bcol_credential: bcol_response = Org.get_bcol_details(bcol_credential, org_info, bearer_token, self._model.id).json() Org._map_response_to_org(bcol_response, org_info) is_premium = True # Update mailing address Or create new one if mailing_address: contacts = self._model.contacts if len(contacts) > 0: contact = self._model.contacts[0].contact contact.update_from_dict(**camelback2snake(mailing_address)) contact.save() else: Org.add_contact_to_org(mailing_address, self._model) if self._model.type_code != OrgType.PREMIUM.value: self._model.update_org_from_dict(camelback2snake(org_info)) org_type: OrgType = OrgType.PREMIUM if is_premium else OrgType.BASIC payment_type = Org._validate_and_get_payment_method( selected_payment_method, org_type) Org._create_payment_settings(self._model, payment_type, False) current_app.logger.debug('>update_org ') return self
def update_org(self, org_info): """Update the passed organization with the new info.""" current_app.logger.debug('<update_org ') existing_similar__org = OrgModel.find_similar_org_by_name( org_info['name']) if existing_similar__org is not None: raise BusinessException(Error.DATA_CONFLICT, None) self._model.update_org_from_dict(camelback2snake(org_info)) current_app.logger.debug('>update_org ') return self
def update_contact(self, contact_info): """Update the existing contact for this org.""" current_app.logger.debug('>update_contact ') contact_link = ContactLinkModel.find_by_org_id(self._model.id) if contact_link is None or contact_link.contact is None: raise BusinessException(Error.DATA_NOT_FOUND, None) contact = contact_link.contact contact.update_from_dict(**camelback2snake(contact_info)) contact.commit() current_app.logger.debug('<update_contact ') return self
def update_contact(self, contact_info: dict): """Update a business contact for this entity.""" # find the contact link object for this entity contact_link = ContactLinkModel.find_by_entity_id(self._model.id) if contact_link is None or contact_link.contact is None: raise BusinessException(Error.DATA_NOT_FOUND, None) contact = contact_link.contact contact.update_from_dict(**camelback2snake(contact_info)) contact.commit() return self
def change_org_ype(self, org_info, action=None, bearer_token: str = None): """Update the passed organization with the new info. if Upgrade: //TODO .Missing RULES 1.do bcol verification 2.attach mailing 3.change the org with bcol org name If downgrade: //TODO .Missing RULES 1.remove contact 2.deactivate payment settings 3.add new payment settings for cc 4.change the org with user passed org name """ if self._model.access_type == AccessType.ANONYMOUS.value: raise BusinessException(Error.INVALID_INPUT, None) bcol_credential = org_info.pop('bcOnlineCredential', None) mailing_address = org_info.pop('mailingAddress', None) current_app.logger.debug('<update_org ', action) if action == ChangeType.DOWNGRADE.value: if org_info.get('typeCode') != OrgType.BASIC.value: raise BusinessException(Error.INVALID_INPUT, None) # if they have not changed the name , they can claim the name. Dont check duplicate..or else check duplicate if org_info.get('name') != self._model.name: Org.raise_error_if_duplicate_name(org_info['name']) payment_settings: AccountPaymentModel = AccountPaymentModel.find_active_by_org_id( account_id=self._model.id) payment_settings.is_active = False payment_settings.add_to_session() Org.add_payment_settings(self._model.id, None, None) Org.__delete_contact(self._model) if action == ChangeType.UPGRADE.value: if org_info.get( 'typeCode' ) != OrgType.PREMIUM.value or bcol_credential is None: raise BusinessException(Error.INVALID_INPUT, None) bcol_org_name = self.add_bcol_to_account(bcol_credential, bearer_token, org_info) org_info['name'] = bcol_org_name # If mailing address is provided, save it if mailing_address: self.add_contact_to_org(mailing_address, self._model) self._model.update_org_from_dict(camelback2snake(org_info), exclude=('status_code')) return self
def test_camel_back_to_snake_case(): """Assert that conversion from camelBack case to snake_case is functioning properly.""" camel_back_dictionary = { 'firstTestKey': 'foo', 'secondTestKey': 'bar', 'thirdTestKey': 'sandwich', 'testkey': 'icecream' } snake_case_dictionary = camelback2snake(camel_back_dictionary) assert snake_case_dictionary assert snake_case_dictionary['first_test_key'] == 'foo' assert snake_case_dictionary['second_test_key'] == 'bar' assert snake_case_dictionary['third_test_key'] == 'sandwich' assert snake_case_dictionary['testkey'] == 'icecream'
def create_org(org_info: dict, user_id): """Create a new organization.""" current_app.logger.debug('<create_org ') existing_similar__org = OrgModel.find_similar_org_by_name(org_info['name']) if existing_similar__org is not None: raise BusinessException(Error.DATA_CONFLICT, None) org = OrgModel.create_from_dict(camelback2snake(org_info)) org.save() current_app.logger.info(f'<created_org org_id:{org.id}') # create the membership record for this user membership = MembershipModel(org_id=org.id, user_id=user_id, membership_type_code='OWNER', membership_type_status=Status.ACTIVE.value) membership.save() return Org(org)
def add_contact(self, contact_info: dict): """Add a business contact to this entity.""" # check for existing contact (we only want one contact per user) contact_link = ContactLinkModel.find_by_entity_id(self._model.id) if contact_link is not None: raise BusinessException(Error.DATA_ALREADY_EXISTS, None) contact = ContactModel(**camelback2snake(contact_info)) contact.commit() contact_link = ContactLinkModel() contact_link.contact = contact contact_link.entity = self._model contact_link.commit() return self
def save_entity(entity_info: dict): """Create/update an entity from the given dictionary.""" if not entity_info: return None existing_entity = EntityModel.find_by_business_identifier(entity_info['businessIdentifier']) if existing_entity is None: entity_model = EntityModel.create_from_dict(entity_info) else: # TODO temporary allow update passcode, should replace with reset passcode endpoint. entity_info['passCode'] = passcode_hash(entity_info['passCode']) existing_entity.update_from_dict(**camelback2snake(entity_info)) entity_model = existing_entity entity_model.commit() entity = Entity(entity_model) return entity
def add_contact(self, contact_info): """Create a new contact for this org.""" # check for existing contact (only one contact per org for now) current_app.logger.debug('>add_contact ') contact_link = ContactLinkModel.find_by_org_id(self._model.id) if contact_link is not None: raise BusinessException(Error.DATA_ALREADY_EXISTS, None) contact = ContactModel(**camelback2snake(contact_info)) contact.commit() contact_link = ContactLinkModel() contact_link.contact = contact contact_link.org = self._model contact_link.commit() current_app.logger.debug('>add_contact ') return self
def create_org(org_info: dict, user_id, token_info: Dict = None): """Create a new organization.""" current_app.logger.debug('<create_org ') is_staff_admin = token_info and 'staff_admin' in token_info.get( 'realm_access').get('roles') if not is_staff_admin: # staff can create any number of orgs count = OrgModel.get_count_of_org_created_by_user_id(user_id) if count >= current_app.config.get('MAX_NUMBER_OF_ORGS'): raise BusinessException(Error.MAX_NUMBER_OF_ORGS_LIMIT, None) if org_info.get('accessType', None) == AccessType.ANONYMOUS.value: raise BusinessException(Error.USER_CANT_CREATE_ANONYMOUS_ORG, None) existing_similar__org = OrgModel.find_similar_org_by_name( org_info['name']) if existing_similar__org is not None: raise BusinessException(Error.DATA_CONFLICT, None) org = OrgModel.create_from_dict(camelback2snake(org_info)) if is_staff_admin: org.access_type = AccessType.ANONYMOUS.value org.billable = False else: org.access_type = AccessType.BCSC.value org.billable = True org.save() current_app.logger.info(f'<created_org org_id:{org.id}') # create the membership record for this user if its not created by staff and access_type is anonymous if not is_staff_admin and org_info.get( 'access_type') != AccessType.ANONYMOUS: membership = MembershipModel( org_id=org.id, user_id=user_id, membership_type_code='OWNER', membership_type_status=Status.ACTIVE.value) membership.save() # Add the user to account_holders group KeycloakService.join_account_holders_group() # TODO Remove later, create payment settings now with default values AccountPaymentModel.create_from_dict({'org_id': org.id}) return Org(org)
def update_contact(org_id, contact_info): """Update the existing contact for this org.""" current_app.logger.debug('>update_contact ') org = OrgModel.find_by_org_id(org_id) if org is None: raise BusinessException(Error.DATA_NOT_FOUND, None) # find the contact link for this org contact_link = ContactLinkModel.find_by_org_id(org_id) if contact_link is None or contact_link.contact is None: raise BusinessException(Error.DATA_NOT_FOUND, None) contact = contact_link.contact contact.update_from_dict(**camelback2snake(contact_info)) contact.save() current_app.logger.debug('<update_contact ') # return the updated contact return ContactService(contact)
def add_contact(token, contact_info: dict): """Add or update contact information for an existing user.""" user = UserModel.find_by_jwt_token(token) if user is None: raise BusinessException(Error.DATA_NOT_FOUND, None) # check for existing contact (we only want one contact per user) contact_link = ContactLinkModel.find_by_user_id(user.id) if contact_link is not None: raise BusinessException(Error.DATA_ALREADY_EXISTS, None) contact = ContactModel(**camelback2snake(contact_info)) contact.commit() contact_link = ContactLinkModel() contact_link.user = user contact_link.contact = contact contact_link.commit() return User(user)
def update_contact(token, contact_info: dict): """Update a contact for an existing user.""" user = UserModel.find_by_jwt_token(token) if user is None: raise BusinessException(Error.DATA_NOT_FOUND, None) # find the contact link for this user contact_link = ContactLinkModel.find_by_user_id(user.id) # now find the contact for the link if contact_link is None or contact_link.contact is None: raise BusinessException(Error.DATA_NOT_FOUND, None) contact = contact_link.contact contact.update_from_dict(**camelback2snake(contact_info)) contact = contact.flush() contact.commit() # return the user with the updated contact return User(user)
def update_contact(token, contact_info: dict): """Update a contact for an existing user.""" current_app.logger.debug('update_contact') user = UserModel.find_by_jwt_token(token) if user is None: raise BusinessException(Error.DATA_NOT_FOUND, None) # find the contact link for this user contact_link = ContactLinkModel.find_by_user_id(user.id) # now find the contact for the link if contact_link is None or contact_link.contact is None: raise BusinessException(Error.DATA_NOT_FOUND, None) contact = contact_link.contact contact.update_from_dict(**camelback2snake(contact_info)) contact = contact.save() # return the updated contact return ContactService(contact)
def add_contact(org_id, contact_info): """Create a new contact for this org.""" # check for existing contact (only one contact per org for now) current_app.logger.debug('>add_contact') org = OrgModel.find_by_org_id(org_id) if org is None: raise BusinessException(Error.DATA_NOT_FOUND, None) contact_link = ContactLinkModel.find_by_org_id(org_id) if contact_link is not None: raise BusinessException(Error.DATA_ALREADY_EXISTS, None) contact = ContactModel(**camelback2snake(contact_info)) contact = contact.flush() contact_link = ContactLinkModel() contact_link.contact = contact contact_link.org = org contact_link.save() current_app.logger.debug('<add_contact') return ContactService(contact)
def create_affidavit(affidavit_info: Dict): """Create a new affidavit record.""" current_app.logger.debug('<create_affidavit ') user = UserService.find_by_jwt_token() # If the user already have a pending affidavit, raise error existing_affidavit: AffidavitModel = AffidavitModel.find_pending_by_user_id( user_id=user.identifier) trigger_task_update = False if existing_affidavit is not None: # inactivate the current affidavit existing_affidavit.status_code = AffidavitStatus.INACTIVE.value existing_affidavit.flush() trigger_task_update = True contact = affidavit_info.pop('contact') affidavit_model = AffidavitModel( issuer=affidavit_info.get('issuer'), document_id=affidavit_info.get('documentId'), status_code=AffidavitStatus.PENDING.value, user_id=user.identifier) affidavit_model.add_to_session() # Save contact for the affidavit if contact: contact = ContactModel(**camelback2snake(contact)) contact.add_to_session() contact_link = ContactLinkModel() contact_link.affidavit = affidavit_model contact_link.contact = contact contact_link.add_to_session() affidavit_model.save() if trigger_task_update: Affidavit._modify_task(user) return Affidavit(affidavit_model)
class Org: # pylint: disable=too-many-public-methods """Manages all aspects of Org data. This service manages creating, updating, and retrieving Org data via the Org model. """ def __init__(self, model): """Return an Org Service.""" self._model = model @ServiceTracing.disable_tracing def as_dict(self): """Return the internal Org model as a dictionary. None fields are not included. """ org_schema = OrgSchema() obj = org_schema.dump(self._model, many=False) return obj @staticmethod def create_org(org_info: dict, user_id): """Create a new organization.""" current_app.logger.debug('<create_org ') # bcol is treated like an access type as well;so its outside the scheme mailing_address = org_info.pop('mailingAddress', None) payment_info = org_info.pop('paymentInfo', {}) product_subscriptions = org_info.pop('productSubscriptions', None) bcol_profile_flags = None response = Org._validate_and_raise_error(org_info) # If the account is created using BCOL credential, verify its valid bc online account bcol_details_response = response.get('bcol_response', None) if bcol_details_response is not None and ( bcol_details := bcol_details_response.json()) is not None: Org._map_response_to_org(bcol_details, org_info) bcol_profile_flags = bcol_details.get('profileFlags') access_type = response.get('access_type') # set premium for GOVM accounts..TODO remove if not needed this logic if access_type == AccessType.GOVM.value: org_info.update({'typeCode': OrgType.PREMIUM.value}) org = OrgModel.create_from_dict(camelback2snake(org_info)) org.access_type = access_type # Set the status based on access type # Check if the user is APPROVED else set the org status to PENDING if access_type == AccessType.GOVM.value: org.status_code = OrgStatus.PENDING_INVITE_ACCEPT.value # If mailing address is provided, save it if mailing_address: Org.add_contact_to_org(mailing_address, org) # create the membership record for this user if its not created by staff and access_type is anonymous Org.create_membership(access_type, org, user_id) if product_subscriptions is not None: subscription_data = {'subscriptions': product_subscriptions} ProductService.create_product_subscription( org.id, subscription_data=subscription_data, skip_auth=True) ProductService.create_subscription_from_bcol_profile( org.id, bcol_profile_flags) Org._create_payment_for_org(mailing_address, org, payment_info, True) # TODO do we have to check anything like this below? # if payment_account_status == PaymentAccountStatus.FAILED: # raise BusinessException(Error.ACCOUNT_CREATION_FAILED_IN_PAY, None) # Send an email to staff to remind review the pending account is_staff_review_needed = access_type in ( AccessType.EXTRA_PROVINCIAL.value, AccessType.REGULAR_BCEID.value, AccessType.GOVN.value ) and not AffidavitModel.find_approved_by_user_id(user_id=user_id) user = UserModel.find_by_jwt_token() if is_staff_review_needed: Org._create_staff_review_task(org, user) org.commit() current_app.logger.info(f'<created_org org_id:{org.id}') return Org(org)
has_status_changing = True self._create_gov_account_task(org_model) if product_subscriptions is not None: subscription_data = {'subscriptions': product_subscriptions} ProductService.create_product_subscription( self._model.id, subscription_data=subscription_data, skip_auth=True) # Update mailing address Or create new one if mailing_address: has_org_updates = True contacts = self._model.contacts if len(contacts) > 0: contact = self._model.contacts[0].contact contact.update_from_dict(**camelback2snake(mailing_address)) contact.save() else: Org.add_contact_to_org(mailing_address, self._model) # Check for other variables if org_info: # Once all org info are popped and variables remains, update the org. has_org_updates = True if has_org_updates: excluded = ( 'type_code', ) if has_status_changing else EXCLUDED_FIELDS self._model.update_org_from_dict(camelback2snake(org_info), exclude=excluded) if is_govm_account_creation: # send mail after the org is committed to DB
def test_camelback2snake(): """Assert that the options methos is added to the class and that the correct access controls are set.""" snake = camelback2snake(TEST_CAMEL_DATA) assert snake['login_source'] == TEST_SNAKE_DATA['login_source']