Skip to content

Commit

Permalink
Use unique userId instead of userName (display name) for ZoomAsk outp…
Browse files Browse the repository at this point in the history
…ut entry (#38129)

* change userName to userId

* update RNs

* fix where user ID vs name is used

* update unit test

* fix error in Zoom.py

Co-authored-by: Maya Goldman <[email protected]>

* increment RN number

* undo mistake on changing RN number

* remove extra newlines

* fix increment RN number

* add user email lookup

* add unit test for new function

* fix wrong import name in test

* added userId to mock_request.json.return_value

* patch zoom_get_user_email_by_id

* fixed expected page size in test

* pre commit

---------

Co-authored-by: Maya Goldman <[email protected]>
Co-authored-by: mayagoldman <[email protected]>
  • Loading branch information
3 people authored Feb 2, 2025
1 parent 2cc5e7f commit 813ffb8
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 28 deletions.
25 changes: 22 additions & 3 deletions Packs/Zoom/Integrations/Zoom/Zoom.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ def next_expiry_time() -> float:
return (datetime.now(timezone.utc) + timedelta(seconds=5)).timestamp()


async def check_and_handle_entitlement(text: str, message_id: str, user_name: str) -> str:
async def check_and_handle_entitlement(text: str, message_id: str, user_name: str, user_email: str) -> str:
"""
Handles an entitlement message (a reply to a question)
Args:
Expand All @@ -434,7 +434,7 @@ async def check_and_handle_entitlement(text: str, message_id: str, user_name: st
entitlement = message.get('entitlement')
reply = message.get('reply', f'Thank you {user_name} for your response {text}.')
guid, incident_id, task_id = extract_entitlement(entitlement)
demisto.handleEntitlementForUser(incident_id, guid, user_name, text, task_id)
demisto.handleEntitlementForUser(incident_id, guid, user_email, text, task_id)
message['remove'] = True
set_to_integration_context_with_retries({'messages': messages}, OBJECTS_TO_KEYS, SYNC_CONTEXT)
return reply
Expand Down Expand Up @@ -786,7 +786,9 @@ async def handle_zoom_response(request: Request, credentials: HTTPBasicCredentia
robot_jid = payload['robotJid']
to_jid = payload['toJid']
user_name = payload['userName']
entitlement_reply = await check_and_handle_entitlement(action, message_id, user_name)
user_id = payload['userId']
user_email = zoom_get_user_email_by_id(CLIENT, user_id)
entitlement_reply = await check_and_handle_entitlement(action, message_id, user_name, user_email)
if entitlement_reply:
await process_entitlement_reply(entitlement_reply, account_id, robot_jid, to_jid, user_name, action)
demisto.updateModuleHealth("")
Expand Down Expand Up @@ -2064,6 +2066,23 @@ def zoom_get_user_name_by_email(client, user_email):
return user_name


def zoom_get_user_email_by_id(client, user_id):
"""
Retrieves the user email address associated with the given user ID.
:param client: The Zoom client object.
user_id: The user ID of the user.
:return: The email address associated with the user ID.
:rtype: str
"""
user_url_suffix = f'users/{user_id}'
user_email = client.zoom_list_users(page_size=1, url_suffix=user_url_suffix).get('email')
if not user_email:
raise DemistoException(USER_NOT_FOUND)
return user_email


def zoom_list_messages_command(client, **args) -> CommandResults:
"""
Lists messages from Zoom chat.
Expand Down
74 changes: 50 additions & 24 deletions Packs/Zoom/Integrations/Zoom/Zoom_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ def test_zoom__create_meeting_command__instant_meeting(mocker):
zoom_create_meeting_command(client=client,
user_id="[email protected]",
topic="nonsense",
type="Instant",)
type="Instant", )
assert zoom_create_meeting_mocker.call_args[1]["json_data"].get("type") == 1


Expand Down Expand Up @@ -631,7 +631,7 @@ def test_zoom_user_list_command__when_user_id(mocker):
client_id="mockclient", client_secret="mocksecret")
from Zoom import zoom_list_users_command
res = zoom_list_users_command(client, user_id="bla")
assert len(res.readable_output) == 159 # type: ignore[arg-type]
assert len(res.readable_output) == 159 # type: ignore[arg-type]


def test_zoom_meeting_list_command__when_user_id(mocker):
Expand All @@ -655,7 +655,7 @@ def test_zoom_meeting_list_command__when_user_id(mocker):
client_id="mockclient", client_secret="mocksecret")
from Zoom import zoom_meeting_list_command
res = zoom_meeting_list_command(client, user_id="bla")
assert len(res.readable_output) == 133 # type: ignore[arg-type]
assert len(res.readable_output) == 133 # type: ignore[arg-type]


def test_remove_None_values_from_dict():
Expand Down Expand Up @@ -990,19 +990,19 @@ def test_zoom_list_user_channels_command(mocker):
expected_raw_data = {
"channels": [
{"jid": "channel_jid_1_t", "id": "channel_id_1", "name": "Channel 1", "type": "public",
"channel_url": "https://test1.com", "next_page_token": "token1"},
"channel_url": "https://test1.com", "next_page_token": "token1"},
{"jid": "channel_jid_2", "id": "channel_id_2", "name": "Channel 2", "type": "public",
"channel_url": "https://test1.com", "next_page_token": "token2"}
"channel_url": "https://test1.com", "next_page_token": "token2"}
]
}

