diff --git a/lib/Controller/PostController.php b/lib/Controller/PostController.php index 545b4ad..2d5018b 100644 --- a/lib/Controller/PostController.php +++ b/lib/Controller/PostController.php @@ -63,65 +63,7 @@ class PostController extends OCSController { } /** - * Get posts by thread - * - * @param int $threadId Thread ID - * @param int<1, 200> $limit Maximum number of posts to return - * @param int $offset Offset for pagination - * @return DataResponse>, array{}> - * - * 200: Posts returned - */ - #[NoAdminRequired] - #[PublicPage] - #[RequirePermission('canView', resourceType: 'category', resourceIdFromThreadId: 'threadId')] - #[ApiRoute(verb: 'GET', url: '/api/threads/{threadId}/posts')] - public function byThread(int $threadId, int $limit = 50, int $offset = 0): DataResponse { - try { - $posts = $this->postMapper->findByThreadId($threadId, $limit, $offset); - - // Prefetch BBCodes once for all posts to avoid repeated queries - $bbcodes = $this->bbCodeMapper->findAllEnabled(); - - // Fetch reactions for all posts at once (performance optimization) - $postIds = array_map(fn ($p) => $p->getId(), $posts); - $reactions = $this->reactionMapper->findByPostIds($postIds); - - // Group reactions by post ID - $reactionsByPostId = []; - foreach ($reactions as $reaction) { - $postId = $reaction->getPostId(); - if (!isset($reactionsByPostId[$postId])) { - $reactionsByPostId[$postId] = []; - } - $reactionsByPostId[$postId][] = $reaction; - } - - // Get current user ID to mark user's reactions - $currentUserId = $this->userSession->getUser()?->getUID(); - - // Extract unique author IDs - $authorIds = array_unique(array_map(fn ($p) => $p->getAuthorId(), $posts)); - - // Batch fetch author data (includes roles) - $authors = $this->userService->enrichMultipleUsers($authorIds); - - // Get category ID for permission checks - $categoryId = $this->permissionService->getCategoryIdFromThread($threadId); - - // Enrich posts with content, reactions, and pre-fetched author data - return new DataResponse(array_map(function ($p) use ($bbcodes, $reactionsByPostId, $currentUserId, $authors, $categoryId) { - $postReactions = $reactionsByPostId[$p->getId()] ?? []; - return $this->postEnrichmentService->enrichPost($p, $bbcodes, $postReactions, $currentUserId, $authors[$p->getAuthorId()], $categoryId); - }, $posts)); - } catch (\Exception $e) { - $this->logger->error('Error fetching posts by thread: ' . $e->getMessage()); - return new DataResponse(['error' => 'Failed to fetch posts'], Http::STATUS_INTERNAL_SERVER_ERROR); - } - } - - /** - * Get paginated posts by thread with first post separated + * Get posts by thread with first post separated * * @param int $threadId Thread ID * @param int $page Page number (1-indexed) @@ -133,8 +75,8 @@ class PostController extends OCSController { #[NoAdminRequired] #[PublicPage] #[RequirePermission('canView', resourceType: 'category', resourceIdFromThreadId: 'threadId')] - #[ApiRoute(verb: 'GET', url: '/api/threads/{threadId}/posts/paginated')] - public function byThreadPaginated(int $threadId, int $page = 0, int $perPage = 20): DataResponse { + #[ApiRoute(verb: 'GET', url: '/api/threads/{threadId}/posts')] + public function byThread(int $threadId, int $page = 0, int $perPage = 20): DataResponse { try { // Get current user ID $currentUserId = $this->userSession->getUser()?->getUID(); @@ -245,7 +187,7 @@ class PostController extends OCSController { ], ]); } catch (\Exception $e) { - $this->logger->error('Error fetching paginated posts by thread: ' . $e->getMessage()); + $this->logger->error('Error fetching posts by thread: ' . $e->getMessage()); return new DataResponse(['error' => 'Failed to fetch posts'], Http::STATUS_INTERNAL_SERVER_ERROR); } } diff --git a/lib/Controller/ThreadController.php b/lib/Controller/ThreadController.php index e59e268..678069c 100644 --- a/lib/Controller/ThreadController.php +++ b/lib/Controller/ThreadController.php @@ -105,51 +105,6 @@ class ThreadController extends OCSController { * Get threads by category * * @param int $categoryId Category ID - * @param int<1, 200> $limit Maximum number of threads to return - * @param int $offset Offset for pagination - * @return DataResponse>, array{}> - * - * 200: Threads returned - */ - #[NoAdminRequired] - #[PublicPage] - #[RequirePermission('canView', resourceType: 'category', resourceIdParam: 'categoryId')] - #[ApiRoute(verb: 'GET', url: '/api/categories/{categoryId}/threads')] - public function byCategory(int $categoryId, int $limit = 50, int $offset = 0): DataResponse { - try { - $threads = $this->threadMapper->findByCategoryId($categoryId, $limit, $offset); - - // Extract unique author IDs (thread authors + last reply authors) - $authorIds = array_map(fn ($t) => $t->getAuthorId(), $threads); - $lastReplyAuthorIds = array_filter(array_map(fn ($t) => $t->getLastReplyAuthorId(), $threads)); - $allAuthorIds = array_unique(array_merge($authorIds, $lastReplyAuthorIds)); - - // Batch fetch author data (includes roles) - $authors = $this->userService->enrichMultipleUsers($allAuthorIds); - - // Enrich threads with pre-fetched author data and last reply info - return new DataResponse(array_map(function ($t) use ($authors) { - $lastReply = null; - $lastReplyAuthorId = $t->getLastReplyAuthorId(); - if ($lastReplyAuthorId !== null) { - $lastReply = [ - 'postId' => $t->getLastPostId(), - 'author' => $authors[$lastReplyAuthorId] ?? null, - 'createdAt' => $t->getLastReplyAt(), - ]; - } - return $this->threadEnrichmentService->enrichThread($t, $authors[$t->getAuthorId()] ?? null, $lastReply); - }, $threads)); - } catch (\Exception $e) { - $this->logger->error('Error fetching threads by category: ' . $e->getMessage()); - return new DataResponse(['error' => 'Failed to fetch threads'], Http::STATUS_INTERNAL_SERVER_ERROR); - } - } - - /** - * Get paginated threads by category - * - * @param int $categoryId Category ID * @param int $page Page number (1-indexed) * @param int $perPage Number of threads per page * @return DataResponse>, pagination: array{page: int, perPage: int, total: int, totalPages: int}}, array{}> @@ -159,8 +114,8 @@ class ThreadController extends OCSController { #[NoAdminRequired] #[PublicPage] #[RequirePermission('canView', resourceType: 'category', resourceIdParam: 'categoryId')] - #[ApiRoute(verb: 'GET', url: '/api/categories/{categoryId}/threads/paginated')] - public function byCategoryPaginated(int $categoryId, int $page = 1, int $perPage = 20): DataResponse { + #[ApiRoute(verb: 'GET', url: '/api/categories/{categoryId}/threads')] + public function byCategory(int $categoryId, int $page = 1, int $perPage = 20): DataResponse { try { // Count total threads in category $totalThreads = $this->threadMapper->countByCategoryId($categoryId); @@ -205,7 +160,7 @@ class ThreadController extends OCSController { ], ]); } catch (\Exception $e) { - $this->logger->error('Error fetching paginated threads by category: ' . $e->getMessage()); + $this->logger->error('Error fetching threads by category: ' . $e->getMessage()); return new DataResponse(['error' => 'Failed to fetch threads'], Http::STATUS_INTERNAL_SERVER_ERROR); } } diff --git a/openapi-full.json b/openapi-full.json index 10f994c..8adf00d 100644 --- a/openapi-full.json +++ b/openapi-full.json @@ -6089,107 +6089,7 @@ "/ocs/v2.php/apps/forum/api/threads/{threadId}/posts": { "get": { "operationId": "post-by-thread", - "summary": "Get posts by thread", - "tags": [ - "post" - ], - "security": [ - {}, - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "threadId", - "in": "path", - "description": "Thread ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "limit", - "in": "query", - "description": "Maximum number of posts to return", - "schema": { - "type": "integer", - "format": "int64", - "default": 50, - "minimum": 1, - "maximum": 200 - } - }, - { - "name": "offset", - "in": "query", - "description": "Offset for pagination", - "schema": { - "type": "integer", - "format": "int64", - "default": 0 - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Posts returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/threads/{threadId}/posts/paginated": { - "get": { - "operationId": "post-by-thread-paginated", - "summary": "Get paginated posts by thread with first post separated", + "summary": "Get posts by thread with first post separated", "tags": [ "post" ], @@ -10513,106 +10413,6 @@ "basic_auth": [] } ], - "parameters": [ - { - "name": "categoryId", - "in": "path", - "description": "Category ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "limit", - "in": "query", - "description": "Maximum number of threads to return", - "schema": { - "type": "integer", - "format": "int64", - "default": 50, - "minimum": 1, - "maximum": 200 - } - }, - { - "name": "offset", - "in": "query", - "description": "Offset for pagination", - "schema": { - "type": "integer", - "format": "int64", - "default": 0 - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Threads returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/categories/{categoryId}/threads/paginated": { - "get": { - "operationId": "thread-by-category-paginated", - "summary": "Get paginated threads by category", - "tags": [ - "thread" - ], - "security": [ - {}, - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], "parameters": [ { "name": "categoryId", diff --git a/openapi.json b/openapi.json index 5f19445..bf0556d 100644 --- a/openapi.json +++ b/openapi.json @@ -6089,107 +6089,7 @@ "/ocs/v2.php/apps/forum/api/threads/{threadId}/posts": { "get": { "operationId": "post-by-thread", - "summary": "Get posts by thread", - "tags": [ - "post" - ], - "security": [ - {}, - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "threadId", - "in": "path", - "description": "Thread ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "limit", - "in": "query", - "description": "Maximum number of posts to return", - "schema": { - "type": "integer", - "format": "int64", - "default": 50, - "minimum": 1, - "maximum": 200 - } - }, - { - "name": "offset", - "in": "query", - "description": "Offset for pagination", - "schema": { - "type": "integer", - "format": "int64", - "default": 0 - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Posts returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/threads/{threadId}/posts/paginated": { - "get": { - "operationId": "post-by-thread-paginated", - "summary": "Get paginated posts by thread with first post separated", + "summary": "Get posts by thread with first post separated", "tags": [ "post" ], @@ -10513,106 +10413,6 @@ "basic_auth": [] } ], - "parameters": [ - { - "name": "categoryId", - "in": "path", - "description": "Category ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "limit", - "in": "query", - "description": "Maximum number of threads to return", - "schema": { - "type": "integer", - "format": "int64", - "default": 50, - "minimum": 1, - "maximum": 200 - } - }, - { - "name": "offset", - "in": "query", - "description": "Offset for pagination", - "schema": { - "type": "integer", - "format": "int64", - "default": 0 - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Threads returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/categories/{categoryId}/threads/paginated": { - "get": { - "operationId": "thread-by-category-paginated", - "summary": "Get paginated threads by category", - "tags": [ - "thread" - ], - "security": [ - {}, - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], "parameters": [ { "name": "categoryId", diff --git a/src/views/CategoryView.vue b/src/views/CategoryView.vue index 3a73a68..53b7f30 100644 --- a/src/views/CategoryView.vue +++ b/src/views/CategoryView.vue @@ -307,15 +307,12 @@ export default defineComponent({ } } - const resp = await ocs.get( - `/categories/${this.category!.id}/threads/paginated`, - { - params: { - page, - perPage: this.perPage, - }, + const resp = await ocs.get(`/categories/${this.category!.id}/threads`, { + params: { + page, + perPage: this.perPage, }, - ) + }) const data = resp.data if (data) { diff --git a/src/views/ThreadView.vue b/src/views/ThreadView.vue index 962bce9..5ac8849 100644 --- a/src/views/ThreadView.vue +++ b/src/views/ThreadView.vue @@ -616,15 +616,12 @@ export default defineComponent({ } } - const resp = await ocs.get( - `/threads/${this.thread!.id}/posts/paginated`, - { - params: { - page, - perPage: this.perPage, - }, + const resp = await ocs.get(`/threads/${this.thread!.id}/posts`, { + params: { + page, + perPage: this.perPage, }, - ) + }) const data = resp.data if (data) { diff --git a/src/views/__tests__/ThreadView.test.ts b/src/views/__tests__/ThreadView.test.ts index d1f800c..377fce9 100644 --- a/src/views/__tests__/ThreadView.test.ts +++ b/src/views/__tests__/ThreadView.test.ts @@ -158,7 +158,7 @@ describe('ThreadView', () => { mockFetchThread.mockResolvedValue(mockThread.value) mockCheckCategoryPermission.mockResolvedValue(false) mockOcsGet.mockImplementation((url: string) => { - if (url.includes('/posts/paginated')) { + if (url.includes('/posts')) { return mockGetResponse({ data: { firstPost: mockFirstPost, @@ -360,7 +360,7 @@ describe('ThreadView', () => { }) mockOcsGet.mockImplementation((url: string) => { - if (url.includes('/posts/paginated')) { + if (url.includes('/posts')) { return mockGetResponse({ data: { firstPost: guestFirstPost, @@ -407,7 +407,7 @@ describe('ThreadView', () => { }) mockOcsGet.mockImplementation((url: string) => { - if (url.includes('/posts/paginated')) { + if (url.includes('/posts')) { return mockGetResponse({ data: { firstPost: mockFirstPost, @@ -459,7 +459,7 @@ describe('ThreadView', () => { mockFetchThread.mockResolvedValue(mockThread.value) mockOcsGet.mockImplementation((url: string) => { - if (url.includes('/posts/paginated')) { + if (url.includes('/posts')) { return mockGetResponse({ data: { firstPost: mockFirstPost, @@ -505,7 +505,7 @@ describe('ThreadView', () => { mockFetchThread.mockResolvedValue(mockThread.value) mockOcsGet.mockImplementation((url: string) => { - if (url.includes('/posts/paginated')) { + if (url.includes('/posts')) { return mockGetResponse({ data: { firstPost: mockFirstPost, @@ -542,7 +542,7 @@ describe('ThreadView', () => { const guestReply = createMockPost({ id: 10, authorId: guestAuthorId, author: guestAuthor }) mockOcsGet.mockImplementation((url: string) => { - if (url.includes('/posts/paginated')) { + if (url.includes('/posts')) { return mockGetResponse({ data: { firstPost: mockFirstPost, diff --git a/tests/unit/Controller/PostControllerTest.php b/tests/unit/Controller/PostControllerTest.php index d4da306..116821f 100644 --- a/tests/unit/Controller/PostControllerTest.php +++ b/tests/unit/Controller/PostControllerTest.php @@ -133,75 +133,25 @@ class PostControllerTest extends TestCase { ); } - public function testByThreadReturnsPostsSuccessfully(): void { - $threadId = 1; - $limit = 50; - $offset = 0; - - // Create mock posts - $post1 = $this->createMockPost(1, $threadId, 'user1', 'Test content 1'); - $post2 = $this->createMockPost(2, $threadId, 'user2', 'Test content 2'); - $posts = [$post1, $post2]; - - // Create mock BBCode - $bbcode = new BBCode(); - $bbcode->setId(1); - $bbcode->setTag('b'); - $bbcode->setReplacement('{content}'); - $bbcode->setEnabled(true); - - // Create mock reactions - $reaction1 = $this->createMockReaction(1, 1, 'user1', '👍'); - $reaction2 = $this->createMockReaction(2, 1, 'user2', '👍'); - - // Mock user session - $user = $this->createMock(IUser::class); - $user->method('getUID')->willReturn('user1'); - $this->userSession->method('getUser')->willReturn($user); - - // Set up expectations - $this->postMapper->expects($this->once()) - ->method('findByThreadId') - ->with($threadId, $limit, $offset) - ->willReturn($posts); - - $this->bbCodeMapper->expects($this->once()) - ->method('findAllEnabled') - ->willReturn([$bbcode]); - - $this->reactionMapper->expects($this->once()) - ->method('findByPostIds') - ->with([1, 2]) - ->willReturn([$reaction1, $reaction2]); - - // Mock userService to return enriched user data - $this->userService->expects($this->once()) - ->method('enrichMultipleUsers') - ->with(['user1', 'user2']) - ->willReturn([ - 'user1' => ['userId' => 'user1', 'displayName' => 'User 1', 'roles' => []], - 'user2' => ['userId' => 'user2', 'displayName' => 'User 2', 'roles' => []], - ]); - - // Execute - $response = $this->controller->byThread($threadId, $limit, $offset); - - // Assert - $this->assertEquals(Http::STATUS_OK, $response->getStatus()); - $data = $response->getData(); - $this->assertIsArray($data); - $this->assertCount(2, $data); - $this->assertEquals(1, $data[0]['id']); - $this->assertEquals(2, $data[1]['id']); - $this->assertArrayHasKey('reactions', $data[0]); - $this->assertArrayHasKey('reactions', $data[1]); - } - public function testByThreadHandlesEmptyPosts(): void { $threadId = 1; + // Mock user session (no user = guest) + $this->userSession->method('getUser')->willReturn(null); + $this->postMapper->expects($this->once()) - ->method('findByThreadId') + ->method('countRepliesByThreadId') + ->with($threadId) + ->willReturn(0); + + $this->postMapper->expects($this->once()) + ->method('findFirstPostByThreadId') + ->with($threadId) + ->willReturn(null); + + $this->postMapper->expects($this->once()) + ->method('findRepliesByThreadId') + ->with($threadId, 20, 0) ->willReturn([]); $this->bbCodeMapper->expects($this->once()) @@ -213,11 +163,20 @@ class PostControllerTest extends TestCase { ->with([]) ->willReturn([]); + $this->userService->method('enrichMultipleUsers')->willReturn([]); + $response = $this->controller->byThread($threadId); $this->assertEquals(Http::STATUS_OK, $response->getStatus()); - $this->assertIsArray($response->getData()); - $this->assertCount(0, $response->getData()); + $data = $response->getData(); + $this->assertArrayHasKey('firstPost', $data); + $this->assertArrayHasKey('replies', $data); + $this->assertArrayHasKey('pagination', $data); + $this->assertNull($data['firstPost']); + $this->assertCount(0, $data['replies']); + $this->assertEquals(1, $data['pagination']['page']); + $this->assertEquals(1, $data['pagination']['totalPages']); + $this->assertEquals(0, $data['pagination']['total']); } public function testShowReturnsPostSuccessfully(): void { @@ -978,7 +937,7 @@ class PostControllerTest extends TestCase { $this->assertEquals(Http::STATUS_OK, $response->getStatus()); } - public function testByThreadPaginatedReturnsPostsSuccessfully(): void { + public function testByThreadReturnsPostsSuccessfully(): void { $threadId = 1; $page = 1; $perPage = 20; @@ -1043,7 +1002,7 @@ class PostControllerTest extends TestCase { ]); // Execute - $response = $this->controller->byThreadPaginated($threadId, $page, $perPage); + $response = $this->controller->byThread($threadId, $page, $perPage); // Assert $this->assertEquals(Http::STATUS_OK, $response->getStatus()); @@ -1059,7 +1018,7 @@ class PostControllerTest extends TestCase { $this->assertEquals(1, $data['pagination']['totalPages']); } - public function testByThreadPaginatedStartsAtLastPageForUnreadThread(): void { + public function testByThreadStartsAtLastPageForUnreadThread(): void { $threadId = 1; $perPage = 20; @@ -1109,7 +1068,7 @@ class PostControllerTest extends TestCase { ]); // Execute with page=0 (auto-calculate start page) - $response = $this->controller->byThreadPaginated($threadId, 0, $perPage); + $response = $this->controller->byThread($threadId, 0, $perPage); // Assert $this->assertEquals(Http::STATUS_OK, $response->getStatus()); @@ -1120,7 +1079,7 @@ class PostControllerTest extends TestCase { $this->assertNull($data['pagination']['lastReadPostId']); } - public function testByThreadPaginatedStartsAtOldestUnreadPage(): void { + public function testByThreadStartsAtOldestUnreadPage(): void { $threadId = 1; $perPage = 20; @@ -1185,7 +1144,7 @@ class PostControllerTest extends TestCase { ]); // Execute with page=0 (auto-calculate start page) - $response = $this->controller->byThreadPaginated($threadId, 0, $perPage); + $response = $this->controller->byThread($threadId, 0, $perPage); // Assert $this->assertEquals(Http::STATUS_OK, $response->getStatus()); @@ -1196,7 +1155,7 @@ class PostControllerTest extends TestCase { $this->assertEquals(31, $data['pagination']['lastReadPostId']); } - public function testByThreadPaginatedGoesToLastPageWhenAllRead(): void { + public function testByThreadGoesToLastPageWhenAllRead(): void { $threadId = 1; $perPage = 20; @@ -1252,7 +1211,7 @@ class PostControllerTest extends TestCase { ]); // Execute with page=0 (auto-calculate start page) - $response = $this->controller->byThreadPaginated($threadId, 0, $perPage); + $response = $this->controller->byThread($threadId, 0, $perPage); // Assert $this->assertEquals(Http::STATUS_OK, $response->getStatus()); @@ -1263,7 +1222,7 @@ class PostControllerTest extends TestCase { $this->assertEquals(50, $data['pagination']['lastReadPostId']); } - public function testByThreadPaginatedWorksForGuestUser(): void { + public function testByThreadWorksForGuestUser(): void { $threadId = 1; $page = 1; $perPage = 20; @@ -1302,7 +1261,7 @@ class PostControllerTest extends TestCase { ]); // Execute - $response = $this->controller->byThreadPaginated($threadId, $page, $perPage); + $response = $this->controller->byThread($threadId, $page, $perPage); // Assert $this->assertEquals(Http::STATUS_OK, $response->getStatus()); @@ -1312,7 +1271,7 @@ class PostControllerTest extends TestCase { $this->assertNull($data['pagination']['lastReadPostId']); } - public function testByThreadPaginatedRespectsExplicitPageParameter(): void { + public function testByThreadRespectsExplicitPageParameter(): void { $threadId = 1; $perPage = 20; @@ -1354,7 +1313,7 @@ class PostControllerTest extends TestCase { ]); // Execute with explicit page=2 - $response = $this->controller->byThreadPaginated($threadId, 2, $perPage); + $response = $this->controller->byThread($threadId, 2, $perPage); // Assert $this->assertEquals(Http::STATUS_OK, $response->getStatus()); diff --git a/tests/unit/Controller/ThreadControllerTest.php b/tests/unit/Controller/ThreadControllerTest.php index 723302b..4953330 100644 --- a/tests/unit/Controller/ThreadControllerTest.php +++ b/tests/unit/Controller/ThreadControllerTest.php @@ -160,15 +160,20 @@ class ThreadControllerTest extends TestCase { public function testByCategoryReturnsThreadsSuccessfully(): void { $categoryId = 1; - $limit = 50; - $offset = 0; + $page = 1; + $perPage = 20; $thread1 = $this->createMockThread(1, $categoryId, 'user1', 'Test Thread 1'); $thread2 = $this->createMockThread(2, $categoryId, 'user2', 'Test Thread 2'); + $this->threadMapper->expects($this->once()) + ->method('countByCategoryId') + ->with($categoryId) + ->willReturn(2); + $this->threadMapper->expects($this->once()) ->method('findByCategoryId') - ->with($categoryId, $limit, $offset) + ->with($categoryId, $perPage, 0) ->willReturn([$thread1, $thread2]); $this->userService->expects($this->once()) @@ -178,12 +183,17 @@ class ThreadControllerTest extends TestCase { 'user2' => ['userId' => 'user2', 'displayName' => 'User 2'], ]); - $response = $this->controller->byCategory($categoryId, $limit, $offset); + $response = $this->controller->byCategory($categoryId, $page, $perPage); $this->assertEquals(Http::STATUS_OK, $response->getStatus()); $data = $response->getData(); - $this->assertIsArray($data); - $this->assertCount(2, $data); + $this->assertArrayHasKey('threads', $data); + $this->assertArrayHasKey('pagination', $data); + $this->assertCount(2, $data['threads']); + $this->assertEquals(1, $data['pagination']['page']); + $this->assertEquals(20, $data['pagination']['perPage']); + $this->assertEquals(2, $data['pagination']['total']); + $this->assertEquals(1, $data['pagination']['totalPages']); } public function testShowReturnsThreadAndIncrementsViewCount(): void { @@ -1141,7 +1151,7 @@ class ThreadControllerTest extends TestCase { 'user2' => ['userId' => 'user2', 'displayName' => 'User 2'], ]); - $response = $this->controller->byCategoryPaginated($categoryId, $page, $perPage); + $response = $this->controller->byCategory($categoryId, $page, $perPage); $this->assertEquals(Http::STATUS_OK, $response->getStatus()); $data = $response->getData(); @@ -1172,7 +1182,7 @@ class ThreadControllerTest extends TestCase { $this->userService->method('enrichMultipleUsers')->willReturn([]); - $response = $this->controller->byCategoryPaginated($categoryId, $page, $perPage); + $response = $this->controller->byCategory($categoryId, $page, $perPage); $this->assertEquals(Http::STATUS_OK, $response->getStatus()); $data = $response->getData(); @@ -1198,7 +1208,7 @@ class ThreadControllerTest extends TestCase { $this->userService->method('enrichMultipleUsers')->willReturn([]); - $response = $this->controller->byCategoryPaginated($categoryId, $page, $perPage); + $response = $this->controller->byCategory($categoryId, $page, $perPage); $this->assertEquals(Http::STATUS_OK, $response->getStatus()); $data = $response->getData(); @@ -1223,7 +1233,7 @@ class ThreadControllerTest extends TestCase { $this->userService->method('enrichMultipleUsers')->willReturn([]); - $response = $this->controller->byCategoryPaginated($categoryId, 5, $perPage); + $response = $this->controller->byCategory($categoryId, 5, $perPage); $this->assertEquals(Http::STATUS_OK, $response->getStatus()); $data = $response->getData(); @@ -1248,7 +1258,7 @@ class ThreadControllerTest extends TestCase { $this->userService->method('enrichMultipleUsers')->willReturn([]); - $response = $this->controller->byCategoryPaginated($categoryId, $page, $perPage); + $response = $this->controller->byCategory($categoryId, $page, $perPage); $this->assertEquals(Http::STATUS_OK, $response->getStatus()); $data = $response->getData(); @@ -1285,7 +1295,7 @@ class ThreadControllerTest extends TestCase { 'user2' => ['userId' => 'user2', 'displayName' => 'User 2'], ]); - $response = $this->controller->byCategoryPaginated($categoryId, $page, $perPage); + $response = $this->controller->byCategory($categoryId, $page, $perPage); $this->assertEquals(Http::STATUS_OK, $response->getStatus()); $data = $response->getData(); @@ -1323,7 +1333,7 @@ class ThreadControllerTest extends TestCase { 'user1' => ['userId' => 'user1', 'displayName' => 'User 1'], ]); - $response = $this->controller->byCategoryPaginated($categoryId, $page, $perPage); + $response = $this->controller->byCategory($categoryId, $page, $perPage); $this->assertEquals(Http::STATUS_OK, $response->getStatus()); $data = $response->getData();