Esempio n. 1
0
    def send_invitation(invitation: InvitationModel, org_name, user, app_url):
        """Send the email notification."""
        current_app.logger.debug('<send_invitation')
        subject = '[BC Registries & Online Services] {} {} has invited you to join a team'.format(
            user['firstname'], user['lastname'])
        sender = CONFIG.MAIL_FROM_ID
        recipient = invitation.recipient_email
        token_confirm_url = '{}/validatetoken/{}'.format(
            app_url, invitation.token)
        template = ENV.get_template(
            'email_templates/business_invitation_email.html')

        sent_response = send_email(
            subject, sender, recipient,
            template.render(
                invitation=invitation,
                url=token_confirm_url,
                user=user,
                org_name=org_name,
                logo_url=f'{app_url}/{CONFIG.REGISTRIES_LOGO_IMAGE_NAME}'))
        if not sent_response:
            invitation.invitation_status_code = 'FAILED'
            invitation.save()
            current_app.logger.debug('>send_invitation failed')
            raise BusinessException(Error.FAILED_INVITATION, None)
        current_app.logger.debug('>send_invitation')
Esempio n. 2
0
    def get_invitations_for_org(org_id, status=None, token_info: Dict = None):
        """Get invitations for an org."""
        org_model = OrgModel.find_by_org_id(org_id)
        if not org_model:
            return None

        if status:
            status = InvitationStatus[status]

        # If staff return full list
        if 'staff' in token_info.get('realm_access').get('roles'):
            return InvitationModel.find_pending_invitations_by_org(org_id)

        current_user: UserService = UserService.find_by_jwt_token(token_info)
        current_user_membership: MembershipModel = \
            MembershipModel.find_membership_by_user_and_org(user_id=current_user.identifier, org_id=org_id)

        # If no active membership return empty array
        if current_user_membership is None or \
                current_user_membership.status != Status.ACTIVE.value:
            return []

        # Ensure either ADMIN or COORDINATOR
        if current_user_membership.membership_type_code == USER:
            return []

        return InvitationModel.find_invitations_by_org(org_id=org_id, status=status)
Esempio n. 3
0
    def send_invitation(invitation: InvitationModel, org_name, user, app_url):
        """Send the email notification."""
        current_app.logger.debug('<send_invitation')
        mail_configs = Invitation.get_invitation_configs(
            invitation.type, org_name)
        subject = mail_configs.get('subject').format(user['firstname'],
                                                     user['lastname'])
        sender = CONFIG.MAIL_FROM_ID
        recipient = invitation.recipient_email
        token_confirm_url = '{}/{}/{}'.format(
            app_url, mail_configs.get('token_confirm_path'), invitation.token)
        template = ENV.get_template(
            f"email_templates/{mail_configs.get('template_name')}.html")

        sent_response = send_email(
            subject, sender, recipient,
            template.render(
                invitation=invitation,
                url=token_confirm_url,
                user=user,
                org_name=org_name,
                logo_url=f'{app_url}/{CONFIG.REGISTRIES_LOGO_IMAGE_NAME}'))
        if not sent_response:
            invitation.invitation_status_code = 'FAILED'
            invitation.save()
            current_app.logger.debug('>send_invitation failed')
            raise BusinessException(Error.FAILED_INVITATION, None)
        current_app.logger.debug('>send_invitation')
Esempio n. 4
0
    def get_invitations_for_org(org_id, status=None, **kwargs):
        """Get invitations for an org."""
        user_from_context: UserContext = kwargs['user_context']
        org_model = OrgModel.find_by_org_id(org_id)
        if not org_model:
            return None

        if status:
            status = InvitationStatus[status]

        # If staff return full list
        if user_from_context.is_staff():
            return InvitationModel.find_pending_invitations_by_org(org_id)

        current_user: UserService = UserService.find_by_jwt_token()
        current_user_membership: MembershipModel = \
            MembershipModel.find_membership_by_user_and_org(user_id=current_user.identifier, org_id=org_id)

        # If no active membership return empty array
        if current_user_membership is None or \
                current_user_membership.status != Status.ACTIVE.value:
            return []

        # Ensure either ADMIN or COORDINATOR
        if current_user_membership.membership_type_code == USER:
            return []

        return InvitationModel.find_invitations_by_org(org_id=org_id,
                                                       status=status)
