Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

18522, 18525 - updates to REQUEST affiliation #2642

Merged
merged 5 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion auth-api/src/auth_api/models/org.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

Basic users will have an internal Org that is not created explicitly, but implicitly upon User account creation.
"""
from typing import List
from flask import current_app
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer, String, and_, cast, event, func, text
from sqlalchemy.orm import contains_eager, relationship
Expand Down Expand Up @@ -158,12 +159,19 @@ def search_org(cls, search: OrgSearch, environment: str):
return pagination.items, pagination.total

@classmethod
def search_orgs_by_business_identifier(cls, business_identifier, pagination_info: PaginationInfo, environment):
def search_orgs_by_business_identifier(cls,
Copy link
Collaborator

@seeker25 seeker25 Nov 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alotta params, would have combined pagination_info, excluded_org_types together - they both affect the query

But this should be ok, environment we'll eventually gun anyways

business_identifier,
pagination_info: PaginationInfo,
environment,
excluded_org_types: List[str] = None
):
"""Find all orgs affiliated with provided business identifier."""
query = db.session.query(Org)

query = cls._search_for_statuses(query, [])
query = cls._search_by_business_identifier(query, business_identifier, environment)
if excluded_org_types:
query = query.filter(Org.type_code.notin_(excluded_org_types))

pagination = query.order_by(Org.name.desc()) \
.paginate(per_page=pagination_info.limit, page=pagination_info.page)
Expand Down
13 changes: 8 additions & 5 deletions auth-api/src/auth_api/resources/v1/org.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
from auth_api.services.authorization import Authorization as AuthorizationService
from auth_api.tracer import Tracer
from auth_api.utils.endpoints_enums import EndpointEnum
from auth_api.utils.enums import AccessType, NotificationType, PatchActions, Status
from auth_api.utils.enums import AccessType, NotificationType, OrgType, PatchActions, Status
from auth_api.utils.role_validator import validate_roles
from auth_api.utils.roles import ALL_ALLOWED_ROLES, CLIENT_ADMIN_ROLES, STAFF, USER, Role # noqa: I005
from auth_api.utils.util import get_request_environment
Expand Down Expand Up @@ -390,17 +390,20 @@ def post_organization_affiliation(org_id):
@_jwt.has_one_of_roles(
[Role.SYSTEM.value, Role.STAFF_VIEW_ACCOUNTS.value, Role.PUBLIC_USER.value])
def get_org_details_by_affiliation(business_identifier):
"""Search orgs by BusinessIdentifier and return org Name and UUID."""
"""Search non staff orgs by BusinessIdentifier and return org Name, branch Name and UUID."""
environment = get_request_environment()
pagination_info = PaginationInfo(
limit=int(request.args.get('limit', 10)),
page=int(request.args.get('page', 1))
)

excluded_org_types = [OrgType.STAFF.value, OrgType.SBC_STAFF.value]
try:
data = OrgService.search_orgs_by_affiliation(business_identifier, pagination_info, environment)
data = OrgService.search_orgs_by_affiliation(
business_identifier, pagination_info, environment, excluded_org_types
)

org_details = [{'name': org.name, 'uuid': org.uuid} for org in data['orgs']]
org_details = \
[{'name': org.name, 'uuid': org.uuid, 'branchName': org.branch_name} for org in data['orgs']]
response, status = {'orgs_details': org_details}, http_status.HTTP_200_OK

except BusinessException as exception:
Expand Down
12 changes: 9 additions & 3 deletions auth-api/src/auth_api/services/org.py
Original file line number Diff line number Diff line change
Expand Up @@ -730,10 +730,16 @@ def search_orgs(search: OrgSearch, environment): # pylint: disable=too-many-loc
return orgs_result

@staticmethod
def search_orgs_by_affiliation(business_identifier,
pagination_info: PaginationInfo, environment):
def search_orgs_by_affiliation(
business_identifier, pagination_info: PaginationInfo, environment, excluded_org_types
):
"""Search for orgs based on input parameters."""
orgs, total = OrgModel.search_orgs_by_business_identifier(business_identifier, pagination_info, environment)
orgs, total = OrgModel.search_orgs_by_business_identifier(
business_identifier,
pagination_info,
environment,
excluded_org_types
)

return {
'orgs': orgs,
Expand Down
58 changes: 52 additions & 6 deletions auth-api/tests/unit/api/test_org.py
Original file line number Diff line number Diff line change
Expand Up @@ -2136,11 +2136,11 @@ def test_new_active_search(client, jwt, session, keycloak_mock):
[('T12dfhsff1', CorpType.BC.value, 'NR 1234567'), ('T12dfhsff2', CorpType.GP.value, 'NR 1234566')],
['NR 1234567', 'NR 1234566'], []),
('affiliations_order', [], [],
[], [('abcde1', CorpType.BC.value, 'NR 123456'),
('abcde2', CorpType.BC.value, 'NR 123457'),
('abcde3', CorpType.BC.value, 'NR 123458'),
('abcde4', CorpType.BC.value, 'NR 123459')],
[datetime(2021, 1, 1), datetime(2022, 2, 1), datetime(2022, 3, 1), datetime(2023, 2, 1)]),
[], [('abcde1', CorpType.BC.value, 'NR 123456'),
('abcde2', CorpType.BC.value, 'NR 123457'),
('abcde3', CorpType.BC.value, 'NR 123458'),
('abcde4', CorpType.BC.value, 'NR 123459')],
[datetime(2021, 1, 1), datetime(2022, 2, 1), datetime(2022, 3, 1), datetime(2023, 2, 1)]),
('all', [('BC1234567', CorpType.BC.value), ('BC1234566', CorpType.BC.value)],
[('T12dfhsff1', CorpType.BC.value), ('T12dfhsff2', CorpType.GP.value)],
[('T12dfhsff3', CorpType.BC.value, 'NR 1234567'), ('T12dfhsff4', CorpType.GP.value, 'NR 1234566')],
Expand Down Expand Up @@ -2248,12 +2248,15 @@ def _create_orgs_entities_and_affiliations(client, jwt, count):

headers = factory_auth_header(jwt=jwt, claims=TestJwtClaims.public_user_role)
client.post('/api/v1/users', headers=headers, content_type='application/json')
new_org = TestOrgInfo.org_details
new_org = TestOrgInfo.org_details.copy()
new_org['name'] = new_org['name'] + ' ' + str(i)
new_org['branchName'] = 'branch-for-' + new_org['name']
rv = client.post('/api/v1/orgs', data=json.dumps(new_org),
headers=headers, content_type='application/json')
dictionary = json.loads(rv.data)
org_id = dictionary['id']
new_org['id'] = org_id
created_orgs.append(new_org)

client.post('/api/v1/orgs/{}/affiliations'.format(org_id), headers=headers,
data=json.dumps(TestAffliationInfo.affiliation3), content_type='application/json')
Expand Down Expand Up @@ -2292,4 +2295,47 @@ def test_get_orgs_by_affiliation(client, jwt, session, keycloak_mock,

for co in created_orgs:
names = [od['name'] for od in orgs_details]
branches = [od['branchName'] for od in orgs_details]
assert co['name'] in names
assert co['branchName'] in branches

for od in orgs_details:
assert 'name' in od
assert 'branchName' in od
assert 'uuid' in od
assert 'id' not in od


def test_get_orgs_by_affiliation_filtering_out_staff_orgs(app, client, jwt, session, keycloak_mock):
"""Assert that fetching orgs by affiliation do not return staff orgs."""
orig_val_max_number_of_orgs = app.config.get('MAX_NUMBER_OF_ORGS')
app.config.update(MAX_NUMBER_OF_ORGS=10)
create_org_count = 6

created_orgs = _create_orgs_entities_and_affiliations(client, jwt, create_org_count)
app.config.update(MAX_NUMBER_OF_ORGS=orig_val_max_number_of_orgs)

org3 = created_orgs[2]
org5 = created_orgs[4]

convert_org_to_staff_org(org3['id'], OrgType.SBC_STAFF.value)
convert_org_to_staff_org(org5['id'], OrgType.STAFF.value)

staff_org_names = [org3['name'], org5['name']]
expected_org_count = create_org_count - len(staff_org_names)

# Create a system token
headers = factory_auth_header(jwt=jwt, claims=TestJwtClaims.system_role)
rv = client.get('/api/v1/orgs/affiliation/{}'.format(TestAffliationInfo.affiliation3.get('businessIdentifier')),
headers=headers, content_type='application/json')

assert rv.status_code == http_status.HTTP_200_OK
assert schema_utils.validate(rv.json, 'orgs_response')[1]

response = json.loads(rv.data)

assert len(response.get('orgsDetails')) == expected_org_count # without org 3 and 5
orgs_details = response.get('orgsDetails')

for od in orgs_details:
assert od['name'] not in staff_org_names
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,31 @@
:disabled="accounts.length < 2"
class="business-identifier mb-n2"
:items="accounts"
item-text="name"
item-value="uuid"
@change="emitSelected"
/>
>
<template #selection="data">
<!-- HTML that describe how select should render selected items -->
<span
v-if="data.item.branchName"
data-test="account-authorization-request-selection"
>{{ data.item.name }} - {{ data.item.branchName }}</span>
<span
v-else
data-test="account-authorization-request-selection"
>{{ data.item.name }}</span>
</template>
<template #item="data">
<span
v-if="data.item.branchName"
data-test="account-authorization-request-option"
>{{ data.item.name }} - {{ data.item.branchName }}</span>
<span
v-else
data-test="account-authorization-request-option"
>{{ data.item.name }}</span>
</template>
</v-select>
<span>You can add a message that will be included as part of your authorization request. </span>
<v-textarea
id="account-authorization-request-additional-message-textarea"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,9 @@ describe('AccountAuthorizationRequest tests', () => {

// verify that account is selected and selector disabled
expect(wrapper.find('#account-authorization-request-request-account-select').attributes().disabled).toBeDefined()
expect(wrapper.find('.v-select__selection--comma').text())
.toBe(orgsDetailsByAffiliationSingleItemResponse.orgsDetails[0].name)
expect(wrapper.findAll('.v-list-item__title').length ===
orgsDetailsByAffiliationSingleItemResponse.orgsDetails.length)
expect(wrapper.find('[data-test="account-authorization-request-selection"]').text())
.toContain(orgsDetailsByAffiliationSingleItemResponse.orgsDetails[0].name)
expect(wrapper.findAll('[data-test="account-authorization-request-option"]').exists()).toBe(false)
})

it('renders enabled select with no preselected item, when multiple affiliated accounts found', async () => {
Expand All @@ -104,7 +103,7 @@ describe('AccountAuthorizationRequest tests', () => {

// verify that account is selected and selector disabled
expect(wrapper.find('#account-authorization-request-request-account-select').attributes().disabled).toBeUndefined()
expect(wrapper.findAll('.v-list-item__title').length ===
console.assert(wrapper.findAll('[data-test="account-authorization-request-option"]').length ===
orgsDetailsByAffiliationMultipleItemsResponse.orgsDetails.length)
})
})
Loading