expected_results = {
'UserChannelsNextToken': None,
"channels": [
{"jid": "channel_jid_1_t", "id": "channel_id_1", "name": "Channel 1", "type": "public",
"channel_url": "https://test1.com", "next_page_token": "token1"},
"channel_url": "https://test1.com", "next_page_token": "token1"},
{"jid": "channel_jid_2", "id": "channel_id_2", "name": "Channel 2", "type": "public",
"channel_url": "https://test1.com", "next_page_token": "token2"}
"channel_url": "https://test1.com", "next_page_token": "token2"}
]
}

Expand Down Expand Up @@ -1316,9 +1316,9 @@ def test_zoom_list_account_public_channels_command(mocker):
expected_raw_data = {
"channels": [
{"jid": "channel_jid_1", "id": "channel_id_1", "name": "Channel 1", "type": "public",
"channel_url": "https://test1.com", "next_page_token": "token1"},
"channel_url": "https://test1.com", "next_page_token": "token1"},
{"jid": "channel_jid_2", "id": "channel_id_2", "name": "Channel 2", "type": "public",
"channel_url": "https://test1.com", "next_page_token": "token2"}
"channel_url": "https://test1.com", "next_page_token": "token2"}
]
}

Expand Down Expand Up @@ -1347,7 +1347,7 @@ def test_zoom_list_account_public_channels_command(mocker):
{"jid": "channel_jid_1", "id": "channel_id_1", "name": "Channel 1", "type": "public",
"channel_url": "https://test1.com", "next_page_token": "token1"},
{"jid": "channel_jid_2", "id": "channel_id_2", "name": "Channel 2", "type": "public",
"channel_url": "https://test1.com", "next_page_token": "token2"}
"channel_url": "https://test1.com", "next_page_token": "token2"}
],
"ChannelsNextToken": None
}
Expand Down Expand Up @@ -1478,7 +1478,7 @@ def test_zoom_send_message_markdown_command(mocker):
'start_position': 39, 'end_position': 44},
{'text': 'HI ', 'format_type': 'paragraph', 'format_attr': 'h1', 'start_position': 0, 'end_position': 2},
{'text': '@John, please review the following report', 'format_type': 'LeftIndent',
'format_attr': 40, 'start_position': 4, 'end_position': 44}
'format_attr': 40, 'start_position': 4, 'end_position': 44}
],
'file_ids': []
}
Expand Down Expand Up @@ -1556,9 +1556,9 @@ def test_zoom_list_messages_command(mocker):
expected_raw_data = {
"messages": [
{"id": "message_id_1", "message": "Message 1", "sender": "sender_1",
"sender_display_name": "Sender 1", "date_time": "2023-03-07T10:30:00Z"},
"sender_display_name": "Sender 1", "date_time": "2023-03-07T10:30:00Z"},
{"id": "message_id_2", "message": "Message 2", "sender": "sender_2",
"sender_display_name": "Sender 2", "date_time": "2023-03-08T09:15:00Z"}
"sender_display_name": "Sender 2", "date_time": "2023-03-08T09:15:00Z"}
]
}
expacted_result = {
Expand Down Expand Up @@ -1592,7 +1592,8 @@ def test_zoom_list_messages_command(mocker):
assert result.outputs['ChatMessage']['messages'][0]['id'] == expacted_result['ChatMessage']['messages'][0]['id']
assert result.outputs['ChatMessage']['messages'][0]['message'] == expacted_result['ChatMessage']['messages'][0]['message']
assert result.outputs['ChatMessage']['messages'][0]['sender'] == expacted_result['ChatMessage']['messages'][0]['sender']
assert result.outputs['ChatMessage']['messages'][0]['sender_display_name'] == expacted_result['ChatMessage']['messages'][0]['sender_display_name'] # noqa: E501
assert result.outputs['ChatMessage']['messages'][0]['sender_display_name'] == expacted_result['ChatMessage']['messages'][0][
'sender_display_name'] # noqa: E501
assert result.outputs['ChatMessage']['messages'][0]['date_time'] == expacted_result['ChatMessage']['messages'][0]['date_time']


Expand Down Expand Up @@ -1621,7 +1622,7 @@ def test_zoom_list_messages_command_pageination(mocker):
expected_raw_data = {
"messages": [
{"id": "message_id_1", "message": "Message 1", "sender": "sender_1",
"sender_display_name": "Sender 1", "date_time": "2023-03-07T10:30:00Z"}
"sender_display_name": "Sender 1", "date_time": "2023-03-07T10:30:00Z"}
],
"next_page_token": "xxxxxxxxxxx"
}
Expand Down Expand Up @@ -1773,6 +1774,29 @@ def test_zoom_get_user_id_by_email(mocker):
assert result == expected_user_id


