2025-12-02 00:53:25 +09:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
|
|
|
|
|
|
use App\Models\Boards\Board;
|
2025-12-29 12:58:06 +09:00
|
|
|
use App\Models\Boards\BoardComment;
|
2025-12-02 00:53:25 +09:00
|
|
|
use App\Models\Boards\Post;
|
|
|
|
|
use App\Services\PostService;
|
|
|
|
|
use Illuminate\Http\JsonResponse;
|
|
|
|
|
use Illuminate\Http\RedirectResponse;
|
|
|
|
|
use Illuminate\Http\Request;
|
|
|
|
|
use Illuminate\View\View;
|
2025-12-27 17:08:53 +09:00
|
|
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
2025-12-02 00:53:25 +09:00
|
|
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
|
|
|
|
|
|
|
|
class PostController extends Controller
|
|
|
|
|
{
|
|
|
|
|
public function __construct(
|
|
|
|
|
private readonly PostService $postService
|
|
|
|
|
) {}
|
|
|
|
|
|
2025-12-28 01:30:50 +09:00
|
|
|
/**
|
|
|
|
|
* board_code + tenant_id로 게시판 조회
|
|
|
|
|
* - t 파라미터가 있으면 해당 테넌트의 게시판
|
|
|
|
|
* - 없으면 시스템 게시판 우선, 그 다음 로그인 회원의 테넌트 게시판
|
|
|
|
|
*/
|
|
|
|
|
private function resolveBoard(string $boardCode, Request $request): Board
|
|
|
|
|
{
|
|
|
|
|
$tenantId = $request->query('t');
|
|
|
|
|
|
|
|
|
|
// t 파라미터가 있으면 해당 테넌트의 게시판 조회
|
|
|
|
|
if ($tenantId) {
|
2025-12-29 09:11:21 +09:00
|
|
|
return Board::with('tenant')
|
|
|
|
|
->where('board_code', $boardCode)
|
2025-12-28 01:30:50 +09:00
|
|
|
->where('tenant_id', $tenantId)
|
|
|
|
|
->where('is_active', true)
|
|
|
|
|
->firstOrFail();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// t 파라미터가 없으면: 시스템 게시판 우선, 그 다음 로그인 회원의 테넌트 게시판
|
2025-12-29 09:11:21 +09:00
|
|
|
$board = Board::with('tenant')
|
|
|
|
|
->where('board_code', $boardCode)
|
2025-12-28 01:30:50 +09:00
|
|
|
->whereNull('tenant_id') // 시스템 게시판
|
|
|
|
|
->where('is_active', true)
|
|
|
|
|
->first();
|
|
|
|
|
|
|
|
|
|
if ($board) {
|
|
|
|
|
return $board;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 시스템 게시판이 없으면 로그인 회원의 테넌트 게시판
|
|
|
|
|
$userTenantId = auth()->user()?->tenant_id;
|
|
|
|
|
|
2025-12-29 09:11:21 +09:00
|
|
|
return Board::with('tenant')
|
|
|
|
|
->where('board_code', $boardCode)
|
2025-12-28 01:30:50 +09:00
|
|
|
->where('tenant_id', $userTenantId)
|
|
|
|
|
->where('is_active', true)
|
|
|
|
|
->firstOrFail();
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 00:53:25 +09:00
|
|
|
/**
|
|
|
|
|
* 게시글 목록
|
|
|
|
|
*/
|
2025-12-28 01:30:50 +09:00
|
|
|
public function index(string $boardCode, Request $request): View
|
2025-12-02 00:53:25 +09:00
|
|
|
{
|
2025-12-28 01:30:50 +09:00
|
|
|
$board = $this->resolveBoard($boardCode, $request);
|
2025-12-29 09:11:21 +09:00
|
|
|
$filters = $request->only(['search', 'is_notice', 'trashed']);
|
|
|
|
|
|
|
|
|
|
// 슈퍼관리자: 삭제된 게시물 포함 조회
|
|
|
|
|
$isSuperAdmin = auth()->user()->hasRole('super-admin');
|
|
|
|
|
$includeTrashed = $isSuperAdmin;
|
|
|
|
|
|
|
|
|
|
$posts = $this->postService->getPosts($board->id, $filters, 15, $includeTrashed);
|
2025-12-02 00:53:25 +09:00
|
|
|
$notices = $this->postService->getNotices($board->id, 5);
|
2025-12-29 09:11:21 +09:00
|
|
|
$stats = $this->postService->getBoardPostStats($board->id, $includeTrashed);
|
2025-12-02 00:53:25 +09:00
|
|
|
|
2025-12-29 09:11:21 +09:00
|
|
|
return view('posts.index', compact('board', 'posts', 'notices', 'stats', 'filters', 'isSuperAdmin'));
|
2025-12-02 00:53:25 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 게시글 작성 폼
|
|
|
|
|
*/
|
2025-12-28 01:30:50 +09:00
|
|
|
public function create(string $boardCode, Request $request): View
|
2025-12-02 00:53:25 +09:00
|
|
|
{
|
2025-12-28 01:30:50 +09:00
|
|
|
$board = $this->resolveBoard($boardCode, $request);
|
2025-12-02 00:53:25 +09:00
|
|
|
$fields = $board->fields;
|
|
|
|
|
|
|
|
|
|
return view('posts.create', compact('board', 'fields'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 게시글 저장
|
|
|
|
|
*/
|
2025-12-28 01:30:50 +09:00
|
|
|
public function store(string $boardCode, Request $request): RedirectResponse
|
2025-12-02 00:53:25 +09:00
|
|
|
{
|
2025-12-28 01:30:50 +09:00
|
|
|
$board = $this->resolveBoard($boardCode, $request);
|
2025-12-02 00:53:25 +09:00
|
|
|
$validated = $request->validate([
|
|
|
|
|
'title' => 'required|string|max:255',
|
|
|
|
|
'content' => 'nullable|string',
|
|
|
|
|
'is_notice' => 'nullable|boolean',
|
|
|
|
|
'is_secret' => 'nullable|boolean',
|
|
|
|
|
'files' => 'nullable|array',
|
|
|
|
|
'files.*' => 'file|max:'.($board->max_file_size),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// 커스텀 필드 값
|
|
|
|
|
$customFields = $request->input('custom_fields', []);
|
|
|
|
|
|
|
|
|
|
// 커스텀 필드 유효성 검사
|
|
|
|
|
foreach ($board->fields as $field) {
|
|
|
|
|
if ($field->is_required && empty($customFields[$field->field_key])) {
|
|
|
|
|
return back()
|
|
|
|
|
->withInput()
|
|
|
|
|
->withErrors([$field->field_key => "{$field->name}은(는) 필수입니다."]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$validated['is_notice'] = $request->boolean('is_notice');
|
|
|
|
|
$validated['is_secret'] = $request->boolean('is_secret');
|
|
|
|
|
|
|
|
|
|
$post = $this->postService->createPost($board, $validated, $customFields);
|
|
|
|
|
|
|
|
|
|
// 파일 업로드 처리
|
|
|
|
|
if ($request->hasFile('files') && $board->allow_files) {
|
|
|
|
|
try {
|
|
|
|
|
$this->postService->uploadFiles($post, $request->file('files'));
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
// 파일 업로드 실패해도 게시글은 저장됨 - 경고 메시지만 표시
|
|
|
|
|
return redirect()
|
2025-12-28 01:30:50 +09:00
|
|
|
->route('boards.posts.show', [$board->board_code, $post, 't' => $board->tenant_id])
|
2025-12-02 00:53:25 +09:00
|
|
|
->with('warning', '게시글이 작성되었으나 일부 파일 업로드에 실패했습니다: '.$e->getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return redirect()
|
2025-12-28 01:30:50 +09:00
|
|
|
->route('boards.posts.show', [$board->board_code, $post, 't' => $board->tenant_id])
|
2025-12-02 00:53:25 +09:00
|
|
|
->with('success', '게시글이 작성되었습니다.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 게시글 상세
|
|
|
|
|
*/
|
2025-12-28 01:30:50 +09:00
|
|
|
public function show(string $boardCode, Post $post, Request $request): View|RedirectResponse
|
2025-12-02 00:53:25 +09:00
|
|
|
{
|
2025-12-28 01:30:50 +09:00
|
|
|
$board = $this->resolveBoard($boardCode, $request);
|
|
|
|
|
|
2025-12-02 00:53:25 +09:00
|
|
|
// 게시판 일치 확인
|
|
|
|
|
if ($post->board_id !== $board->id) {
|
|
|
|
|
abort(404);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 비밀글 접근 권한 확인
|
|
|
|
|
if (! $post->canAccess(auth()->user())) {
|
|
|
|
|
return back()->with('error', '비밀글은 작성자만 볼 수 있습니다.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 조회수 증가
|
|
|
|
|
$this->postService->incrementViews($post);
|
|
|
|
|
|
|
|
|
|
// 이전/다음 글
|
|
|
|
|
$adjacent = $this->postService->getAdjacentPosts($post);
|
|
|
|
|
|
|
|
|
|
// 커스텀 필드 값
|
|
|
|
|
$customFieldValues = $post->getCustomFieldsArray();
|
|
|
|
|
|
2025-12-29 12:58:06 +09:00
|
|
|
// 댓글 목록
|
|
|
|
|
$comments = $this->postService->getComments($post);
|
|
|
|
|
|
|
|
|
|
return view('posts.show', compact('board', 'post', 'adjacent', 'customFieldValues', 'comments'));
|
2025-12-02 00:53:25 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 게시글 수정 폼
|
|
|
|
|
*/
|
2025-12-28 01:30:50 +09:00
|
|
|
public function edit(string $boardCode, Post $post, Request $request): View|RedirectResponse
|
2025-12-02 00:53:25 +09:00
|
|
|
{
|
2025-12-28 01:30:50 +09:00
|
|
|
$board = $this->resolveBoard($boardCode, $request);
|
|
|
|
|
|
2025-12-02 00:53:25 +09:00
|
|
|
// 게시판 일치 확인
|
|
|
|
|
if ($post->board_id !== $board->id) {
|
|
|
|
|
abort(404);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 수정 권한 확인 (작성자 또는 관리자)
|
|
|
|
|
if ($post->user_id !== auth()->id() && ! auth()->user()->hasRole(['admin', 'super-admin'])) {
|
|
|
|
|
return back()->with('error', '수정 권한이 없습니다.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$fields = $board->fields;
|
|
|
|
|
$customFieldValues = $post->getCustomFieldsArray();
|
|
|
|
|
|
|
|
|
|
return view('posts.edit', compact('board', 'post', 'fields', 'customFieldValues'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 게시글 수정 저장
|
|
|
|
|
*/
|
2025-12-28 01:30:50 +09:00
|
|
|
public function update(string $boardCode, Post $post, Request $request): RedirectResponse
|
2025-12-02 00:53:25 +09:00
|
|
|
{
|
2025-12-28 01:30:50 +09:00
|
|
|
$board = $this->resolveBoard($boardCode, $request);
|
|
|
|
|
|
2025-12-02 00:53:25 +09:00
|
|
|
// 게시판 일치 확인
|
|
|
|
|
if ($post->board_id !== $board->id) {
|
|
|
|
|
abort(404);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 수정 권한 확인
|
|
|
|
|
if ($post->user_id !== auth()->id() && ! auth()->user()->hasRole(['admin', 'super-admin'])) {
|
|
|
|
|
return back()->with('error', '수정 권한이 없습니다.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$validated = $request->validate([
|
|
|
|
|
'title' => 'required|string|max:255',
|
|
|
|
|
'content' => 'nullable|string',
|
|
|
|
|
'is_notice' => 'nullable|boolean',
|
|
|
|
|
'is_secret' => 'nullable|boolean',
|
|
|
|
|
'files' => 'nullable|array',
|
|
|
|
|
'files.*' => 'file|max:'.($board->max_file_size),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// 커스텀 필드 값
|
|
|
|
|
$customFields = $request->input('custom_fields', []);
|
|
|
|
|
|
|
|
|
|
// 커스텀 필드 유효성 검사
|
|
|
|
|
foreach ($board->fields as $field) {
|
|
|
|
|
if ($field->is_required && empty($customFields[$field->field_key])) {
|
|
|
|
|
return back()
|
|
|
|
|
->withInput()
|
|
|
|
|
->withErrors([$field->field_key => "{$field->name}은(는) 필수입니다."]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$validated['is_notice'] = $request->boolean('is_notice');
|
|
|
|
|
$validated['is_secret'] = $request->boolean('is_secret');
|
|
|
|
|
|
|
|
|
|
$this->postService->updatePost($post, $validated, $customFields);
|
|
|
|
|
|
|
|
|
|
// 파일 업로드 처리
|
|
|
|
|
if ($request->hasFile('files') && $board->allow_files) {
|
|
|
|
|
try {
|
|
|
|
|
$this->postService->uploadFiles($post, $request->file('files'));
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
return redirect()
|
2025-12-28 01:30:50 +09:00
|
|
|
->route('boards.posts.show', [$board->board_code, $post, 't' => $board->tenant_id])
|
2025-12-02 00:53:25 +09:00
|
|
|
->with('warning', '게시글이 수정되었으나 일부 파일 업로드에 실패했습니다: '.$e->getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return redirect()
|
2025-12-28 01:30:50 +09:00
|
|
|
->route('boards.posts.show', [$board->board_code, $post, 't' => $board->tenant_id])
|
2025-12-02 00:53:25 +09:00
|
|
|
->with('success', '게시글이 수정되었습니다.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 게시글 삭제
|
|
|
|
|
*/
|
2025-12-28 01:30:50 +09:00
|
|
|
public function destroy(string $boardCode, Post $post, Request $request): RedirectResponse
|
2025-12-02 00:53:25 +09:00
|
|
|
{
|
2025-12-28 01:30:50 +09:00
|
|
|
$board = $this->resolveBoard($boardCode, $request);
|
|
|
|
|
|
2025-12-02 00:53:25 +09:00
|
|
|
// 게시판 일치 확인
|
|
|
|
|
if ($post->board_id !== $board->id) {
|
|
|
|
|
abort(404);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 삭제 권한 확인
|
|
|
|
|
if ($post->user_id !== auth()->id() && ! auth()->user()->hasRole(['admin', 'super-admin'])) {
|
|
|
|
|
return back()->with('error', '삭제 권한이 없습니다.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 첨부 파일 삭제
|
|
|
|
|
$this->postService->deleteAllFiles($post);
|
|
|
|
|
|
|
|
|
|
$this->postService->deletePost($post);
|
|
|
|
|
|
|
|
|
|
return redirect()
|
2025-12-28 01:30:50 +09:00
|
|
|
->route('boards.posts.index', [$board->board_code, 't' => $board->tenant_id])
|
2025-12-02 00:53:25 +09:00
|
|
|
->with('success', '게시글이 삭제되었습니다.');
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-29 09:11:21 +09:00
|
|
|
/**
|
|
|
|
|
* 게시글 복원 (슈퍼관리자 전용)
|
|
|
|
|
*/
|
|
|
|
|
public function restore(string $boardCode, int $postId, Request $request): RedirectResponse
|
|
|
|
|
{
|
|
|
|
|
// 슈퍼관리자 권한 확인
|
|
|
|
|
if (! auth()->user()->hasRole('super-admin')) {
|
|
|
|
|
abort(403);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$board = $this->resolveBoard($boardCode, $request);
|
|
|
|
|
$post = Post::onlyTrashed()->where('board_id', $board->id)->findOrFail($postId);
|
|
|
|
|
|
|
|
|
|
$this->postService->restorePost($post);
|
|
|
|
|
|
|
|
|
|
return redirect()
|
|
|
|
|
->route('boards.posts.index', [$board->board_code, 't' => $board->tenant_id])
|
|
|
|
|
->with('success', '게시글이 복원되었습니다.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 게시글 영구 삭제 (슈퍼관리자 전용)
|
|
|
|
|
*/
|
|
|
|
|
public function forceDestroy(string $boardCode, int $postId, Request $request): RedirectResponse
|
|
|
|
|
{
|
|
|
|
|
// 슈퍼관리자 권한 확인
|
|
|
|
|
if (! auth()->user()->hasRole('super-admin')) {
|
|
|
|
|
abort(403);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$board = $this->resolveBoard($boardCode, $request);
|
|
|
|
|
$post = Post::withTrashed()->where('board_id', $board->id)->findOrFail($postId);
|
|
|
|
|
|
|
|
|
|
$this->postService->forceDeletePost($post);
|
|
|
|
|
|
|
|
|
|
return redirect()
|
|
|
|
|
->route('boards.posts.index', [$board->board_code, 't' => $board->tenant_id])
|
|
|
|
|
->with('success', '게시글이 영구 삭제되었습니다.');
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 00:53:25 +09:00
|
|
|
// =========================================================================
|
|
|
|
|
// File Management
|
|
|
|
|
// =========================================================================
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 파일 업로드 (AJAX)
|
|
|
|
|
*/
|
2025-12-28 01:30:50 +09:00
|
|
|
public function uploadFiles(string $boardCode, Post $post, Request $request): JsonResponse
|
2025-12-02 00:53:25 +09:00
|
|
|
{
|
2025-12-28 01:30:50 +09:00
|
|
|
$board = $this->resolveBoard($boardCode, $request);
|
|
|
|
|
|
2025-12-02 00:53:25 +09:00
|
|
|
// 게시판 일치 확인
|
|
|
|
|
if ($post->board_id !== $board->id) {
|
|
|
|
|
return response()->json(['success' => false, 'message' => '게시글을 찾을 수 없습니다.'], 404);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 수정 권한 확인
|
|
|
|
|
if ($post->user_id !== auth()->id() && ! auth()->user()->hasRole(['admin', 'super-admin'])) {
|
|
|
|
|
return response()->json(['success' => false, 'message' => '권한이 없습니다.'], 403);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 파일 첨부 허용 여부
|
|
|
|
|
if (! $board->allow_files) {
|
|
|
|
|
return response()->json(['success' => false, 'message' => '이 게시판은 파일 첨부가 허용되지 않습니다.'], 400);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$request->validate([
|
|
|
|
|
'files' => 'required|array',
|
|
|
|
|
'files.*' => 'file|max:'.($board->max_file_size),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
$uploadedFiles = $this->postService->uploadFiles($post, $request->file('files'));
|
|
|
|
|
|
|
|
|
|
return response()->json([
|
|
|
|
|
'success' => true,
|
|
|
|
|
'message' => count($uploadedFiles).'개의 파일이 업로드되었습니다.',
|
|
|
|
|
'files' => collect($uploadedFiles)->map(fn ($file) => [
|
|
|
|
|
'id' => $file->id,
|
|
|
|
|
'name' => $file->display_name ?? $file->original_name,
|
|
|
|
|
'size' => $file->getFormattedSize(),
|
|
|
|
|
'type' => $file->file_type,
|
|
|
|
|
]),
|
|
|
|
|
]);
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
return response()->json(['success' => false, 'message' => $e->getMessage()], 400);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 파일 다운로드
|
|
|
|
|
*/
|
2025-12-28 01:30:50 +09:00
|
|
|
public function downloadFile(string $boardCode, Post $post, int $fileId, Request $request): BinaryFileResponse|StreamedResponse|RedirectResponse
|
2025-12-02 00:53:25 +09:00
|
|
|
{
|
2025-12-28 01:30:50 +09:00
|
|
|
$board = $this->resolveBoard($boardCode, $request);
|
|
|
|
|
|
2025-12-02 00:53:25 +09:00
|
|
|
// 게시판 일치 확인
|
|
|
|
|
if ($post->board_id !== $board->id) {
|
|
|
|
|
abort(404);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 비밀글 접근 권한 확인
|
|
|
|
|
if (! $post->canAccess(auth()->user())) {
|
|
|
|
|
return back()->with('error', '파일에 접근할 수 없습니다.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->postService->downloadFile($post, $fileId);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-27 17:08:53 +09:00
|
|
|
/**
|
|
|
|
|
* 파일 미리보기 (이미지 인라인 표시)
|
|
|
|
|
*/
|
2025-12-28 01:30:50 +09:00
|
|
|
public function previewFile(string $boardCode, Post $post, int $fileId, Request $request): BinaryFileResponse|StreamedResponse|RedirectResponse
|
2025-12-27 17:08:53 +09:00
|
|
|
{
|
2025-12-28 01:30:50 +09:00
|
|
|
$board = $this->resolveBoard($boardCode, $request);
|
|
|
|
|
|
2025-12-27 17:08:53 +09:00
|
|
|
// 게시판 일치 확인
|
|
|
|
|
if ($post->board_id !== $board->id) {
|
|
|
|
|
abort(404);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 비밀글 접근 권한 확인
|
|
|
|
|
if (! $post->canAccess(auth()->user())) {
|
|
|
|
|
return back()->with('error', '파일에 접근할 수 없습니다.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->postService->previewFile($post, $fileId);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 00:53:25 +09:00
|
|
|
/**
|
|
|
|
|
* 파일 삭제 (AJAX)
|
|
|
|
|
*/
|
2025-12-28 01:30:50 +09:00
|
|
|
public function deleteFile(string $boardCode, Post $post, int $fileId, Request $request): JsonResponse
|
2025-12-02 00:53:25 +09:00
|
|
|
{
|
2025-12-28 01:30:50 +09:00
|
|
|
$board = $this->resolveBoard($boardCode, $request);
|
|
|
|
|
|
2025-12-02 00:53:25 +09:00
|
|
|
// 게시판 일치 확인
|
|
|
|
|
if ($post->board_id !== $board->id) {
|
|
|
|
|
return response()->json(['success' => false, 'message' => '게시글을 찾을 수 없습니다.'], 404);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 삭제 권한 확인 (작성자 또는 관리자)
|
|
|
|
|
if ($post->user_id !== auth()->id() && ! auth()->user()->hasRole(['admin', 'super-admin'])) {
|
|
|
|
|
return response()->json(['success' => false, 'message' => '권한이 없습니다.'], 403);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
$this->postService->deleteFile($post, $fileId);
|
|
|
|
|
|
|
|
|
|
return response()->json(['success' => true, 'message' => '파일이 삭제되었습니다.']);
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
return response()->json(['success' => false, 'message' => $e->getMessage()], 400);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-12-29 12:58:06 +09:00
|
|
|
|
|
|
|
|
// =========================================================================
|
|
|
|
|
// Comment Management
|
|
|
|
|
// =========================================================================
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 댓글 작성
|
|
|
|
|
*/
|
|
|
|
|
public function storeComment(string $boardCode, Post $post, Request $request): RedirectResponse
|
|
|
|
|
{
|
|
|
|
|
$board = $this->resolveBoard($boardCode, $request);
|
|
|
|
|
|
|
|
|
|
// 게시판 일치 확인
|
|
|
|
|
if ($post->board_id !== $board->id) {
|
|
|
|
|
abort(404);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 비밀글 접근 권한 확인
|
|
|
|
|
if (! $post->canAccess(auth()->user())) {
|
|
|
|
|
return back()->with('error', '댓글을 작성할 수 없습니다.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$validated = $request->validate([
|
|
|
|
|
'content' => 'required|string|max:1000',
|
|
|
|
|
'parent_id' => 'nullable|integer|exists:board_comments,id',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$this->postService->createComment($post, $validated);
|
|
|
|
|
|
|
|
|
|
return redirect()
|
|
|
|
|
->route('boards.posts.show', [$board->board_code, $post, 't' => $board->tenant_id])
|
|
|
|
|
->with('success', '댓글이 작성되었습니다.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 댓글 수정
|
|
|
|
|
*/
|
|
|
|
|
public function updateComment(string $boardCode, Post $post, BoardComment $comment, Request $request): RedirectResponse
|
|
|
|
|
{
|
|
|
|
|
$board = $this->resolveBoard($boardCode, $request);
|
|
|
|
|
|
|
|
|
|
// 게시판 일치 확인
|
|
|
|
|
if ($post->board_id !== $board->id) {
|
|
|
|
|
abort(404);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 댓글-게시글 일치 확인
|
|
|
|
|
if ($comment->post_id !== $post->id) {
|
|
|
|
|
abort(404);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 수정 권한 확인 (작성자 또는 관리자)
|
|
|
|
|
if ($comment->user_id !== auth()->id() && ! auth()->user()->hasRole(['admin', 'super-admin'])) {
|
|
|
|
|
return back()->with('error', '수정 권한이 없습니다.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$validated = $request->validate([
|
|
|
|
|
'content' => 'required|string|max:1000',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$this->postService->updateComment($comment, $validated);
|
|
|
|
|
|
|
|
|
|
return redirect()
|
|
|
|
|
->route('boards.posts.show', [$board->board_code, $post, 't' => $board->tenant_id])
|
|
|
|
|
->with('success', '댓글이 수정되었습니다.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 댓글 삭제
|
|
|
|
|
*/
|
|
|
|
|
public function destroyComment(string $boardCode, Post $post, BoardComment $comment, Request $request): RedirectResponse
|
|
|
|
|
{
|
|
|
|
|
$board = $this->resolveBoard($boardCode, $request);
|
|
|
|
|
|
|
|
|
|
// 게시판 일치 확인
|
|
|
|
|
if ($post->board_id !== $board->id) {
|
|
|
|
|
abort(404);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 댓글-게시글 일치 확인
|
|
|
|
|
if ($comment->post_id !== $post->id) {
|
|
|
|
|
abort(404);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 삭제 권한 확인 (작성자 또는 관리자)
|
|
|
|
|
if ($comment->user_id !== auth()->id() && ! auth()->user()->hasRole(['admin', 'super-admin'])) {
|
|
|
|
|
return back()->with('error', '삭제 권한이 없습니다.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->postService->deleteComment($comment);
|
|
|
|
|
|
|
|
|
|
return redirect()
|
|
|
|
|
->route('boards.posts.show', [$board->board_code, $post, 't' => $board->tenant_id])
|
|
|
|
|
->with('success', '댓글이 삭제되었습니다.');
|
|
|
|
|
}
|
2025-12-02 00:53:25 +09:00
|
|
|
}
|