Esempio n. 5
0
 def get_invitations_by_org_id(org_id, status, token_info: Dict = None):
     """Get invitations for an org."""
     check_auth(token_info, org_id=org_id, one_of_roles=(OWNER, ADMIN))
     collection = []
     if status == 'ALL':
         invitations = InvitationModel.find_invitations_by_org(org_id)
     else:
         invitations = InvitationModel.find_pending_invitations_by_org(
             org_id)
     for invitation in invitations:
         collection.append(Invitation(invitation).as_dict())
     return collection
Esempio n. 6
0
    def create_invitation(invitation_info: Dict, user, token_info: Dict, invitation_origin):
        """Create a new invitation."""
        # Ensure that the current user is ADMIN or COORDINATOR on each org being invited to
        context_path = CONFIG.AUTH_WEB_TOKEN_CONFIRM_PATH
        org_id = invitation_info['membership'][0]['orgId']
        # get the org and check the access_type
        org = OrgModel.find_by_org_id(org_id)
        if not org:
            raise BusinessException(Error.DATA_NOT_FOUND, None)

        check_auth(token_info, org_id=org_id, one_of_roles=(ADMIN, COORDINATOR, STAFF))

        org_name = org.name
        invitation_type = InvitationType.DIRECTOR_SEARCH.value if org.access_type == AccessType.ANONYMOUS.value \
            else InvitationType.STANDARD.value
        if org.access_type == AccessType.ANONYMOUS.value:  # anonymous account never get bceid or bcsc choices
            mandatory_login_source = LoginSource.BCROS.value
        else:
            default_login_option_based_on_accesstype = LoginSource.BCSC.value if \
                org.access_type == AccessType.REGULAR.value else LoginSource.BCEID.value
            role = invitation_info['membership'][0]['membershipType']
            account_login_options = AccountLoginOptionsModel.find_active_by_org_id(org.id)
            mandatory_login_source = LoginSource.BCSC.value if \
                role == ADMIN else getattr(account_login_options, 'login_source',
                                           default_login_option_based_on_accesstype)

        invitation = InvitationModel.create_from_dict(invitation_info, user.identifier, invitation_type)
        confirmation_token = Invitation.generate_confirmation_token(invitation.id, invitation.type)
        invitation.token = confirmation_token
        invitation.login_source = mandatory_login_source
        invitation.save()
        Invitation.send_invitation(invitation, org_name, user.as_dict(),
                                   '{}/{}'.format(invitation_origin, context_path), mandatory_login_source)
        return Invitation(invitation)
Esempio n. 7
0
    def create_invitation(invitation_info: Dict, user, token_info: Dict,
                          invitation_origin):
        """Create a new invitation."""
        # Ensure that the current user is OWNER or ADMIN on each org being invited to
        context_path = CONFIG.AUTH_WEB_TOKEN_CONFIRM_PATH
        for membership in invitation_info['membership']:
            org_id = membership['orgId']
            if invitation_info.get(
                    'type') == InvitationType.DIRECTOR_SEARCH.value:
                check_auth(token_info, org_id=org_id, equals_role=STAFF_ADMIN)
            else:
                check_auth(token_info,
                           org_id=org_id,
                           one_of_roles=(OWNER, ADMIN))
        # TODO doesnt work when invited to multiple teams.. Re-work the logic when multiple teams introduced
        org_name = OrgModel.find_by_org_id(
            invitation_info['membership'][0]['orgId']).name

        invitation = InvitationModel.create_from_dict(invitation_info,
                                                      user.identifier)
        confirmation_token = Invitation.generate_confirmation_token(
            invitation.id, invitation.type)
        invitation.token = confirmation_token
        invitation.save()
        Invitation.send_invitation(
            invitation, org_name, user.as_dict(),
            '{}/{}'.format(invitation_origin, context_path))
        return Invitation(invitation)
Esempio n. 8
0
    def create_invitation(invitation_info: Dict, user, token_info: Dict,
                          invitation_origin):
        """Create a new invitation."""
        # Ensure that the current user is OWNER or ADMIN on each org being invited to
        context_path = CONFIG.AUTH_WEB_TOKEN_CONFIRM_PATH
        org_id = invitation_info['membership'][0]['orgId']
        # get the org and check the access_type
        org = OrgModel.find_by_org_id(org_id)
        if not org:
            raise BusinessException(Error.DATA_NOT_FOUND, None)
        if org.access_type == AccessType.ANONYMOUS.value:
            check_auth(token_info, org_id=org_id, equals_role=STAFF_ADMIN)
        elif org.access_type == AccessType.BCSC.value:
            check_auth(token_info, org_id=org_id, one_of_roles=(OWNER, ADMIN))

        org_name = org.name
        invitation_type = InvitationType.DIRECTOR_SEARCH.value if org.access_type == AccessType.ANONYMOUS.value \
            else InvitationType.STANDARD.value

        invitation = InvitationModel.create_from_dict(invitation_info,
                                                      user.identifier,
                                                      invitation_type)
        confirmation_token = Invitation.generate_confirmation_token(
            invitation.id, invitation.type)
        invitation.token = confirmation_token
        invitation.save()
        Invitation.send_invitation(
            invitation, org_name, user.as_dict(),
            '{}/{}'.format(invitation_origin, context_path))
        return Invitation(invitation)