def test_zoom_get_user_email_by_id(mocker):
"""
Given -
client
When -
get user email address by their user ID
Then -
Validate that the get_user_email_by_id function is called with the correct arguments
Validate the command results
"""
client = Client(base_url='https://test.com', account_id="mockaccount",
client_id="mockclient", client_secret="mocksecret")
user_id = "user_id"
expected_user_email = "[email protected]"
expected_response = {"email": expected_user_email}

mock_zoom_list_users = mocker.patch.object(client, 'zoom_list_users', return_value=expected_response)
from Zoom import zoom_get_user_email_by_id
result = zoom_get_user_email_by_id(client, user_id)
mock_zoom_list_users.assert_called_with(page_size=1, url_suffix=f'users/{user_id}')
assert result == expected_user_email


def test_zoom_send_notification_command(mocker):
"""
Given -
Expand Down Expand Up @@ -1839,9 +1863,9 @@ def test_zoom_delete_user_token_command(mocker):


@pytest.mark.parametrize("channel_name, investigation_id, expected_result", [
('Channel1', None, 'JID1'), # Scenario 1: Find by channel_name
(None, 'Incident123', 'JID1'), # Scenario 2: Find by investigation_id
('NonExistentChannel', None, None), # Scenario 3: Channel not found
('Channel1', None, 'JID1'), # Scenario 1: Find by channel_name
(None, 'Incident123', 'JID1'), # Scenario 2: Find by investigation_id
('NonExistentChannel', None, None), # Scenario 3: Channel not found
])
def test_get_channel_jid_by_channel_name(channel_name, investigation_id, expected_result, mocker):
"""
Expand Down Expand Up @@ -1870,9 +1894,9 @@ def test_get_channel_jid_by_channel_name(channel_name, investigation_id, expecte
# Test cases for check_authentication_bot_parameters
@pytest.mark.parametrize("bot_Jid, client_id, client_secret, expected_exception", [
('bot_Jid', 'client_id', 'client_secret', None), # Scenario 1: All parameters provided
(None, None, None, None), # Scenario 2: All parameters None
('bot_Jid', None, None, DemistoException), # Scenario 3: bot_Jid provided, others None
(None, 'client_id', None, DemistoException), # Scenario 4: client_id provided, others None
(None, None, None, None), # Scenario 2: All parameters None
('bot_Jid', None, None, DemistoException), # Scenario 3: bot_Jid provided, others None
(None, 'client_id', None, DemistoException), # Scenario 4: client_id provided, others None
(None, None, 'client_secret', DemistoException), # Scenario 5: client_secret provided, others None
])
def test_check_authentication_bot_parameters(bot_Jid, client_id, client_secret, expected_exception):
Expand Down Expand Up @@ -1966,10 +1990,11 @@ async def test_check_and_handle_entitlement(mocker):
text = "Entitlement Text"
message_id = "MessageID123"
user_name = "User123"
user_id = "[email protected]"

# Call the async function and await its result
from Zoom import check_and_handle_entitlement
result = await check_and_handle_entitlement(text, message_id, user_name)
result = await check_and_handle_entitlement(text, message_id, user_name, user_id)

assert result == 'thanks' # Adjust the expected reply as needed

Expand Down Expand Up @@ -2157,6 +2182,7 @@ async def test_handle_zoom_response(event_type, expected_status,
mocker.patch('Zoom.check_and_handle_entitlement')
mocker.patch('Zoom.process_entitlement_reply')
mocker.patch('Zoom.handle_mirroring')
mocker.patch('Zoom.zoom_get_user_email_by_id', return_value="mock_user_email")
mocker.patch.object(demisto, 'params', return_value={'credentials': {'identifier': 'test', 'password': 'testpass'}})

# Create a mock HTTPBasicCredentials object
Expand All @@ -2181,7 +2207,8 @@ async def test_handle_zoom_response(event_type, expected_status,
"messageId": "message_id",
"robotJid": "robot_jid",
"toJid": "mock_jid",
"userName": "admin zoom"
"userName": "admin zoom",
"userId": "mock_userId"
}
}

Expand Down Expand Up @@ -2253,7 +2280,6 @@ def test_save_entitlement():
# Mock the required functions (get_integration_context, set_to_integration_context_with_retries) and any other dependencies
with patch('Zoom.get_integration_context') as mock_get_integration_context, \
patch('Zoom.set_to_integration_context_with_retries') as mock_set_integration_context:

# Mock the return values of the mocked functions
mock_get_integration_context.return_value = {'messages': []}
fixed_timestamp = '2023-09-09 20:08:50'
Expand Down
5 changes: 5 additions & 0 deletions Packs/Zoom/ReleaseNotes/1_6_23.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#### Integrations

##### Zoom

- Improved implementation by recording **ZoomAsk** response under the responder's unique user ID, rather than their display name.
2 changes: 1 addition & 1 deletion Packs/Zoom/pack_metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "Zoom",
"description": "Use the Zoom integration manage your Zoom users and meetings",
"support": "xsoar",
"currentVersion": "1.6.22",
"currentVersion": "1.6.23",
"author": "Cortex XSOAR",
"url": "https://www.paloaltonetworks.com/cortex",
"email": "",
Expand Down

0 comments on commit 813ffb8

Please sign in to comment.