NewsController.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. <?php
  2. namespace App\Controllers\Api;
  3. use CodeIgniter\HTTP\ResponseInterface;
  4. class NewsController extends BaseApiController
  5. {
  6. /**
  7. * Get news 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('news');
  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('created_at', 'DESC');
  31. $builder->orderBy('id', 'DESC');
  32. $result = $this->paginatedResponse($builder, $params);
  33. return $this->respondSuccess($result);
  34. }
  35. /**
  36. * Get single news
  37. */
  38. public function show($id = null)
  39. {
  40. $auth = $this->requireAuth();
  41. if ($auth instanceof ResponseInterface) {
  42. return $auth;
  43. }
  44. $builder = $this->getDB()->table('news');
  45. $news = $builder->where('id', $id)->get()->getRow();
  46. if (!$news) {
  47. return $this->respondError('뉴스를 찾을 수 없습니다.', ResponseInterface::HTTP_NOT_FOUND);
  48. }
  49. // Parse file_urls JSON
  50. $news->file_urls = json_decode($news->file_urls ?? '[]');
  51. // Fix image paths in content
  52. if (!empty($news->content)) {
  53. // YouTube iframe 경로 수정: /embed/ID -> https://www.youtube.com/embed/ID
  54. $news->content = str_replace('src="/embed/', 'src="https://www.youtube.com/embed/', $news->content);
  55. $news->content = str_replace("src='/embed/", "src='https://www.youtube.com/embed/", $news->content);
  56. // 도메인 추가: src="/uploads -> src="http://도메인/uploads
  57. // 단, 이미 http:// 또는 https://로 시작하는 URL은 제외
  58. $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https://' : 'http://';
  59. $currentDomain = $protocol . ($_SERVER['HTTP_HOST'] ?? 'localhost');
  60. // 정규표현식으로 /uploads로 시작하고 앞에 http(s)://가 없는 경우만 도메인 추가
  61. $news->content = preg_replace(
  62. '/src="(?!https?:\/\/)\/uploads\//',
  63. 'src="' . $currentDomain . '/uploads/',
  64. $news->content
  65. );
  66. $news->content = preg_replace(
  67. "/src='(?!https?:\/\/)\/uploads\//",
  68. "src='" . $currentDomain . "/uploads/",
  69. $news->content
  70. );
  71. }
  72. // Increment view count
  73. $builder->where('id', $id)->set('views', 'views + 1', false)->update();
  74. return $this->respondSuccess($news);
  75. }
  76. /**
  77. * Create news
  78. */
  79. public function create()
  80. {
  81. $auth = $this->requireAuth();
  82. if ($auth instanceof ResponseInterface) {
  83. return $auth;
  84. }
  85. $json = $this->request->getJSON();
  86. $data = [
  87. 'allow_comment' => isset($json->allow_comment) ? (int)$json->allow_comment : 0,
  88. 'is_notice' => isset($json->is_notice) ? (int)$json->is_notice : 0,
  89. 'name' => $json->name ?? '',
  90. 'email' => $json->email ?? '',
  91. 'url' => $json->url ?? '',
  92. 'title' => $json->title ?? '',
  93. 'content' => $json->content ?? '',
  94. 'file_urls' => json_encode($json->file_urls ?? []),
  95. 'views' => 0,
  96. 'created_at' => date('Y-m-d H:i:s')
  97. ];
  98. $builder = $this->getDB()->table('news');
  99. $builder->insert($data);
  100. return $this->respondSuccess(['id' => $this->getDB()->insertID()], '뉴스가 등록되었습니다.');
  101. }
  102. /**
  103. * Update news
  104. */
  105. public function update($id = null)
  106. {
  107. $auth = $this->requireAuth();
  108. if ($auth instanceof ResponseInterface) {
  109. return $auth;
  110. }
  111. $json = $this->request->getJSON();
  112. $data = [
  113. 'allow_comment' => isset($json->allow_comment) ? (int)$json->allow_comment : 0,
  114. 'is_notice' => isset($json->is_notice) ? (int)$json->is_notice : 0,
  115. 'name' => $json->name ?? '',
  116. 'email' => $json->email ?? '',
  117. 'url' => $json->url ?? '',
  118. 'title' => $json->title ?? '',
  119. 'content' => $json->content ?? '',
  120. 'file_urls' => json_encode($json->file_urls ?? []),
  121. 'updated_at' => date('Y-m-d H:i:s')
  122. ];
  123. $builder = $this->getDB()->table('news');
  124. $builder->where('id', $id)->update($data);
  125. return $this->respondSuccess(null, '뉴스가 수정되었습니다.');
  126. }
  127. /**
  128. * Delete news
  129. */
  130. public function delete($id = null)
  131. {
  132. $auth = $this->requireAuth();
  133. if ($auth instanceof ResponseInterface) {
  134. return $auth;
  135. }
  136. $builder = $this->getDB()->table('news');
  137. $builder->where('id', $id)->delete();
  138. return $this->respondSuccess(null, '뉴스가 삭제되었습니다.');
  139. }
  140. /**
  141. * Get public news list (no auth required)
  142. */
  143. public function publicList()
  144. {
  145. $params = $this->getPaginationParams();
  146. $builder = $this->getDB()->table('news');
  147. $builder->orderBy('is_notice', 'DESC');
  148. $builder->orderBy('created_at', 'DESC');
  149. $builder->orderBy('id', 'DESC');
  150. $result = $this->paginatedResponse($builder, $params);
  151. // Parse file_urls for each item
  152. if (!empty($result['items'])) {
  153. foreach ($result['items'] as &$item) {
  154. $item->file_urls = json_decode($item->file_urls ?? '[]');
  155. }
  156. }
  157. return $this->respondSuccess($result);
  158. }
  159. /**
  160. * Get single news (no auth required)
  161. */
  162. public function publicShow($id = null)
  163. {
  164. $builder = $this->getDB()->table('news');
  165. $news = $builder->where('id', $id)->get()->getRow();
  166. if (!$news) {
  167. return $this->respondError('뉴스를 찾을 수 없습니다.', ResponseInterface::HTTP_NOT_FOUND);
  168. }
  169. // Parse file_urls JSON
  170. $news->file_urls = json_decode($news->file_urls ?? '[]');
  171. // Fix image paths in content
  172. if (!empty($news->content)) {
  173. // YouTube iframe 경로 수정: /embed/ID -> https://www.youtube.com/embed/ID
  174. $news->content = str_replace('src="/embed/', 'src="https://www.youtube.com/embed/', $news->content);
  175. $news->content = str_replace("src='/embed/", "src='https://www.youtube.com/embed/", $news->content);
  176. // 도메인 추가: src="/uploads -> src="http://도메인/uploads
  177. // 단, 이미 http:// 또는 https://로 시작하는 URL은 제외
  178. $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https://' : 'http://';
  179. $currentDomain = $protocol . ($_SERVER['HTTP_HOST'] ?? 'localhost');
  180. // 정규표현식으로 /uploads로 시작하고 앞에 http(s)://가 없는 경우만 도메인 추가
  181. $news->content = preg_replace(
  182. '/src="(?!https?:\/\/)\/uploads\//',
  183. 'src="' . $currentDomain . '/uploads/',
  184. $news->content
  185. );
  186. $news->content = preg_replace(
  187. "/src='(?!https?:\/\/)\/uploads\//",
  188. "src='" . $currentDomain . "/uploads/",
  189. $news->content
  190. );
  191. }
  192. // Increment view count
  193. $builder->where('id', $id)->set('views', 'views + 1', false)->update();
  194. return $this->respondSuccess($news);
  195. }
  196. }