Esempio n. 9
0
    def validate_token(token):
        """Check whether the passed token is valid."""
        serializer = URLSafeTimedSerializer(CONFIG.EMAIL_TOKEN_SECRET_KEY)
        token_valid_for = int(
            CONFIG.TOKEN_EXPIRY_PERIOD
        ) * 3600 * 24 if CONFIG.TOKEN_EXPIRY_PERIOD else 3600 * 24 * 7
        try:
            invitation_id = serializer.loads(
                token,
                salt=CONFIG.EMAIL_SECURITY_PASSWORD_SALT,
                max_age=token_valid_for).get('id')
        except:  # noqa: E722
            raise BusinessException(Error.EXPIRED_INVITATION, None)

        invitation: InvitationModel = InvitationModel.find_invitation_by_id(
            invitation_id)

        if invitation is None:
            raise BusinessException(Error.DATA_NOT_FOUND, None)
        if invitation.invitation_status_code == 'ACCEPTED':
            raise BusinessException(Error.ACTIONED_INVITATION, None)
        if invitation.invitation_status_code == 'EXPIRED':
            raise BusinessException(Error.EXPIRED_INVITATION, None)

        return Invitation(invitation)
Esempio n. 10
0
    def notify_admin(user, invitation_id, membership_id, invitation_origin):
        """Admins should be notified if user has responded to invitation."""
        current_app.logger.debug('<notify_admin')
        admin_list = UserService.get_admins_for_membership(membership_id)
        invitation: InvitationModel = InvitationModel.find_invitation_by_id(
            invitation_id)
        context_path = CONFIG.AUTH_WEB_TOKEN_CONFIRM_PATH

        # Don't send email in case no admin exist in the org. (staff sent invitation)
        if len(admin_list) >= 1:
            admin_emails = ','.join([
                str(x.contacts[0].contact.email) for x in admin_list
                if x.contacts
            ])
        else:
            # No admin, find Sender email to notify sender (staff)
            admin_emails = invitation.sender.email

        if admin_emails != '':
            Invitation.send_admin_notification(
                user.as_dict(), '{}/{}'.format(invitation_origin,
                                               context_path), admin_emails,
                invitation.membership[0].org.name,
                invitation.membership[0].org.id)
            current_app.logger.debug('>notify_admin')

        return Invitation(invitation)
Esempio n. 11
0
    def accept_invitation(invitation_id, user: UserService, origin, add_membership: bool = True,
                          token_info: Dict = None):
        """Add user, role and org from the invitation to membership."""
        current_app.logger.debug('>accept_invitation')
        invitation: InvitationModel = InvitationModel.find_invitation_by_id(invitation_id)

        if invitation is None:
            raise BusinessException(Error.DATA_NOT_FOUND, None)
        if invitation.invitation_status_code == 'ACCEPTED':
            raise BusinessException(Error.ACTIONED_INVITATION, None)
        if invitation.invitation_status_code == 'EXPIRED':
            raise BusinessException(Error.EXPIRED_INVITATION, None)

        if getattr(token_info, 'loginSource', None) is not None:  # bcros comes with out token
            login_source = token_info.get('loginSource', None)
            if invitation.login_source != login_source:
                raise BusinessException(Error.INVALID_USER_CREDENTIALS, None)

        if add_membership:
            for membership in invitation.membership:
                membership_model = MembershipModel()
                membership_model.org_id = membership.org_id
                membership_model.user_id = user.identifier
                membership_model.membership_type = membership.membership_type

                # check to ensure an invitation for this user/org has not already been processed
                existing_membership = MembershipService \
                    .get_membership_for_org_and_user(org_id=membership_model.org_id, user_id=membership_model.user_id)

                if existing_membership:
                    raise BusinessException(Error.DATA_ALREADY_EXISTS, None)
                org_model: OrgModel = OrgModel.find_by_org_id(membership.org_id)

                # GOVM users gets direct approval since they are IDIR users.
                membership_model.status = Invitation._get_status_based_on_org(org_model)
                membership_model.save()
                try:
                    Invitation.notify_admin(user, invitation_id, membership_model.id, origin)
                except BusinessException as exception:
                    current_app.logger.error('<send_notification_to_admin failed', exception.message)
        invitation.accepted_date = datetime.now()
        invitation.invitation_status = InvitationStatusModel.get_status_by_code('ACCEPTED')
        invitation.save()

        # Call keycloak to add the user to the group.
        if user:
            group_name: str = KeycloakService.join_users_group(token_info)
            KeycloakService.join_account_holders_group(user.keycloak_guid)

            if group_name == GROUP_GOV_ACCOUNT_USERS:
                # TODO Remove this if gov account users needs Terms of Use.
                tos_document = DocumentsModel.fetch_latest_document_by_type(DocumentType.TERMS_OF_USE.value)
                user.update_terms_of_use(token_info, True, tos_document.version_id)
                # Add contact to the user.
                user.add_contact(token_info, dict(email=token_info.get('email', None)))

        current_app.logger.debug('<accept_invitation')
        return Invitation(invitation)
