made pagination work

This commit is contained in:
Peter Annabel 2025-07-24 18:26:17 -05:00
parent 146431e818
commit e2bb030b71
27 changed files with 101 additions and 86 deletions

View File

@ -37,16 +37,16 @@ class HuntressClient(ABC):
def _get_url(self) -> str:
pass
def _make_request(
def _make_request( # noqa: C901
self,
method: RequestMethod,
url: str,
data: RequestData | None = None,
rawdata: RequestData | None = None,
# rawdata: RequestData | None = None,
params: RequestParams | None = None,
headers: dict[str, str] | None = None,
retry_count: int = 0,
stream: bool = False,
stream: bool = False, # noqa: FBT001, FBT002
) -> Response:
"""
Make an API request using the specified method, endpoint, data, and parameters.
@ -76,19 +76,19 @@ class HuntressClient(ABC):
method,
url,
headers=headers,
json=data,
params=cast(dict[str, Any], params or {}),
stream=stream,
)
elif rawdata:
response = requests.request(
method,
url,
headers=headers,
data=rawdata,
data=data,
params=cast(dict[str, Any], params or {}),
stream=stream,
)
# elif rawdata:
# response = requests.request(
# method,
# url,
# headers=headers,
# data=rawdata,
# params=cast(dict[str, Any], params or {}),
# stream=stream,
# )
else:
response = requests.request(
method,

View File

@ -135,7 +135,7 @@ class HuntressSATAPIClient(HuntressClient):
auth_response = self._make_request(
"POST",
token_url,
rawdata={
data={
"grant_type": "client_credentials",
"client_id": self.client_id,
"client_secret": self.client_secret,

View File

@ -52,10 +52,10 @@ class AccountsEndpoint(
PaginatedResponse[SATData]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATAccounts,

View File

@ -38,10 +38,10 @@ class AccountsIdAssignmentsEndpoint(
PaginatedResponse[SATAssignments]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATAssignments,

View File

@ -38,10 +38,10 @@ class AccountsIdUsersEndpoint(
PaginatedResponse[SATUsers]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATUsers,

View File

@ -52,10 +52,10 @@ class AssignmentsEndpoint(
PaginatedResponse[SATData]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATAssignments,

View File

@ -49,10 +49,10 @@ class AssignmentsIdEndpoint(
PaginatedResponse[SATAssignments]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATAssignments,

View File

@ -38,10 +38,10 @@ class AssignmentsIdLearnerActivityEndpoint(
PaginatedResponse[SATLearnerActivities]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATLearnerActivities,

View File

@ -38,10 +38,10 @@ class AssignmentsIdLearnersEndpoint(
PaginatedResponse[SATLearners]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATLearners,

View File

@ -52,10 +52,10 @@ class DepartmentsEndpoint(
PaginatedResponse[SATDepartments]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATDepartments,

View File

@ -38,10 +38,10 @@ class DepartmentsIdEndpoint(
PaginatedResponse[SATDepartments]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATDepartments,

View File

@ -52,10 +52,10 @@ class EpisodesEndpoint(
PaginatedResponse[SATData]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATEpisodes,

View File

@ -38,10 +38,10 @@ class EpisodesIdEndpoint(
PaginatedResponse[SATEpisodes]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATEpisodes,

View File

@ -52,10 +52,10 @@ class GroupsEndpoint(
PaginatedResponse[SATGroups]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATGroups,

View File

@ -38,10 +38,10 @@ class GroupsIdEndpoint(
PaginatedResponse[SATGroups]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATGroups,

View File

@ -52,10 +52,10 @@ class LearnersEndpoint(
PaginatedResponse[SATLearners]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATLearners,

View File

@ -38,10 +38,10 @@ class LearnersIdEndpoint(
PaginatedResponse[SATLearners]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATLearners,

View File

@ -52,10 +52,10 @@ class PhishingCampaignScenariosEndpoint(
PaginatedResponse[SATData]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATPhishingScenarios,

View File

@ -45,10 +45,10 @@ class PhishingCampaignScenariosIdEndpoint(
PaginatedResponse[SATPhishingScenarios]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATPhishingScenarios,

View File

@ -52,10 +52,10 @@ class PhishingCampaignsEndpoint(
PaginatedResponse[SATData]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATPhishingCampaigns,

View File

@ -43,10 +43,10 @@ class PhishingCampaignsIdEndpoint(
PaginatedResponse[SATPhishingCampaigns]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATPhishingCampaigns,

View File

@ -52,10 +52,10 @@ class PhishingScenariosEndpoint(
PaginatedResponse[SATPhishingScenarios]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATPhishingScenarios,

View File

@ -38,10 +38,10 @@ class PhishingScenariosIdEndpoint(
PaginatedResponse[SATPhishingScenarios]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATPhishingScenarios,

View File

@ -54,10 +54,10 @@ class UsersEndpoint(
PaginatedResponse[SATData]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATUsers,

View File

@ -39,10 +39,10 @@ class UsersIdEndpoint(
PaginatedResponse[SATUsers]: The initialized PaginatedResponse object.
"""
if params:
params["page"] = page
params["limit"] = limit
params["page[number]"] = page
params["page[size]"] = limit
else:
params = {"page": page, "limit": limit}
params = {"page[number]": page, "page[size]": limit}
return PaginatedResponse(
super()._make_request("GET", params=params),
SATUsers,

View File

@ -84,8 +84,11 @@ class PaginatedResponse(Generic[TModel]):
self.endpointmodel = endpointmodel
self.endpoint = endpoint
self.limit = limit
# The following for SIEM is in the response body, not the headers
# Get page data from the response body
try:
self.parsed_pagination_response = parse_response_body(json.loads(response.content.decode('utf-8')).get('pagination', {}))
except:
self.parsed_pagination_response = parse_response_body(json.loads(response.content.decode('utf-8')).get('meta.page', {}))
self.params = params
if self.parsed_pagination_response is not None:
# Huntress SIEM API gives us a handy response to parse for Pagination

View File

@ -77,12 +77,19 @@ def parse_response_body(
elif body.get("current_page") is not None:
if body.get("current_page") > 1:
result["prev_page"] = body.get("current_page") - 1
elif body.get("currentPage") is not None:
if body.get("currentPage") > 1:
result["prev_page"] = body.get("currentPage") - 1
if body.get("next_page") is not None:
result["next_page"] = body.get("next_page")
elif body.get("currentPage") is not None and body.get("currentPage") < body.get("lastPage"):
result["next_page"] = body.get("currentPage") + 1
if body.get("last_page") is not None:
result["last_page"] = body.get("last_page")
elif body.get("lastPage") is not None:
result["last_page"] = body.get("lastPage")
elif body.get("last_page") is None and body.get("current_page") is not None:
result["last_page"] = math.ceil(body.get("total_count")/body.get("limit"))
@ -92,12 +99,17 @@ def parse_response_body(
result["has_next_page"] = True
elif body.get("current_page") is not None and body.get("next_page") is None:
result["has_next_page"] = False
elif body.get("currentPage") is not None and body.get("currentPage") < body.get("lastPage"):
result["has_next_page"] = True
if body.get("has_prev_page"):
result["has_prev_page"] = body.get("has_prev_page")
elif body.get("current_page") is not None:
if body.get("current_page") > 1:
result["has_prev_page"] = True
elif body.get("currentPage") is not None:
if body.get("currentPage") > 1:
result["has_prev_page"] = True
return result