diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1d048ad..f524e6f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,13 @@ master ------ +7.1.0 (2026-05-29) +------------------ + +Features: +~~~~~~~~~ +- add ``events_schema``, ``query_events``, and ``group_events`` for the Events API + 7.0.0 (2026-05-29) ------------------ diff --git a/castle/client.py b/castle/client.py index d7cd3b6..7322303 100644 --- a/castle/client.py +++ b/castle/client.py @@ -18,6 +18,9 @@ from castle.commands.list_items.unarchive import CommandsListItemsUnarchive from castle.commands.privacy.request_data import CommandsPrivacyRequestData from castle.commands.privacy.delete_data import CommandsPrivacyDeleteData +from castle.commands.events.schema import CommandsEventsSchema +from castle.commands.events.query import CommandsEventsQuery +from castle.commands.events.group import CommandsEventsGroup from castle.configuration import configuration from castle.context.prepare import ContextPrepare from castle.errors import InternalServerError, RequestError @@ -138,6 +141,15 @@ def request_user_data(self, options): def delete_user_data(self, options): return self.api.call(CommandsPrivacyDeleteData.call(options)) + def events_schema(self, options=None): + return self.api.call(CommandsEventsSchema.call(options)) + + def query_events(self, options): + return self.api.call(CommandsEventsQuery.call(options)) + + def group_events(self, options): + return self.api.call(CommandsEventsGroup.call(options)) + def disable_tracking(self): self.do_not_track = True diff --git a/castle/commands/events/__init__.py b/castle/commands/events/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/castle/commands/events/group.py b/castle/commands/events/group.py new file mode 100644 index 0000000..da4b25a --- /dev/null +++ b/castle/commands/events/group.py @@ -0,0 +1,14 @@ +from castle.command import Command +from castle.validators.present import ValidatorsPresent + + +class CommandsEventsGroup(object): + @staticmethod + def call(options=None): + options = options or {} + for query_filter in options.get('filters') or []: + ValidatorsPresent.call(query_filter, 'field', 'op', 'value') + if options.get('sort'): + ValidatorsPresent.call(options['sort'], 'field', 'order') + + return Command(method='post', path='events/group', data=options) diff --git a/castle/commands/events/query.py b/castle/commands/events/query.py new file mode 100644 index 0000000..5f6f880 --- /dev/null +++ b/castle/commands/events/query.py @@ -0,0 +1,14 @@ +from castle.command import Command +from castle.validators.present import ValidatorsPresent + + +class CommandsEventsQuery(object): + @staticmethod + def call(options=None): + options = options or {} + for query_filter in options.get('filters') or []: + ValidatorsPresent.call(query_filter, 'field', 'op', 'value') + if options.get('sort'): + ValidatorsPresent.call(options['sort'], 'field', 'order') + + return Command(method='post', path='events/query', data=options) diff --git a/castle/commands/events/schema.py b/castle/commands/events/schema.py new file mode 100644 index 0000000..4157c79 --- /dev/null +++ b/castle/commands/events/schema.py @@ -0,0 +1,7 @@ +from castle.command import Command + + +class CommandsEventsSchema(object): + @staticmethod + def call(options=None): + return Command(method='get', path='events/schema', data=None) diff --git a/castle/test/__init__.py b/castle/test/__init__.py index 5f9cdf6..c053fcd 100644 --- a/castle/test/__init__.py +++ b/castle/test/__init__.py @@ -15,6 +15,7 @@ 'castle.test.commands.lists_test', 'castle.test.commands.list_items_test', 'castle.test.commands.privacy_test', + 'castle.test.commands.events_test', 'castle.test.configuration_test', 'castle.test.context.get_default_test', 'castle.test.context.merge_test', diff --git a/castle/test/client_test.py b/castle/test/client_test.py index b5fb740..449cb08 100644 --- a/castle/test/client_test.py +++ b/castle/test/client_test.py @@ -255,6 +255,42 @@ def test_delete_user_data(self): options = {'identifier': 'a@b.com', 'identifier_type': '$email'} self.assertEqual(client.delete_user_data(options), response_text) + @responses.activate + def test_events_schema(self): + response_text = {'fields': []} + responses.add( + responses.GET, + 'https://api.castle.io/v1/events/schema', + json=response_text, + status=200, + ) + client = Client.from_request(request(), {}) + self.assertEqual(client.events_schema(), response_text) + + @responses.activate + def test_query_events(self): + response_text = {'data': []} + responses.add( + responses.POST, + 'https://api.castle.io/v1/events/query', + json=response_text, + status=200, + ) + client = Client.from_request(request(), {}) + self.assertEqual(client.query_events({'filters': []}), response_text) + + @responses.activate + def test_group_events(self): + response_text = {'data': []} + responses.add( + responses.POST, + 'https://api.castle.io/v1/events/group', + json=response_text, + status=200, + ) + client = Client.from_request(request(), {}) + self.assertEqual(client.group_events({'filters': []}), response_text) + def test_disable_tracking(self): client = Client.from_request(request(), {}) client.disable_tracking() diff --git a/castle/test/commands/events_test.py b/castle/test/commands/events_test.py new file mode 100644 index 0000000..e5b6b2a --- /dev/null +++ b/castle/test/commands/events_test.py @@ -0,0 +1,39 @@ +from castle.test import unittest +from castle.command import Command +from castle.commands.events.schema import CommandsEventsSchema +from castle.commands.events.query import CommandsEventsQuery +from castle.commands.events.group import CommandsEventsGroup +from castle.errors import InvalidParametersError + + +class CommandsEventsTestCase(unittest.TestCase): + def test_schema(self): + self.assertEqual( + CommandsEventsSchema.call(), + Command(method='get', path='events/schema', data=None), + ) + + def test_query(self): + options = { + 'filters': [{'field': 'name', 'op': '$eq', 'value': 'x'}], + 'sort': {'field': 'created_at', 'order': 'desc'}, + } + self.assertEqual( + CommandsEventsQuery.call(options), + Command(method='post', path='events/query', data=options), + ) + + def test_query_invalid_filter(self): + with self.assertRaises(InvalidParametersError): + CommandsEventsQuery.call({'filters': [{'field': 'name'}]}) + + def test_group(self): + options = {'filters': [{'field': 'name', 'op': '$eq', 'value': 'x'}]} + self.assertEqual( + CommandsEventsGroup.call(options), + Command(method='post', path='events/group', data=options), + ) + + def test_group_invalid_sort(self): + with self.assertRaises(InvalidParametersError): + CommandsEventsGroup.call({'sort': {'field': 'created_at'}}) diff --git a/castle/version.py b/castle/version.py index 3e75d64..e5ec502 100644 --- a/castle/version.py +++ b/castle/version.py @@ -1 +1 @@ -VERSION = '7.0.0' +VERSION = '7.1.0'