297 lines
12 KiB
PHP
297 lines
12 KiB
PHP
<?php
|
|
|
|
namespace Modules\Sirsoft\Board\Tests\Feature\User;
|
|
|
|
// 테스트 베이스 클래스 수동 require (autoload 전에 로드 필요)
|
|
require_once __DIR__.'/../../ModuleTestCase.php';
|
|
|
|
use App\Models\Permission;
|
|
use App\Models\Role;
|
|
use App\Models\User;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Modules\Sirsoft\Board\Tests\BoardTestCase;
|
|
|
|
/**
|
|
* 사용자 게시판 삭제 글/댓글 포함 토글 테스트
|
|
*
|
|
* manager 권한 보유 + del=1 파라미터가 있을 때만
|
|
* 삭제된 게시글/댓글이 목록에 노출되는지 검증합니다.
|
|
*
|
|
* @scenario viewer=manager
|
|
* @effects manager_sees_deleted_post_original_title_and_content, manager_sees_deleted_comment_original_content
|
|
*/
|
|
class PostDeletedToggleTest extends BoardTestCase
|
|
{
|
|
private User $regularUser;
|
|
|
|
private User $managerUser;
|
|
|
|
protected function getTestBoardSlug(): string
|
|
{
|
|
return 'deleted-toggle';
|
|
}
|
|
|
|
protected function getDefaultBoardAttributes(string $slug): array
|
|
{
|
|
return [
|
|
'slug' => $slug,
|
|
'name' => ['ko' => '삭제 토글 테스트 게시판', 'en' => 'Deleted Toggle Test Board'],
|
|
'is_active' => true,
|
|
'use_comment' => true,
|
|
'secret_mode' => 'disabled',
|
|
'blocked_keywords' => [],
|
|
];
|
|
}
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
$slug = $this->board->slug;
|
|
|
|
// 일반 사용자 (posts.read 권한만)
|
|
$this->regularUser = User::factory()->create();
|
|
$userRole = Role::where('identifier', 'user')->first();
|
|
if ($userRole) {
|
|
$readPerm = Permission::firstOrCreate(
|
|
['identifier' => "sirsoft-board.{$slug}.posts.read"],
|
|
['name' => ['ko' => '게시글 조회', 'en' => 'Read Posts'], 'type' => 'user']
|
|
);
|
|
$userRole->permissions()->syncWithoutDetaching([$readPerm->id]);
|
|
$this->regularUser->roles()->attach($userRole->id);
|
|
}
|
|
|
|
// manager 권한 사용자 (posts.read + manager)
|
|
$this->managerUser = User::factory()->create();
|
|
$managerRole = Role::firstOrCreate(
|
|
['identifier' => "{$slug}-manager"],
|
|
['name' => ['ko' => '게시판 매니저', 'en' => 'Board Manager']]
|
|
);
|
|
foreach (['posts.read', 'comments.read', 'manager'] as $key) {
|
|
$perm = Permission::firstOrCreate(
|
|
['identifier' => "sirsoft-board.{$slug}.{$key}"],
|
|
['name' => ['ko' => $key, 'en' => $key], 'type' => 'user']
|
|
);
|
|
$managerRole->permissions()->syncWithoutDetaching([$perm->id]);
|
|
}
|
|
$this->managerUser->roles()->attach($managerRole->id);
|
|
}
|
|
|
|
// ==========================================
|
|
// can_view_deleted abilities 키 테스트
|
|
// ==========================================
|
|
|
|
/**
|
|
* manager 권한 사용자는 abilities.can_view_deleted = true 반환
|
|
*/
|
|
public function test_manager_receives_can_view_deleted_true_in_abilities(): void
|
|
{
|
|
$response = $this->actingAs($this->managerUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts");
|
|
|
|
$response->assertStatus(200);
|
|
$this->assertTrue($response->json('data.abilities.can_view_deleted'));
|
|
}
|
|
|
|
/**
|
|
* 일반 사용자는 abilities.can_view_deleted = false 반환
|
|
*/
|
|
public function test_regular_user_receives_can_view_deleted_false_in_abilities(): void
|
|
{
|
|
$response = $this->actingAs($this->regularUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts");
|
|
|
|
$response->assertStatus(200);
|
|
$this->assertFalse($response->json('data.abilities.can_view_deleted'));
|
|
}
|
|
|
|
// ==========================================
|
|
// include_deleted 토글 테스트 (게시글 목록)
|
|
// ==========================================
|
|
|
|
/**
|
|
* manager + del=1 → 삭제된 게시글 목록에 포함
|
|
*/
|
|
public function test_manager_with_include_deleted_sees_deleted_posts(): void
|
|
{
|
|
// Given: 일반 게시글 1개 + 삭제된 게시글 1개
|
|
$normalPostId = $this->createTestPost(['title' => '일반 게시글']);
|
|
$deletedPostId = $this->createTestPost([
|
|
'title' => '삭제된 게시글',
|
|
'deleted_at' => now(),
|
|
]);
|
|
|
|
// When: manager가 del=1로 목록 조회
|
|
$response = $this->actingAs($this->managerUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts?del=1");
|
|
|
|
$response->assertStatus(200);
|
|
|
|
$postIds = collect($response->json('data.data'))->pluck('id')->toArray();
|
|
$this->assertContains($deletedPostId, $postIds, '삭제된 게시글이 목록에 포함되어야 합니다');
|
|
$this->assertContains($normalPostId, $postIds, '일반 게시글도 목록에 포함되어야 합니다');
|
|
}
|
|
|
|
/**
|
|
* manager라도 include_deleted 파라미터 없으면 삭제된 게시글 미포함
|
|
*/
|
|
public function test_manager_without_include_deleted_does_not_see_deleted_posts(): void
|
|
{
|
|
// Given: 삭제된 게시글 생성
|
|
$deletedPostId = $this->createTestPost([
|
|
'title' => '삭제된 게시글',
|
|
'deleted_at' => now(),
|
|
]);
|
|
|
|
// When: include_deleted 파라미터 없이 조회
|
|
$response = $this->actingAs($this->managerUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts");
|
|
|
|
$response->assertStatus(200);
|
|
|
|
$postIds = collect($response->json('data.data'))->pluck('id')->toArray();
|
|
$this->assertNotContains($deletedPostId, $postIds, '삭제된 게시글이 목록에 포함되지 않아야 합니다');
|
|
}
|
|
|
|
/**
|
|
* 일반 사용자는 del=1 파라미터를 넘겨도 삭제된 게시글 미포함
|
|
*/
|
|
public function test_regular_user_cannot_see_deleted_posts_even_with_include_deleted(): void
|
|
{
|
|
// Given: 삭제된 게시글 생성
|
|
$deletedPostId = $this->createTestPost([
|
|
'title' => '삭제된 게시글',
|
|
'deleted_at' => now(),
|
|
]);
|
|
|
|
// When: 일반 사용자가 del=1로 조회 시도
|
|
$response = $this->actingAs($this->regularUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts?del=1");
|
|
|
|
$response->assertStatus(200);
|
|
|
|
$postIds = collect($response->json('data.data'))->pluck('id')->toArray();
|
|
$this->assertNotContains($deletedPostId, $postIds, '일반 사용자에게는 삭제된 게시글이 노출되지 않아야 합니다');
|
|
}
|
|
|
|
// ==========================================
|
|
// include_deleted_comments 토글 테스트 (댓글)
|
|
// ==========================================
|
|
|
|
/**
|
|
* manager + del_cmt=1 → 삭제된 댓글 상세에 포함
|
|
*/
|
|
public function test_manager_with_include_deleted_comments_sees_deleted_comments(): void
|
|
{
|
|
// Given: 게시글 + 일반 댓글 + 삭제된 댓글
|
|
$postId = $this->createTestPost(['title' => '댓글 테스트 게시글']);
|
|
$normalCommentId = $this->createTestComment($postId, ['content' => '일반 댓글']);
|
|
$deletedCommentId = $this->createTestComment($postId, [
|
|
'content' => '삭제된 댓글',
|
|
'deleted_at' => now(),
|
|
]);
|
|
|
|
// When: manager가 del_cmt=1로 게시글 상세 조회
|
|
$response = $this->actingAs($this->managerUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts/{$postId}?del_cmt=1");
|
|
|
|
$response->assertStatus(200);
|
|
|
|
$commentIds = collect($response->json('data.comments'))->pluck('id')->toArray();
|
|
$this->assertContains($deletedCommentId, $commentIds, '삭제된 댓글이 포함되어야 합니다');
|
|
$this->assertContains($normalCommentId, $commentIds, '일반 댓글도 포함되어야 합니다');
|
|
}
|
|
|
|
/**
|
|
* manager라도 include_deleted_comments 없으면 삭제 댓글 미포함
|
|
*/
|
|
public function test_manager_without_include_deleted_comments_does_not_see_deleted_comments(): void
|
|
{
|
|
// Given
|
|
$postId = $this->createTestPost(['title' => '댓글 테스트 게시글']);
|
|
$deletedCommentId = $this->createTestComment($postId, [
|
|
'content' => '삭제된 댓글',
|
|
'deleted_at' => now(),
|
|
]);
|
|
|
|
// When: include_deleted_comments 파라미터 없이 조회
|
|
$response = $this->actingAs($this->managerUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts/{$postId}");
|
|
|
|
$response->assertStatus(200);
|
|
|
|
$commentIds = collect($response->json('data.comments'))->pluck('id')->toArray();
|
|
$this->assertNotContains($deletedCommentId, $commentIds, '삭제된 댓글이 포함되지 않아야 합니다');
|
|
}
|
|
|
|
/**
|
|
* 일반 사용자는 del_cmt=1을 넘겨도 삭제 댓글 미포함
|
|
*/
|
|
public function test_regular_user_cannot_see_deleted_comments_even_with_include_deleted_comments(): void
|
|
{
|
|
// Given
|
|
$postId = $this->createTestPost(['title' => '댓글 테스트 게시글']);
|
|
$deletedCommentId = $this->createTestComment($postId, [
|
|
'content' => '삭제된 댓글',
|
|
'deleted_at' => now(),
|
|
]);
|
|
|
|
// When: 일반 사용자가 del_cmt=1로 조회 시도
|
|
$response = $this->actingAs($this->regularUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts/{$postId}?del_cmt=1");
|
|
|
|
$response->assertStatus(200);
|
|
|
|
$commentIds = collect($response->json('data.comments'))->pluck('id')->toArray();
|
|
$this->assertNotContains($deletedCommentId, $commentIds, '일반 사용자에게는 삭제된 댓글이 노출되지 않아야 합니다');
|
|
}
|
|
|
|
// ==========================================
|
|
// 삭제 게시글/댓글 원본 노출 권한 (#413-50-2)
|
|
// manager 권한자는 삭제글 상세에서 제목/본문 원본을 볼 수 있어야 한다.
|
|
// 기존: getFilteredTitle/Content 가 admin.manage 만 검사 → manager 진입자에게도
|
|
// "삭제된 게시글" 문구로 필터링되는 권한 불일치.
|
|
// ==========================================
|
|
|
|
/**
|
|
* manager 권한자는 삭제된 게시글 상세에서 제목/본문 원본을 본다.
|
|
*/
|
|
public function test_manager_sees_deleted_post_original_title_and_content(): void
|
|
{
|
|
$deletedPostId = $this->createTestPost([
|
|
'title' => '삭제글 원본 제목 ORIG',
|
|
'content' => '삭제글 원본 본문 ORIG',
|
|
'status' => 'deleted',
|
|
'deleted_at' => now(),
|
|
]);
|
|
|
|
$response = $this->actingAs($this->managerUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts/{$deletedPostId}");
|
|
|
|
$response->assertStatus(200);
|
|
$this->assertSame('삭제글 원본 제목 ORIG', $response->json('data.title'));
|
|
$this->assertSame('삭제글 원본 본문 ORIG', $response->json('data.content'));
|
|
}
|
|
|
|
/**
|
|
* manager 권한자는 삭제된 댓글의 원본 본문을 본다.
|
|
*/
|
|
public function test_manager_sees_deleted_comment_original_content(): void
|
|
{
|
|
$postId = $this->createTestPost(['title' => '댓글 원본 테스트 게시글']);
|
|
$deletedCommentId = $this->createTestComment($postId, [
|
|
'content' => '삭제 댓글 원본 ORIG',
|
|
'deleted_at' => now(),
|
|
]);
|
|
|
|
$response = $this->actingAs($this->managerUser, 'sanctum')
|
|
->getJson("/api/modules/sirsoft-board/boards/{$this->board->slug}/posts/{$postId}?del_cmt=1");
|
|
|
|
$response->assertStatus(200);
|
|
$deletedComment = collect($response->json('data.comments'))
|
|
->firstWhere('id', $deletedCommentId);
|
|
$this->assertNotNull($deletedComment, '삭제 댓글이 응답에 포함되어야 합니다');
|
|
$this->assertSame('삭제 댓글 원본 ORIG', $deletedComment['content']);
|
|
}
|
|
}
|