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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ and this project adheres to

## [Unreleased]

### Added

- Add `get_plugin(name)` method to fetch plugin description by name
([dbb4d57], [#85])

### Changed

- README: update PyPI badges and add supported Python versions
Expand Down Expand Up @@ -100,6 +105,7 @@ and this project adheres to
[0.1.9]: https://github.com/LeakIX/LeakIXClient-Python/releases/tag/v0.1.9

<!-- Commit links -->
[dbb4d57]: https://github.com/LeakIX/LeakIXClient-Python/commit/dbb4d57
[d9e4bf8]: https://github.com/LeakIX/LeakIXClient-Python/commit/d9e4bf8
[87b68f6]: https://github.com/LeakIX/LeakIXClient-Python/commit/87b68f6
[591c046]: https://github.com/LeakIX/LeakIXClient-Python/commit/591c046
Expand All @@ -124,6 +130,7 @@ and this project adheres to
[4dd4948]: https://github.com/LeakIX/LeakIXClient-Python/commit/4dd4948

<!-- PR links -->
[#85]: https://github.com/LeakIX/LeakIXClient-Python/issues/85
[#84]: https://github.com/LeakIX/LeakIXClient-Python/issues/84
[#66]: https://github.com/LeakIX/LeakIXClient-Python/pull/66
[#65]: https://github.com/LeakIX/LeakIXClient-Python/issues/65
Expand Down
4 changes: 4 additions & 0 deletions leakix/async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ async def get_plugins(self) -> AbstractResponse:
"""Returns the list of plugins the authenticated user has access to."""
return self._parse_plugins(await self.__get("/api/plugins"))

async def get_plugin(self, name: str) -> AbstractResponse:
"""Returns the description of a plugin by its name."""
return self._parse_plugin(await self.__get(f"/api/plugins/{name}"))

async def get_subdomains(self, domain: str) -> AbstractResponse:
"""Returns the list of subdomains for a given domain."""
return self._parse_subdomains(await self.__get(f"/api/subdomains/{domain}"))
Expand Down
6 changes: 6 additions & 0 deletions leakix/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ def _parse_plugins(response: AbstractResponse) -> AbstractResponse:
response.response_json = [APIResult.from_dict(d) for d in response.json()]
return response

@staticmethod
def _parse_plugin(response: AbstractResponse) -> AbstractResponse:
if response.is_success():
response.response_json = APIResult.from_dict(response.json())
return response

@staticmethod
def _parse_subdomains(response: AbstractResponse) -> AbstractResponse:
if response.is_success():
Expand Down
9 changes: 9 additions & 0 deletions leakix/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,15 @@ def get_plugins(self) -> AbstractResponse:
url = f"{self.base_url}/api/plugins"
return self._parse_plugins(self.__get(url, params=None))

def get_plugin(self, name: str) -> AbstractResponse:
"""
Returns the description of a plugin by its name.

The output is an `APIResult` object with `name` and `description` fields.
"""
url = f"{self.base_url}/api/plugins/{name}"
return self._parse_plugin(self.__get(url, params=None))

def get_subdomains(self, domain: str) -> AbstractResponse:
"""
Returns the list of subdomains for a given domain.
Expand Down
42 changes: 42 additions & 0 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,48 @@ def test_get_plugins_unauthorized(self, client):
assert response.status_code() == 401


class TestGetPlugin:
def test_get_plugin_success(self, client_with_api_key):
res_json = {
"name": "GrafanaOpenPlugin",
"description": "Grafana open instances",
}
with requests_mock.Mocker() as m:
m.get(
f"{client_with_api_key.base_url}/api/plugins/GrafanaOpenPlugin",
json=res_json,
status_code=200,
)
response = client_with_api_key.get_plugin("GrafanaOpenPlugin")
assert response.is_success()
assert response.json().name == "GrafanaOpenPlugin"
assert response.json().description == "Grafana open instances"

def test_get_plugin_not_found(self, client):
res_json = {"title": "Not Found", "description": "Plugin not found"}
with requests_mock.Mocker() as m:
m.get(
f"{client.base_url}/api/plugins/NonExistent",
json=res_json,
status_code=404,
)
response = client.get_plugin("NonExistent")
assert response.is_error()
assert response.status_code() == 404

def test_get_plugin_unauthorized(self, client):
res_json = {"error": "unauthorized"}
with requests_mock.Mocker() as m:
m.get(
f"{client.base_url}/api/plugins/GrafanaOpenPlugin",
json=res_json,
status_code=401,
)
response = client.get_plugin("GrafanaOpenPlugin")
assert response.is_error()
assert response.status_code() == 401


class TestGetSubdomains:
def test_get_subdomains_success(self, client):
res_json = [
Expand Down
Loading