diff --git a/app/Http/Controllers/Api/V1/PostController.php b/app/Http/Controllers/Api/V1/PostController.php index 7899349..e28e35a 100644 --- a/app/Http/Controllers/Api/V1/PostController.php +++ b/app/Http/Controllers/Api/V1/PostController.php @@ -21,6 +21,19 @@ public function __construct( protected PostService $postService ) {} + /** + * 나의 게시글 목록 조회 + */ + public function myPosts() + { + return ApiResponse::handle(function () { + $filters = request()->only(['board_code', 'search', 'status']); + $perPage = (int) request()->get('per_page', 15); + + return $this->postService->getMyPosts($filters, $perPage); + }, __('message.fetched')); + } + /** * 게시글 목록 조회 */ diff --git a/app/Services/Boards/PostService.php b/app/Services/Boards/PostService.php index e23e527..10e511b 100644 --- a/app/Services/Boards/PostService.php +++ b/app/Services/Boards/PostService.php @@ -324,4 +324,30 @@ public function getCustomFieldValues(int $postId): Collection ->with('field') ->get(); } + + // ========================================================================= + // 나의 게시글 메서드 + // ========================================================================= + + /** + * 나의 게시글 목록 조회 + */ + public function getMyPosts(array $filters = [], int $perPage = 15): LengthAwarePaginator + { + return Post::where('user_id', $this->apiUserId()) + ->where('tenant_id', $this->tenantId()) + ->with(['board:id,board_code,name']) + ->when(isset($filters['board_code']), function ($q) use ($filters) { + $q->whereHas('board', fn ($query) => $query->where('board_code', $filters['board_code'])); + }) + ->when(isset($filters['search']), function ($q) use ($filters) { + $q->where(function ($query) use ($filters) { + $query->where('title', 'like', "%{$filters['search']}%") + ->orWhere('content', 'like', "%{$filters['search']}%"); + }); + }) + ->when(isset($filters['status']), fn ($q) => $q->where('status', $filters['status'])) + ->orderByDesc('created_at') + ->paginate($perPage); + } } diff --git a/app/Swagger/v1/PostApi.php b/app/Swagger/v1/PostApi.php index 2e8403d..b0b1aef 100644 --- a/app/Swagger/v1/PostApi.php +++ b/app/Swagger/v1/PostApi.php @@ -98,6 +98,34 @@ */ class PostApi { + /** + * @OA\Get( + * path="/api/v1/posts/my", + * tags={"Post"}, + * summary="나의 게시글 목록", + * description="로그인한 사용자가 작성한 모든 게시글을 조회합니다.", + * security={{"ApiKeyAuth":{}},{"BearerAuth":{}}}, + * + * @OA\Parameter(name="board_code", in="query", description="게시판 코드 필터", @OA\Schema(type="string")), + * @OA\Parameter(name="search", in="query", description="제목/내용 검색", @OA\Schema(type="string")), + * @OA\Parameter(name="status", in="query", description="상태 필터", @OA\Schema(type="string", enum={"draft","published","hidden"})), + * @OA\Parameter(name="page", in="query", @OA\Schema(type="integer", example=1)), + * @OA\Parameter(name="per_page", in="query", @OA\Schema(type="integer", example=15)), + * + * @OA\Response(response=200, description="조회 성공", + * + * @OA\JsonContent(allOf={ + * + * @OA\Schema(ref="#/components/schemas/ApiResponse"), + * @OA\Schema(@OA\Property(property="data", ref="#/components/schemas/PostPagination")) + * }) + * ), + * + * @OA\Response(response=401, description="인증 실패", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")) + * ) + */ + public function myPosts() {} + /** * @OA\Get( * path="/api/v1/boards/{code}/posts", diff --git a/routes/api.php b/routes/api.php index 29bcdb1..3d4cc00 100644 --- a/routes/api.php +++ b/routes/api.php @@ -1000,6 +1000,11 @@ Route::delete('/{code}/posts/{postId}/comments/{commentId}', [PostController::class, 'destroyComment'])->name('v1.boards.posts.comments.destroy'); // 댓글 삭제 }); + // 게시글 API (사용자 중심) + Route::prefix('posts')->group(function () { + Route::get('/my', [PostController::class, 'myPosts'])->name('v1.posts.my'); // 나의 게시글 목록 + }); + }); // 공유 링크 다운로드 (인증 불필요 - auth.apikey 그룹 밖)