Skip to content
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
2 changes: 1 addition & 1 deletion .github/workflows/pypi-prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
run: |
python -m tox -e build-dists --parallel 0
- name: Publish 📦 to Prod PyPI
uses: pypa/gh-action-pypi-publish@master
uses: pypa/gh-action-pypi-publish@release/v1
with:
username: __token__
password: ${{ secrets.Prod_PyPI_token }}
2 changes: 1 addition & 1 deletion .github/workflows/pypi-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
run: |
python -m tox -e build-dists --parallel 0
- name: Publish 📦 to Test PyPI
uses: pypa/gh-action-pypi-publish@master
uses: pypa/gh-action-pypi-publish@release/v1
with:
username: __token__
password: ${{ secrets.Test_PyPI_token }}
Expand Down
11 changes: 11 additions & 0 deletions gremlinapi/gremlinapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,17 @@ def _error_if_not_json_body(cls, **kwargs: dict) -> dict:
raise GremlinParameterError(error_msg)
return body

@classmethod
def _error_if_not_team_ids(cls, **kwargs: dict) -> list:
team_ids: Union[list, str] = cls._info_if_not_param("team_ids", **kwargs)
if not team_ids:
error_msg: str = f"team_ids not passed to users endpoint: {kwargs}"
log.error(error_msg)
raise GremlinParameterError(error_msg)
if isinstance(team_ids, str):
team_ids = [team_ids]
return team_ids

@classmethod
def _error_if_not_email(cls, **kwargs: dict) -> str:
email: str = cls._info_if_not_param("email", **kwargs)
Expand Down
16 changes: 16 additions & 0 deletions gremlinapi/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,22 @@ def deactivate_user(
(resp, body) = https_client.api_call(method, endpoint, **payload)
return body

@classmethod
@register_cli_action("remove_user_from_team", ("email", "team_ids"), ("",))
def remove_user_from_team(
cls,
https_client: Type[GremlinAPIHttpClient] = get_gremlin_httpclient(),
*args: tuple,
**kwargs: dict,
) -> dict:
method: str = "POST"
email: str = cls._error_if_not_email(**kwargs)
team_ids: Union[list, str] = cls._error_if_not_team_ids(**kwargs)
endpoint: str = f"/users/{email}/teams/remove"
payload: dict = cls._payload(**{"headers": https_client.header(), "data": {"teamIds": team_ids}}) # type: ignore

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think we want to set the "body" field instead of the "data" field here, as the other modify endpoints set that instead. It will auto set the content type:

kwargs["headers"]["Content-Type"] = "application/json"

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

body forces application/json, and this new endpoint uses application/x-www-form-urlencoded.

(resp, body) = https_client.api_call(method, endpoint, **payload)
return body

@classmethod
@register_cli_action("list_active_user", ("",), ("teamId", "pageSize"))
def list_active_users(
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "gremlinapi"
version = "0.19.3"
version = "0.20.1"
description = "Gremlin library for Python"
readme = "README.md"
license = { text = "Apache 2.0" }
Expand Down
11 changes: 10 additions & 1 deletion tests/test_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
GremlinAPIUsersAuthMFA,
)

from .util import mock_json, mock_data, mock_users, mock_body, mock_paged_json, mock_paged_data
from .util import mock_json, mock_data, mock_users, mock_body, mock_team_ids, mock_paged_json, mock_paged_data


class TestUsers(unittest.TestCase):
Expand Down Expand Up @@ -46,6 +46,15 @@ def test_deactivate_user_with_decorator(self, mock_get) -> None:
mock_get.return_value.json = mock_json
self.assertEqual(GremlinAPIUsers.deactivate_user(**mock_users), mock_data)

@patch("requests.post")
def test_remove_user_from_team_with_decorator(self, mock_get) -> None:
mock_get.return_value = requests.Response()
mock_get.return_value.status_code = 200
mock_get.return_value.json = mock_json
self.assertEqual(
GremlinAPIUsers.remove_user_from_team(**{**mock_users, **mock_team_ids}), mock_data
)

@patch("requests.get")
def test_list_active_users_with_decorator(self, mock_get) -> None:
mock_get.return_value = requests.Response()
Expand Down
1 change: 1 addition & 0 deletions tests/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def mock_paged_json_page2():

mock_org_id = "1234567890a"
mock_team_id = "1234567890a"
mock_team_ids = {"team_ids": [mock_team_id]}
mock_body = {"body": mock_data}
mock_guid = {"guid": mock_data}
mock_scenario_guid = {
Expand Down
Loading