Skip to content

feat(audit_logs):activity logs client endpoints #308

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
Empty file.
18 changes: 18 additions & 0 deletions lago_python_client/activity_logs/clients.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from typing import ClassVar, Type

from ..base_client import BaseClient
from ..mixins import (
FindAllCommandMixin,
FindCommandMixin,
)
from ..models.activity_log import ActivityLogResponse


class ActivityLogClient(
FindAllCommandMixin[ActivityLogResponse],
FindCommandMixin[ActivityLogResponse],
BaseClient,
):
API_RESOURCE: ClassVar[str] = "activity_logs"
RESPONSE_MODEL: ClassVar[Type[ActivityLogResponse]] = ActivityLogResponse
ROOT_NAME: ClassVar[str] = "activity_log"
5 changes: 5 additions & 0 deletions lago_python_client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from .wallets.clients import WalletClient, WalletTransactionClient
from .webhooks.clients import WebhookClient
from .webhook_endpoints.clients import WebhookEndpointClient
from .activity_logs.clients import ActivityLogClient

try:
from typing import Final
Expand Down Expand Up @@ -159,3 +160,7 @@ def webhooks(self) -> WebhookClient:
@callable_cached_property
def webhook_endpoints(self) -> WebhookEndpointClient:
return WebhookEndpointClient(self.base_api_url, self.api_key)

@callable_cached_property
def activity_logs(self) -> ActivityLogClient:
return ActivityLogClient(self.base_api_url, self.api_key)
1 change: 1 addition & 0 deletions lago_python_client/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .activity_log import ActivityLog as ActivityLog, ActivityLogResponse as ActivityLogResponse
from .applied_coupon import AppliedCoupon as AppliedCoupon
from .billable_metric import (
BillableMetric as BillableMetric,
Expand Down
36 changes: 36 additions & 0 deletions lago_python_client/models/activity_log.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from typing import Optional

from lago_python_client.base_model import BaseModel

from ..base_model import BaseResponseModel


class ActivityLog(BaseModel):
activity_type: str
activity_object: Optional[dict]
activity_object_changes: Optional[dict]
activity_source: str
activity_type: str
logged_at: str
resource_type: str
created_at: str
activity_id: str
external_customer_id: Optional[str]
external_subscription_id: Optional[str]
resource_id: str
user_email: Optional[str]


class ActivityLogResponse(BaseResponseModel):
activity_id: str
activity_type: str
activity_source: str
activity_object: Optional[dict]
activity_object_changes: Optional[dict]
user_email: Optional[str]
resource_id: str
resource_type: str
external_customer_id: Optional[str]
external_subscription_id: Optional[str]
logged_at: str
created_at: str
21 changes: 21 additions & 0 deletions tests/fixtures/activity_log.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"activity_log": {
"activity_id": "1262046f-ea6e-423b-8bf7-3a985232f91b",
"activity_type": "billable_metric.created",
"activity_source": "api",
"activity_object": {
"foo": "bar",
"baz": "qux"
},
"activity_object_changes": {
"foo": "bar"
},
"user_email": "[email protected]",
"resource_id": "fd417abf-4273-42bf-bf93-fc3f93d4e987",
"resource_type": "BillableMetric",
"external_customer_id": "0c60aa34-74aa-470d-9d9c-409c79d05d56",
"external_subscription_id": "b0a3fa29-5ba8-4363-b45e-0ea4c700acf8",
"logged_at": "2025-05-05T15:06:21Z",
"created_at": "2025-05-05T15:06:21Z"
}
}
49 changes: 49 additions & 0 deletions tests/fixtures/activity_log_index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"activity_logs": [
{
"activity_id": "1262046f-ea6e-423b-8bf7-3a985232f91b",
"activity_type": "billable_metric.created",
"activity_source": "api",
"activity_object": {
"foo": "bar",
"baz": "qux"
},
"activity_object_changes": {
"foo": "bar"
},
"user_email": "[email protected]",
"resource_id": "fd417abf-4273-42bf-bf93-fc3f93d4e987",
"resource_type": "BillableMetric",
"external_customer_id": "0c60aa34-74aa-470d-9d9c-409c79d05d56",
"external_subscription_id": "b0a3fa29-5ba8-4363-b45e-0ea4c700acf8",
"logged_at": "2025-05-05T15:06:21Z",
"created_at": "2025-05-05T15:06:21Z"
},
{
"activity_id": "6744ddec-3516-4e26-9c7e-dc3c30fc4e80",
"activity_type": "plan.created",
"activity_source": "api",
"activity_object": {
"foo": "bar-2",
"baz": "qux-2"
},
"activity_object_changes": {
"foo": "bar-2"
},
"user_email": "[email protected]",
"resource_id": "010f1c2f-b86e-447e-8a79-e4d8cd3f8e96",
"resource_type": "Plan",
"external_customer_id": "8f326a03-852b-408f-ba5b-d633420b59d6",
"external_subscription_id": "8bdbe7c8-2817-4d93-b264-ce8417f09b2a",
"logged_at": "2025-05-05T15:33:50Z",
"created_at": "2025-05-05T15:33:50Z"
}
],
"meta": {
"current_page": 1,
"next_page": 2,
"prev_page": null,
"total_pages": 8,
"total_count": 73
}
}
100 changes: 100 additions & 0 deletions tests/test_activity_logs_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import os

