NoticeController.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. <?php
  2. namespace App\Controllers\Api;
  3. use CodeIgniter\HTTP\ResponseInterface;
  4. class NoticeController extends BaseApiController
  5. {
  6. /**
  7. * Get notice list
  8. */
  9. public function index()
  10. {
  11. $auth = $this->requireAuth();
  12. if ($auth instanceof ResponseInterface) {
  13. return $auth;
  14. }
  15. $params = $this->getPaginationParams();
  16. $builder = $this->getDB()->table('notices');
  17. // Search
  18. $searchType = $this->request->getGet('search_type');
  19. $searchKeyword = $this->request->getGet('search_keyword');
  20. if ($searchType && $searchKeyword) {
  21. if ($searchType === 'title') {
  22. $builder->like('title', $searchKeyword);
  23. } elseif ($searchType === 'name') {
  24. $builder->like('name', $searchKeyword);
  25. } elseif ($searchType === 'content') {
  26. $builder->like('content', $searchKeyword);
  27. }
  28. }
  29. $builder->orderBy('is_notice', 'DESC');
  30. $builder->orderBy('id', 'DESC');
  31. $result = $this->paginatedResponse($builder, $params);
  32. return $this->respondSuccess($result);
  33. }
  34. /**
  35. * Get single notice
  36. */
  37. public function show($id = null)
  38. {
  39. $auth = $this->requireAuth();
  40. if ($auth instanceof ResponseInterface) {
  41. return $auth;
  42. }
  43. $builder = $this->getDB()->table('notices');
  44. $notice = $builder->where('id', $id)->get()->getRow();
  45. if (!$notice) {
  46. return $this->respondError('공지사항을 찾을 수 없습니다.', ResponseInterface::HTTP_NOT_FOUND);
  47. }
  48. // Parse file_urls JSON
  49. $notice->file_urls = $this->normalizeFileUrls($notice->file_urls ?? '[]');
  50. // Fix image paths in content
  51. if (!empty($notice->content)) {
  52. // 도메인 추가: src="/uploads -> src="http://도메인/uploads
  53. // 단, 이미 http:// 또는 https://로 시작하는 URL은 제외
  54. $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https://' : 'http://';
  55. $currentDomain = $protocol . ($_SERVER['HTTP_HOST'] ?? 'localhost');
  56. // 정규표현식으로 /uploads로 시작하고 앞에 http(s)://가 없는 경우만 도메인 추가
  57. $notice->content = preg_replace(
  58. '/src="(?!https?:\/\/)\/uploads\//',
  59. 'src="' . $currentDomain . '/uploads/',
  60. $notice->content
  61. );
  62. $notice->content = preg_replace(
  63. "/src='(?!https?:\/\/)\/uploads\//",
  64. "src='" . $currentDomain . "/uploads/",
  65. $notice->content
  66. );
  67. }
  68. // Increment view count
  69. $builder->where('id', $id)->set('views', 'views + 1', false)->update();
  70. return $this->respondSuccess($notice);
  71. }
  72. /**
  73. * Create notice
  74. */
  75. public function create()
  76. {
  77. $auth = $this->requireAuth();
  78. if ($auth instanceof ResponseInterface) {
  79. return $auth;
  80. }
  81. $json = $this->request->getJSON();
  82. $data = [
  83. 'allow_comment' => isset($json->allow_comment) ? (int)$json->allow_comment : 0,
  84. 'is_notice' => isset($json->is_notice) ? (int)$json->is_notice : 0,
  85. 'name' => $json->name ?? '',
  86. 'email' => $json->email ?? '',
  87. 'url' => $json->url ?? '',
  88. 'title' => $json->title ?? '',
  89. 'content' => $json->content ?? '',
  90. 'file_urls' => json_encode($json->file_urls ?? []),
  91. 'views' => 0,
  92. 'created_at' => date('Y-m-d H:i:s')
  93. ];
  94. $builder = $this->getDB()->table('notices');
  95. $builder->insert($data);
  96. return $this->respondSuccess(['id' => $this->getDB()->insertID()], '공지사항이 등록되었습니다.');
  97. }
  98. /**
  99. * Update notice
  100. */
  101. public function update($id = null)
  102. {
  103. $auth = $this->requireAuth();
  104. if ($auth instanceof ResponseInterface) {
  105. return $auth;
  106. }
  107. $json = $this->request->getJSON();
  108. $data = [
  109. 'allow_comment' => isset($json->allow_comment) ? (int)$json->allow_comment : 0,
  110. 'is_notice' => isset($json->is_notice) ? (int)$json->is_notice : 0,
  111. 'name' => $json->name ?? '',
  112. 'email' => $json->email ?? '',
  113. 'url' => $json->url ?? '',
  114. 'title' => $json->title ?? '',
  115. 'content' => $json->content ?? '',
  116. 'file_urls' => json_encode($json->file_urls ?? []),
  117. 'updated_at' => date('Y-m-d H:i:s')
  118. ];
  119. $builder = $this->getDB()->table('notices');
  120. $builder->where('id', $id)->update($data);
  121. return $this->respondSuccess(null, '공지사항이 수정되었습니다.');
  122. }
  123. /**
  124. * Delete notice
  125. */
  126. public function delete($id = null)
  127. {
  128. $auth = $this->requireAuth();
  129. if ($auth instanceof ResponseInterface) {
  130. return $auth;
  131. }
  132. $builder = $this->getDB()->table('notices');
  133. $builder->where('id', $id)->delete();
  134. return $this->respondSuccess(null, '공지사항이 삭제되었습니다.');
  135. }
  136. /**
  137. * Normalize file_urls to always return object array
  138. * Handles both old format (string array) and new format (object array)
  139. */
  140. private function normalizeFileUrls($fileUrlsJson)
  141. {
  142. $fileUrls = json_decode($fileUrlsJson ?? '[]');
  143. if (empty($fileUrls) || !is_array($fileUrls)) {
  144. return [];
  145. }
  146. $normalized = [];
  147. foreach ($fileUrls as $item) {
  148. // If already an object with url property, keep it
  149. if (is_object($item) && isset($item->url)) {
  150. $normalized[] = $item;
  151. }
  152. // If it's a string (old format), convert to object
  153. elseif (is_string($item)) {
  154. $filename = basename($item);
  155. $normalized[] = (object)[
  156. 'name' => $filename,
  157. 'url' => $item,
  158. 'size' => 0 // Size unknown for migrated data
  159. ];
  160. }
  161. }
  162. return $normalized;
  163. }
  164. /**
  165. * Get public notice list (no auth required)
  166. */
  167. public function publicList()
  168. {
  169. $params = $this->getPaginationParams();
  170. $builder = $this->getDB()->table('notices');
  171. // Show all notices
  172. $builder->orderBy('id', 'DESC');
  173. $result = $this->paginatedResponse($builder, $params);
  174. // Parse file_urls for each item
  175. if (!empty($result['items'])) {
  176. foreach ($result['items'] as &$item) {
  177. $item->file_urls = $this->normalizeFileUrls($item->file_urls ?? '[]');
  178. }
  179. }
  180. return $this->respondSuccess($result);
  181. }
  182. /**
  183. * Get public single notice (no auth required)
  184. */
  185. public function publicShow($id = null)
  186. {
  187. $builder = $this->getDB()->table('notices');
  188. $notice = $builder->where('id', $id)->get()->getRow();
  189. if (!$notice) {
  190. return $this->respondError('공지사항을 찾을 수 없습니다.', ResponseInterface::HTTP_NOT_FOUND);
  191. }
  192. // Parse file_urls JSON
  193. $notice->file_urls = $this->normalizeFileUrls($notice->file_urls ?? '[]');
  194. // Fix image paths in content
  195. if (!empty($notice->content)) {
  196. // 도메인 추가: src="/uploads -> src="http://도메인/uploads
  197. // 단, 이미 http:// 또는 https://로 시작하는 URL은 제외
  198. $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https://' : 'http://';
  199. $currentDomain = $protocol . ($_SERVER['HTTP_HOST'] ?? 'localhost');
  200. // 정규표현식으로 /uploads로 시작하고 앞에 http(s)://가 없는 경우만 도메인 추가
  201. $notice->content = preg_replace(
  202. '/src="(?!https?:\/\/)\/uploads\//',
  203. 'src="' . $currentDomain . '/uploads/',
  204. $notice->content
  205. );
  206. $notice->content = preg_replace(
  207. "/src='(?!https?:\/\/)\/uploads\//",
  208. "src='" . $currentDomain . "/uploads/",
  209. $notice->content
  210. );
  211. }
  212. // Increment view count
  213. $builder->where('id', $id)->set('views', 'views + 1', false)->update();
  214. return $this->respondSuccess($notice);
  215. }
  216. }