Esempio n. 12
0
def test_find_invitation_by_id(session):  # pylint:disable=unused-argument
    """Assert that an Invitation can retrieved by its id."""
    invitation = factory_invitation_model(session=session, status='PENDING')
    session.add(invitation)
    session.commit()

    retrieved_invitation = InvitationModel.find_invitation_by_id(invitation.id)
    assert retrieved_invitation
    assert retrieved_invitation.id == invitation.id
Esempio n. 13
0
def test_invitations_by_status(session):  # pylint:disable=unused-argument
    """Assert that an Invitation can retrieved by the user id."""
    invitation = factory_invitation_model(session=session, status='PENDING')
    session.add(invitation)
    session.commit()

    retrieved_invitation = InvitationModel.find_invitations_by_status(
        invitation.sender_id, 'FAILED')
    assert len(retrieved_invitation) == 0
Esempio n. 14
0
 def delete_invitation(invitation_id, token_info: Dict = None):
     """Delete the specified invitation."""
     # Ensure that the current user is ADMIN or COORDINATOR for each org in the invitation
     invitation = InvitationModel.find_invitation_by_id(invitation_id)
     if invitation is None:
         raise BusinessException(Error.DATA_NOT_FOUND, None)
     for membership in invitation.membership:
         org_id = membership.org_id
         check_auth(token_info, org_id=org_id, one_of_roles=(ADMIN, COORDINATOR, STAFF))
     invitation.delete()
Esempio n. 15
0
    def send_invitation(
            invitation: InvitationModel,
            org_name,
            org_id,
            user,  # pylint: disable=too-many-arguments
            app_url,
            login_source,
            org_status=None,
            query_params: Dict[str, any] = None):
        """Send the email notification."""
        current_app.logger.debug('<send_invitation')
        mail_configs = Invitation._get_invitation_configs(
            org_name, login_source, org_status)
        recipient = invitation.recipient_email
        token_confirm_url = f"{app_url}/{mail_configs.get('token_confirm_path')}/{invitation.token}"
        if query_params:
            token_confirm_url += f'?{urlencode(query_params)}'
        role = invitation.membership[0].membership_type.display_name
        data = {
            'accountId': org_id,
            'emailAddresses': recipient,
            'contextUrl': token_confirm_url,
            'userFirstName': user.get('firstname', None),
            'userLastName': user.get('lastname', None),
            'orgName': org_name,
            'role': role
        }

        try:
            publish_to_mailer(
                notification_type=mail_configs.get('notification_type'),
                org_id=org_id,
                data=data)
        except BusinessException as exception:
            invitation.invitation_status_code = 'FAILED'
            invitation.save()
            current_app.logger.debug('>send_invitation failed')
            current_app.logger.debug(exception)
            raise BusinessException(Error.FAILED_INVITATION,
                                    None) from exception

        current_app.logger.debug('>send_invitation')
Esempio n. 16
0
def test_find_pending_invitations_by_org(session):  # pylint:disable=unused-argument
    """Assert that an Invitation can retrieved by the org id."""
    invitation = factory_invitation_model(session=session, status='PENDING')
    session.add(invitation)
    session.commit()

    retrieved_invitation = InvitationModel.find_pending_invitations_by_org(
        invitation.membership[0].org_id)
    assert len(retrieved_invitation) == 1
    assert retrieved_invitation[
        0].recipient_email == invitation.recipient_email