import pytest
from pytest_httpx import HTTPXMock

from urllib.parse import urlencode

from lago_python_client.client import Client
from lago_python_client.exceptions import LagoApiError

ENDPOINT = "https://api.getlago.com/api/v1/activity_logs"


def mock_response(fixture_path):
this_dir = os.path.dirname(os.path.abspath(__file__))
data_path = os.path.join(this_dir, fixture_path)

with open(data_path, "rb") as response:
return response.read()


def test_valid_find_activity_log_request(httpx_mock: HTTPXMock):
client = Client(api_key="886fe239-927d-4072-ab72-6dd345e8dd0d")
activity_id = "1262046f-ea6e-423b-8bf7-3a985232f91b"

httpx_mock.add_response(
method="GET",
url=ENDPOINT + f"/{activity_id}",
content=mock_response("fixtures/activity_log.json"),
)
response = client.activity_logs.find(activity_id)

assert response.activity_id == activity_id
assert response.activity_type == "billable_metric.created"


def test_invalid_find_activity_log_request(httpx_mock: HTTPXMock):
client = Client(api_key="invalid")
activity_id = "invalid"

httpx_mock.add_response(
method="GET",
url=ENDPOINT + f"/{activity_id}",
status_code=404,
content=b"",
)

with pytest.raises(LagoApiError):
client.activity_logs.find(activity_id)


def test_valid_find_all_activity_log_request(httpx_mock: HTTPXMock):
client = Client(api_key="886fe239-927d-4072-ab72-6dd345e8dd0d")

httpx_mock.add_response(
method="GET",
url=ENDPOINT,
content=mock_response("fixtures/activity_log_index.json"),
)
response = client.activity_logs.find_all()

assert response["activity_logs"][0].activity_id == "1262046f-ea6e-423b-8bf7-3a985232f91b"
assert response["activity_logs"][1].activity_id == "6744ddec-3516-4e26-9c7e-dc3c30fc4e80"
assert response["meta"]["current_page"] == 1


def test_valid_find_all_activity_log_request_with_options(httpx_mock: HTTPXMock):
client = Client(api_key="886fe239-927d-4072-ab72-6dd345e8dd0d")
options = {"per_page": 1, "page": 1}

httpx_mock.add_response(
method="GET",
url=ENDPOINT + f"?{urlencode(options)}",
content=mock_response("fixtures/activity_log_index.json"),
)
response = client.activity_logs.find_all(options)

assert response["activity_logs"][1].activity_id == "6744ddec-3516-4e26-9c7e-dc3c30fc4e80"
assert response["meta"]["current_page"] == 1


def test_invalid_find_all_activity_log_request(httpx_mock: HTTPXMock):
client = Client(api_key="invalid")

httpx_mock.add_response(
method="GET",
url=ENDPOINT,
status_code=404,
content=b"",
)

with pytest.raises(LagoApiError):
client.activity_logs.find_all()


def test_invalid_operations_for_activity_log_request():
client = Client(api_key="886fe239-927d-4072-ab72-6dd345e8dd0d")
assert not hasattr(client.activity_logs, "create")
assert not hasattr(client.activity_logs, "update")
assert not hasattr(client.activity_logs, "destroy")