boardModel = new Board(); $this->boardMetaModel = new BoardMeta(); $this->postModel = new Post(); $this->postMetaModel = new PostMeta(); $this->postHistoryModel = new PostHistory(); $this->postBookmarkModel = new PostBookmark(); $this->postLikeModel = new PostLike(); $this->postTagModel = new PostTag(); $this->postFileModel = new PostFile(); $this->postFileDownLogModel = new PostFileDownLog(); $this->postBlameModel = new PostBlame(); $this->postLinkModel = new PostLink(); $this->postLinkClickLogModel = new PostLinkClickLog(); $this->postDeletedModel = new PostDeleted(); $this->userModel = new User(); $this->fileLib = new FileLib(); $this->editorImageModel = new EditorImage(); } public function meta(int $postID): ?PostMeta { return $this->postMetaModel->getAllMeta($postID); } /** * 게시글 정보 조회 */ public function find(int $postID): Post { $post = $this->postModel->get($postID); if(!$post->exists) { return $post; } $code = $post->board->code; $boardMeta = $this->boardMetaModel->getAllMeta($post->board_id); // 게시글 정보 $post->viewURL = route('board.post.view', [$code, $postID]); $post->beforeViewURL = ($post->beforePostID ? route('board.post.view', [$code, $post->beforePostID]) : null); $post->nextViewURL = ($post->nextPostID ? route('board.post.view', [$code, $post->nextPostID]) : null); $post->createdAt = $post->created_at->format('Y.m.d H:i:s'); $post->ipAddress = null; $post->isBookmark = false; $post->isLike = false; $post->isDislike = false; // 본문 URL 링크 자동 생성 if ($boardMeta->item('use_auto_url', 0)) { $post->content = $this->urlAutoLink($post->content, $boardMeta->item('content_target_blank', 0)); // Link 새창 여부 } // 익명 게시판일 경우 if( $boardMeta->item('use_anonymous', 0) && (!$post->user->is_admin || !$boardMeta->item('anonymous_except_admin', 0)) && $post->user->id ) { $post->username = $this->createAnonymousName( $boardMeta->item('anonymous_name'), $post->user_id, $post->id ); } if($post->user->exists) { $post->user->thumb = $this->profileThumbSrc($post->user->thumb); $post->user->createdAt = $post->user->created_at->format('Y.m.d'); } // IP 형식 처리 $showPostIP = $boardMeta->item('show_post_ip'); // 노출 방법 if ($showPostIP) { $ipDisplayStyle = ($showPostIP == 2 || IS_ADMIN ? '1111' : config('ip_display_style')); // IP 형식 $post->ipAddress = $this->ipAddrMasking($post->ip_address, $ipDisplayStyle); } // 즐겨찾기 if ($boardMeta->item('use_bookmark', 0)) { $post->isBookmark = $this->postBookmarkModel->isAlready($post, UID); } // 좋아요 if ($boardMeta->item('use_post_like', 0)) { $post->isLike = $this->postLikeModel->isAlready($post, UID, LIKE); } // 싫어요 if ($boardMeta->item('use_post_dislike', 0)) { $post->isDislike = $this->postLikeModel->isAlready($post, UID, DISLIKE); } // 태그 $post->tags = $post->postTag; // 첨부파일 $post->files = $post->postFile; // 링크 첨부 $post->links = $post->postLink; return $post; } /** * 게시글 등록 처리 */ public function register(PostRequest $request, ResponseData $response): ResponseData { DB::beginTransaction(); try { $user = $request->user(); $boardID = intval($request->post('bid')); $boardMeta = $request->boardMeta; // 게시글 첨부 사진 저장 $content = $this->getContent($request); $thumbnail = $this->getThumbnail($content, ($boardMeta->item('board_layout_type') == BOARD_LAYOUT_TYPE_1 ? NO_IMAGE_NORMAL_SRC : null) ); $imageRows = $this->getImageRows($content); $videoRows = $this->getVideoRows($content); // 게시글 정보 저장 $post = $this->postModel->register([ 'board_id' => $boardID, 'board_category_id' => $request->post('category'), 'user_id' => $user?->id, 'thumbnail' => $thumbnail, 'subject' => trim($request->post('subject')), 'content' => $content, 'sid' => $user?->sid, 'username' => $request->post('username', $user?->name), 'email' => $user?->email, 'password' => $request->post('password'), 'comment_rows' => 0, 'comment_updated_at' => null, 'is_reply' => 0, 'is_personal' => $boardMeta->item('use_personal', 0), 'is_secret' => ($boardMeta->item('use_post_secret', 0) == '2' ? 1 : $request->post('is_secret', 0)), 'is_notice' => $request->post('is_notice', 0), 'is_speaker' => $request->post('is_speaker', 0), 'is_html' => $boardMeta->item('use_post_dhtml', 0), 'use_comment' => $boardMeta->item('use_comment', 0), 'receive_email' => 0, 'hit' => 0, 'like' => 0, 'dislike' => 0, 'blame' => 0, 'device_type' => DEVICE_TYPE, 'file_rows' => 0, 'image_rows' => $imageRows, 'video_rows' => $videoRows, 'link_rows' => 0, 'tag_rows' => 0, 'is_delete' => 0, 'ip_address' => IP_ADDRESS, 'user_agent' => USER_AGENT, 'deleted_at' => null, 'updated_at' => null, 'created_at' => now() ]); // 게시글 Tag 저장 $this->postTagModel->register($post, $request->post('tags')); // 게시글 Link 저장 $this->postLinkModel->register($post, $request->post('links')); // 게시글 File 저장 $this->postFileModel->register($post, $request->file('files')); // 게시글 기록 저장 if ($boardMeta->use_post_history) { $this->postHistoryModel->register($post,'게시글 등록'); } // 게시판 게시글 수 갱신 $this->boardModel->updatePostRows($boardID); $response->post = $post; DB::commit(); } catch (Exception $e) { $response = $response::fromException($e); DB::rollBack(); } return $response; } /** * 게시글 수정 처리 */ public function updater(PostRequest $request, ResponseData $response): ResponseData { DB::beginTransaction(); try { $user = $request->user(); $boardMeta = $request->boardMeta; $boardID = intval($request->post('bid')); $postID = intval($request->post('pid')); // 게시글 첨부 사진 저장 $content = $this->getContent($request); $thumbnail = $this->getThumbnail($content, ($boardMeta->item('board_layout_type') == BOARD_LAYOUT_TYPE_1 ? NO_IMAGE_NORMAL_SRC : null) ); $imageRows = $this->getImageRows($content); $videoRows = $this->getVideoRows($content); // 게시글 기록 저장 if ($boardMeta->item('use_post_history', 0)) { $this->postHistoryModel->updater($request->post, '게시글 수정'); } // 게시글 정보 저장 $post = $this->postModel->updater($postID, [ 'board_id' => $boardID, 'board_category_id' => $request->post('category'), 'user_id' => $user?->id, 'thumbnail' => $thumbnail, 'subject' => trim($request->post('subject')), 'content' => $content, 'sid' => $user?->sid, 'username' => $request->post('username', $user?->name), 'email' => $user?->email, 'password' => $request->post('password'), 'is_personal' => $boardMeta->item('use_personal', 0), 'is_secret' => ($boardMeta->item('use_post_secret', 0) == '2' ? 1 : $request->post('is_secret', 0)), 'is_notice' => $request->post('is_notice', 0), 'is_speaker' => $request->post('is_speaker', 0), 'is_html' => $boardMeta->item('use_post_dhtml', 0), 'use_comment' => $boardMeta->item('use_comment', 0), 'receive_email' => 0, 'device_type' => DEVICE_TYPE, 'file_rows' => 0, 'image_rows' => $imageRows, 'video_rows' => $videoRows, 'link_rows' => 0, 'tag_rows' => 0, 'ip_address' => IP_ADDRESS, 'user_agent' => USER_AGENT, 'updated_at' => now() ]); // 게시글 Tag 저장 $this->postTagModel->updater($post, $request->post('tags')); // 게시글 Link 저장 $this->postLinkModel->updater($post, $request->post('links')); // 게시글 File 저장 $this->postFileModel->updater($post, $request->post('file_is_delete', []), $request->file('files')); DB::commit(); } catch (Exception $e) { $response = $response::fromException($e); DB::rollBack(); } return $response; } /** * 게시글 삭제 */ public function delete(Request $request, ResponseData $response): ResponseData { DB::beginTransaction(); try { $post = $request->post; // 게시글 존재 확인 if (!$post->exists) { throw new Exception('게시글이 존재 하지 않습니다.'); } $user = $request->user(); // 게시글 삭제 여부 승인 $this->postModel->remove($post, $user); DB::commit(); } catch (Exception $e) { $response = $response::fromException($e); DB::rollBack(); } return $response; } /** * 게시글 즐겨찾기 */ public function bookmark(Request $request, ResponseData $response): ResponseData { DB::beginTransaction(); try { $post = $this->postModel->findOrNew( $request->input('pid') ); // 게시글 존재 확인 if (!$post->exists) { throw new Exception('게시글이 존재 하지 않습니다.'); } $boardMeta = $this->boardMetaModel->getAllMeta($post->board_id); if (!$boardMeta->item('use_bookmark', 0)) { throw new Exception('즐겨찾기 기능은 사용하지 않습니다.'); } $userID = $request->user()->id; if ($this->postBookmarkModel->isAlready($post, $userID)) { $this->postBookmarkModel->remove($post, $userID); } else { $this->postBookmarkModel->register([ 'board_id' => $post->board_id, 'post_id' => $post->id, 'user_id' => $userID, 'ip_address' => IP_ADDRESS, 'user_agent' => USER_AGENT, 'created_at' => now() ]); } // 즐겨찾기 수 저장 $this->postMetaModel->save($post->id, [ 'bookmark_rows' => $this->postBookmarkModel->rows($post) ]); $response->post = $post; DB::commit(); } catch (Exception $e) { $response = $response::fromException($e); DB::rollBack(); } return $response; } /** * 게시글 신고 */ public function blame(Request $request, ResponseData $response): ResponseData { DB::beginTransaction(); try { $post = $this->postModel->findOrNew( $request->input('pid') ); // 게시글 존재 확인 if(!$post->exists) { throw new Exception('게시글이 존재 하지 않습니다.'); } $boardMeta = $this->boardMetaModel->getAllMeta($post->board_id); if (!$boardMeta->item('use_blame', 0)) { throw new Exception('신고 기능은 사용하지 않습니다.'); } $userID = $request->user()->id; // 이미 신고했는지 확인 if ($this->postBlameModel->isAlready($post, $userID)) { throw new Exception('이미 신고하셨습니다.'); } $this->postBlameModel->register([ 'board_id' => $post->board_id, 'post_id' => $post->id, 'user_id' => $userID, 'type' => $request->post('type'), 'reason' => $request->post('reason'), 'status' => 0, 'memo' => null, 'ip_address' => IP_ADDRESS, 'user_agent' => USER_AGENT, 'created_at' => now() ]); // 게시글 신고 수 증가 $this->postModel->increaseBlame($post->id); $response->post = $post; DB::commit(); } catch (Exception $e) { $response = $response::fromException($e); DB::rollBack(); } return $response; } /** * 게시글 좋아요 */ public function like(Request $request, ResponseData $response): ResponseData { DB::beginTransaction(); try { $post = $this->postModel->findOrNew( $request->input('pid') ); // 게시글 존재 확인 if(!$post->exists) { throw new Exception('게시글이 존재 하지 않습니다.'); } $boardMeta = $this->boardMetaModel->getAllMeta($post->board_id); if (!$boardMeta->item('use_post_like', 0)) { throw new Exception('추천 기능은 사용하지 않습니다.'); } $userID = $request->user()->id; $saveData = [ 'board_id' => $post->board_id, 'post_id' => $post->id, 'user_id' => $userID, 'type' => LIKE, 'ip_address' => IP_ADDRESS, 'user_agent' => USER_AGENT, 'created_at' => now() ]; $likeInfo = $this->postLikeModel->info($post, $userID); if ($likeInfo->exists) { // 이미 추천함 $this->postLikeModel->remove($post, $userID); if ($likeInfo->type == LIKE) { $this->postModel->decreaseLike($post->id); } else if ($likeInfo->type == DISLIKE) { $this->postLikeModel->register($saveData); $this->postModel->increaseLike($post->id); $this->postModel->decreaseDisLike($post->id); } } else { // 추천 $this->postLikeModel->register($saveData); $this->postModel->increaseLike($post->id); } $response->post = $post; DB::commit(); } catch (Exception $e) { $response = $response::fromException($e); DB::rollBack(); } return $response; } /** * 게시글 싫어요 */ public function dislike(Request $request, ResponseData $response): ResponseData { DB::beginTransaction(); try { $post = $this->postModel->findOrNew( $request->input('pid') ); // 게시글 존재 확인 if(!$post->exists) { throw new Exception('게시글이 존재 하지 않습니다.'); } $boardMeta = $this->boardMetaModel->getAllMeta($post->board_id); if (!$boardMeta->item('use_post_dislike', 0)) { throw new Exception('비추천 기능은 사용하지 않습니다.'); } $userID = $request->user()->id; $saveData = [ 'board_id' => $post->board_id, 'post_id' => $post->id, 'user_id' => $userID, 'type' => DISLIKE, 'ip_address' => IP_ADDRESS, 'user_agent' => USER_AGENT, 'created_at' => now() ]; $likeInfo = $this->postLikeModel->info($post, $userID); if ($likeInfo->exists) { // 이미 추천함 $this->postLikeModel->remove($post, $userID); if ($likeInfo->type == DISLIKE) { $this->postModel->decreaseDisLike($post->id); } else if ($likeInfo->type == LIKE) { $this->postLikeModel->register($saveData); $this->postModel->increaseDisLike($post->id); $this->postModel->decreaseLike($post->id); } } else { $this->postLikeModel->register($saveData); $this->postModel->increaseDisLike($post->id); } $response->post = $post; DB::commit(); } catch (Exception $e) { $response = $response::fromException($e); DB::rollBack(); } return $response; } /** * 게시글 첨부파일 다운로드 */ public function download(Request $request): object { $ret = (object)[ 'path' => null, 'name' => null ]; $file = $this->postFileModel->info( $request->post('fid') ); if (!$file->exists) { return $ret; } // 다운로드 횟수 증가 $file->increaseDownload($file->id); // 다운로드 기록 $boardMeta = $this->boardMetaModel->getAllMeta($file->board_id); if ($boardMeta->item('use_download_log', 0)) { $this->postFileDownLogModel->register([ 'post_file_id' => $file->id, 'board_id' => $file->board_id, 'post_id' => $file->post_id, 'user_id' => $file->user_id, 'ip_address' => IP_ADDRESS, 'user_agent' => USER_AGENT, 'created_at' => now() ]); } $ret->path = $file->file_path; $ret->name = $file->origin_name; return $ret; } /** * 게시글 Link 클릭 */ public function linked(Request $request): string|null { $link = $this->postLinkModel->info( $request->post('lid') ); if (!$link->exists) { return null; } // Link 클릭 횟수 증가 $link->increaseHit($link->id); // Link 클릭 기록 $boardMeta = $this->boardMetaModel->getAllMeta($link->board_id); if ($boardMeta->item('use_link_click_log', 0)) { $this->postLinkClickLogModel->register([ 'post_link_id' => $link->id, 'board_id' => $link->board_id, 'post_id' => $link->post_id, 'user_id' => $link->user_id, 'ip_address' => IP_ADDRESS, 'user_agent' => USER_AGENT, 'created_at' => now() ]); } return ($link->url ?? null); } /** * 게시글 보기 조회 수 증가 */ public function addHit(Post $post): void { if($this->postModel->addHit($post)) { $this->postModel->increaseHit($post->id); } } /** * 게시글 작성 개수 */ public function userPostRows(Board $board, ?User $user): int { return $this->postModel->where([ ['board_id', $board->id], ['user_id', $user?->id], ['ip_address', IP_ADDRESS] ])->whereRaw('DATE(created_at) = CURDATE()')->count(); } /** * 게시글 추천 여부 */ public function userPostIsLike(Post $post, User $user): int { return $this->postLikeModel->where([ ['board_id', $post->board_id], ['post_id', $post->id], ['user_id', $user->id] ])->orWhere('ip_address', IP_ADDRESS)->exists(); } /** * 첨부 사진 저장 */ private function getContent(PostRequest $request): string { // 게시글 이미지 저장 $boardMeta = $request->boardMeta; $postID = $this->postModel->lastedKey(); $content = trim($request->post('content')); if ($boardMeta->item('save_external_image', 0)) { // link $content = $this->fileLib->saveImageFromUrl($content, UPLOAD_PATH_POST, $postID); } // blob $content = $this->fileLib->saveImageFromBlob($content, UPLOAD_PATH_POST, $postID); // 이미지 DB 기록 $images = $this->fileLib->getImageFromContent($content); if(count($images) > 0) { foreach($images as $img) { $this->editorImageModel->register([ 'target_type' => EDITOR_IMG_TYPE_1, 'target_id' => $postID, 'user_id' => UID, 'origin_name' => $img->origin, 'file_name' => $img->name, 'file_path' => $img->path, 'file_url' => $img->url, 'file_size' => $img->size, 'file_type' => $img->type, 'width' => $img->width, 'height' => $img->height, 'ip_address' => IP_ADDRESS, 'user_agent' => USER_AGENT ]); } } return $content; } /** * 게시글 경험치 지급 */ public function setUserExp(Post $post, User $user, int $type): bool { if(!$post->exists) { return false; } $boardMeta = $this->boardMetaModel->getAllMeta($post->board_id); if (!$boardMeta->item('use_exp', 0)) { return false; } $column = MAP_EXP_TYPE[$type]; $content = MAP_EXP_CONTENT[$type]; $value = intval($boardMeta->{$column}); $relatedID = sprintf("%d-%d", $post->board_id, $post->id); // 경험치 지급 구분 return (new Exp)->register([ 'user_id' => $user->id, 'content' => $content, 'value' => $value, 'type' => $type, 'related_id' => $relatedID, 'method' => request()->getMethod(), 'created_at' => now() ]); } /** * 게시글 관련 메일 발송 */ public function sendEmailNotify(Post $post, string $sendMailFormType): bool { if (!in_array($sendMailFormType, MAP_SEND_MAIL_TYPE)) { return false; } $boardMeta = $this->boardMetaModel->getAllMeta($post->board_id); $sendMailType = str_replace('_form', '', $sendMailFormType); // 최고 관리자에게 발송 $admin = ($boardMeta->item($sendMailType . '_super_admin', 0) ? $this->userModel->getMaster() : null); // 게시글 작성자에게 발송 $postWriter = ($boardMeta->item($sendMailType . '_post_writer', 0) ? $post->user : null); if (!$admin && !$postWriter) { return false; } return (new EmailLib)->send($sendMailFormType, $admin, $postWriter); } }