Esempio n. 17
0
def test_create_from_dict_no_schema(session):  # pylint:disable=unused-argument
    """Assert that an Entity can not be created without schema."""
    user = User(username='******',
                keycloak_guid='1b20db59-19a0-4727-affe-c6f64309fd04')

    session.add(user)
    session.commit()

    result_invitation = InvitationModel.create_from_dict(
        None, user.id, 'STANDARD')

    assert result_invitation is None
Esempio n. 18
0
def test_find_invitations_by_user(session):  # pylint:disable=unused-argument
    """Assert that an Invitation can retrieved by the user id."""
    invitation = factory_invitation_model(session=session, status='PENDING')
    session.add(invitation)
    session.commit()

    retrieved_invitation = InvitationModel.find_invitations_by_user(
        invitation.sender_id)
    assert len(retrieved_invitation) > 0
    assert retrieved_invitation[
        0].recipient_email == invitation.recipient_email
    assert retrieved_invitation[0].token == invitation.token
Esempio n. 19
0
 def notify_admin(user, invitation_id, membership_id, invitation_origin):
     """Admins should be notified if user has responded to invitation."""
     current_app.logger.debug('<notify_admin')
     admin_list = UserService.get_admins_for_membership(membership_id)
     invitation: InvitationModel = InvitationModel.find_invitation_by_id(invitation_id)
     context_path = CONFIG.AUTH_WEB_TOKEN_CONFIRM_PATH
     admin_emails = ','.join([str(x.contacts[0].contact.email) for x in admin_list if x.contacts])
     Invitation.send_admin_notification(user.as_dict(),
                                        '{}/{}'.format(invitation_origin, context_path),
                                        admin_emails, invitation.membership[0].org.name)
     current_app.logger.debug('>notify_admin')
     return Invitation(invitation)
Esempio n. 20
0
    def accept_invitation(invitation_id,
                          user,
                          origin,
                          add_membership: bool = True):
        """Add user, role and org from the invitation to membership."""
        current_app.logger.debug('>accept_invitation')
        invitation: InvitationModel = InvitationModel.find_invitation_by_id(
            invitation_id)

        if invitation is None:
            raise BusinessException(Error.DATA_NOT_FOUND, None)
        if invitation.invitation_status_code == 'ACCEPTED':
            raise BusinessException(Error.ACTIONED_INVITATION, None)
        if invitation.invitation_status_code == 'EXPIRED':
            raise BusinessException(Error.EXPIRED_INVITATION, None)

        if add_membership:
            for membership in invitation.membership:
                membership_model = MembershipModel()
                membership_model.org_id = membership.org_id
                membership_model.user_id = user.identifier
                membership_model.membership_type = membership.membership_type

                # check to ensure an invitation for this user/org has not already been processed
                existing_membership = MembershipService \
                    .get_membership_for_org_and_user(org_id=membership_model.org_id, user_id=membership_model.user_id)

                if existing_membership:
                    raise BusinessException(Error.DATA_ALREADY_EXISTS, None)

                # user needs to get approval
                is_auto_approval = OrgSettingsModel.is_admin_auto_approved_invitees(
                    membership.org_id)
                if is_auto_approval:
                    membership_model.status = Status.ACTIVE.value
                else:
                    membership_model.status = Status.PENDING_APPROVAL.value
                membership_model.save()
                if not is_auto_approval:
                    try:
                        Invitation.notify_admin(user, invitation_id,
                                                membership_model.id, origin)
                    except BusinessException as exception:
                        current_app.logger.error(
                            '<send_notification_to_admin failed',
                            exception.message)
        invitation.accepted_date = datetime.now()
        invitation.invitation_status = InvitationStatusModel.get_status_by_code(
            'ACCEPTED')
        invitation.save()
        current_app.logger.debug('<accept_invitation')
        return Invitation(invitation)
