diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 557d5ae..b09c505 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['8.1', '8.2', '8.3'] + php-versions: ['8.1', '8.2', '8.3', '8.4', '8.5'] steps: - uses: actions/checkout@v4 @@ -53,7 +53,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['8.1', '8.2', '8.3'] + php-versions: ['8.1', '8.2', '8.3', '8.4', '8.5'] steps: - uses: actions/checkout@v3 @@ -76,7 +76,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['8.1', '8.2', '8.3'] + php-versions: ['8.1', '8.2', '8.3', '8.4', '8.5'] steps: - uses: actions/checkout@v3 diff --git a/README.md b/README.md index 67eaab7..4aecca4 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ To see full documentation visit the official [documentation](https://adrosoftwar ## Requirements -* PHP >= 8.1 +* PHP >= 8.1 (tested through PHP 8.5) * A [PSR-17 implementation](https://packagist.org/providers/psr/http-factory-implementation) * A [PSR-18 implementation](https://packagist.org/providers/psr/http-client-implementation) @@ -58,6 +58,11 @@ $circleSo = CircleSo::make('5up3r53cr3770k3n'); $me = $circleSo->me()->info(); ``` +The V1 client covers the complete published API surface, including communities, +members, spaces, space groups, posts, comments, messages, events, attendees, +subscriptions, charges, likes, tags, courses, topics, notifications, contacts, +profile fields, and flagged content. + ## License This package is licensed under the MIT License - see the [LICENSE](https://github.com/adrosoftware/circle-so-api-php-sdk/blob/main/LICENSE) file for details @@ -69,4 +74,4 @@ This library is maintained by: ## Contributors -See all the contributors [here](https://github.com/adrosoftware/circle-so-api-php-sdk/graphs/contributors) \ No newline at end of file +See all the contributors [here](https://github.com/adrosoftware/circle-so-api-php-sdk/graphs/contributors) diff --git a/docs/content/usage/api.md b/docs/content/usage/api.md index 543b839..af4274b 100644 --- a/docs/content/usage/api.md +++ b/docs/content/usage/api.md @@ -67,3 +67,41 @@ $member = $circleSo->members()->update( skipInvitation: true // Optional ); ``` + +## V1 endpoint groups + +The client exposes the complete published V1 resource set: + +```php +$circleSo->communities(); +$circleSo->spaceGroups(); +$circleSo->spaceGroupMembers(); +$circleSo->spaces(); +$circleSo->spaceMembers(); +$circleSo->posts(); +$circleSo->comments(); +$circleSo->members(); +$circleSo->memberTags(); +$circleSo->taggedMembers(); +$circleSo->messages(); +$circleSo->subscriptions(); +$circleSo->events(); +$circleSo->eventAttendees(); +$circleSo->charges(); +$circleSo->likes(); +$circleSo->communityMemberSpaces(); +$circleSo->profileFields(); +$circleSo->courses(); +$circleSo->notifications(); +$circleSo->topics(); +$circleSo->contacts(); +$circleSo->flaggedContents(); +``` + +Set a community once when making several scoped calls: + +```php +$posts = $circleSo->posts() + ->communityId(123) + ->all(spaceId: 456); +``` diff --git a/src/AbstractClient.php b/src/AbstractClient.php index 10ba4f0..9e28ea7 100644 --- a/src/AbstractClient.php +++ b/src/AbstractClient.php @@ -17,6 +17,7 @@ use Http\Client\Common\Plugin\BaseUriPlugin; use Http\Client\Common\Plugin\HeaderDefaultsPlugin; use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\UriInterface; abstract class AbstractClient { @@ -26,6 +27,8 @@ abstract class AbstractClient protected ResponseTransformerInterface $responseTransformer; + private HeaderDefaultsPlugin $headerDefaultsPlugin; + public function __construct( protected string $token, protected ?Options $options = null, @@ -36,20 +39,25 @@ public function __construct( $this->responseFactory = $this->options->getResponseFactory(); $this->clientBuilder = $this->options->getClientBuilder(); - $this->clientBuilder->addPlugin(new BaseUriPlugin($this->options->getUri())); - $this->clientBuilder->addPlugin( - new HeaderDefaultsPlugin([ - 'User-Agent' => $this->options->getUserAgent(), - 'Content-Type' => 'application/json', - 'Accept' => 'application/json', - 'Authorization' => "Token {$this->token}", - ]) - ); + $this->headerDefaultsPlugin = new HeaderDefaultsPlugin([ + 'User-Agent' => $this->options->getUserAgent(), + 'Content-Type' => 'application/json', + 'Accept' => 'application/json', + 'Authorization' => "Token {$this->token}", + ]); + } + + public function getHttpClient(?UriInterface $baseUri = null): HttpMethodsClientInterface + { + return $this->clientBuilder->getHttpClient([ + new BaseUriPlugin($baseUri ?? $this->options->getUri()), + $this->headerDefaultsPlugin, + ]); } - public function getHttpClient(): HttpMethodsClientInterface + public function uri(string $uri): UriInterface { - return $this->clientBuilder->getHttpClient(); + return $this->options->getUriFactory()->createUri($uri); } public function getResponseTransformer(): ResponseTransformerInterface diff --git a/src/CircleSo.php b/src/CircleSo.php index d4a231a..173f2cb 100644 --- a/src/CircleSo.php +++ b/src/CircleSo.php @@ -6,14 +6,30 @@ use AdroSoftware\CircleSoSdk\Contracts\InteractsWithEndpoints; use AdroSoftware\CircleSoSdk\Endpoint\{ + Charge\Charges, + Comment\Comments, + CommunityMemberSpace\CommunityMemberSpaces, Community\Communities, + Contact\Contacts, Course\Courses, + Event\Events, + EventAttendee\EventAttendees, + FlaggedContent\FlaggedContents, + Like\Likes, Me\Me, Member\Members, MemberTag\MemberTag, + Message\Messages, + Notification\Notifications, + Post\Posts, + ProfileField\ProfileFields, Space\Spaces, SpaceGroup\SpaceGroups, + SpaceGroupMember\SpaceGroupMembers, + SpaceMember\SpaceMembers, + Subscription\Subscriptions, TaggedMembers\TaggedMembers, + Topic\Topics, }; final class CircleSo extends AbstractClient implements InteractsWithEndpoints @@ -64,4 +80,84 @@ public function taggedMembers(): TaggedMembers { return new TaggedMembers($this); } + + public function spaceGroupMembers(): SpaceGroupMembers + { + return new SpaceGroupMembers($this); + } + + public function spaceMembers(): SpaceMembers + { + return new SpaceMembers($this); + } + + public function posts(): Posts + { + return new Posts($this); + } + + public function comments(): Comments + { + return new Comments($this); + } + + public function messages(): Messages + { + return new Messages($this); + } + + public function subscriptions(): Subscriptions + { + return new Subscriptions($this); + } + + public function events(): Events + { + return new Events($this); + } + + public function eventAttendees(): EventAttendees + { + return new EventAttendees($this); + } + + public function charges(): Charges + { + return new Charges($this); + } + + public function likes(): Likes + { + return new Likes($this); + } + + public function communityMemberSpaces(): CommunityMemberSpaces + { + return new CommunityMemberSpaces($this); + } + + public function profileFields(): ProfileFields + { + return new ProfileFields($this); + } + + public function notifications(): Notifications + { + return new Notifications($this); + } + + public function topics(): Topics + { + return new Topics($this); + } + + public function contacts(): Contacts + { + return new Contacts($this); + } + + public function flaggedContents(): FlaggedContents + { + return new FlaggedContents($this); + } } diff --git a/src/ClientBuilder.php b/src/ClientBuilder.php index 683412f..916dcde 100644 --- a/src/ClientBuilder.php +++ b/src/ClientBuilder.php @@ -33,9 +33,13 @@ public function addPlugin(Plugin $plugin): void $this->plugins[] = $plugin; } - public function getHttpClient(): HttpMethodsClientInterface + /** @param array $plugins */ + public function getHttpClient(array $plugins = []): HttpMethodsClientInterface { - $pluginClient = (new PluginClientFactory())->createClient($this->httpClient, $this->plugins); + $pluginClient = (new PluginClientFactory())->createClient( + $this->httpClient, + [...$this->plugins, ...$plugins], + ); return new HttpMethodsClient( $pluginClient, diff --git a/src/Contracts/InteractsWithEndpoints.php b/src/Contracts/InteractsWithEndpoints.php index 94fbf51..975167d 100644 --- a/src/Contracts/InteractsWithEndpoints.php +++ b/src/Contracts/InteractsWithEndpoints.php @@ -5,11 +5,30 @@ namespace AdroSoftware\CircleSoSdk\Contracts; use AdroSoftware\CircleSoSdk\Endpoint\{ + Charge\Charges, + Comment\Comments, Community\Communities, + CommunityMemberSpace\CommunityMemberSpaces, + Contact\Contacts, + Course\Courses, + Event\Events, + EventAttendee\EventAttendees, + FlaggedContent\FlaggedContents, + Like\Likes, Me\Me, Member\Members, MemberTag\MemberTag, + Message\Messages, + Notification\Notifications, + Post\Posts, + ProfileField\ProfileFields, + Space\Spaces, + SpaceGroup\SpaceGroups, + SpaceGroupMember\SpaceGroupMembers, + SpaceMember\SpaceMembers, + Subscription\Subscriptions, TaggedMembers\TaggedMembers, + Topic\Topics, }; interface InteractsWithEndpoints @@ -23,4 +42,42 @@ public function members(): Members; public function memberTags(): MemberTag; public function taggedMembers(): TaggedMembers; + + public function courses(): Courses; + + public function spaces(): Spaces; + + public function spaceGroups(): SpaceGroups; + + public function spaceGroupMembers(): SpaceGroupMembers; + + public function spaceMembers(): SpaceMembers; + + public function posts(): Posts; + + public function comments(): Comments; + + public function messages(): Messages; + + public function subscriptions(): Subscriptions; + + public function events(): Events; + + public function eventAttendees(): EventAttendees; + + public function charges(): Charges; + + public function likes(): Likes; + + public function communityMemberSpaces(): CommunityMemberSpaces; + + public function profileFields(): ProfileFields; + + public function notifications(): Notifications; + + public function topics(): Topics; + + public function contacts(): Contacts; + + public function flaggedContents(): FlaggedContents; } diff --git a/src/Endpoint/AbstractEndpoint.php b/src/Endpoint/AbstractEndpoint.php index a1dbe10..0401ea3 100644 --- a/src/Endpoint/AbstractEndpoint.php +++ b/src/Endpoint/AbstractEndpoint.php @@ -12,6 +12,7 @@ UnsuccessfulResponseException, }; use Psr\Http\Message\ResponseInterface; +use JsonException; abstract class AbstractEndpoint { @@ -31,13 +32,63 @@ public function communityId(int $communityId): static */ protected function ensureCommunityIdIsPresent(?int $communityId = null): void { - if ($communityId === null && $this->communityId === null) { - throw new CommunityIdNotPresentException(); + if ($communityId !== null) { + $this->communityId = $communityId; } if ($this->communityId === null) { - $this->communityId === $communityId; + throw new CommunityIdNotPresentException(); + } + } + + /** + * @param array $query + * @param array|null $data + * @throws JsonException + */ + protected function request( + string $method, + string $path, + array $query = [], + ?array $data = null, + bool $throwNotFoundException = false, + ): mixed { + $query = array_filter($query, static fn (mixed $value): bool => $value !== null); + $uri = $path; + + if ($query !== []) { + $uri .= (str_contains($uri, '?') ? '&' : '?') . http_build_query( + $query, + '', + '&', + PHP_QUERY_RFC3986, + ); } + + $body = $data === null ? null : json_encode($data, JSON_THROW_ON_ERROR); + $client = str_starts_with($path, '/public/') + ? $this->circleSo->getHttpClient($this->circleSo->uri('https://app.circle.so/')) + : $this->circleSo->getHttpClient(); + $response = match (strtoupper($method)) { + 'GET' => $client->get($uri), + 'POST' => $client->post($uri, [], $body), + 'PUT' => $client->put($uri, [], $body), + 'PATCH' => $client->patch($uri, [], $body), + 'DELETE' => $client->delete($uri, [], $body), + default => throw new \InvalidArgumentException("Unsupported HTTP method: {$method}"), + }; + + return $this->factorResponse($response, $throwNotFoundException); + } + + /** + * @return array{community_id: int} + */ + protected function communityQuery(?int $communityId = null): array + { + $this->ensureCommunityIdIsPresent($communityId); + + return ['community_id' => $this->communityId]; } /** diff --git a/src/Endpoint/Charge/Charges.php b/src/Endpoint/Charge/Charges.php new file mode 100644 index 0000000..8d7748d --- /dev/null +++ b/src/Endpoint/Charge/Charges.php @@ -0,0 +1,20 @@ +request('GET', '/community_member_charges', [ + ...$this->communityQuery($communityId), + 'per_page' => $perPage, + 'page' => $page, + ]); + } +} diff --git a/src/Endpoint/Comment/Comments.php b/src/Endpoint/Comment/Comments.php new file mode 100644 index 0000000..b85878b --- /dev/null +++ b/src/Endpoint/Comment/Comments.php @@ -0,0 +1,45 @@ +request('GET', '/comments', [ + ...$this->communityQuery($communityId), + 'space_id' => $spaceId, + 'post_id' => $postId, + 'topic_id' => $topicId, + ]); + } + + public function show(int $id, ?int $communityId = null): mixed + { + return $this->request('GET', "/comments/{$id}", $this->communityQuery($communityId)); + } + + /** @param array $data */ + public function create(int $spaceId, int $postId, array $data, ?int $communityId = null): mixed + { + return $this->request('POST', '/comments', [ + ...$this->communityQuery($communityId), + 'space_id' => $spaceId, + 'post_id' => $postId, + ], $data); + } + + public function delete(int $id, ?int $communityId = null): mixed + { + return $this->request('DELETE', "/comments/{$id}", $this->communityQuery($communityId)); + } +} diff --git a/src/Endpoint/Community/Communities.php b/src/Endpoint/Community/Communities.php index 2ff6af7..c2126cf 100644 --- a/src/Endpoint/Community/Communities.php +++ b/src/Endpoint/Community/Communities.php @@ -11,17 +11,15 @@ final class Communities extends AbstractEndpoint implements EndpointInterface { public function all(): mixed { - return $this->factorResponse( - $this->circleSo->getHttpClient()->get('/communities') - ); + return $this->request('GET', '/communities'); } public function community(string $slug, ?int $communityId = null): mixed { - $this->ensureCommunityIdIsPresent($communityId); - - return $this->factorResponse( - response: $this->circleSo->getHttpClient()->get('/communities'), + return $this->request( + 'GET', + "/communities/{$this->communityQuery($communityId)['community_id']}", + ['slug' => $slug], throwNotFoundException: true, ); } diff --git a/src/Endpoint/CommunityMemberSpace/CommunityMemberSpaces.php b/src/Endpoint/CommunityMemberSpace/CommunityMemberSpaces.php new file mode 100644 index 0000000..5730bff --- /dev/null +++ b/src/Endpoint/CommunityMemberSpace/CommunityMemberSpaces.php @@ -0,0 +1,16 @@ +request('GET', '/community_member_spaces', ['user_email' => $userEmail]); + } +} diff --git a/src/Endpoint/Contact/Contacts.php b/src/Endpoint/Contact/Contacts.php new file mode 100644 index 0000000..0a849fa --- /dev/null +++ b/src/Endpoint/Contact/Contacts.php @@ -0,0 +1,17 @@ + $data */ + public function create(array $data): mixed + { + return $this->request('POST', '/contacts', data: $data); + } +} diff --git a/src/Endpoint/Cource/Coruces.php b/src/Endpoint/Cource/Coruces.php deleted file mode 100644 index f78caf7..0000000 --- a/src/Endpoint/Cource/Coruces.php +++ /dev/null @@ -1,153 +0,0 @@ -ensureCommunityIdIsPresent($communityId); - - $query = [ - 'community_id' => $this->communityId, - 'space_id' => $spaceId, - ]; - - if ($page) { - $query['page'] = $page; - } - - if ($perPage) { - $query['per_page'] = $perPage; - } - - return $this->factorResponse( - $this->circleSo->getHttpClient()->get( - '/course_sections?' . http_build_query($query) - ) - ); - } - - /** - * @throws CommunityIdNotPresentException - * @throws UnsuccessfulResponseException - */ - public function showSection(int $id, ?int $communityId = null): mixed - { - $this->ensureCommunityIdIsPresent($communityId); - - return $this->factorResponse( - $this->circleSo->getHttpClient()->get( - "/course_sections/{$id}?community_id={$this->communityId}" - ) - ); - } - - /** - * @throws CommunityIdNotPresentException - */ - public function lessons( - int $spaceId, - int $sectionId, - ?int $communityId = null, - ?int $page = null, - ?int $perPage = null, - ): mixed { - $this->ensureCommunityIdIsPresent($communityId); - - $query = [ - 'community_id' => $this->communityId, - 'space_id' => $spaceId, - 'section_id' => $sectionId, - ]; - - if ($page) { - $query['page'] = $page; - } - - if ($perPage) { - $query['per_page'] = $perPage; - } - - return $this->factorResponse( - $this->circleSo->getHttpClient()->get( - '/course_lessons?' . http_build_query($query) - ) - ); - } - - /** - * @throws CommunityIdNotPresentException - * @throws UnsuccessfulResponseException - */ - public function showLesson(int $id, ?int $communityId = null): mixed - { - $this->ensureCommunityIdIsPresent($communityId); - - return $this->factorResponse( - $this->circleSo->getHttpClient()->get( - "/course_lessons/{$id}?community_id={$this->communityId}" - ) - ); - } - - /** - * Create a course lesson. - * - * @param array $data - * @throws CommunityIdNotPresentException - * @throws UnsuccessfulResponseException - */ - public function createLesson( - array $data, - ?int $communityId = null, - ): mixed { - $this->ensureCommunityIdIsPresent($communityId); - - return $this->factorResponse( - $this->circleSo->getHttpClient()->post( - uri: "/course_lessons?community_id={$this->communityId}", - body: json_encode($data), - ) - ); - } - - /** - * Delete a course lesson. - * - * @throws CommunityIdNotPresentException - * @throws Exception - * @throws RequestUnauthorizedException - * @throws ResourceNotFoundException - * @throws UnsuccessfulResponseException - */ - public function deleteLesson( - int $id, - ?int $communityId = null, - ): mixed { - $this->ensureCommunityIdIsPresent($communityId); - - return $this->factorResponse( - $this->circleSo->getHttpClient()->delete( - "/course_lessons/{$id}?community_id={$this->communityId}", - ) - ); - } -} diff --git a/src/Endpoint/Course/Courses.php b/src/Endpoint/Course/Courses.php new file mode 100644 index 0000000..756104e --- /dev/null +++ b/src/Endpoint/Course/Courses.php @@ -0,0 +1,97 @@ +request('GET', '/course_sections', [ + ...$this->communityQuery($communityId), + 'space_id' => $spaceId, + 'page' => $page, + 'per_page' => $perPage, + ]); + } + + public function showSection(int $id, ?int $communityId = null): mixed + { + return $this->request('GET', "/course_sections/{$id}", $this->communityQuery($communityId)); + } + + /** @param array $data */ + public function createSection(array $data, ?int $communityId = null): mixed + { + return $this->request('POST', '/course_sections', $this->communityQuery($communityId), $data); + } + + /** @param array $data */ + public function updateSection(int $id, array $data, ?int $communityId = null): mixed + { + return $this->request('PATCH', "/course_sections/{$id}", $this->communityQuery($communityId), $data); + } + + public function deleteSection(int $id, ?int $communityId = null): mixed + { + return $this->request('DELETE', "/course_sections/{$id}", $this->communityQuery($communityId)); + } + + public function lessons( + ?int $spaceId = null, + ?int $sectionId = null, + ?int $communityId = null, + ?int $page = null, + ?int $perPage = null, + ): mixed { + return $this->request('GET', '/course_lessons', [ + ...$this->communityQuery($communityId), + 'space_id' => $spaceId, + 'section_id' => $sectionId, + 'page' => $page, + 'per_page' => $perPage, + ]); + } + + public function showLesson(int $id, ?int $communityId = null): mixed + { + return $this->request('GET', "/course_lessons/{$id}", $this->communityQuery($communityId)); + } + + /** @param array $data */ + public function createLesson(array $data, ?int $communityId = null): mixed + { + return $this->request('POST', '/course_lessons', $this->communityQuery($communityId), $data); + } + + /** @param array $data */ + public function updateLesson(int $id, array $data, ?int $communityId = null): mixed + { + return $this->request('PATCH', "/course_lessons/{$id}", $this->communityQuery($communityId), $data); + } + + public function deleteLesson(int $id, ?int $communityId = null): mixed + { + return $this->request('DELETE', "/course_lessons/{$id}", $this->communityQuery($communityId)); + } + + public function updateLessonProgress( + int $lessonId, + string $memberEmail, + ?int $communityId = null, + ): mixed { + return $this->request('PATCH', '/course_lesson_progress', [ + ...$this->communityQuery($communityId), + 'lesson_id' => $lessonId, + 'member_email' => $memberEmail, + ]); + } +} diff --git a/src/Endpoint/Event/Events.php b/src/Endpoint/Event/Events.php new file mode 100644 index 0000000..d0ba353 --- /dev/null +++ b/src/Endpoint/Event/Events.php @@ -0,0 +1,46 @@ +request('GET', '/events', [ + ...$this->communityQuery($communityId), + 'per_page' => $perPage, + 'page' => $page, + ]); + } + + /** @param array $data */ + public function create(int $spaceId, array $data, ?int $communityId = null): mixed + { + return $this->request('POST', '/events', [ + ...$this->communityQuery($communityId), + 'space_id' => $spaceId, + ], $data); + } + + /** @param array $data */ + public function update(int $id, int $spaceId, array $data, ?int $communityId = null): mixed + { + return $this->request('PUT', "/events/{$id}", [ + ...$this->communityQuery($communityId), + 'space_id' => $spaceId, + ], $data); + } + + public function delete(int $id, int $spaceId, ?int $communityId = null): mixed + { + return $this->request('DELETE', "/events/{$id}", [ + ...$this->communityQuery($communityId), + 'space_id' => $spaceId, + ]); + } +} diff --git a/src/Endpoint/EventAttendee/EventAttendees.php b/src/Endpoint/EventAttendee/EventAttendees.php new file mode 100644 index 0000000..dce82ad --- /dev/null +++ b/src/Endpoint/EventAttendee/EventAttendees.php @@ -0,0 +1,43 @@ +request('GET', '/event_attendees', [ + ...$this->communityQuery($communityId), + 'event_id' => $eventId, + 'per_page' => $perPage, + 'page' => $page, + ]); + } + + public function rsvp(int $eventId, string $memberEmail, ?int $communityId = null): mixed + { + return $this->request('POST', '/event_attendees', [ + ...$this->communityQuery($communityId), + 'event_id' => $eventId, + 'member_email' => $memberEmail, + ]); + } + + public function remove(int $eventId, string $memberEmail, ?int $communityId = null): mixed + { + return $this->request('DELETE', '/event_attendees', [ + ...$this->communityQuery($communityId), + 'event_id' => $eventId, + 'member_email' => $memberEmail, + ]); + } +} diff --git a/src/Endpoint/FlaggedContent/FlaggedContents.php b/src/Endpoint/FlaggedContent/FlaggedContents.php new file mode 100644 index 0000000..b6eea87 --- /dev/null +++ b/src/Endpoint/FlaggedContent/FlaggedContents.php @@ -0,0 +1,25 @@ +request('GET', '/flagged_contents', [ + ...$this->communityQuery($communityId), + 'per_page' => $perPage, + 'page' => $page, + 'status' => $status, + ]); + } +} diff --git a/src/Endpoint/Like/Likes.php b/src/Endpoint/Like/Likes.php new file mode 100644 index 0000000..8a5c842 --- /dev/null +++ b/src/Endpoint/Like/Likes.php @@ -0,0 +1,41 @@ +request('GET', "/posts/{$postId}/likes"); + } + + public function likePost(int $postId, ?string $userEmail = null): mixed + { + return $this->request('POST', "/posts/{$postId}/likes", ['user_email' => $userEmail]); + } + + public function unlikePost(int $postId, ?string $userEmail = null): mixed + { + return $this->request('DELETE', "/posts/{$postId}/likes", ['user_email' => $userEmail]); + } + + public function forComment(int $commentId): mixed + { + return $this->request('GET', "/comments/{$commentId}/likes"); + } + + public function likeComment(int $commentId, ?string $userEmail = null): mixed + { + return $this->request('POST', "/comments/{$commentId}/likes", ['user_email' => $userEmail]); + } + + public function unlikeComment(int $commentId, ?string $userEmail = null): mixed + { + return $this->request('DELETE', "/comments/{$commentId}/likes", ['user_email' => $userEmail]); + } +} diff --git a/src/Endpoint/Me/Me.php b/src/Endpoint/Me/Me.php index 9f4bc3e..5c67adf 100644 --- a/src/Endpoint/Me/Me.php +++ b/src/Endpoint/Me/Me.php @@ -11,8 +11,6 @@ final class Me extends AbstractEndpoint implements EndpointInterface { public function info(): mixed { - return $this->factorResponse( - $this->circleSo->getHttpClient()->get('/me') - ); + return $this->request('GET', '/me'); } } diff --git a/src/Endpoint/Member/Members.php b/src/Endpoint/Member/Members.php index 70f4288..7fa9253 100644 --- a/src/Endpoint/Member/Members.php +++ b/src/Endpoint/Member/Members.php @@ -20,20 +20,15 @@ public function communityMembers( ?int $page = null, ?string $status = null, ): mixed { - $this->ensureCommunityIdIsPresent($communityId); - $query = [ + ...$this->communityQuery($communityId), 'sort' => $sortBy ?? 'latest', 'per_page' => $perPage ?? 10, 'page' => $page ?? 1, 'status' => $status ?? 'active', ]; - return $this->factorResponse( - $this->circleSo->getHttpClient()->get( - "/community_members?" . http_build_query($query) - ) - ); + return $this->request('GET', '/community_members', $query); } /** @@ -41,13 +36,10 @@ public function communityMembers( */ public function search(string $email, ?int $communityId = null): mixed { - $this->ensureCommunityIdIsPresent($communityId); - - return $this->factorResponse( - $this->circleSo->getHttpClient()->get( - "/community_members/search?community_id={$this->communityId}&email={$email}" - ) - ); + return $this->request('GET', '/community_members/search', [ + ...$this->communityQuery($communityId), + 'email' => $email, + ]); } /** @@ -56,13 +48,7 @@ public function search(string $email, ?int $communityId = null): mixed */ public function member(int $id, ?int $communityId = null): mixed { - $this->ensureCommunityIdIsPresent($communityId); - - return $this->factorResponse( - $this->circleSo->getHttpClient()->get( - "/community_members/{$id}?community_id={$this->communityId}" - ) - ); + return $this->request('GET', "/community_members/{$id}", $this->communityQuery($communityId)); } /** @@ -105,10 +91,8 @@ public function update( ?array $spaceGroupIds = null, ?bool $skipInvitation = null, ): mixed { - $this->ensureCommunityIdIsPresent($communityId); - $params = [ - 'community_id' => $this->communityId, + ...$this->communityQuery($communityId), ]; if (is_array($spaceIds)) { @@ -119,18 +103,9 @@ public function update( $params['space_group_ids'] = '[' . implode(',', $spaceGroupIds) . ']'; } - if ($skipInvitation) { - $params['skip_invitation'] = 'true'; - } - - $endpoint = "/community_members/{$id}?" . urldecode(http_build_query($params)); + $params['skip_invitation'] = $skipInvitation; - return $this->factorResponse( - $this->circleSo->getHttpClient()->put( - uri: $endpoint, - body: json_encode($data), - ) - ); + return $this->request('PUT', "/community_members/{$id}", $params, $data); } /** @@ -138,13 +113,10 @@ public function update( */ public function remove(string $email, ?int $communityId = null): mixed { - $this->ensureCommunityIdIsPresent($communityId); - - return $this->factorResponse( - $this->circleSo->getHttpClient()->delete( - "/community_members?community_id={$this->communityId}&email={$email}" - ) - ); + return $this->request('DELETE', '/community_members', [ + ...$this->communityQuery($communityId), + 'email' => $email, + ]); } /** @@ -152,22 +124,14 @@ public function remove(string $email, ?int $communityId = null): mixed */ public function invite(string $email, ?int $communityId = null): mixed { - $endpoint = "/community_members/"; - $data = [ 'email' => $email, ]; - if (!empty($communityId)) { - $this->ensureCommunityIdIsPresent($communityId); - $data['community_id'] = $communityId; + if ($communityId !== null || $this->communityId !== null) { + $data['community_id'] = $this->communityQuery($communityId)['community_id']; } - return $this->factorResponse( - $this->circleSo->getHttpClient()->post( - uri: $endpoint, - body: json_encode($data), - ) - ); + return $this->request('POST', '/community_members', data: $data); } } diff --git a/src/Endpoint/MemberTag/MemberTag.php b/src/Endpoint/MemberTag/MemberTag.php index 525597a..6df8ca1 100644 --- a/src/Endpoint/MemberTag/MemberTag.php +++ b/src/Endpoint/MemberTag/MemberTag.php @@ -18,13 +18,7 @@ final class MemberTag extends AbstractEndpoint implements EndpointInterface */ public function memberTags(?int $communityId = null): mixed { - $this->ensureCommunityIdIsPresent($communityId); - - return $this->factorResponse( - $this->circleSo->getHttpClient()->get( - "/member_tags?community_id={$this->communityId}" - ) - ); + return $this->request('GET', '/member_tags', $this->communityQuery($communityId)); } /** @@ -33,12 +27,6 @@ public function memberTags(?int $communityId = null): mixed */ public function show(int $id, ?int $communityId = null): mixed { - $this->ensureCommunityIdIsPresent($communityId); - - return $this->factorResponse( - $this->circleSo->getHttpClient()->get( - "/member_tags/{$id}?community_id={$this->communityId}" - ) - ); + return $this->request('GET', "/member_tags/{$id}", $this->communityQuery($communityId)); } } diff --git a/src/Endpoint/Message/Messages.php b/src/Endpoint/Message/Messages.php new file mode 100644 index 0000000..2048b29 --- /dev/null +++ b/src/Endpoint/Message/Messages.php @@ -0,0 +1,31 @@ + $userEmails */ + public function group(array $userEmails, string $message, ?int $communityId = null): mixed + { + return $this->request( + 'POST', + '/messages', + [...$this->communityQuery($communityId), 'message_body' => $message], + ['user_emails' => $userEmails], + ); + } + + public function direct(string $userEmail, string $message, ?int $communityId = null): mixed + { + return $this->request('POST', '/messages', [ + ...$this->communityQuery($communityId), + 'user_email' => $userEmail, + 'message_body' => $message, + ]); + } +} diff --git a/src/Endpoint/Notification/Notifications.php b/src/Endpoint/Notification/Notifications.php new file mode 100644 index 0000000..a375add --- /dev/null +++ b/src/Endpoint/Notification/Notifications.php @@ -0,0 +1,39 @@ + $query */ + public function unsubscribe(array $query): mixed + { + return $this->request('GET', self::PUBLIC_BASE_URI . '/unsubscribe', $query); + } + + /** @param array $query */ + public function preferences(array $query): mixed + { + return $this->request('GET', self::PUBLIC_BASE_URI . '/notification_preferences', $query); + } + + /** + * @param array $data + * @param array $query + */ + public function updatePreferences(array $data, array $query = []): mixed + { + return $this->request( + 'PATCH', + self::PUBLIC_BASE_URI . '/notification_preferences', + $query, + $data, + ); + } +} diff --git a/src/Endpoint/Post/Posts.php b/src/Endpoint/Post/Posts.php new file mode 100644 index 0000000..755f7a1 --- /dev/null +++ b/src/Endpoint/Post/Posts.php @@ -0,0 +1,46 @@ + $topicIds */ + public function all(int $spaceId, ?int $communityId = null, array $topicIds = []): mixed + { + return $this->request('GET', '/posts', [ + ...$this->communityQuery($communityId), + 'space_id' => $spaceId, + 'topics' => $topicIds === [] ? null : $topicIds, + ]); + } + + public function show(int $id, ?int $communityId = null): mixed + { + return $this->request('GET', "/posts/{$id}", $this->communityQuery($communityId)); + } + + /** @param array $data */ + public function create(int $spaceId, array $data, ?int $communityId = null): mixed + { + return $this->request('POST', '/posts', [ + ...$this->communityQuery($communityId), + 'space_id' => $spaceId, + ], $data); + } + + /** @param array $data */ + public function update(int $id, array $data, ?int $communityId = null): mixed + { + return $this->request('PUT', "/posts/{$id}", $this->communityQuery($communityId), $data); + } + + public function delete(int $id, ?int $communityId = null): mixed + { + return $this->request('DELETE', "/posts/{$id}", $this->communityQuery($communityId)); + } +} diff --git a/src/Endpoint/ProfileField/ProfileFields.php b/src/Endpoint/ProfileField/ProfileFields.php new file mode 100644 index 0000000..405d826 --- /dev/null +++ b/src/Endpoint/ProfileField/ProfileFields.php @@ -0,0 +1,16 @@ +request('GET', '/page_profile_fields', ['page_name' => $pageName]); + } +} diff --git a/src/Endpoint/Space/Spaces.php b/src/Endpoint/Space/Spaces.php index 15e4976..f4984a6 100644 --- a/src/Endpoint/Space/Spaces.php +++ b/src/Endpoint/Space/Spaces.php @@ -16,15 +16,18 @@ class Spaces extends AbstractEndpoint implements EndpointInterface /** * @throws CommunityIdNotPresentException */ - public function spaces(?int $communityId = null): mixed - { - $this->ensureCommunityIdIsPresent($communityId); - - return $this->factorResponse( - $this->circleSo->getHttpClient()->get( - "/spaces?community_id={$this->communityId}" - ) - ); + public function spaces( + ?int $communityId = null, + ?string $sort = null, + ?int $perPage = null, + ?int $page = null, + ): mixed { + return $this->request('GET', '/spaces', [ + ...$this->communityQuery($communityId), + 'sort' => $sort, + 'per_page' => $perPage, + 'page' => $page, + ]); } /** @@ -33,13 +36,7 @@ public function spaces(?int $communityId = null): mixed */ public function show(int $id, ?int $communityId = null): mixed { - $this->ensureCommunityIdIsPresent($communityId); - - return $this->factorResponse( - $this->circleSo->getHttpClient()->get( - "/spaces/{$id}?community_id={$this->communityId}" - ) - ); + return $this->request('GET', "/spaces/{$id}", $this->communityQuery($communityId)); } /** @@ -65,14 +62,7 @@ public function create( array $data, ?int $communityId = null, ): mixed { - $this->ensureCommunityIdIsPresent($communityId); - - return $this->factorResponse( - $this->circleSo->getHttpClient()->post( - uri: "/spaces?community_id={$this->communityId}", - body: json_encode($data), - ) - ); + return $this->request('POST', '/spaces', $this->communityQuery($communityId), $data); } /** @@ -85,25 +75,16 @@ public function delete( int $id, ?int $communityId = null, ): mixed { - $this->ensureCommunityIdIsPresent($communityId); - - return $this->factorResponse( - $this->circleSo->getHttpClient()->delete( - "/spaces/{$id}?community_id={$this->communityId}", - ) - ); + return $this->request('DELETE', "/spaces/{$id}", $this->communityQuery($communityId)); } public function members( int $id, ?int $communityId = null ): mixed { - $this->ensureCommunityIdIsPresent($communityId); - - return $this->factorResponse( - $this->circleSo->getHttpClient()->delete( - "/space_members/{$id}?space_id={$id}&community_id={$this->communityId}", - ) - ); + return $this->request('GET', '/space_members', [ + ...$this->communityQuery($communityId), + 'space_id' => $id, + ]); } } diff --git a/src/Endpoint/SpaceGroup/SpaceGroups.php b/src/Endpoint/SpaceGroup/SpaceGroups.php index fd7f099..1857d9a 100644 --- a/src/Endpoint/SpaceGroup/SpaceGroups.php +++ b/src/Endpoint/SpaceGroup/SpaceGroups.php @@ -18,13 +18,7 @@ class SpaceGroups extends AbstractEndpoint implements EndpointInterface */ public function spaceGroups(?int $communityId = null): mixed { - $this->ensureCommunityIdIsPresent($communityId); - - return $this->factorResponse( - $this->circleSo->getHttpClient()->get( - "/space_groups?community_id={$this->communityId}" - ) - ); + return $this->request('GET', '/space_groups', $this->communityQuery($communityId)); } /** @@ -33,13 +27,7 @@ public function spaceGroups(?int $communityId = null): mixed */ public function show(int $id, ?int $communityId = null): mixed { - $this->ensureCommunityIdIsPresent($communityId); - - return $this->factorResponse( - $this->circleSo->getHttpClient()->get( - "/space_groups/{$id}?community_id={$this->communityId}" - ) - ); + return $this->request('GET', "/space_groups/{$id}", $this->communityQuery($communityId)); } /** @@ -67,14 +55,7 @@ public function create( array $data, ?int $communityId = null, ): mixed { - $this->ensureCommunityIdIsPresent($communityId); - - return $this->factorResponse( - $this->circleSo->getHttpClient()->post( - uri: "/space_groups?community_id={$this->communityId}", - body: json_encode($data), - ) - ); + return $this->request('POST', '/space_groups', $this->communityQuery($communityId), $data); } /** @@ -101,14 +82,7 @@ public function update( array $data, ?int $communityId = null, ): mixed { - $this->ensureCommunityIdIsPresent($communityId); - - return $this->factorResponse( - $this->circleSo->getHttpClient()->put( - uri: "/space_groups/{$id}?community_id={$this->communityId}", - body: json_encode($data), - ) - ); + return $this->request('PUT', "/space_groups/{$id}", $this->communityQuery($communityId), $data); } /** @@ -121,12 +95,6 @@ public function delete( int $id, ?int $communityId = null, ): mixed { - $this->ensureCommunityIdIsPresent($communityId); - - return $this->factorResponse( - $this->circleSo->getHttpClient()->delete( - "/space_groups/{$id}?community_id={$this->communityId}", - ) - ); + return $this->request('DELETE', "/space_groups/{$id}", $this->communityQuery($communityId)); } } diff --git a/src/Endpoint/SpaceGroupMember/SpaceGroupMembers.php b/src/Endpoint/SpaceGroupMember/SpaceGroupMembers.php new file mode 100644 index 0000000..0254ac0 --- /dev/null +++ b/src/Endpoint/SpaceGroupMember/SpaceGroupMembers.php @@ -0,0 +1,38 @@ +request('GET', '/space_group_member', [ + ...$this->communityQuery($communityId), + 'email' => $email, + 'space_group_id' => $spaceGroupId, + ]); + } + + public function add(string $email, int $spaceGroupId, ?int $communityId = null): mixed + { + return $this->request('POST', '/space_group_members', [ + ...$this->communityQuery($communityId), + 'email' => $email, + 'space_group_id' => $spaceGroupId, + ]); + } + + public function remove(string $email, int $spaceGroupId, ?int $communityId = null): mixed + { + return $this->request('DELETE', '/space_group_members', [ + ...$this->communityQuery($communityId), + 'email' => $email, + 'space_group_id' => $spaceGroupId, + ]); + } +} diff --git a/src/Endpoint/SpaceMember/SpaceMembers.php b/src/Endpoint/SpaceMember/SpaceMembers.php new file mode 100644 index 0000000..f157774 --- /dev/null +++ b/src/Endpoint/SpaceMember/SpaceMembers.php @@ -0,0 +1,29 @@ +request('POST', '/space_members', [ + ...$this->communityQuery($communityId), + 'email' => $email, + 'space_id' => $spaceId, + ]); + } + + public function remove(string $email, int $spaceId, ?int $communityId = null): mixed + { + return $this->request('DELETE', '/space_members', [ + ...$this->communityQuery($communityId), + 'email' => $email, + 'space_id' => $spaceId, + ]); + } +} diff --git a/src/Endpoint/Subscription/Subscriptions.php b/src/Endpoint/Subscription/Subscriptions.php new file mode 100644 index 0000000..f672eb2 --- /dev/null +++ b/src/Endpoint/Subscription/Subscriptions.php @@ -0,0 +1,20 @@ +request('GET', '/community_member_subscriptions', [ + ...$this->communityQuery($communityId), + 'per_page' => $perPage, + 'page' => $page, + ]); + } +} diff --git a/src/Endpoint/TaggedMembers/TaggedMembers.php b/src/Endpoint/TaggedMembers/TaggedMembers.php index 858ecf8..afafc90 100644 --- a/src/Endpoint/TaggedMembers/TaggedMembers.php +++ b/src/Endpoint/TaggedMembers/TaggedMembers.php @@ -13,27 +13,29 @@ final class TaggedMembers extends AbstractEndpoint implements EndpointInterface { + public function all(?string $sort = null, ?int $perPage = null, ?int $page = null): mixed + { + return $this->request('GET', '/tagged_members', [ + 'sort' => $sort, + 'per_page' => $perPage, + 'page' => $page, + ]); + } + + public function show(int $id): mixed + { + return $this->request('GET', "/tagged_members/{$id}"); + } + /** * @throws CommunityIdNotPresentException */ public function tagMember(string|array $email, int $memberTagId): mixed { - if (is_array($email)) { - $emailParam = ''; - foreach ($email as $e) { - $emailParam .= "user_email[]={$e}&"; - } - - $emailParam = trim($emailParam, '&'); - } else { - $emailParam = "user_email={$email}"; - } - - return $this->factorResponse( - $this->circleSo->getHttpClient()->post( - "/tagged_members?{$emailParam}&member_tag_id={$memberTagId}" - ) - ); + return $this->request('POST', '/tagged_members', [ + 'user_email' => $email, + 'member_tag_id' => $memberTagId, + ]); } /** @@ -41,12 +43,10 @@ public function tagMember(string|array $email, int $memberTagId): mixed */ public function untagMember(string $email, int $memberTagId, ?int $communityId = null): mixed { - $this->ensureCommunityIdIsPresent($communityId); - - return $this->factorResponse( - $this->circleSo->getHttpClient()->delete( - "/tagged_members?email={$email}&member_tag_id={$memberTagId}&community_id={$this->communityId}" - ) - ); + return $this->request('DELETE', '/tagged_members', [ + 'email' => $email, + 'member_tag_id' => $memberTagId, + ...$this->communityQuery($communityId), + ]); } } diff --git a/src/Endpoint/Topic/Topics.php b/src/Endpoint/Topic/Topics.php new file mode 100644 index 0000000..ed6f60a --- /dev/null +++ b/src/Endpoint/Topic/Topics.php @@ -0,0 +1,37 @@ +request('GET', '/topics', [ + ...$this->communityQuery($communityId), + 'per_page' => $perPage, + 'page' => $page, + ]); + } + + /** @param array $data */ + public function create(array $data, ?int $communityId = null): mixed + { + return $this->request('POST', '/topics', $this->communityQuery($communityId), $data); + } + + /** @param array $data */ + public function update(int $id, array $data, ?int $communityId = null): mixed + { + return $this->request('PUT', "/topics/{$id}", $this->communityQuery($communityId), $data); + } + + public function delete(int $id, ?int $communityId = null): mixed + { + return $this->request('DELETE', "/topics/{$id}", $this->communityQuery($communityId)); + } +} diff --git a/tests/CircleSoTest.php b/tests/CircleSoTest.php index a243e8e..8e89fe1 100644 --- a/tests/CircleSoTest.php +++ b/tests/CircleSoTest.php @@ -4,10 +4,13 @@ namespace AdroSoftware\CircleSoSdk\Tests; +use AdroSoftware\CircleSoSdk\ClientBuilder; use AdroSoftware\CircleSoSdk\CircleSo; use AdroSoftware\CircleSoSdk\Exception\{ CommunityIdNotPresentException, }; +use AdroSoftware\CircleSoSdk\Options; +use AdroSoftware\CircleSoSdk\Response\FactoryInterface; use GuzzleHttp\Psr7\Response; final class CircleSoTest extends TestCase @@ -36,4 +39,25 @@ public function test_community_id_not_set(): void data: ['first_name' => 'Adroeck'], ); } + + public function test_endpoint_requests_use_the_configured_response_factory(): void + { + $factory = new class implements FactoryInterface { + public function factor(?array $response = null): object + { + return (object) $response; + } + }; + $circleSo = CircleSo::make('token', new Options([ + 'client_builder' => new ClientBuilder($this->mockedClient([ + new Response(200, [], '{"records":[]}'), + ])), + 'response_factory' => $factory, + ])); + + $response = $circleSo->posts()->all(spaceId: 1, communityId: 2); + + $this->assertIsObject($response); + $this->assertSame([], $response->records); + } } diff --git a/tests/Endpoint/V1EndpointCoverageTest.php b/tests/Endpoint/V1EndpointCoverageTest.php new file mode 100644 index 0000000..20092c3 --- /dev/null +++ b/tests/Endpoint/V1EndpointCoverageTest.php @@ -0,0 +1,285 @@ +push(Middleware::history($history)); + $sdk = $this->sdk(new Client(['handler' => $stack])); + + $sdk->posts()->create(12, ['name' => 'A post', 'is_pinned' => false], 34); + + $request = $history[0]['request']; + parse_str($request->getUri()->getQuery(), $query); + + $this->assertSame('34', $query['community_id']); + $this->assertSame('12', $query['space_id']); + $this->assertSame( + ['name' => 'A post', 'is_pinned' => false], + json_decode((string) $request->getBody(), true, flags: JSON_THROW_ON_ERROR), + ); + } + + /** + * @dataProvider endpointProvider + */ + public function test_v1_endpoint( + string $method, + string $path, + Closure $call, + ): void { + $history = []; + $stack = HandlerStack::create(new MockHandler([new Response(200, [], '{}')])); + $stack->push(Middleware::history($history)); + $sdk = $this->sdk(new Client(['handler' => $stack])); + + $call($sdk); + + $this->assertCount(1, $history); + $request = $history[0]['request']; + $this->assertSame($method, $request->getMethod()); + $this->assertSame($path, $request->getUri()->getPath()); + } + + /** + * @return iterable + */ + public static function endpointProvider(): iterable + { + yield 'space group member show' => [ + 'GET', '/api/v1/space_group_member', + static fn (CircleSo $sdk): mixed => $sdk->spaceGroupMembers()->show('a@example.com', 2, 5), + ]; + yield 'space group member add' => [ + 'POST', '/api/v1/space_group_members', + static fn (CircleSo $sdk): mixed => $sdk->spaceGroupMembers()->add('a@example.com', 2, 5), + ]; + yield 'space group member remove' => [ + 'DELETE', '/api/v1/space_group_members', + static fn (CircleSo $sdk): mixed => $sdk->spaceGroupMembers()->remove('a@example.com', 2, 5), + ]; + yield 'space member add' => [ + 'POST', '/api/v1/space_members', + static fn (CircleSo $sdk): mixed => $sdk->spaceMembers()->add('a@example.com', 2, 5), + ]; + yield 'space member remove' => [ + 'DELETE', '/api/v1/space_members', + static fn (CircleSo $sdk): mixed => $sdk->spaceMembers()->remove('a@example.com', 2, 5), + ]; + yield 'posts index' => [ + 'GET', '/api/v1/posts', + static fn (CircleSo $sdk): mixed => $sdk->posts()->all(2, 5), + ]; + yield 'posts show' => [ + 'GET', '/api/v1/posts/3', + static fn (CircleSo $sdk): mixed => $sdk->posts()->show(3, 5), + ]; + yield 'posts create' => [ + 'POST', '/api/v1/posts', + static fn (CircleSo $sdk): mixed => $sdk->posts()->create(2, ['name' => 'Post'], 5), + ]; + yield 'posts update' => [ + 'PUT', '/api/v1/posts/3', + static fn (CircleSo $sdk): mixed => $sdk->posts()->update(3, ['name' => 'Post'], 5), + ]; + yield 'posts delete' => [ + 'DELETE', '/api/v1/posts/3', + static fn (CircleSo $sdk): mixed => $sdk->posts()->delete(3, 5), + ]; + yield 'comments index' => [ + 'GET', '/api/v1/comments', + static fn (CircleSo $sdk): mixed => $sdk->comments()->all(5, postId: 3), + ]; + yield 'comments show' => [ + 'GET', '/api/v1/comments/4', + static fn (CircleSo $sdk): mixed => $sdk->comments()->show(4, 5), + ]; + yield 'comments create' => [ + 'POST', '/api/v1/comments', + static fn (CircleSo $sdk): mixed => $sdk->comments()->create(2, 3, ['body' => 'Hi'], 5), + ]; + yield 'comments delete' => [ + 'DELETE', '/api/v1/comments/4', + static fn (CircleSo $sdk): mixed => $sdk->comments()->delete(4, 5), + ]; + yield 'group message' => [ + 'POST', '/api/v1/messages', + static fn (CircleSo $sdk): mixed => $sdk->messages()->group(['a@example.com'], 'Hi', 5), + ]; + yield 'direct message' => [ + 'POST', '/api/v1/messages', + static fn (CircleSo $sdk): mixed => $sdk->messages()->direct('a@example.com', 'Hi', 5), + ]; + yield 'subscriptions index' => [ + 'GET', '/api/v1/community_member_subscriptions', + static fn (CircleSo $sdk): mixed => $sdk->subscriptions()->all(5), + ]; + yield 'events index' => [ + 'GET', '/api/v1/events', + static fn (CircleSo $sdk): mixed => $sdk->events()->all(5), + ]; + yield 'events create' => [ + 'POST', '/api/v1/events', + static fn (CircleSo $sdk): mixed => $sdk->events()->create(2, ['event' => []], 5), + ]; + yield 'events update' => [ + 'PUT', '/api/v1/events/3', + static fn (CircleSo $sdk): mixed => $sdk->events()->update(3, 2, ['event' => []], 5), + ]; + yield 'events delete' => [ + 'DELETE', '/api/v1/events/3', + static fn (CircleSo $sdk): mixed => $sdk->events()->delete(3, 2, 5), + ]; + yield 'event attendees index' => [ + 'GET', '/api/v1/event_attendees', + static fn (CircleSo $sdk): mixed => $sdk->eventAttendees()->all(3, 5), + ]; + yield 'event attendees create' => [ + 'POST', '/api/v1/event_attendees', + static fn (CircleSo $sdk): mixed => $sdk->eventAttendees()->rsvp(3, 'a@example.com', 5), + ]; + yield 'event attendees delete' => [ + 'DELETE', '/api/v1/event_attendees', + static fn (CircleSo $sdk): mixed => $sdk->eventAttendees()->remove(3, 'a@example.com', 5), + ]; + yield 'charges index' => [ + 'GET', '/api/v1/community_member_charges', + static fn (CircleSo $sdk): mixed => $sdk->charges()->all(5), + ]; + yield 'post likes index' => [ + 'GET', '/api/v1/posts/3/likes', + static fn (CircleSo $sdk): mixed => $sdk->likes()->forPost(3), + ]; + yield 'post likes create' => [ + 'POST', '/api/v1/posts/3/likes', + static fn (CircleSo $sdk): mixed => $sdk->likes()->likePost(3, 'a@example.com'), + ]; + yield 'post likes delete' => [ + 'DELETE', '/api/v1/posts/3/likes', + static fn (CircleSo $sdk): mixed => $sdk->likes()->unlikePost(3, 'a@example.com'), + ]; + yield 'comment likes index' => [ + 'GET', '/api/v1/comments/4/likes', + static fn (CircleSo $sdk): mixed => $sdk->likes()->forComment(4), + ]; + yield 'comment likes create' => [ + 'POST', '/api/v1/comments/4/likes', + static fn (CircleSo $sdk): mixed => $sdk->likes()->likeComment(4, 'a@example.com'), + ]; + yield 'comment likes delete' => [ + 'DELETE', '/api/v1/comments/4/likes', + static fn (CircleSo $sdk): mixed => $sdk->likes()->unlikeComment(4, 'a@example.com'), + ]; + yield 'community member spaces index' => [ + 'GET', '/api/v1/community_member_spaces', + static fn (CircleSo $sdk): mixed => $sdk->communityMemberSpaces()->all('a@example.com'), + ]; + yield 'profile fields index' => [ + 'GET', '/api/v1/page_profile_fields', + static fn (CircleSo $sdk): mixed => $sdk->profileFields()->all(), + ]; + yield 'course sections index' => [ + 'GET', '/api/v1/course_sections', + static fn (CircleSo $sdk): mixed => $sdk->courses()->sections(2, 5), + ]; + yield 'course sections show' => [ + 'GET', '/api/v1/course_sections/3', + static fn (CircleSo $sdk): mixed => $sdk->courses()->showSection(3, 5), + ]; + yield 'course sections create' => [ + 'POST', '/api/v1/course_sections', + static fn (CircleSo $sdk): mixed => $sdk->courses()->createSection(['name' => 'Section'], 5), + ]; + yield 'course sections update' => [ + 'PATCH', '/api/v1/course_sections/3', + static fn (CircleSo $sdk): mixed => $sdk->courses()->updateSection(3, ['name' => 'Section'], 5), + ]; + yield 'course sections delete' => [ + 'DELETE', '/api/v1/course_sections/3', + static fn (CircleSo $sdk): mixed => $sdk->courses()->deleteSection(3, 5), + ]; + yield 'course lessons index' => [ + 'GET', '/api/v1/course_lessons', + static fn (CircleSo $sdk): mixed => $sdk->courses()->lessons(2, 3, 5), + ]; + yield 'course lessons show' => [ + 'GET', '/api/v1/course_lessons/4', + static fn (CircleSo $sdk): mixed => $sdk->courses()->showLesson(4, 5), + ]; + yield 'course lessons create' => [ + 'POST', '/api/v1/course_lessons', + static fn (CircleSo $sdk): mixed => $sdk->courses()->createLesson(['name' => 'Lesson'], 5), + ]; + yield 'course lessons update' => [ + 'PATCH', '/api/v1/course_lessons/4', + static fn (CircleSo $sdk): mixed => $sdk->courses()->updateLesson(4, ['name' => 'Lesson'], 5), + ]; + yield 'course lessons delete' => [ + 'DELETE', '/api/v1/course_lessons/4', + static fn (CircleSo $sdk): mixed => $sdk->courses()->deleteLesson(4, 5), + ]; + yield 'course lesson progress update' => [ + 'PATCH', '/api/v1/course_lesson_progress', + static fn (CircleSo $sdk): mixed => $sdk->courses()->updateLessonProgress(4, 'a@example.com', 5), + ]; + yield 'notifications unsubscribe' => [ + 'GET', '/public/unsubscribe', + static fn (CircleSo $sdk): mixed => $sdk->notifications()->unsubscribe(['token' => 'abc']), + ]; + yield 'notification preferences index' => [ + 'GET', '/public/notification_preferences', + static fn (CircleSo $sdk): mixed => $sdk->notifications()->preferences(['token' => 'abc']), + ]; + yield 'notification preferences update' => [ + 'PATCH', '/public/notification_preferences', + static fn (CircleSo $sdk): mixed => $sdk->notifications()->updatePreferences([]), + ]; + yield 'topics index' => [ + 'GET', '/api/v1/topics', + static fn (CircleSo $sdk): mixed => $sdk->topics()->all(5), + ]; + yield 'topics create' => [ + 'POST', '/api/v1/topics', + static fn (CircleSo $sdk): mixed => $sdk->topics()->create(['name' => 'Topic'], 5), + ]; + yield 'topics update' => [ + 'PUT', '/api/v1/topics/3', + static fn (CircleSo $sdk): mixed => $sdk->topics()->update(3, ['name' => 'Topic'], 5), + ]; + yield 'topics delete' => [ + 'DELETE', '/api/v1/topics/3', + static fn (CircleSo $sdk): mixed => $sdk->topics()->delete(3, 5), + ]; + yield 'contacts create' => [ + 'POST', '/api/v1/contacts', + static fn (CircleSo $sdk): mixed => $sdk->contacts()->create(['email' => 'a@example.com']), + ]; + yield 'flagged contents index' => [ + 'GET', '/api/v1/flagged_contents', + static fn (CircleSo $sdk): mixed => $sdk->flaggedContents()->all(5), + ]; + yield 'tagged members index' => [ + 'GET', '/api/v1/tagged_members', + static fn (CircleSo $sdk): mixed => $sdk->taggedMembers()->all(), + ]; + yield 'tagged members show' => [ + 'GET', '/api/v1/tagged_members/3', + static fn (CircleSo $sdk): mixed => $sdk->taggedMembers()->show(3), + ]; + } +} diff --git a/tests/Endpoint/V1ResponseFixtureTest.php b/tests/Endpoint/V1ResponseFixtureTest.php new file mode 100644 index 0000000..7587713 --- /dev/null +++ b/tests/Endpoint/V1ResponseFixtureTest.php @@ -0,0 +1,111 @@ +getSdkWithMockedClient([ + new Response(200, [], $json), + ]); + + $response = $call($sdk); + + $this->assertSame(json_decode($json, true, flags: JSON_THROW_ON_ERROR), $response); + } + + /** @return iterable */ + public static function responseProvider(): iterable + { + yield 'space group member' => [ + 'space_group_member', + static fn (CircleSo $sdk): mixed => $sdk->spaceGroupMembers()->show('member@example.com', 12, 5), + ]; + yield 'space member mutation' => [ + 'success_true', + static fn (CircleSo $sdk): mixed => $sdk->spaceMembers()->add('member@example.com', 12, 5), + ]; + yield 'spaces' => [ + 'spaces', + static fn (CircleSo $sdk): mixed => $sdk->spaces()->spaces(5), + ]; + yield 'posts' => [ + 'posts', + static fn (CircleSo $sdk): mixed => $sdk->posts()->all(12, 5), + ]; + yield 'comments' => [ + 'comments', + static fn (CircleSo $sdk): mixed => $sdk->comments()->all(5, postId: 21), + ]; + yield 'tagged members' => [ + 'tagged_members', + static fn (CircleSo $sdk): mixed => $sdk->taggedMembers()->all(), + ]; + yield 'messages' => [ + 'message', + static fn (CircleSo $sdk): mixed => $sdk->messages()->direct('member@example.com', 'Hello', 5), + ]; + yield 'subscriptions' => [ + 'subscriptions', + static fn (CircleSo $sdk): mixed => $sdk->subscriptions()->all(5), + ]; + yield 'events' => [ + 'events', + static fn (CircleSo $sdk): mixed => $sdk->events()->all(5), + ]; + yield 'event attendees' => [ + 'event_attendees', + static fn (CircleSo $sdk): mixed => $sdk->eventAttendees()->all(71, 5), + ]; + yield 'charges' => [ + 'charges', + static fn (CircleSo $sdk): mixed => $sdk->charges()->all(5), + ]; + yield 'likes' => [ + 'likes', + static fn (CircleSo $sdk): mixed => $sdk->likes()->forPost(21), + ]; + yield 'community member spaces' => [ + 'community_member_spaces', + static fn (CircleSo $sdk): mixed => $sdk->communityMemberSpaces()->all('member@example.com'), + ]; + yield 'profile fields' => [ + 'profile_fields', + static fn (CircleSo $sdk): mixed => $sdk->profileFields()->all(), + ]; + yield 'course sections' => [ + 'course_sections', + static fn (CircleSo $sdk): mixed => $sdk->courses()->sections(12, 5), + ]; + yield 'course lessons' => [ + 'course_lessons', + static fn (CircleSo $sdk): mixed => $sdk->courses()->lessons(12, 121, 5), + ]; + yield 'notification preferences' => [ + 'notification_preferences', + static fn (CircleSo $sdk): mixed => $sdk->notifications()->preferences(['token' => 'abc']), + ]; + yield 'topics' => [ + 'topics', + static fn (CircleSo $sdk): mixed => $sdk->topics()->all(5), + ]; + yield 'contacts' => [ + 'contact', + static fn (CircleSo $sdk): mixed => $sdk->contacts()->create(['email' => 'lead@example.com']), + ]; + yield 'flagged contents' => [ + 'flagged_contents', + static fn (CircleSo $sdk): mixed => $sdk->flaggedContents()->all(5), + ]; + } +} diff --git a/tests/stubs/responses/charges.json b/tests/stubs/responses/charges.json new file mode 100644 index 0000000..8661ea2 --- /dev/null +++ b/tests/stubs/responses/charges.json @@ -0,0 +1,43 @@ +[ + { + "id": 0, + "user_id": 0, + "community_id": 11111, + "community_member_id": 0, + "processor_id": "sub_1a2b3456cDE7890122", + "status": "paid", + "amount": 120, + "fee_amount": 1, + "amount_refunded": 0, + "deleted_at": null, + "created_at": "2021-12-29T19:57:30.105Z", + "updated_at": "2021-12-29T20:02:02.443Z", + "community_member_subscription_id": 0, + "currency": "usd", + "community_member": { + "id": 0, + "name": "Member One", + "email": "member@circle.co", + "public_uid": "123fe0e1", + "created_at": "2021-12-29T19:57:34.622Z", + "updated_at": "2021-12-29T19:58:11.019Z", + "deleted_at": null + }, + "paywalls": [ + { + "id": 0, + "status": "active", + "display_name": "Level A", + "internal_name": "Basic membership annual", + "currency": "usd", + "price": { + "amount_in_cents": 12000, + "type": "subscription", + "interval_count": 1, + "interval": "yearly", + "currency": "usd" + } + } + ] + } +] diff --git a/tests/stubs/responses/comments.json b/tests/stubs/responses/comments.json new file mode 100644 index 0000000..deaeb19 --- /dev/null +++ b/tests/stubs/responses/comments.json @@ -0,0 +1,101 @@ +[ + { + "id": 19209776, + "body": { + "id": 26156734, + "name": "body", + "body": "
 I could see that you commented - we'll take it from here!
", + "record_type": "Comment", + "record_id": 19209776, + "created_at": "2023-05-17T08:57:55.000Z", + "updated_at": "2023-05-17T08:57:55.000Z" + }, + "user_id": 351629, + "user_name": "First Last", + "user_email": "member@circle.so", + "user_avatar_url": "https://app.circle.so/rails/active_storage/representations/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBeDRJTWc9PSIsImV4cCI6bnVsbCwicHVyIjoiYmxvYl9pZCJ9fQ==--4221ed6ef196e6fc147da7f353371ca375b8771c/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDRG9MWm05eWJXRjBTU0lJVUU1SEJqb0dSVlE2RkhKbGMybDZaVjkwYjE5c2FXMXBkRnNIYVFJc0FXa0NMQUU2Q25OaGRtVnlld1k2Q25OMGNtbHdWQT09IiwiZXhwIjpudWxsLCJwdXIiOiJ2YXJpYXRpb24ifX0=--67d61e1ece4c2627be0acf5d87aa36959ef3de56/IMG_2037.PNG", + "url": "https://app.circle.so/c/api-test-only/this-is-a-test-for-api#comment_wrapper_19209776", + "post_id": 6480025, + "post_name": "This is a test for API", + "post_slug": "this-is-a-test-for-api", + "space_id": 693100, + "space_slug": "api-test-only", + "community_id": 11111, + "parent_comment_id": null, + "flagged_for_approval_at": null, + "created_at": "2023-05-17T08:57:55.084Z", + "topic_id": 6480025, + "topic_name": "This is a test for API", + "likes_count": 0, + "user_posts_count": 2, + "user_topics_count": 2, + "user_likes_count": 0, + "user_comments_count": 2 + }, + { + "id": 19209748, + "body": { + "id": 26156698, + "name": "body", + "body": "
 yes I did - could you see this comment?
", + "record_type": "Comment", + "record_id": 19209748, + "created_at": "2023-05-17T08:56:33.000Z", + "updated_at": "2023-05-17T08:56:33.000Z" + }, + "user_id": 351101, + "user_name": "First Last", + "user_email": "member1@circle.co", + "user_avatar_url": "https://app.circle.so/rails/active_storage/representations/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBNlVYWEE9PSIsImV4cCI6bnVsbCwicHVyIjoiYmxvYl9pZCJ9fQ==--53a0e45f41254f9d5d0414969df893595eab16b6/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDRG9MWm05eWJXRjBTU0lJYW5CbkJqb0dSVlE2RkhKbGMybDZaVjkwYjE5c2FXMXBkRnNIYVFJc0FXa0NMQUU2Q25OaGRtVnlld1k2Q25OMGNtbHdWQT09IiwiZXhwIjpudWxsLCJwdXIiOiJ2YXJpYXRpb24ifX0=--67365f61f655fbc86c65a51f2e9992ab818c41cd/271951961_3121832371426899_8729833769040377312_n.jpg", + "url": "https://app.circle.so/c/api-test-only/this-is-a-test-for-api#comment_wrapper_19209748", + "post_id": 6480025, + "post_name": "This is a test for API", + "post_slug": "this-is-a-test-for-api", + "space_id": 693100, + "space_slug": "api-test-only", + "community_id": 11111, + "parent_comment_id": null, + "flagged_for_approval_at": null, + "created_at": "2023-05-17T08:56:33.756Z", + "topic_id": 6480025, + "topic_name": "This is a test for API", + "likes_count": 0, + "user_posts_count": 234, + "user_topics_count": 234, + "user_likes_count": 4, + "user_comments_count": 5 + }, + { + "id": 19209674, + "body": { + "id": 26156601, + "name": "body", + "body": "
Did you comment on this?
", + "record_type": "Comment", + "record_id": 19209674, + "created_at": "2023-05-17T08:53:30.000Z", + "updated_at": "2023-05-17T08:53:30.000Z" + }, + "user_id": 351629, + "user_name": "First Last", + "user_email": "member@circle.so", + "user_avatar_url": "https://app.circle.so/rails/active_storage/representations/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBeDRJTWc9PSIsImV4cCI6bnVsbCwicHVyIjoiYmxvYl9pZCJ9fQ==--4221ed6ef196e6fc147da7f353371ca375b8771c/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDRG9MWm05eWJXRjBTU0lJVUU1SEJqb0dSVlE2RkhKbGMybDZaVjkwYjE5c2FXMXBkRnNIYVFJc0FXa0NMQUU2Q25OaGRtVnlld1k2Q25OMGNtbHdWQT09IiwiZXhwIjpudWxsLCJwdXIiOiJ2YXJpYXRpb24ifX0=--67d61e1ece4c2627be0acf5d87aa36959ef3de56/IMG_2037.PNG", + "url": "https://app.circle.so/c/api-test-only/this-is-a-test-for-api#comment_wrapper_19209674", + "post_id": 6480025, + "post_name": "This is a test for API", + "post_slug": "this-is-a-test-for-api", + "space_id": 693100, + "space_slug": "api-test-only", + "community_id": 11111, + "parent_comment_id": null, + "flagged_for_approval_at": null, + "created_at": "2023-05-17T08:53:30.057Z", + "topic_id": 6480025, + "topic_name": "This is a test for API", + "likes_count": 0, + "user_posts_count": 2, + "user_topics_count": 2, + "user_likes_count": 0, + "user_comments_count": 2 + } +] diff --git a/tests/stubs/responses/community_member_spaces.json b/tests/stubs/responses/community_member_spaces.json new file mode 100644 index 0000000..250ac33 --- /dev/null +++ b/tests/stubs/responses/community_member_spaces.json @@ -0,0 +1,80 @@ +{ + "page": 1, + "per_page": 30, + "has_next_page": false, + "count": 3, + "page_count": 3, + "records": [ + { + "id": 0, + "name": "1:1 Sessions", + "slug": "1-1-sessions", + "emoji": null, + "space_group_id": 0, + "space_group_name": "Information", + "url": "https://app.circle.so/c/1-1-sessions", + "community_id": 11111, + "is_private": false, + "hide_post_settings": true, + "display_view": "posts", + "post_ids": [ + 0 + ], + "is_post_disabled": true, + "space_type": "event", + "hide_topic_settings": true, + "is_topic_disabled": true, + "topic_ids": [ + 0 + ] + }, + { + "id": 0, + "name": "Private Posts", + "slug": "private-posts", + "emoji": null, + "space_group_id": 0, + "space_group_name": "Information", + "url": "https://app.circle.so/c/private-posts", + "community_id": 11111, + "is_private": true, + "hide_post_settings": false, + "display_view": "posts", + "post_ids": [ + 0 + ], + "is_post_disabled": false, + "space_type": "basic", + "hide_topic_settings": false, + "is_topic_disabled": false, + "topic_ids": [ + 0 + ] + }, + { + "id": 0, + "name": "Public posts", + "slug": "public-posts", + "emoji": null, + "space_group_id": 0, + "space_group_name": "Information", + "url": "https://app.circle.so/c/public-posts", + "community_id": 11111, + "is_private": false, + "hide_post_settings": false, + "display_view": "posts", + "post_ids": [ + 0 + ], + "is_post_disabled": true, + "space_type": "basic", + "hide_topic_settings": false, + "is_topic_disabled": true, + "topic_ids": [ + 0 + ] + } + ], + "meta": { + } +} diff --git a/tests/stubs/responses/contact.json b/tests/stubs/responses/contact.json new file mode 100644 index 0000000..748ee9d --- /dev/null +++ b/tests/stubs/responses/contact.json @@ -0,0 +1,34 @@ +{ + "id": 1, + "first_name": "John", + "last_name": "Doe", + "email": "johndoe@example.com", + "created_at": "2023-06-01T20:28:25.277Z", + "member_tags": [ + { + "id": 1, + "name": "Friends" + }, + { + "id": 2, + "name": "VIPs" + } + ], + "profile_fields": [ + { + "key": "headline", + "value": "Software Engineer" + }, + { + "key": "bio", + "value": "Software Engineer at Circle" + }, + { + "key": "hobbies", + "value": [ + "reading", + "running" + ] + } + ] +} diff --git a/tests/stubs/responses/course_lessons.json b/tests/stubs/responses/course_lessons.json new file mode 100644 index 0000000..c530117 --- /dev/null +++ b/tests/stubs/responses/course_lessons.json @@ -0,0 +1,48 @@ +{ + "page": 1, + "per_page": 10, + "has_next_page": false, + "count": 3, + "page_count": 3, + "records": [ + { + "id": 233933, + "name": "Lesson 3", + "status": "published", + "created_at": "2023-06-01T20:28:25.277Z", + "updated_at": "2023-06-01T20:28:25.280Z", + "section_id": 71814, + "is_comments_enabled": true, + "is_featured_media_enabled": false, + "is_featured_media_download_enabled": false, + "body_html": "

Lesson Content

", + "space_id": 700930 + }, + { + "id": 233932, + "name": "Lesson 2", + "status": "published", + "created_at": "2023-06-01T20:28:15.909Z", + "updated_at": "2023-06-01T20:28:15.912Z", + "section_id": 71814, + "is_comments_enabled": true, + "is_featured_media_enabled": false, + "is_featured_media_download_enabled": false, + "body_html": "

Lesson Content

", + "space_id": 700930 + }, + { + "id": 233930, + "name": "Introduction to research", + "status": "published", + "created_at": "2023-06-01T20:27:09.535Z", + "updated_at": "2023-06-01T20:27:09.538Z", + "section_id": 71814, + "is_comments_enabled": true, + "is_featured_media_enabled": false, + "is_featured_media_download_enabled": false, + "body_html": "

I'm glad you're here!

", + "space_id": 700930 + } + ] +} diff --git a/tests/stubs/responses/course_sections.json b/tests/stubs/responses/course_sections.json new file mode 100644 index 0000000..1f95e59 --- /dev/null +++ b/tests/stubs/responses/course_sections.json @@ -0,0 +1,37 @@ +{ + "page": 1, + "per_page": 10, + "has_next_page": false, + "count": 4, + "page_count": 4, + "records": [ + { + "id": 71817, + "space_id": 700930, + "name": "Section 4", + "created_at": "2023-06-01T20:01:16.962Z", + "updated_at": "2023-06-01T20:01:16.962Z" + }, + { + "id": 71816, + "space_id": 700930, + "name": "Section 3", + "created_at": "2023-06-01T20:01:11.775Z", + "updated_at": "2023-06-01T20:01:11.775Z" + }, + { + "id": 71815, + "space_id": 700930, + "name": "Section 2", + "created_at": "2023-06-01T20:01:06.817Z", + "updated_at": "2023-06-01T20:01:06.817Z" + }, + { + "id": 71814, + "space_id": 700930, + "name": "Section 1", + "created_at": "2023-06-01T20:00:50.662Z", + "updated_at": "2023-06-01T20:00:50.662Z" + } + ] +} diff --git a/tests/stubs/responses/event_attendees.json b/tests/stubs/responses/event_attendees.json new file mode 100644 index 0000000..6bac897 --- /dev/null +++ b/tests/stubs/responses/event_attendees.json @@ -0,0 +1,12 @@ +[ + { + "id": 0, + "event_id": 0, + "community_member_id": 0, + "member_name": "Member One", + "member_email": "member@circle.so", + "headline": "Community builder", + "member_avatar_url": "https://app.circle.so/rails/active_storage/representations/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBNzR5QlE9PSIsImV4cCI6bnVsbCwicHVyIjoiYmxvYl9pZCJ9fQ==--8585dcc27e82033fefb93409e115e9f8dd228d57/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdCem9MWm05eWJXRjBTU0lJY0c1bkJqb0dSVlE2RkhKbGMybDZaVjkwYjE5c2FXMXBkRnNIYVFJc0FXa0NMQUU9IiwiZXhwIjpudWxsLCJwdXIiOiJ2YXJpYXRpb24ifX0=--303343140e2172dc8c24fca3ba2b0156e869f191/member.png", + "rsvp_date": "2023-02-05T19:56:13.392Z" + } +] diff --git a/tests/stubs/responses/events.json b/tests/stubs/responses/events.json new file mode 100644 index 0000000..d395989 --- /dev/null +++ b/tests/stubs/responses/events.json @@ -0,0 +1,146 @@ +[ + { + "id": 6516736, + "name": "Toronto convention", + "slug": "toronto-convention", + "body": { + "id": 26299672, + "name": "body", + "body": null, + "record_type": "Post", + "record_id": 6516736, + "created_at": "2023-05-19T19:27:40.000Z", + "updated_at": "2023-05-19T19:27:40.000Z" + }, + "space_id": 0, + "user_id": 0, + "community_member_id": 0, + "created_at": "2023-05-19T19:27:44.268Z", + "updated_at": "2023-05-19T19:27:44.280Z", + "hide_meta_info": null, + "starts_at": "2023-09-03T13:30:00.000Z", + "duration_in_seconds": 9000, + "rsvp_disabled": false, + "hide_attendees": false, + "virtual_location_url": null, + "hide_location_from_non_attendees": true, + "send_email_reminder": true, + "send_in_app_notification_reminder": true, + "enable_custom_thank_you_message": false, + "send_email_confirmation": true, + "send_in_app_notification_confirmation": true, + "confirmation_message_title": null, + "confirmation_message_button_title": null, + "confirmation_message_button_link": null, + "ends_at": "2023-09-03T16:00:00.000Z", + "confirmation_message_description": null, + "location_type": "in_person", + "in_person_location": "{\"formatted_address\":\"123 Queen St W, Toronto, ON M5H 3M9, Canada\",\"geometry\":{\"location\":{\"lat\":43.6511644,\"lng\":-79.3841716}},\"name\":\"123 Queen St W\",\"place_id\":\"ChIJoZ8Hus00K4gRfgPGjqVFR5w\",\"url\":\"https://maps.google.com/?q=123+Queen+St+W,+Toronto,+ON+M5H+3M9,+Canada&ftid=0x882b34cdba079fa1:0x9c4745a58ec6037e\",\"html_attributions\":[]}", + "url": "https://app.circle.so/c/events/toronto-convention", + "space_name": "Community Events", + "space_slug": "community-events", + "member_email": "member5@circle.co", + "member_name": "Member Five", + "comments_count": 0, + "likes_count": 0, + "community_id": 11111, + "member_avatar_url": "https://secure.gravatar.com/avatar/e3c3f12e5e34b91fc8866796c21d80d9?default=404&secure=true&size=300", + "zapier_display_title": "Toronto convention 3 Sep 2023 1:30PM UTC" + }, + { + "id": 6516720, + "name": "Team check in", + "slug": "team-check-in", + "body": { + "id": 26299576, + "name": "body", + "body": null, + "record_type": "Post", + "record_id": 6516720, + "created_at": "2023-05-19T19:26:00.000Z", + "updated_at": "2023-05-19T19:26:00.000Z" + }, + "space_id": 0, + "user_id": 0, + "community_member_id": 0, + "created_at": "2023-05-19T19:26:08.683Z", + "updated_at": "2023-05-19T19:26:08.695Z", + "hide_meta_info": null, + "starts_at": "2023-07-19T13:00:00.000Z", + "duration_in_seconds": 3600, + "rsvp_disabled": false, + "hide_attendees": false, + "virtual_location_url": null, + "hide_location_from_non_attendees": false, + "send_email_reminder": true, + "send_in_app_notification_reminder": true, + "enable_custom_thank_you_message": false, + "send_email_confirmation": true, + "send_in_app_notification_confirmation": true, + "confirmation_message_title": null, + "confirmation_message_button_title": null, + "confirmation_message_button_link": null, + "ends_at": "2023-07-19T14:00:00.000Z", + "confirmation_message_description": null, + "location_type": "live_room", + "in_person_location": null, + "url": "https://app.circle.so/c/events/team-check-in", + "space_name": "Community Events", + "space_slug": "community-events", + "member_email": "member@circle.co", + "member_name": "Member One", + "comments_count": 0, + "likes_count": 0, + "community_id": 11111, + "member_avatar_url": "https://secure.gravatar.com/avatar/971a73e753c5d11414300994ada66f85?default=404&secure=true&size=300", + "zapier_display_title": "Team check in 19 Jul 2023 1:00PM UTC" + }, + { + "id": 6486499, + "name": "Special Guest Speaker: James C", + "slug": "guest-speaker", + "body": { + "id": 26178627, + "name": "body", + "body": null, + "record_type": "Post", + "record_id": 6486499, + "created_at": "2023-05-17T16:29:14.000Z", + "updated_at": "2023-05-17T16:29:14.000Z" + }, + "space_id": 0, + "user_id": 0, + "community_member_id": 0, + "created_at": "2023-05-17T16:29:59.891Z", + "updated_at": "2023-05-17T16:29:59.903Z", + "hide_meta_info": null, + "starts_at": "2023-05-17T16:30:00.000Z", + "duration_in_seconds": 3600, + "rsvp_disabled": false, + "hide_attendees": false, + "virtual_location_url": null, + "hide_location_from_non_attendees": false, + "send_email_reminder": true, + "send_in_app_notification_reminder": true, + "enable_custom_thank_you_message": false, + "send_email_confirmation": true, + "send_in_app_notification_confirmation": true, + "confirmation_message_title": null, + "confirmation_message_button_title": null, + "confirmation_message_button_link": null, + "ends_at": "2023-05-17T17:30:00.000Z", + "confirmation_message_description": null, + "location_type": "live_room", + "in_person_location": null, + "url": "https://app.circle.so/c/events/speaker-test", + "space_name": "Public Events", + "space_slug": "public-events", + "member_email": "member@circle.co", + "member_name": "Member One", + "comments_count": 0, + "likes_count": 0, + "community_id": 11111, + "member_avatar_url": "https://secure.gravatar.com/avatar/971a73e753c5d11414300994ada66f85?default=404&secure=true&size=300", + "zapier_display_title": "Speaker test 17 May 2023 4:30PM UTC" + } +] diff --git a/tests/stubs/responses/flagged_contents.json b/tests/stubs/responses/flagged_contents.json new file mode 100644 index 0000000..c338f7f --- /dev/null +++ b/tests/stubs/responses/flagged_contents.json @@ -0,0 +1,75 @@ +{ + "page": 2, + "per_page": 3, + "has_next_page": true, + "count": 30, + "page_count": 10, + "records": [ + { + "id": 91, + "status": "rejected", + "reported_reason_type": "other", + "reported_reason_body": "Reason provided by the reporter", + "reported_at": "2025-05-15T14:26:23.000Z", + "action_taken_at": "2025-07-14T22:39:22.000Z", + "action_reason_body": "Violates the community guidelines", + "created_at": "2025-05-15T14:26:23.862Z", + "updated_at": "2025-07-14T22:39:22.894Z", + "content_id": 108, + "content_type": "comment", + "content_authored_by_id": 15, + "content_authored_by_name": "John", + "content_authored_by_email": "john@world.org", + "reported_by_id": 5, + "reported_by_name": "Jane", + "reported_by_email": "jane@world.org", + "action_by_id": 2, + "action_by_name": "Alice", + "action_by_email": "alice@world.org" + }, + { + "id": 92, + "status": "rejected", + "reported_reason_type": "other", + "reported_reason_body": "Reason provided by the reporter", + "reported_at": "2025-06-11T14:04:48.000Z", + "action_taken_at": "2025-07-14T22:38:55.000Z", + "action_reason_body": "Violates the community guidelines", + "created_at": "2025-06-11T14:04:48.140Z", + "updated_at": "2025-07-14T22:38:55.639Z", + "content_id": 114, + "content_type": "comment", + "content_authored_by_id": 15, + "content_authored_by_name": "John", + "content_authored_by_email": "john@world.org", + "reported_by_id": null, + "reported_by_name": null, + "reported_by_email": null, + "action_by_id": 2, + "action_by_name": "Alice", + "action_by_email": "alice@world.org" + }, + { + "id": 93, + "status": "rejected", + "reported_reason_type": "other", + "reported_reason_body": "Reason provided by the reporter", + "reported_at": "2025-06-11T14:04:48.000Z", + "action_taken_at": "2025-07-14T22:38:55.000Z", + "action_reason_body": "Violates the community guidelines", + "created_at": "2025-06-11T14:04:48.140Z", + "updated_at": "2025-07-14T22:38:55.639Z", + "content_id": 115, + "content_type": "post", + "content_authored_by_id": 15, + "content_authored_by_name": "John", + "content_authored_by_email": "john@world.org", + "reported_by_id": 5, + "reported_by_name": "Thomas", + "reported_by_email": "thomas@world.org", + "action_by_id": 2, + "action_by_name": "Alice", + "action_by_email": "alice@world.org" + } + ] +} diff --git a/tests/stubs/responses/likes.json b/tests/stubs/responses/likes.json new file mode 100644 index 0000000..75dc938 --- /dev/null +++ b/tests/stubs/responses/likes.json @@ -0,0 +1,35 @@ +{ + "page": 1, + "per_page": 10, + "has_next_page": false, + "count": 2, + "page_count": 2, + "records": [ + { + "id": 0, + "user_id": 0, + "public_uid": "a82e3938", + "first_name": "Member", + "last_name": "One", + "name": "Member One", + "headline": "Community educator", + "admin": false, + "user_attachable_sgid": "BAh7CEkiCGdpZAY6BkVUSSIqZ2lkOi8vanVtcHN0YXJ0LWFwcC9Vc2VyLzY_ZXhwaXJlc19pbggxwdXJwb3NlBjsAVEkiD2F0dGFjaGFibGUGOwBUSSIPZXhwaXJlc19hdAY7AFQw--77a66970902ae68209ba20e749b569f3d3cee302", + "avatar_url": "https://secure.gravatar.com/avatar/68798b556442142a01495bff24b5e850c?default=blank&secure=true&size=300" + }, + { + "id": 0, + "user_id": 0, + "public_uid": "40a4da7d", + "first_name": "Member", + "last_name": "Two", + "name": "Member Two", + "headline": "Legacy Administration Liaison", + "admin": true, + "user_attachable_sgid": "BAh7CEkiCGdpZAY6BkVUSSIqZ2lkOi8vanVtcHN0YXJ0LWFwcC95465515XhwaXJlc19pbgY7AFRJIgxwdXJwb3NlBjsAVEkiD2F0dGFjaGFibGUGOwBUSSIPZXhwaXJlc19hdAY7AFQw--4d1bed584868dc70512e0a3976e1e84c6daf46f9", + "avatar_url": "https://secure.gravatar.com/avatar/2c34e4a00bf664d54d5cdc303f3005d07?default=blank&secure=true&size=300" + } + ], + "meta": { + } +} diff --git a/tests/stubs/responses/message.json b/tests/stubs/responses/message.json new file mode 100644 index 0000000..194fd06 --- /dev/null +++ b/tests/stubs/responses/message.json @@ -0,0 +1,26 @@ +{ + "success": true, + "message": "Message sent", + "chat_room_message": { + "id": 12911178, + "updated_at": "2023-05-11T20:51:50.178Z", + "deleted_at": null, + "parent_message_id": null, + "created_at": "2023-05-11T20:51:50.174Z", + "chat_room_id": 2115586, + "chat_room_uuid": "45ab2af5-3d64-4079-ad7e-87a889f094fa", + "chat_room_participant_id": 54726113, + "body": "Hello and welcome to my Community", + "rich_text_body": null, + "sent_at": "2023-05-11T20:51:50.174Z", + "embedded": false, + "sender": { + "id": 0, + "name": "Community Admin", + "community_member_id": 0, + "user_public_uid": "00000", + "avatar_url": "https://secure.gravatar.com/avatar/971a73e753c5d11414300994ada66f85?default=404&secure=true&size=300" + }, + "chat_thread_id": null + } +} diff --git a/tests/stubs/responses/notification_preferences.json b/tests/stubs/responses/notification_preferences.json new file mode 100644 index 0000000..c530117 --- /dev/null +++ b/tests/stubs/responses/notification_preferences.json @@ -0,0 +1,48 @@ +{ + "page": 1, + "per_page": 10, + "has_next_page": false, + "count": 3, + "page_count": 3, + "records": [ + { + "id": 233933, + "name": "Lesson 3", + "status": "published", + "created_at": "2023-06-01T20:28:25.277Z", + "updated_at": "2023-06-01T20:28:25.280Z", + "section_id": 71814, + "is_comments_enabled": true, + "is_featured_media_enabled": false, + "is_featured_media_download_enabled": false, + "body_html": "

Lesson Content

", + "space_id": 700930 + }, + { + "id": 233932, + "name": "Lesson 2", + "status": "published", + "created_at": "2023-06-01T20:28:15.909Z", + "updated_at": "2023-06-01T20:28:15.912Z", + "section_id": 71814, + "is_comments_enabled": true, + "is_featured_media_enabled": false, + "is_featured_media_download_enabled": false, + "body_html": "

Lesson Content

", + "space_id": 700930 + }, + { + "id": 233930, + "name": "Introduction to research", + "status": "published", + "created_at": "2023-06-01T20:27:09.535Z", + "updated_at": "2023-06-01T20:27:09.538Z", + "section_id": 71814, + "is_comments_enabled": true, + "is_featured_media_enabled": false, + "is_featured_media_download_enabled": false, + "body_html": "

I'm glad you're here!

", + "space_id": 700930 + } + ] +} diff --git a/tests/stubs/responses/posts.json b/tests/stubs/responses/posts.json new file mode 100644 index 0000000..ce058e9 --- /dev/null +++ b/tests/stubs/responses/posts.json @@ -0,0 +1,48 @@ +[ + { + "id": 6480025, + "status": "published", + "name": "This is a test for API", + "body": { + "id": 26155191, + "name": "body", + "body": "
This is a test for API
", + "record_type": "Post", + "record_id": 6480025, + "created_at": "2023-05-17T08:01:28.000Z", + "updated_at": "2023-05-17T08:01:28.000Z" + }, + "slug": "this-is-a-test-for-api", + "url": "https://app.circle.so/c/api-test-only/this-is-a-test-for-api", + "space_name": "API-TEST-ONLY", + "space_slug": "api-test-only", + "space_id": 693100, + "user_id": 351629, + "user_email": "member@circle.so", + "user_name": "Test user", + "comments_count": 0, + "community_id": 11111, + "hide_meta_info": false, + "user_avatar_url": "https://app.circle.so/rails/active_storage/representations/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBeDRJTWc9PSIsImV4cCI6bnVsbCwicHVyIjoiYmxvYl9pZCJ9fQ==--4221ed6ef196e6fc147da7f353371ca375b8771c/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDRG9MWm05eWJXRjBTU0lJVUU1SEJqb0dSVlE2RkhKbGMybDZaVjkwYjE5c2FXMXBkRnNIYVFJc0FXa0NMQUU2Q25OaGRtVnlld1k2Q25OMGNtbHdWQT09IiwiZXhwIjpudWxsLCJwdXIiOiJ2YXJpYXRpb24ifX0=--67d61e1ece4c2627be0acf5d87aa36959ef3de56/IMG_2037.PNG", + "published_at": "2023-05-17T08:01:28.717Z", + "created_at": "2023-05-17T08:01:28.717Z", + "updated_at": "2023-05-17T08:01:28.744Z", + "cover_image": null, + "cover_image_url": null, + "cardview_thumbnail": null, + "cardview_thumbnail_url": null, + "is_comments_enabled": true, + "is_comments_closed": false, + "is_liking_enabled": true, + "flagged_for_approval_at": null, + "custom_html": null, + "likes_count": 0, + "topics": [ + 96 + ], + "user_posts_count": 1, + "user_topics_count": 1, + "user_likes_count": 0, + "user_comments_count": 0 + } +] diff --git a/tests/stubs/responses/profile_fields.json b/tests/stubs/responses/profile_fields.json new file mode 100644 index 0000000..5c6f086 --- /dev/null +++ b/tests/stubs/responses/profile_fields.json @@ -0,0 +1,199 @@ +[ + { + "id": 703707, + "label": "Preferred programming language", + "field_type": "select", + "key": "preferred_programming_language", + "placeholder": "", + "description": "Choose your preferred programming language", + "required": false, + "allow_null": false, + "platform_field": false, + "number_options": null, + "choices": [ + { + "id": 133, + "value": "Ruby" + }, + { + "id": 134, + "value": "Javascript" + }, + { + "id": 135, + "value": "Python" + } + ] + }, + { + "id": 108349, + "label": "Bio", + "field_type": "textarea", + "key": "bio", + "placeholder": "Tell us a bit about yourself", + "description": "A short bio about yourself", + "required": false, + "allow_null": false, + "platform_field": true, + "number_options": null, + "choices": [ + + ] + }, + { + "id": 108350, + "label": "Location", + "field_type": "text", + "key": "location", + "placeholder": "Add your location", + "description": "Your location", + "required": false, + "allow_null": false, + "platform_field": true, + "number_options": null, + "choices": [ + + ] + }, + { + "id": 108351, + "label": "Website", + "field_type": "link", + "key": "website", + "placeholder": "Add your website", + "description": "Your website URL", + "required": false, + "allow_null": false, + "platform_field": true, + "number_options": null, + "choices": [ + + ] + }, + { + "id": 108352, + "label": "Twitter URL", + "field_type": "link", + "key": "twitter_url", + "placeholder": "Add your Twitter URL", + "description": "Your Twitter URL", + "required": false, + "allow_null": false, + "platform_field": true, + "number_options": null, + "choices": [ + + ] + }, + { + "id": 108354, + "label": "Instagram URL", + "field_type": "link", + "key": "instagram_url", + "placeholder": "Add your Instagram URL", + "description": "Your Instagram URL", + "required": false, + "allow_null": false, + "platform_field": true, + "number_options": null, + "choices": [ + + ] + }, + { + "id": 108353, + "label": "Facebook URL", + "field_type": "link", + "key": "facebook_url", + "placeholder": "Add your Facebook URL", + "description": "Your Facebook URL", + "required": false, + "allow_null": false, + "platform_field": true, + "number_options": null, + "choices": [ + + ] + }, + { + "id": 108355, + "label": "Linkedin URL", + "field_type": "link", + "key": "linkedin_url", + "placeholder": "Add your LinkedIn URL", + "description": "Your LinkedIn URL", + "required": false, + "allow_null": false, + "platform_field": true, + "number_options": null, + "choices": [ + + ] + }, + { + "id": 797625, + "label": "Age", + "field_type": "number", + "key": "age", + "placeholder": "", + "description": "Age", + "required": false, + "allow_null": false, + "platform_field": false, + "number_options": { + "id": 46, + "format": "number", + "decimal": 0, + "position": "right", + "text": "" + }, + "choices": [ + + ] + }, + { + "id": 108356, + "label": "Profession", + "field_type": "text", + "key": "profession", + "placeholder": "Add your profession", + "description": "Your profession", + "required": false, + "allow_null": false, + "platform_field": false, + "number_options": null, + "choices": [ + + ] + }, + { + "id": 108357, + "label": "Birthday", + "field_type": "text", + "key": "birthday", + "placeholder": "Add your birthday", + "description": "Your birthday", + "required": false, + "allow_null": false, + "platform_field": false, + "number_options": null, + "choices": [ + + ] + }, + { + "id": 108358, + "label": "Company", + "field_type": "text", + "key": "company", + "placeholder": "Add your company", + "description": "Your company", + "required": false, + "allow_null": false, + "platform_field": false, + "number_options": null, + "choices": [ + + ] + } +] diff --git a/tests/stubs/responses/space_group_member.json b/tests/stubs/responses/space_group_member.json new file mode 100644 index 0000000..a510d49 --- /dev/null +++ b/tests/stubs/responses/space_group_member.json @@ -0,0 +1,11 @@ +{ + "id": 3314450, + "space_group_id": 54575, + "user_id": 351629, + "created_at": "2021-10-14T06:34:22.963Z", + "updated_at": "2021-10-14T06:34:22.963Z", + "moderator": false, + "community_member_id": 1989341, + "access_type": "invite", + "status": "active" +} diff --git a/tests/stubs/responses/spaces.json b/tests/stubs/responses/spaces.json new file mode 100644 index 0000000..4f8b886 --- /dev/null +++ b/tests/stubs/responses/spaces.json @@ -0,0 +1,1198 @@ +[ + { + "id": 952, + "name": "Travel tips", + "slug": "getting-started", + "space_group_id": 75, + "space_group_name": "Pro members", + "url": "https://circle.upfront.so/c/getting-started", + "community_id": 5, + "is_private": true, + "hide_post_settings": false, + "display_view": "cards", + "post_ids": [ + 4071909, + 3496561, + 1646747, + 969361, + 961057, + 708398, + 396998, + 373174, + 359112, + 358722, + 332721, + 332715, + 25464, + 25463, + 25462, + 25461, + 25460, + 27343, + 27342, + 27340, + 27314, + 27313, + 25842, + 25841, + 25302, + 27316, + 27308, + 27307, + 27334, + 27294, + 27281, + 27274, + 27262, + 27356, + 27350, + 27333, + 27296, + 27361, + 27300, + 27285, + 27275, + 25840, + 27341, + 27339, + 27328, + 27322, + 27320, + 27310, + 27302, + 27293, + 27291, + 27288, + 27287, + 27276, + 27272, + 27268, + 25836, + 27335, + 27306, + 27299, + 27298, + 27265, + 25659, + 27359, + 27357, + 27355, + 27349, + 27332, + 27352, + 27289, + 27280, + 25495, + 27336, + 27325, + 27323, + 27297, + 27295, + 27283, + 27277, + 25662, + 27358, + 27338, + 27319, + 27317, + 27264, + 27344, + 27329, + 27327, + 25660, + 25657, + 25655, + 27360, + 27354, + 27312, + 27311, + 27278, + 25835, + 25664, + 27353, + 27345, + 27324, + 27292, + 27279, + 27263, + 25837, + 27270, + 25663, + 25658, + 27348, + 27315, + 27273, + 27271, + 27269, + 25834, + 25661, + 27351, + 27330, + 27309, + 27303, + 27266, + 25839, + 27346, + 27326, + 27304, + 27301, + 27284, + 27282, + 27267, + 25838, + 27337, + 27331, + 27321, + 27318, + 25513, + 27347, + 27305, + 27290, + 27286, + 25656 + ], + "is_post_disabled": false, + "space_type": "basic", + "hide_topic_settings": false, + "is_topic_disabled": false, + "topic_ids": [ + 4071909, + 3496561, + 1646747, + 969361, + 961057, + 708398, + 396998, + 373174, + 359112, + 358722, + 332721, + 332715, + 25464, + 25463, + 25462, + 25461, + 25460, + 27343, + 27342, + 27340, + 27314, + 27313, + 25842, + 25841, + 25302, + 27316, + 27308, + 27307, + 27334, + 27294, + 27281, + 27274, + 27262, + 27356, + 27350, + 27333, + 27296, + 27361, + 27300, + 27285, + 27275, + 25840, + 27341, + 27339, + 27328, + 27322, + 27320, + 27310, + 27302, + 27293, + 27291, + 27288, + 27287, + 27276, + 27272, + 27268, + 25836, + 27335, + 27306, + 27299, + 27298, + 27265, + 25659, + 27359, + 27357, + 27355, + 27349, + 27332, + 27352, + 27289, + 27280, + 25495, + 27336, + 27325, + 27323, + 27297, + 27295, + 27283, + 27277, + 25662, + 27358, + 27338, + 27319, + 27317, + 27264, + 27344, + 27329, + 27327, + 25660, + 25657, + 25655, + 27360, + 27354, + 27312, + 27311, + 27278, + 25835, + 25664, + 27353, + 27345, + 27324, + 27292, + 27279, + 27263, + 25837, + 27270, + 25663, + 25658, + 27348, + 27315, + 27273, + 27271, + 27269, + 25834, + 25661, + 27351, + 27330, + 27309, + 27303, + 27266, + 25839, + 27346, + 27326, + 27304, + 27301, + 27284, + 27282, + 27267, + 25838, + 27337, + 27331, + 27321, + 27318, + 25513, + 27347, + 27305, + 27290, + 27286, + 25656 + ], + "topics": [ + 1 + ], + "emoji": "👌", + "custom_emoji_url": null, + "custom_emoji_dark_url": null + }, + { + "id": 15, + "name": "Members directory", + "slug": "community-guidelines", + "space_group_id": 130, + "space_group_name": "First Class", + "url": "https://circle.upfront.so/c/community-guidelines", + "community_id": 5, + "is_private": true, + "hide_post_settings": false, + "display_view": "cards", + "post_ids": [ + 171521, + 25394, + 25393, + 25392, + 25391, + 25390, + 25389, + 25388, + 25387, + 25386, + 25385, + 25384, + 25383, + 25382, + 25381, + 25952, + 25940, + 25933, + 25877, + 25874, + 25947, + 25930, + 25701, + 25958, + 25950, + 25938, + 25928, + 25900, + 25884, + 25704, + 25934, + 25909, + 25887, + 25883, + 25699, + 25967, + 25954, + 25923, + 25892, + 25703, + 25696, + 25522, + 25972, + 25961, + 25948, + 25899, + 25898, + 25895, + 25885, + 25875, + 25966, + 25960, + 25942, + 25939, + 25919, + 25913, + 25702, + 24776, + 25963, + 25944, + 25936, + 25916, + 25953, + 25941, + 25959, + 25935, + 25932, + 25908, + 25902, + 25893, + 25891, + 25886, + 25880, + 25519, + 25517, + 25956, + 25951, + 25920, + 25905, + 25896, + 25881, + 25697, + 25523, + 25971, + 25965, + 25929, + 25889, + 25700, + 25695, + 25499, + 25964, + 25962, + 25957, + 25927, + 25921, + 25915, + 25912, + 25906, + 25894, + 25890, + 25876, + 25698, + 25524, + 25945, + 25926, + 25925, + 25924, + 25904, + 25882, + 25878, + 25968, + 25931, + 25525, + 25520, + 25518, + 25970, + 25969, + 25949, + 25888, + 25946, + 25918, + 25911, + 25903, + 25897, + 25879, + 25526, + 25521, + 23605, + 23602, + 23585, + 23580, + 25955, + 25937, + 25917, + 25914, + 25910, + 25907, + 25901, + 25873 + ], + "is_post_disabled": false, + "space_type": "basic", + "hide_topic_settings": false, + "is_topic_disabled": false, + "topic_ids": [ + 171521, + 25394, + 25393, + 25392, + 25391, + 25390, + 25389, + 25388, + 25387, + 25386, + 25385, + 25384, + 25383, + 25382, + 25381, + 25952, + 25940, + 25933, + 25877, + 25874, + 25947, + 25930, + 25701, + 25958, + 25950, + 25938, + 25928, + 25900, + 25884, + 25704, + 25934, + 25909, + 25887, + 25883, + 25699, + 25967, + 25954, + 25923, + 25892, + 25703, + 25696, + 25522, + 25972, + 25961, + 25948, + 25899, + 25898, + 25895, + 25885, + 25875, + 25966, + 25960, + 25942, + 25939, + 25919, + 25913, + 25702, + 24776, + 25963, + 25944, + 25936, + 25916, + 25953, + 25941, + 25959, + 25935, + 25932, + 25908, + 25902, + 25893, + 25891, + 25886, + 25880, + 25519, + 25517, + 25956, + 25951, + 25920, + 25905, + 25896, + 25881, + 25697, + 25523, + 25971, + 25965, + 25929, + 25889, + 25700, + 25695, + 25499, + 25964, + 25962, + 25957, + 25927, + 25921, + 25915, + 25912, + 25906, + 25894, + 25890, + 25876, + 25698, + 25524, + 25945, + 25926, + 25925, + 25924, + 25904, + 25882, + 25878, + 25968, + 25931, + 25525, + 25520, + 25518, + 25970, + 25969, + 25949, + 25888, + 25946, + 25918, + 25911, + 25903, + 25897, + 25879, + 25526, + 25521, + 23605, + 23602, + 23585, + 23580, + 25955, + 25937, + 25917, + 25914, + 25910, + 25907, + 25901, + 25873 + ], + "topics": [ + 1 + ], + "emoji": "🙋‍♀️", + "custom_emoji_url": null, + "custom_emoji_dark_url": null + }, + { + "id": 364, + "name": "Introductions", + "slug": "introductions", + "space_group_id": 5, + "space_group_name": "Welcome", + "url": "https://circle.upfront.so/c/introductions", + "community_id": 5, + "is_private": true, + "hide_post_settings": false, + "display_view": "posts", + "post_ids": [ + 986287, + 444782, + 58522, + 25423, + 25422, + 25421, + 25420, + 25424, + 26551, + 26543, + 26539, + 26501, + 26484, + 26522, + 26549, + 26523, + 26520, + 26512, + 26474, + 26513, + 26511, + 26499, + 26495, + 26493, + 25762, + 26545, + 26526, + 26508, + 26561, + 26552, + 26550, + 26541, + 26507, + 26486, + 26476, + 26563, + 26547, + 26525, + 26516, + 26502, + 26494, + 26489, + 26468, + 25754, + 25505, + 26531, + 26528, + 26518, + 26514, + 26488, + 26481, + 26479, + 26470, + 25760, + 26535, + 26519, + 26506, + 26491, + 25757, + 26560, + 26553, + 26534, + 25583, + 25578, + 25487, + 26559, + 26537, + 26509, + 26498, + 25577, + 26548, + 26540, + 26527, + 26510, + 26482, + 26473, + 25758, + 25580, + 26564, + 26562, + 26472, + 25586, + 25579, + 26555, + 26524, + 25761, + 25759, + 25584, + 25581, + 26554, + 26546, + 26542, + 26517, + 26500, + 26483, + 26467, + 23958, + 26558, + 26532, + 26530, + 26521, + 26505, + 26556, + 26538, + 26497, + 26496, + 26471, + 25763, + 25755, + 26544, + 26536, + 26533, + 26529, + 26504, + 26503, + 26492, + 26490, + 26487, + 26480, + 26478, + 26477, + 26475, + 26557, + 26515, + 26485, + 25582, + 23599, + 23596, + 23593, + 23592, + 23582, + 26469, + 25756, + 25585, + 23296, + 21565, + 4246 + ], + "is_post_disabled": false, + "space_type": "basic", + "hide_topic_settings": false, + "is_topic_disabled": false, + "topic_ids": [ + 986287, + 444782, + 58522, + 25423, + 25422, + 25421, + 25420, + 25424, + 26551, + 26543, + 26539, + 26501, + 26484, + 26522, + 26549, + 26523, + 26520, + 26512, + 26474, + 26513, + 26511, + 26499, + 26495, + 26493, + 25762, + 26545, + 26526, + 26508, + 26561, + 26552, + 26550, + 26541, + 26507, + 26486, + 26476, + 26563, + 26547, + 26525, + 26516, + 26502, + 26494, + 26489, + 26468, + 25754, + 25505, + 26531, + 26528, + 26518, + 26514, + 26488, + 26481, + 26479, + 26470, + 25760, + 26535, + 26519, + 26506, + 26491, + 25757, + 26560, + 26553, + 26534, + 25583, + 25578, + 25487, + 26559, + 26537, + 26509, + 26498, + 25577, + 26548, + 26540, + 26527, + 26510, + 26482, + 26473, + 25758, + 25580, + 26564, + 26562, + 26472, + 25586, + 25579, + 26555, + 26524, + 25761, + 25759, + 25584, + 25581, + 26554, + 26546, + 26542, + 26517, + 26500, + 26483, + 26467, + 23958, + 26558, + 26532, + 26530, + 26521, + 26505, + 26556, + 26538, + 26497, + 26496, + 26471, + 25763, + 25755, + 26544, + 26536, + 26533, + 26529, + 26504, + 26503, + 26492, + 26490, + 26487, + 26480, + 26478, + 26477, + 26475, + 26557, + 26515, + 26485, + 25582, + 23599, + 23596, + 23593, + 23592, + 23582, + 26469, + 25756, + 25585, + 23296, + 21565, + 4246 + ], + "topics": [ + 1 + ], + "emoji": "👋", + "custom_emoji_url": null, + "custom_emoji_dark_url": null + }, + { + "id": 369, + "name": "Trip reports", + "slug": "channels", + "space_group_id": 2112, + "space_group_name": "Economy", + "url": "https://circle.upfront.so/c/channels", + "community_id": 5, + "is_private": true, + "hide_post_settings": false, + "display_view": "list", + "post_ids": [ + 645166, + 565972, + 98389, + 25444, + 25442, + 25441, + 25440, + 25443, + 26957, + 26944, + 26931, + 26905, + 26872, + 26867, + 25797, + 26954, + 26926, + 26924, + 26919, + 26887, + 26947, + 26932, + 26882, + 26877, + 25801, + 26955, + 26945, + 26941, + 26934, + 26927, + 26910, + 26886, + 26870, + 26865, + 26951, + 26917, + 26893, + 26888, + 25803, + 26960, + 26906, + 26904, + 26897, + 26885, + 25798, + 26948, + 26915, + 26900, + 26889, + 25800, + 26907, + 26903, + 26902, + 26901, + 26892, + 26884, + 25491, + 26930, + 26868, + 25619, + 26962, + 26895, + 26880, + 26864, + 26929, + 26922, + 26874, + 26920, + 26912, + 26908, + 26899, + 26896, + 25623, + 26938, + 26928, + 26913, + 26890, + 26875, + 25795, + 26958, + 26953, + 26923, + 26879, + 26876, + 25799, + 25796, + 25625, + 25620, + 26961, + 26956, + 26952, + 26943, + 26921, + 26881, + 26863, + 25616, + 26959, + 26939, + 26911, + 26866, + 25624, + 25621, + 26949, + 26940, + 26937, + 26936, + 26933, + 26925, + 26916, + 26898, + 26894, + 26883, + 26871, + 26869, + 25794, + 25509, + 26950, + 26935, + 26918, + 26942, + 26891, + 26878, + 25802, + 25618, + 25617, + 26946, + 26914, + 26909, + 26873, + 25622, + 5115 + ], + "is_post_disabled": false, + "space_type": "basic", + "hide_topic_settings": false, + "is_topic_disabled": false, + "topic_ids": [ + 645166, + 565972, + 98389, + 25444, + 25442, + 25441, + 25440, + 25443, + 26957, + 26944, + 26931, + 26905, + 26872, + 26867, + 25797, + 26954, + 26926, + 26924, + 26919, + 26887, + 26947, + 26932, + 26882, + 26877, + 25801, + 26955, + 26945, + 26941, + 26934, + 26927, + 26910, + 26886, + 26870, + 26865, + 26951, + 26917, + 26893, + 26888, + 25803, + 26960, + 26906, + 26904, + 26897, + 26885, + 25798, + 26948, + 26915, + 26900, + 26889, + 25800, + 26907, + 26903, + 26902, + 26901, + 26892, + 26884, + 25491, + 26930, + 26868, + 25619, + 26962, + 26895, + 26880, + 26864, + 26929, + 26922, + 26874, + 26920, + 26912, + 26908, + 26899, + 26896, + 25623, + 26938, + 26928, + 26913, + 26890, + 26875, + 25795, + 26958, + 26953, + 26923, + 26879, + 26876, + 25799, + 25796, + 25625, + 25620, + 26961, + 26956, + 26952, + 26943, + 26921, + 26881, + 26863, + 25616, + 26959, + 26939, + 26911, + 26866, + 25624, + 25621, + 26949, + 26940, + 26937, + 26936, + 26933, + 26925, + 26916, + 26898, + 26894, + 26883, + 26871, + 26869, + 25794, + 25509, + 26950, + 26935, + 26918, + 26942, + 26891, + 26878, + 25802, + 25618, + 25617, + 26946, + 26914, + 26909, + 26873, + 25622, + 5115 + ], + "topics": [ + 1 + ], + "emoji": "👩‍💻", + "custom_emoji_url": null, + "custom_emoji_dark_url": null + } +] diff --git a/tests/stubs/responses/subscriptions.json b/tests/stubs/responses/subscriptions.json new file mode 100644 index 0000000..a4e4331 --- /dev/null +++ b/tests/stubs/responses/subscriptions.json @@ -0,0 +1,125 @@ +[ + { + "id": 266787, + "user_id": 0, + "community_id": 11111, + "community_member_id": 0, + "processor_id": "sub_1a2b3456cDE7890122", + "status": "active", + "fee_percent": "0.5", + "ends_at": null, + "trial_ends_at": null, + "deleted_at": null, + "created_at": "2023-05-11T16:18:53.042Z", + "updated_at": "2023-05-11T16:18:53.042Z", + "renews_at": "2023-06-11T16:18:51.000Z", + "currency": "usd", + "community_member": { + "id": 0, + "name": "Member One", + "email": "member1@circle.co", + "public_uid": "a38bb250", + "created_at": "2022-03-16T14:13:54.248Z", + "updated_at": "2023-04-18T14:32:52.809Z", + "deleted_at": null + }, + "paywalls": [ + { + "id": 0, + "status": "active", + "display_name": "My Course", + "internal_name": "Course only", + "currency": "usd", + "price": { + "amount_in_cents": 1000, + "type": "subscription", + "interval_count": 1, + "interval": "monthly", + "currency": "usd" + } + } + ] + }, + { + "id": 169143, + "user_id": 0, + "community_id": 11111, + "community_member_id": 0, + "processor_id": "sub_1a2b3456cDE78901234", + "status": "active", + "fee_percent": "0.5", + "ends_at": null, + "trial_ends_at": "2023-04-19T18:25:10.000Z", + "deleted_at": null, + "created_at": "2023-04-18T18:25:11.150Z", + "updated_at": "2023-04-19T18:26:51.348Z", + "renews_at": "2023-05-19T18:25:10.000Z", + "currency": "usd", + "community_member": { + "id": 0, + "name": "Member Two", + "email": "member2@circle.co", + "public_uid": "97c573eb", + "created_at": "2023-04-18T18:25:09.921Z", + "updated_at": "2023-04-18T18:25:32.137Z", + "deleted_at": null + }, + "paywalls": [ + { + "id": 0, + "status": "active", + "display_name": "Level A", + "internal_name": "Basic membership monthly", + "currency": "usd", + "price": { + "amount_in_cents": 1200, + "type": "subscription", + "interval_count": 1, + "interval": "monthly", + "currency": "usd" + } + } + ] + }, + { + "id": 156687, + "user_id": 0, + "community_id": 11111, + "community_member_id": 0, + "processor_id": "sub_1a2b3456cDE7890122345t57", + "status": "active", + "fee_percent": "0.5", + "ends_at": null, + "trial_ends_at": "2023-04-18T19:36:34.000Z", + "deleted_at": null, + "created_at": "2023-03-27T19:36:35.441Z", + "updated_at": "2023-04-18T19:36:54.639Z", + "renews_at": "2024-04-18T19:36:34.000Z", + "currency": "usd", + "community_member": { + "id": 0, + "name": "Member Three", + "email": "member3@circle.co", + "public_uid": "02fd30e4", + "created_at": "2023-03-27T19:36:33.952Z", + "updated_at": "2023-03-30T15:01:24.446Z", + "deleted_at": null + }, + "paywalls": [ + { + "id": 0, + "status": "active", + "display_name": "Level A", + "internal_name": "Basic membership annual", + "currency": "usd", + "price": { + "amount_in_cents": 1200, + "type": "subscription", + "interval_count": 1, + "interval": "yearly", + "currency": "usd" + } + } + ] + } +] diff --git a/tests/stubs/responses/tagged_members.json b/tests/stubs/responses/tagged_members.json new file mode 100644 index 0000000..594493c --- /dev/null +++ b/tests/stubs/responses/tagged_members.json @@ -0,0 +1,24 @@ +[ + { + "id": 7781149, + "member_tag_id": 54710, + "member_tag_name": "Founder", + "member_tag_emoji": "👑", + "user_id": 0, + "user_email": "member1@circle.co", + "community_member_id": 0, + "created_at": "2023-05-10T21:35:32.426Z", + "updated_at": "2023-05-10T21:35:32.426Z" + }, + { + "id": 7778852, + "member_tag_id": 54710, + "member_tag_name": "Founder", + "member_tag_emoji": "👑", + "user_id": 0, + "user_email": "member2@circle.co", + "community_member_id": 0, + "created_at": "2023-05-10T20:44:14.457Z", + "updated_at": "2023-05-10T20:44:14.457Z" + } +] diff --git a/tests/stubs/responses/topics.json b/tests/stubs/responses/topics.json new file mode 100644 index 0000000..bd031c9 --- /dev/null +++ b/tests/stubs/responses/topics.json @@ -0,0 +1,422 @@ +[ + { + "id": 5671, + "name": "123456789", + "admin_only": false, + "created_at": "2024-05-13T19:06:53.793Z", + "updated_at": "2024-05-13T19:06:53.793Z" + }, + { + "id": 12375, + "name": "123456789123456789123456789122345678912345", + "admin_only": false, + "created_at": "2024-05-24T12:42:55.717Z", + "updated_at": "2024-05-24T12:42:55.717Z" + }, + { + "id": 36, + "name": "Add", + "admin_only": false, + "created_at": "2024-05-01T09:40:36.287Z", + "updated_at": "2024-05-01T09:40:36.287Z" + }, + { + "id": 35, + "name": "Admin Only Topic", + "admin_only": true, + "created_at": "2024-04-29T06:35:13.787Z", + "updated_at": "2024-04-29T06:35:13.787Z" + }, + { + "id": 23, + "name": "android", + "admin_only": false, + "created_at": "2024-04-22T20:11:44.249Z", + "updated_at": "2024-04-22T20:11:44.249Z" + }, + { + "id": 1, + "name": "Community", + "admin_only": false, + "created_at": "2024-02-28T15:58:42.478Z", + "updated_at": "2024-02-28T15:58:42.478Z" + }, + { + "id": 9, + "name": "Community feedback", + "admin_only": false, + "created_at": "2024-03-26T07:56:44.534Z", + "updated_at": "2024-03-26T07:56:44.534Z" + }, + { + "id": 2, + "name": "Courses", + "admin_only": false, + "created_at": "2024-02-28T15:59:09.214Z", + "updated_at": "2024-02-28T15:59:09.214Z" + }, + { + "id": 10450, + "name": "Drinks", + "admin_only": false, + "created_at": "2024-05-21T14:07:38.206Z", + "updated_at": "2024-05-21T14:07:38.206Z" + }, + { + "id": 37, + "name": "Duplicate", + "admin_only": false, + "created_at": "2024-05-01T09:40:42.258Z", + "updated_at": "2024-05-01T09:40:42.258Z" + }, + { + "id": 42, + "name": "FAQs", + "admin_only": false, + "created_at": "2024-05-01T22:40:47.249Z", + "updated_at": "2024-05-03T21:54:02.550Z" + }, + { + "id": 43, + "name": "Get started", + "admin_only": true, + "created_at": "2024-05-02T21:55:14.820Z", + "updated_at": "2024-05-03T21:29:55.968Z" + }, + { + "id": 7, + "name": "How to earn", + "admin_only": false, + "created_at": "2024-03-26T07:55:58.675Z", + "updated_at": "2024-03-26T07:55:58.675Z" + }, + { + "id": 8, + "name": "Important topic", + "admin_only": false, + "created_at": "2024-03-26T07:56:13.623Z", + "updated_at": "2024-03-26T07:56:13.623Z" + }, + { + "id": 28, + "name": "jim", + "admin_only": false, + "created_at": "2024-04-23T11:58:10.850Z", + "updated_at": "2024-04-23T11:58:10.850Z" + }, + { + "id": 5669, + "name": "Maluco", + "admin_only": false, + "created_at": "2024-05-13T19:06:38.098Z", + "updated_at": "2024-05-13T19:06:38.098Z" + }, + { + "id": 18, + "name": "Marketing", + "admin_only": false, + "created_at": "2024-04-18T16:09:27.411Z", + "updated_at": "2024-04-18T16:09:27.411Z" + }, + { + "id": 38, + "name": "My first shot", + "admin_only": false, + "created_at": "2024-05-01T09:40:51.472Z", + "updated_at": "2024-05-01T09:40:51.472Z" + }, + { + "id": 6465, + "name": "Newsletter", + "admin_only": false, + "created_at": "2024-05-14T18:20:45.716Z", + "updated_at": "2024-05-14T18:20:45.716Z" + }, + { + "id": 5668, + "name": "Odara", + "admin_only": false, + "created_at": "2024-05-13T19:06:32.969Z", + "updated_at": "2024-05-13T19:06:32.969Z" + }, + { + "id": 5655, + "name": "Palmeiras", + "admin_only": false, + "created_at": "2024-05-13T19:01:50.648Z", + "updated_at": "2024-05-13T19:01:50.648Z" + }, + { + "id": 26, + "name": "palmeiras and this topic is too big I want to see how this is going to be reflected in different areas", + "admin_only": false, + "created_at": "2024-04-22T20:12:25.366Z", + "updated_at": "2024-05-01T08:10:40.678Z" + }, + { + "id": 5, + "name": "Pinned", + "admin_only": true, + "created_at": "2024-03-25T19:17:47.041Z", + "updated_at": "2024-03-25T19:17:47.041Z" + }, + { + "id": 29, + "name": "Product", + "admin_only": false, + "created_at": "2024-04-24T14:02:30.922Z", + "updated_at": "2024-04-24T14:02:30.922Z" + }, + { + "id": 24, + "name": "react native", + "admin_only": false, + "created_at": "2024-04-22T20:11:52.662Z", + "updated_at": "2024-04-22T20:11:52.662Z" + }, + { + "id": 11079, + "name": "Reading", + "admin_only": false, + "created_at": "2024-05-22T13:13:16.679Z", + "updated_at": "2024-05-22T13:13:16.679Z" + }, + { + "id": 25, + "name": "really long topic name for testing, really long topic name for testing", + "admin_only": false, + "created_at": "2024-04-22T20:12:19.322Z", + "updated_at": "2024-04-22T20:12:19.322Z" + }, + { + "id": 9857, + "name": "Rob's Test Topic No. 1", + "admin_only": false, + "created_at": "2024-05-20T16:41:18.005Z", + "updated_at": "2024-05-20T16:41:18.005Z" + }, + { + "id": 5657, + "name": "Rony Rustico", + "admin_only": false, + "created_at": "2024-05-13T19:02:07.585Z", + "updated_at": "2024-05-13T19:02:07.585Z" + }, + { + "id": 44, + "name": "Sample", + "admin_only": false, + "created_at": "2024-05-06T15:49:29.652Z", + "updated_at": "2024-05-06T15:49:29.652Z" + }, + { + "id": 5659, + "name": "São Paulo", + "admin_only": false, + "created_at": "2024-05-13T19:02:26.399Z", + "updated_at": "2024-05-13T19:02:26.399Z" + }, + { + "id": 271, + "name": "Social Media", + "admin_only": false, + "created_at": "2024-05-07T18:10:49.302Z", + "updated_at": "2024-05-07T18:10:49.302Z" + }, + { + "id": 30, + "name": "Solved", + "admin_only": false, + "created_at": "2024-04-24T17:30:33.941Z", + "updated_at": "2024-04-24T17:30:33.941Z" + }, + { + "id": 41, + "name": "Spaces", + "admin_only": true, + "created_at": "2024-05-01T20:49:41.306Z", + "updated_at": "2024-05-01T20:49:41.306Z" + }, + { + "id": 14392, + "name": "Test", + "admin_only": false, + "created_at": "2024-05-29T08:51:49.869Z", + "updated_at": "2024-05-29T08:51:49.869Z" + }, + { + "id": 5656, + "name": "Test 2", + "admin_only": false, + "created_at": "2024-05-13T19:01:57.395Z", + "updated_at": "2024-05-13T19:01:57.395Z" + }, + { + "id": 27, + "name": "test123", + "admin_only": false, + "created_at": "2024-04-23T11:58:00.205Z", + "updated_at": "2024-04-23T11:58:00.205Z" + }, + { + "id": 5652, + "name": "Testing 1 testing 1 tes", + "admin_only": false, + "created_at": "2024-05-13T19:01:37.255Z", + "updated_at": "2024-05-13T19:01:37.255Z" + }, + { + "id": 5670, + "name": "testing testing testing testing testing testing", + "admin_only": false, + "created_at": "2024-05-13T19:06:47.534Z", + "updated_at": "2024-05-13T19:06:47.534Z" + }, + { + "id": 14391, + "name": "Topic", + "admin_only": false, + "created_at": "2024-05-29T08:51:31.737Z", + "updated_at": "2024-05-29T08:51:31.737Z" + }, + { + "id": 16803, + "name": "topic 10", + "admin_only": false, + "created_at": "2024-06-03T12:55:14.995Z", + "updated_at": "2024-06-03T12:55:14.995Z" + }, + { + "id": 16804, + "name": "topic 11", + "admin_only": false, + "created_at": "2024-06-03T12:55:17.401Z", + "updated_at": "2024-06-03T12:55:17.401Z" + }, + { + "id": 16805, + "name": "topic 12", + "admin_only": false, + "created_at": "2024-06-03T12:55:20.039Z", + "updated_at": "2024-06-03T12:55:20.039Z" + }, + { + "id": 16806, + "name": "topic 13", + "admin_only": false, + "created_at": "2024-06-03T12:55:23.172Z", + "updated_at": "2024-06-03T12:55:23.172Z" + }, + { + "id": 16807, + "name": "topic 14", + "admin_only": false, + "created_at": "2024-06-03T12:55:26.266Z", + "updated_at": "2024-06-03T12:55:26.266Z" + }, + { + "id": 16808, + "name": "topic 15", + "admin_only": false, + "created_at": "2024-06-03T12:55:29.938Z", + "updated_at": "2024-06-03T12:55:29.938Z" + }, + { + "id": 16809, + "name": "topic 16", + "admin_only": false, + "created_at": "2024-06-03T12:55:33.373Z", + "updated_at": "2024-06-03T12:55:33.373Z" + }, + { + "id": 16810, + "name": "topic 17", + "admin_only": false, + "created_at": "2024-06-03T12:55:36.008Z", + "updated_at": "2024-06-03T12:55:36.008Z" + }, + { + "id": 16811, + "name": "topic 18", + "admin_only": false, + "created_at": "2024-06-03T12:55:38.754Z", + "updated_at": "2024-06-03T12:55:38.754Z" + }, + { + "id": 16812, + "name": "topic 19", + "admin_only": false, + "created_at": "2024-06-03T12:55:42.760Z", + "updated_at": "2024-06-03T12:55:42.760Z" + }, + { + "id": 16795, + "name": "topic 2", + "admin_only": false, + "created_at": "2024-06-03T12:54:50.734Z", + "updated_at": "2024-06-03T12:54:50.734Z" + }, + { + "id": 16813, + "name": "topic 20", + "admin_only": false, + "created_at": "2024-06-03T12:55:45.423Z", + "updated_at": "2024-06-03T12:55:45.423Z" + }, + { + "id": 16796, + "name": "topic 3", + "admin_only": false, + "created_at": "2024-06-03T12:54:53.600Z", + "updated_at": "2024-06-03T12:54:53.600Z" + }, + { + "id": 16797, + "name": "topic 4", + "admin_only": false, + "created_at": "2024-06-03T12:54:56.471Z", + "updated_at": "2024-06-03T12:54:56.471Z" + }, + { + "id": 16798, + "name": "topic 5", + "admin_only": false, + "created_at": "2024-06-03T12:55:00.306Z", + "updated_at": "2024-06-03T12:55:00.306Z" + }, + { + "id": 16799, + "name": "topic 6", + "admin_only": false, + "created_at": "2024-06-03T12:55:03.267Z", + "updated_at": "2024-06-03T12:55:03.267Z" + }, + { + "id": 16800, + "name": "topic 7", + "admin_only": false, + "created_at": "2024-06-03T12:55:06.408Z", + "updated_at": "2024-06-03T12:55:06.408Z" + }, + { + "id": 16801, + "name": "topic 8", + "admin_only": false, + "created_at": "2024-06-03T12:55:08.967Z", + "updated_at": "2024-06-03T12:55:08.967Z" + }, + { + "id": 16802, + "name": "topic 9", + "admin_only": false, + "created_at": "2024-06-03T12:55:11.379Z", + "updated_at": "2024-06-03T12:55:11.379Z" + }, + { + "id": 6, + "name": "Where people gather", + "admin_only": false, + "created_at": "2024-03-26T07:55:39.323Z", + "updated_at": "2024-03-26T07:55:39.323Z" + } +]