여러 화면에서 조건부(FormRequest) 검증이 우회되거나 과도하게 제한되던 결함을 한 계열로 묶어 수정한다. - 검증 규칙 확장 필터 이름 10개를 나머지 92개와 동일 규칙으로 통일 - 설명 길이를 바이트가 아닌 글자 수로 계산(한글 오검출 해소) - 비활성 언어팩 번역 보존한 채 수정 허용 - 알림 템플릿 제목 nullable 존중, 미지원 발송 수단 저장 차단 - 일정/실행 이력 목록 조회 검증 정합 - 게시판 첨부 미사용 시 빈 확장자 통과, new_display_hours/최소 길이 0 허용, 일괄 적용 override_values 범위 검증(SSoT) - 이커머스 클레임 사유 조회 검증, 용어 정정 - 원문 i18n 키 노출 다수 해소, 저장/삭제 실패 시 사유 화면 노출 - 아이콘 크기/다크모드 대비 회귀 수정 번들 확장(모듈3·플러그인6·템플릿2·언어팩5) 버전 new-bump 및 CHANGELOG 반영, ja 언어팩 동기.
647 lines
23 KiB
PHP
647 lines
23 KiB
PHP
<?php
|
|
|
|
namespace Modules\Sirsoft\Board\Tests\Feature;
|
|
|
|
// 테스트 베이스 클래스 수동 require (autoload 전에 로드 필요)
|
|
require_once __DIR__.'/../ModuleTestCase.php';
|
|
|
|
use App\Models\Permission;
|
|
use App\Models\Role;
|
|
use App\Models\User;
|
|
use Modules\Sirsoft\Board\Tests\BoardTestCase;
|
|
use PHPUnit\Framework\Attributes\Test;
|
|
|
|
/**
|
|
* PostResource 권한 API 응답 구조 테스트
|
|
*
|
|
* Admin/User 페이지별 권한 분기 및 소유권 플래그 테스트
|
|
*/
|
|
class PostResourcePermissionTest extends BoardTestCase
|
|
{
|
|
private User $adminUser;
|
|
|
|
private User $regularUser;
|
|
|
|
private User $postAuthor;
|
|
|
|
/**
|
|
* 테스트 게시판 slug
|
|
*/
|
|
protected function getTestBoardSlug(): string
|
|
{
|
|
return 'permission-test';
|
|
}
|
|
|
|
/**
|
|
* 기본 게시판 속성
|
|
*/
|
|
protected function getDefaultBoardAttributes(string $slug): array
|
|
{
|
|
return [
|
|
'slug' => $slug,
|
|
'name' => ['ko' => '권한 테스트 게시판', 'en' => 'Permission Test Board'],
|
|
'is_active' => true,
|
|
'secret_mode' => 'disabled',
|
|
'blocked_keywords' => [],
|
|
];
|
|
}
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
// 테스트 사용자 생성
|
|
$this->createTestUsers();
|
|
|
|
// 권한 설정
|
|
$this->setupPermissions();
|
|
}
|
|
|
|
/**
|
|
* 테스트 사용자 생성
|
|
*/
|
|
private function createTestUsers(): void
|
|
{
|
|
$this->adminUser = User::factory()->create();
|
|
$this->regularUser = User::factory()->create();
|
|
$this->postAuthor = User::factory()->create();
|
|
}
|
|
|
|
/**
|
|
* 권한 설정
|
|
*/
|
|
private function setupPermissions(): void
|
|
{
|
|
$slug = $this->board->slug;
|
|
|
|
// Admin 권한 생성 및 할당 (라우트 미들웨어와 일치하는 식별자 사용)
|
|
$adminPermissions = [];
|
|
$adminPermissionDefs = [
|
|
'admin.posts.read' => ['ko' => '관리자 게시글 조회', 'en' => 'Admin Posts Read'],
|
|
'admin.posts.write' => ['ko' => '관리자 게시글 작성', 'en' => 'Admin Posts Write'],
|
|
'admin.manage' => ['ko' => '관리자 관리', 'en' => 'Admin Manage'],
|
|
];
|
|
|
|
foreach ($adminPermissionDefs as $action => $name) {
|
|
$permission = Permission::firstOrCreate(
|
|
['identifier' => "sirsoft-board.{$slug}.{$action}"],
|
|
[
|
|
'name' => $name,
|
|
'slug' => "sirsoft-board.{$slug}.{$action}",
|
|
'type' => 'admin',
|
|
]
|
|
);
|
|
$adminPermissions[] = $permission->id;
|
|
}
|
|
|
|
$adminRole = Role::firstOrCreate(
|
|
['identifier' => "{$slug}-admin"],
|
|
['name' => ['ko' => '게시판 관리자', 'en' => 'Board Admin']]
|
|
);
|
|
|
|
$adminRole->permissions()->syncWithoutDetaching($adminPermissions);
|
|
$this->adminUser->roles()->attach($adminRole->id);
|
|
|
|
// User 권한 생성 및 할당 (라우트 미들웨어와 일치하는 식별자 사용)
|
|
$userPermissions = [];
|
|
$userPermissionDefs = [
|
|
'posts.read' => ['ko' => '게시글 조회', 'en' => 'Read Posts'],
|
|
'posts.write' => ['ko' => '게시글 작성', 'en' => 'Write Posts'],
|
|
'comments.read' => ['ko' => '댓글 조회', 'en' => 'Read Comments'],
|
|
'comments.write' => ['ko' => '댓글 작성', 'en' => 'Write Comments'],
|
|
];
|
|
|
|
foreach ($userPermissionDefs as $action => $name) {
|
|
$permission = Permission::firstOrCreate(
|
|
['identifier' => "sirsoft-board.{$slug}.{$action}"],
|
|
[
|
|
'name' => $name,
|
|
'slug' => "sirsoft-board.{$slug}.{$action}",
|
|
'type' => 'user',
|
|
]
|
|
);
|
|
$userPermissions[] = $permission->id;
|
|
}
|
|
|
|
$userRole = Role::firstOrCreate(
|
|
['identifier' => "{$slug}-user"],
|
|
['name' => ['ko' => '일반 사용자', 'en' => 'Regular User']]
|
|
);
|
|
|
|
$userRole->permissions()->syncWithoutDetaching($userPermissions);
|
|
$this->regularUser->roles()->attach($userRole->id);
|
|
$this->postAuthor->roles()->attach($userRole->id);
|
|
|
|
// 관리자도 유저 라우트를 열려면 user 타입 권한이 필요하다.
|
|
// 유저 게시글 상세는 `permission:user,sirsoft-board.{slug}.posts.read` 로 가드되므로
|
|
// admin 타입 권한만으로는 403 이다 (실제 운영에서도 관리자는 두 역할을 함께 보유).
|
|
// can_access_admin 게이트는 이 라우트를 통과한 뒤 admin.manage 보유 여부로 판정된다.
|
|
$this->adminUser->roles()->attach($userRole->id);
|
|
}
|
|
|
|
// ==========================================
|
|
// Admin 페이지 권한 테스트
|
|
// ==========================================
|
|
|
|
/**
|
|
* Admin 페이지에서는 admin_* 권한만 반환
|
|
*/
|
|
#[Test]
|
|
public function admin_page_returns_admin_permissions_only(): void
|
|
{
|
|
// Given: 회원 게시글 생성
|
|
$postId = $this->createPost([
|
|
'user_id' => $this->postAuthor->id,
|
|
'title' => 'Test Post',
|
|
'content' => 'Test Content',
|
|
]);
|
|
|
|
// When: Admin API 호출
|
|
$response = $this->actingAs($this->adminUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/admin/board/{$this->board->slug}/posts/{$postId}");
|
|
|
|
// Then: admin 컨텍스트의 can_* abilities 포함
|
|
$response->assertStatus(200);
|
|
$abilities = $response->json('data.abilities');
|
|
|
|
$this->assertArrayHasKey('can_read', $abilities);
|
|
$this->assertArrayHasKey('can_write', $abilities);
|
|
$this->assertArrayHasKey('can_manage', $abilities);
|
|
|
|
// Admin 컨텍스트이므로 admin.* 권한 기반으로 체크됨
|
|
// User 전용 키는 통합 can_* 키 사용으로 별도 존재하지 않음
|
|
$this->assertTrue($abilities['can_read']);
|
|
$this->assertTrue($abilities['can_write']);
|
|
$this->assertTrue($abilities['can_manage']);
|
|
}
|
|
|
|
/**
|
|
* Admin 페이지에서 User 권한 미반환
|
|
*/
|
|
#[Test]
|
|
public function admin_page_excludes_user_permissions(): void
|
|
{
|
|
// Given
|
|
$postId = $this->createPost([
|
|
'user_id' => $this->postAuthor->id,
|
|
'title' => 'Test Post',
|
|
'content' => 'Test Content',
|
|
]);
|
|
|
|
// When
|
|
$response = $this->actingAs($this->adminUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/admin/board/{$this->board->slug}/posts/{$postId}");
|
|
|
|
// Then: abilities에 통합 can_* 키만 존재 (admin/user 구분 없음)
|
|
$response->assertStatus(200);
|
|
$abilities = $response->json('data.abilities');
|
|
|
|
// 통합 키 사용으로 old-style 키는 존재하지 않음
|
|
$this->assertArrayNotHasKey('posts_read', $abilities);
|
|
$this->assertArrayNotHasKey('posts_write', $abilities);
|
|
$this->assertArrayNotHasKey('comments_read', $abilities);
|
|
$this->assertArrayNotHasKey('comments_write', $abilities);
|
|
}
|
|
|
|
// ==========================================
|
|
// User 페이지 권한 테스트
|
|
// ==========================================
|
|
|
|
/**
|
|
* User 페이지에서는 posts_*, comments_* 권한만 반환
|
|
*/
|
|
#[Test]
|
|
public function user_page_returns_user_permissions_only(): void
|
|
{
|
|
// Given
|
|
$postId = $this->createPost([
|
|
'user_id' => $this->postAuthor->id,
|
|
'title' => 'Test Post',
|
|
'content' => 'Test Content',
|
|
]);
|
|
|
|
// When: User API 호출
|
|
$response = $this->actingAs($this->regularUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts/{$postId}");
|
|
|
|
// Then: User 컨텍스트의 can_* abilities 포함
|
|
$response->assertStatus(200);
|
|
$abilities = $response->json('data.abilities');
|
|
|
|
$this->assertArrayHasKey('can_read', $abilities);
|
|
$this->assertArrayHasKey('can_write', $abilities);
|
|
$this->assertArrayHasKey('can_read_secret', $abilities);
|
|
$this->assertArrayHasKey('can_read_comments', $abilities);
|
|
$this->assertArrayHasKey('can_write_comments', $abilities);
|
|
|
|
// User 컨텍스트이므로 user.* 권한 기반으로 체크됨
|
|
$this->assertTrue($abilities['can_read']);
|
|
$this->assertTrue($abilities['can_write']);
|
|
$this->assertTrue($abilities['can_read_comments']);
|
|
$this->assertTrue($abilities['can_write_comments']);
|
|
}
|
|
|
|
/**
|
|
* User 페이지에서 Admin 권한 미반환
|
|
*/
|
|
#[Test]
|
|
public function user_page_excludes_admin_permissions(): void
|
|
{
|
|
// Given
|
|
$postId = $this->createPost([
|
|
'user_id' => $this->postAuthor->id,
|
|
'title' => 'Test Post',
|
|
'content' => 'Test Content',
|
|
]);
|
|
|
|
// When
|
|
$response = $this->actingAs($this->regularUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts/{$postId}");
|
|
|
|
// Then: abilities에 통합 can_* 키만 존재 (admin/user 구분 없음)
|
|
$response->assertStatus(200);
|
|
$abilities = $response->json('data.abilities');
|
|
|
|
// 통합 키 사용으로 old-style admin 키는 존재하지 않음
|
|
$this->assertArrayNotHasKey('admin_posts_read', $abilities);
|
|
$this->assertArrayNotHasKey('admin_posts_write', $abilities);
|
|
$this->assertArrayNotHasKey('admin_manage', $abilities);
|
|
}
|
|
|
|
// ==========================================
|
|
// can_access_admin 게이트 테스트 (#450)
|
|
// 유저 화면에서 관리자 게시판 화면 진입 크로스링크 노출 여부
|
|
// ==========================================
|
|
|
|
/**
|
|
* User 상세: admin.manage(Admin 타입) 권한 보유자는 can_access_admin = true
|
|
*
|
|
* @scenario link=user_board_to_admin, permitted=true
|
|
*
|
|
* @effects board_admin_gate_true_shows_link
|
|
*/
|
|
#[Test]
|
|
public function user_detail_returns_can_access_admin_true_for_admin_permission_holder(): void
|
|
{
|
|
// Given: 게시글 + admin.manage 권한 보유 사용자
|
|
$postId = $this->createPost([
|
|
'user_id' => $this->postAuthor->id,
|
|
'title' => 'Test Post',
|
|
'content' => 'Test Content',
|
|
]);
|
|
|
|
// When: 관리 권한 보유자가 유저 라우트로 상세 조회
|
|
$response = $this->actingAs($this->adminUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts/{$postId}");
|
|
|
|
// Then: 유저 컨텍스트에도 can_access_admin 노출 + true
|
|
$response->assertStatus(200);
|
|
$abilities = $response->json('data.abilities');
|
|
|
|
$this->assertArrayHasKey('can_access_admin', $abilities);
|
|
$this->assertTrue($abilities['can_access_admin']);
|
|
}
|
|
|
|
/**
|
|
* User 상세: 일반 사용자(admin.manage 미보유)는 can_access_admin = false
|
|
*
|
|
* @scenario link=user_board_to_admin, permitted=false
|
|
*
|
|
* @effects board_admin_gate_false_hides_link
|
|
*/
|
|
#[Test]
|
|
public function user_detail_returns_can_access_admin_false_for_regular_user(): void
|
|
{
|
|
// Given
|
|
$postId = $this->createPost([
|
|
'user_id' => $this->postAuthor->id,
|
|
'title' => 'Test Post',
|
|
'content' => 'Test Content',
|
|
]);
|
|
|
|
// When: user 권한만 보유한 사용자가 유저 라우트로 상세 조회
|
|
$response = $this->actingAs($this->regularUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts/{$postId}");
|
|
|
|
// Then: can_access_admin 은 노출되나 false
|
|
$response->assertStatus(200);
|
|
$abilities = $response->json('data.abilities');
|
|
|
|
$this->assertArrayHasKey('can_access_admin', $abilities);
|
|
$this->assertFalse($abilities['can_access_admin']);
|
|
}
|
|
|
|
/**
|
|
* User 목록: 컬렉션 abilities 에도 can_access_admin 노출
|
|
*/
|
|
#[Test]
|
|
public function user_list_collection_exposes_can_access_admin(): void
|
|
{
|
|
// Given
|
|
$this->createPost([
|
|
'user_id' => $this->postAuthor->id,
|
|
'title' => 'List Post',
|
|
'content' => 'List Content',
|
|
]);
|
|
|
|
// When: 관리 권한 보유자가 유저 라우트로 목록 조회
|
|
$response = $this->actingAs($this->adminUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts");
|
|
|
|
// Then: 컬렉션 abilities 에 can_access_admin = true
|
|
$response->assertStatus(200);
|
|
$abilities = $response->json('data.abilities');
|
|
|
|
$this->assertArrayHasKey('can_access_admin', $abilities);
|
|
$this->assertTrue($abilities['can_access_admin']);
|
|
}
|
|
|
|
/**
|
|
* User 목록/상세 응답의 board 정보에 id 가 포함된다 (#450)
|
|
*
|
|
* "게시판 관리" 크로스링크가 /admin/boards/:id/edit 로 이동하려면 board id 필요.
|
|
*/
|
|
#[Test]
|
|
public function user_response_board_info_includes_id(): void
|
|
{
|
|
// Given
|
|
$postId = $this->createPost([
|
|
'user_id' => $this->postAuthor->id,
|
|
'title' => 'Board Id Post',
|
|
'content' => 'Board Id Content',
|
|
]);
|
|
|
|
// When: 목록
|
|
$listResponse = $this->actingAs($this->regularUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts");
|
|
// And: 상세
|
|
$detailResponse = $this->actingAs($this->regularUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts/{$postId}");
|
|
|
|
// Then: 목록/상세 board 정보 모두 실제 게시판 id 노출
|
|
$listResponse->assertStatus(200);
|
|
$this->assertSame($this->board->id, $listResponse->json('data.board.id'));
|
|
|
|
$detailResponse->assertStatus(200);
|
|
$this->assertSame($this->board->id, $detailResponse->json('data.board.id'));
|
|
}
|
|
|
|
// ==========================================
|
|
// 소유권 플래그 테스트
|
|
// ==========================================
|
|
|
|
/**
|
|
* 본인 글: is_author = true
|
|
*/
|
|
#[Test]
|
|
public function is_author_true_for_own_post(): void
|
|
{
|
|
// Given: 작성자가 작성한 게시글
|
|
$postId = $this->createPost([
|
|
'user_id' => $this->postAuthor->id,
|
|
'title' => 'My Post',
|
|
'content' => 'My Content',
|
|
]);
|
|
|
|
// When: 작성자 본인이 조회
|
|
$response = $this->actingAs($this->postAuthor, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts/{$postId}");
|
|
|
|
// Then
|
|
$response->assertStatus(200);
|
|
$this->assertTrue($response->json('data.is_author'));
|
|
$this->assertFalse($response->json('data.is_guest_post'));
|
|
}
|
|
|
|
/**
|
|
* 타인 글: is_author = false
|
|
*/
|
|
#[Test]
|
|
public function is_author_false_for_others_post(): void
|
|
{
|
|
// Given: 다른 사용자가 작성한 게시글
|
|
$postId = $this->createPost([
|
|
'user_id' => $this->postAuthor->id,
|
|
'title' => 'Others Post',
|
|
'content' => 'Others Content',
|
|
]);
|
|
|
|
// When: 다른 사용자가 조회
|
|
$response = $this->actingAs($this->regularUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts/{$postId}");
|
|
|
|
// Then
|
|
$response->assertStatus(200);
|
|
$this->assertFalse($response->json('data.is_author'));
|
|
$this->assertFalse($response->json('data.is_guest_post'));
|
|
}
|
|
|
|
/**
|
|
* 비회원 글: is_guest_post = true
|
|
*/
|
|
#[Test]
|
|
public function is_guest_post_true_for_guest_post(): void
|
|
{
|
|
// Given: 비회원이 작성한 게시글
|
|
$postId = $this->createPost([
|
|
'user_id' => null,
|
|
'author_name' => 'Guest Author',
|
|
'title' => 'Guest Post',
|
|
'content' => 'Guest Content',
|
|
]);
|
|
|
|
// When: 로그인 사용자가 조회
|
|
$response = $this->actingAs($this->regularUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts/{$postId}");
|
|
|
|
// Then
|
|
$response->assertStatus(200);
|
|
$this->assertFalse($response->json('data.is_author'));
|
|
$this->assertTrue($response->json('data.is_guest_post'));
|
|
}
|
|
|
|
/**
|
|
* 회원 글: is_guest_post = false
|
|
*/
|
|
#[Test]
|
|
public function is_guest_post_false_for_member_post(): void
|
|
{
|
|
// Given: 회원이 작성한 게시글
|
|
$postId = $this->createPost([
|
|
'user_id' => $this->postAuthor->id,
|
|
'title' => 'Member Post',
|
|
'content' => 'Member Content',
|
|
]);
|
|
|
|
// When
|
|
$response = $this->actingAs($this->regularUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts/{$postId}");
|
|
|
|
// Then
|
|
$response->assertStatus(200);
|
|
$this->assertFalse($response->json('data.is_guest_post'));
|
|
}
|
|
|
|
// ==========================================
|
|
// 비회원 권한 테스트
|
|
// ==========================================
|
|
|
|
/**
|
|
* 비회원: guest_permissions에 따라 권한 체크
|
|
*/
|
|
#[Test]
|
|
public function guest_permissions_respected_for_non_authenticated_user(): void
|
|
{
|
|
// Given: 비회원 게시글
|
|
$postId = $this->createPost([
|
|
'user_id' => null,
|
|
'author_name' => 'Guest',
|
|
'title' => 'Public Post',
|
|
'content' => 'Public Content',
|
|
]);
|
|
|
|
// When: 비로그인 상태로 조회
|
|
$response = $this->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts/{$postId}");
|
|
|
|
// Then: grantDefaultGuestPermissions()에서 posts.read, posts.write, attachments.upload 부여
|
|
$response->assertStatus(200);
|
|
$abilities = $response->json('data.abilities');
|
|
|
|
$this->assertTrue($abilities['can_read']); // guest에 posts.read 있음
|
|
$this->assertTrue($abilities['can_write']); // guest에 posts.write 있음
|
|
$this->assertFalse($abilities['can_read_comments']); // guest에 comments.read 없음
|
|
$this->assertFalse($abilities['can_write_comments']); // guest에 comments.write 없음
|
|
}
|
|
|
|
/**
|
|
* 로그인 사용자: Gate로 권한 체크
|
|
*/
|
|
#[Test]
|
|
public function authenticated_user_permissions_check_via_gate(): void
|
|
{
|
|
// Given
|
|
$postId = $this->createPost([
|
|
'user_id' => $this->postAuthor->id,
|
|
'title' => 'Test Post',
|
|
'content' => 'Test Content',
|
|
]);
|
|
|
|
// When: 로그인 사용자 조회
|
|
$response = $this->actingAs($this->regularUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts/{$postId}");
|
|
|
|
// Then: Role-Permission으로 체크
|
|
$response->assertStatus(200);
|
|
$abilities = $response->json('data.abilities');
|
|
|
|
// regularUser는 posts.read, posts.write, comments.read, comments.write 권한 보유
|
|
$this->assertTrue($abilities['can_read']);
|
|
$this->assertTrue($abilities['can_write']);
|
|
$this->assertTrue($abilities['can_read_comments']);
|
|
$this->assertTrue($abilities['can_write_comments']);
|
|
}
|
|
|
|
// ==========================================
|
|
// 답글 섹션 삭제 게시글 필터링 테스트
|
|
// ==========================================
|
|
|
|
/**
|
|
* 일반 사용자는 답글 섹션에서 삭제된 답글을 볼 수 없다
|
|
*/
|
|
#[Test]
|
|
public function regular_user_cannot_see_deleted_reply_in_post_detail(): void
|
|
{
|
|
// Given: 원글 생성
|
|
$parentId = $this->createTestPost([
|
|
'user_id' => $this->postAuthor->id,
|
|
'title' => '원글',
|
|
'content' => '원글 내용',
|
|
]);
|
|
|
|
// 정상 답글 생성
|
|
$normalReplyId = $this->createTestPost([
|
|
'user_id' => $this->postAuthor->id,
|
|
'parent_id' => $parentId,
|
|
'title' => '정상 답글',
|
|
'content' => '정상 답글 내용',
|
|
'status' => 'published',
|
|
]);
|
|
|
|
// 삭제된 답글 생성 (status='deleted', deleted_at 설정)
|
|
$this->createTestPost([
|
|
'user_id' => $this->postAuthor->id,
|
|
'parent_id' => $parentId,
|
|
'title' => '삭제된 답글',
|
|
'content' => '삭제된 답글 내용',
|
|
'status' => 'deleted',
|
|
'deleted_at' => now(),
|
|
]);
|
|
|
|
// When: 일반 사용자가 원글 상세 조회
|
|
$response = $this->actingAs($this->regularUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts/{$parentId}");
|
|
|
|
// Then: replies에 삭제된 답글이 포함되지 않음
|
|
$response->assertStatus(200);
|
|
$replies = $response->json('data.replies');
|
|
$this->assertCount(1, $replies);
|
|
$this->assertEquals($normalReplyId, $replies[0]['id']);
|
|
}
|
|
|
|
/**
|
|
* 관리자는 답글 섹션에서 삭제된 답글을 볼 수 있다
|
|
*/
|
|
#[Test]
|
|
public function admin_user_can_see_deleted_reply_in_post_detail(): void
|
|
{
|
|
// Given: 원글 생성
|
|
$parentId = $this->createTestPost([
|
|
'user_id' => $this->postAuthor->id,
|
|
'title' => '원글',
|
|
'content' => '원글 내용',
|
|
]);
|
|
|
|
// 정상 답글 생성
|
|
$this->createTestPost([
|
|
'user_id' => $this->postAuthor->id,
|
|
'parent_id' => $parentId,
|
|
'title' => '정상 답글',
|
|
'content' => '정상 답글 내용',
|
|
'status' => 'published',
|
|
]);
|
|
|
|
// 삭제된 답글 생성
|
|
$this->createTestPost([
|
|
'user_id' => $this->postAuthor->id,
|
|
'parent_id' => $parentId,
|
|
'title' => '삭제된 답글',
|
|
'content' => '삭제된 답글 내용',
|
|
'status' => 'deleted',
|
|
'deleted_at' => now(),
|
|
]);
|
|
|
|
// When: 관리자가 Admin API로 원글 상세 조회
|
|
$response = $this->actingAs($this->adminUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/admin/board/{$this->board->slug}/posts/{$parentId}");
|
|
|
|
// Then: replies에 삭제된 답글이 포함됨
|
|
$response->assertStatus(200);
|
|
$replies = $response->json('data.replies');
|
|
$this->assertCount(2, $replies);
|
|
}
|
|
|
|
// ==========================================
|
|
// 헬퍼 메서드
|
|
// ==========================================
|
|
|
|
/**
|
|
* 게시글 생성 헬퍼
|
|
*/
|
|
private function createPost(array $attributes): int
|
|
{
|
|
$postId = $this->createTestPost($attributes);
|
|
|
|
return $postId;
|
|
}
|
|
}
|