Esempio n. 21
0
    def accept_invitation(invitation_id,
                          user,
                          origin,
                          add_membership: bool = True,
                          token_info: Dict = None):
        """Add user, role and org from the invitation to membership."""
        current_app.logger.debug('>accept_invitation')
        invitation: InvitationModel = InvitationModel.find_invitation_by_id(
            invitation_id)

        if invitation is None:
            raise BusinessException(Error.DATA_NOT_FOUND, None)
        if invitation.invitation_status_code == 'ACCEPTED':
            raise BusinessException(Error.ACTIONED_INVITATION, None)
        if invitation.invitation_status_code == 'EXPIRED':
            raise BusinessException(Error.EXPIRED_INVITATION, None)

        if getattr(token_info, 'loginSource',
                   None) is not None:  # bcros comes with out token
            login_source = token_info.get('loginSource', None)
            if invitation.login_source != login_source:
                raise BusinessException(Error.INVALID_USER_CREDENTIALS, None)

        if add_membership:
            for membership in invitation.membership:
                membership_model = MembershipModel()
                membership_model.org_id = membership.org_id
                membership_model.user_id = user.identifier
                membership_model.membership_type = membership.membership_type

                # check to ensure an invitation for this user/org has not already been processed
                existing_membership = MembershipService \
                    .get_membership_for_org_and_user(org_id=membership_model.org_id, user_id=membership_model.user_id)

                if existing_membership:
                    raise BusinessException(Error.DATA_ALREADY_EXISTS, None)

                membership_model.status = Status.PENDING_APPROVAL.value
                membership_model.save()
                try:
                    Invitation.notify_admin(user, invitation_id,
                                            membership_model.id, origin)
                except BusinessException as exception:
                    current_app.logger.error(
                        '<send_notification_to_admin failed',
                        exception.message)
        invitation.accepted_date = datetime.now()
        invitation.invitation_status = InvitationStatusModel.get_status_by_code(
            'ACCEPTED')
        invitation.save()
        current_app.logger.debug('<accept_invitation')
        return Invitation(invitation)
Esempio n. 22
0
def test_find_invitations_by_org(session):  # pylint:disable=unused-argument
    """Assert that Invitations for a specified org can be retrieved."""
    invitation = factory_invitation_model(session=session, status='PENDING')
    session.add(invitation)
    session.commit()

    found_invitations = InvitationModel.find_invitations_by_org(
        invitation.membership[0].org_id)
    assert found_invitations
    assert len(found_invitations) == 1
    assert found_invitations[0].membership[0].org_id == invitation.membership[
        0].org_id
    assert invitation.invitation_status_code == 'PENDING'
Esempio n. 23
0
    def find_invitation_by_id(invitation_id, token_info: Dict = None):
        """Find an existing invitation with the provided id."""
        if invitation_id is None:
            return None

        invitation = InvitationModel.find_invitation_by_id(invitation_id)
        if not invitation:
            return None

        # Ensure that the current user is an ADMIN or COORDINATOR on each org in the invite being retrieved
        for membership in invitation.membership:
            org_id = membership.org_id
            check_auth(token_info, org_id=org_id, one_of_roles=(ADMIN, COORDINATOR, STAFF))

        return Invitation(invitation)
Esempio n. 24
0
def test_send_invitation_exception(session, notify_mock, keycloak_mock):  # pylint:disable=unused-argument
    """Send an existing invitation with exception."""
    user = factory_user_model(TestUserInfo.user_test)
    user_dictionary = User(user).as_dict()
    org = OrgService.create_org(TestOrgInfo.org1, user_id=user.id)
    org_dictionary = org.as_dict()

    invitation_info = factory_invitation(org_dictionary['id'])

    invitation = InvitationModel.create_from_dict(invitation_info, user.id, 'STANDARD')

    with patch.object(notification, 'send_email', return_value=False):
        with pytest.raises(BusinessException) as exception:
            InvitationService.send_invitation(invitation, org_dictionary['name'], user_dictionary, '', '')

    assert exception.value.code == Error.FAILED_INVITATION.name
Esempio n. 25
0
def factory_invitation_model(session, status, sent_date=datetime.now()):
    """Produce a templated invitation model."""
    user = User(username='******',
                roles='{edit, uma_authorization, staff}',
                keycloak_guid='1b20db59-19a0-4727-affe-c6f64309fd04')

    session.add(user)
    session.commit()

    org_type = OrgTypeModel(code='TEST', desc='Test')
    session.add(org_type)
    session.commit()

    org_status = OrgStatusModel(code='TEST', desc='Test')
    session.add(org_status)
    session.commit()

    preferred_payment = PaymentTypeModel(code='TEST', desc='Test')
    session.add(preferred_payment)
    session.commit()

    org = OrgModel()
    org.name = 'Test Org'
    org.org_type = org_type
    org.org_status = org_status
    org.preferred_payment = preferred_payment
    org.save()

    invitation = InvitationModel()
    invitation.recipient_email = '*****@*****.**'
    invitation.sender = user
    invitation.sent_date = sent_date
    invitation.invitation_status_code = status
    invitation.token = 'ABCD'

    invitation_membership = InvitationMembershipModel()
    invitation_membership.org_id = org.id
    invitation_membership.membership_type_code = 'USER'
    invitation.membership.append(invitation_membership)

    invitation.save()
    return invitation
Esempio n. 26
0
    def create_invitation(invitation_info: Dict, user,  # pylint: disable=too-many-locals
                          token_info: Dict, invitation_origin):
        """Create a new invitation."""
        # Ensure that the current user is ADMIN or COORDINATOR on each org being invited to
        context_path = CONFIG.AUTH_WEB_TOKEN_CONFIRM_PATH
        org_id = invitation_info['membership'][0]['orgId']
        # get the org and check the access_type
        org: OrgModel = OrgModel.find_by_org_id(org_id)
        if not org:
            raise BusinessException(Error.DATA_NOT_FOUND, None)

        check_auth(token_info, org_id=org_id, one_of_roles=(ADMIN, COORDINATOR, STAFF))

        org_name = org.name
        invitation_type = Invitation._get_inv_type(org)

        if org.access_type == AccessType.ANONYMOUS.value:  # anonymous account never get bceid or bcsc choices
            mandatory_login_source = LoginSource.BCROS.value
        elif org.access_type == AccessType.GOVM.value:
            mandatory_login_source = LoginSource.STAFF.value
        else:
            default_login_option_based_on_accesstype = LoginSource.BCSC.value if \
                org.access_type == AccessType.REGULAR.value else LoginSource.BCEID.value
            role = invitation_info['membership'][0]['membershipType']
            account_login_options = AccountLoginOptionsModel.find_active_by_org_id(org.id)
            mandatory_login_source = LoginSource.BCSC.value if \
                role == ADMIN else getattr(account_login_options, 'login_source',
                                           default_login_option_based_on_accesstype)

        invitation = InvitationModel.create_from_dict(invitation_info, user.identifier, invitation_type)
        confirmation_token = Invitation.generate_confirmation_token(invitation.id, invitation.type)
        invitation.token = confirmation_token
        invitation.login_source = mandatory_login_source
        invitation.save()
        Invitation.send_invitation(invitation, org_name, user.as_dict(),
                                   '{}/{}'.format(invitation_origin, context_path), mandatory_login_source,
                                   org_status=org.status_code)
        # notify admin if staff adds team members
        is_staff_access = token_info and 'staff' in token_info.get('realm_access', {}).get('roles', None)
        if is_staff_access and invitation_type == InvitationType.STANDARD.value:
            publish_to_mailer('teamMemberInvited', org_id)
        return Invitation(invitation)
Esempio n. 27
0
    def accept_invitation(invitation_id, user, origin):
        """Add user, role and org from the invitation to membership."""
        current_app.logger.debug('>accept_invitation')
        invitation: InvitationModel = InvitationModel.find_invitation_by_id(
            invitation_id)

        if invitation is None:
            raise BusinessException(Error.DATA_NOT_FOUND, None)
        if invitation.invitation_status_code == 'ACCEPTED':
            raise BusinessException(Error.ACTIONED_INVITATION, None)
        if invitation.invitation_status_code == 'EXPIRED':
            raise BusinessException(Error.EXPIRED_INVITATION, None)
        # TODO : isnt this only one?remove for loop
        for membership in invitation.membership:
            membership_model = MembershipModel()
            membership_model.org_id = membership.org_id
            membership_model.user_id = user.identifier
            membership_model.membership_type = membership.membership_type
            # user needs to get approval
            is_auto_approval = OrgSettingsModel.is_admin_auto_approved_invitees(
                membership.org_id)
            if is_auto_approval:
                membership_model.status = Status.ACTIVE.value
            else:
                membership_model.status = Status.PENDING_APPROVAL.value
            membership_model.save()
            if not is_auto_approval:
                try:
                    Invitation.notify_admin(user, invitation_id,
                                            membership_model.id, origin)
                except BusinessException as exception:
                    current_app.logger.error(
                        '<send_notification_to_admin failed',
                        exception.message)
        invitation.accepted_date = datetime.now()
        invitation.invitation_status = InvitationStatusModel.get_status_by_code(
            'ACCEPTED')
        invitation.save()
        current_app.logger.debug('<accept_invitation')
        return Invitation(invitation)
Esempio n. 28
0
    def accept_invitation(invitation_id,
                          user: UserService,
                          origin,
                          add_membership: bool = True,
                          **kwargs):
        """Add user, role and org from the invitation to membership."""
        current_app.logger.debug('>accept_invitation')
        user_from_context: UserContext = kwargs['user_context']
        invitation: InvitationModel = InvitationModel.find_invitation_by_id(
            invitation_id)

        if invitation is None:
            raise BusinessException(Error.DATA_NOT_FOUND, None)
        if invitation.invitation_status_code == 'ACCEPTED':
            raise BusinessException(Error.ACTIONED_INVITATION, None)
        if invitation.invitation_status_code == 'EXPIRED':
            raise BusinessException(Error.EXPIRED_INVITATION, None)

        if (login_source := user_from_context.login_source
            ) is not None:  # bcros comes with out token
            if invitation.login_source != login_source:
                raise BusinessException(Error.INVALID_USER_CREDENTIALS, None)
Esempio n. 29
0
def test_create_from_dict(session):  # pylint:disable=unused-argument
    """Assert that an Entity can be created from schema."""
    user = User(username='******',
                roles='{edit, uma_authorization, staff}',
                keycloak_guid='1b20db59-19a0-4727-affe-c6f64309fd04')

    session.add(user)
    session.commit()

    org_type = OrgTypeModel(code='TEST', desc='Test')
    session.add(org_type)
    session.commit()

    org_status = OrgStatusModel(code='TEST', desc='Test')
    session.add(org_status)
    session.commit()

    preferred_payment = PaymentTypeModel(code='TEST', desc='Test')
    session.add(preferred_payment)
    session.commit()

    org = OrgModel()
    org.name = 'Test Org'
    org.org_type = org_type
    org.org_status = org_status
    org.preferred_payment = preferred_payment
    org.save()

    invitation_info = {
        'recipientEmail': '*****@*****.**',
        'membership': [{
            'membershipType': 'USER',
            'orgId': org.id
        }]
    }
    result_invitation = InvitationModel.create_from_dict(
        invitation_info, user.id, 'STANDARD')

    assert result_invitation.id is not None
Esempio n. 30
0
    def create_invitation(invitation_info: Dict, user, invitation_origin,
                          **kwargs):  # pylint: disable=too-many-locals
        """Create a new invitation."""
        user_from_context: UserContext = kwargs['user_context']
        # Ensure that the current user is ADMIN or COORDINATOR on each org being invited to
        context_path = CONFIG.AUTH_WEB_TOKEN_CONFIRM_PATH
        org_id = invitation_info['membership'][0]['orgId']
        # get the org and check the access_type
        org: OrgModel = OrgModel.find_by_org_id(org_id)
        if not org:
            raise BusinessException(Error.DATA_NOT_FOUND, None)

        check_auth(org_id=org_id, one_of_roles=(ADMIN, COORDINATOR, STAFF))

        org_name = org.name
        invitation_type = Invitation._get_inv_type(org)

        if org.access_type == AccessType.ANONYMOUS.value:  # anonymous account never get bceid or bcsc choices
            mandatory_login_source = LoginSource.BCROS.value
        elif org.access_type == AccessType.GOVM.value:
            mandatory_login_source = LoginSource.STAFF.value
        else:
            default_login_option_based_on_accesstype = LoginSource.BCSC.value if \
                org.access_type == AccessType.REGULAR.value else LoginSource.BCEID.value
            role = invitation_info['membership'][0]['membershipType']
            account_login_options = AccountLoginOptionsModel.find_active_by_org_id(
                org.id)
            mandatory_login_source = LoginSource.BCSC.value if \
                role == ADMIN else getattr(account_login_options, 'login_source',
                                           default_login_option_based_on_accesstype)

        invitation = InvitationModel.create_from_dict(invitation_info,
                                                      user.identifier,
                                                      invitation_type)
        confirmation_token = Invitation.generate_confirmation_token(
            invitation.id, invitation.type)
        invitation.token = confirmation_token
        invitation.login_source = mandatory_login_source
        invitation.save()
        Invitation.send_invitation(invitation,
                                   org_name,
                                   org.id,
                                   user.as_dict(),
                                   '{}/{}'.format(invitation_origin,
                                                  context_path),
                                   mandatory_login_source,
                                   org_status=org.status_code)
        # notify admin if staff adds team members
        if user_from_context.is_staff(
        ) and invitation_type == InvitationType.STANDARD.value:
            try:
                current_app.logger.debug(
                    '<send_team_member_invitation_notification')
                publish_to_mailer(notification_type='teamMemberInvited',
                                  org_id=org_id)
                current_app.logger.debug(
                    'send_team_member_invitation_notification>')
            except Exception as e:  # noqa=B901
                current_app.logger.error(
                    '<send_team_member_invitation_notification failed')
                raise BusinessException(Error.FAILED_NOTIFICATION, None) from e
        return Invitation(invitation)