adminController.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. <?php
  2. namespace nabu\controllers\adminController;
  3. defined('NABU') || exit;
  4. require_once 'libs/csrf.php';
  5. require_once 'libs/validations.php';
  6. require_once 'models/adminModel.php';
  7. require_once 'libs/utils.php';
  8. use nabu\libs\csrf\csrf,
  9. nabu\libs\validations\validations,
  10. nabu\models\adminModel\adminModel,
  11. nabu\libs\utils\utils;
  12. // Administra cuentas de usuario y modera las publicaciones de artículos.
  13. class adminController {
  14. private static function default_route() {
  15. $GLOBALS['messages'] -> redirect(NABU_ROUTES['admin']);
  16. }
  17. private static function home() {
  18. $GLOBALS['messages'] -> redirect(NABU_ROUTES['home']);
  19. }
  20. // Renderiza la página web principal del panel de administración,
  21. // edición, autorización y eliminación de artículos.
  22. public static function admin() {
  23. if (!utils::is_admin())
  24. self::home();
  25. if (empty($_GET['page'])) {
  26. $head_title = 'Administración';
  27. $messages = $GLOBALS['messages'] -> messages();
  28. $adminModel = new adminModel();
  29. // Lista todos los artículos enviados.
  30. $articles = $adminModel -> sent_articles();
  31. // Formatea los datos de los artículos durante la marcha.
  32. foreach ($articles as &$article) {
  33. $article['title'] = utils::str_escape($article['title']);
  34. $article['author'] = utils::str_escape($article['author']);
  35. }
  36. unset($adminModel, $article);
  37. require_once 'views/layouts/head.php';
  38. require_once 'views/layouts/admin_navbar.php';
  39. require_once 'views/admin/admin.php';
  40. require_once 'views/layouts/footer.php';
  41. }
  42. else {
  43. if (empty($_GET['slug']))
  44. self::default_route();
  45. switch ($_GET['page']) {
  46. case 'edit':
  47. self::edit_article();
  48. break;
  49. case 'authorize':
  50. self::authorize_article();
  51. break;
  52. case 'delete':
  53. self::delete_article();
  54. break;
  55. default:
  56. self::default_route();
  57. }
  58. }
  59. }
  60. // Renderiza la página web de edición de artículos.
  61. private static function edit_article() {
  62. if (empty($_POST['edit_article'])) {
  63. $adminModel = new adminModel();
  64. // Busca los datos de un artículo dado su URL.
  65. $article = $adminModel -> find_article($_GET['slug']);
  66. unset($adminModel);
  67. if ($article === false)
  68. self::default_route();
  69. $head_title = 'Editar artículo';
  70. $token = csrf::generate_token();
  71. $messages = $GLOBALS['messages'] -> messages();
  72. // Muestra la portada de un artículo si fue cargado anteriormente.
  73. if (!empty($article['cover']))
  74. $article['cover'] = NABU_DIRECTORY['covers'] . '/' . $article['cover'];
  75. require_once 'views/layouts/head.php';
  76. require_once 'views/layouts/admin_navbar.php';
  77. require_once 'views/admin/edit_article.php';
  78. require_once 'views/layouts/footer.php';
  79. }
  80. else {
  81. csrf::validate_token($_POST['csrf']);
  82. self::update_article($_POST);
  83. }
  84. }
  85. // Valida los campos del formulario de edición de artículos y
  86. // actualiza los datos de un artículo.
  87. private static function update_article($form) {
  88. $adminModel = new adminModel();
  89. $article = $adminModel -> find_article($_GET['slug']);
  90. if ($article === false)
  91. self::default_route();
  92. $form = array_merge($form, $_FILES);
  93. $validations = new validations(NABU_ROUTES['edit_article'] . '&slug=' . $article['slug']);
  94. // Valida los campos del formulario de edición de artículos.
  95. $data = $validations -> validate_form($form, array(
  96. array('cover', 'type' => 'image', 'max' => NABU_DEFAULT['image_size']),
  97. array('title', 'exist' => true, 'max' => 246, 'trim_all' => true),
  98. array('synopsis', 'exist' => true, 'trim_all' => true),
  99. array('content', 'exist' => true, 'max' => NABU_DEFAULT['article_size'], 'trim' => true)
  100. ));
  101. global $messages;
  102. $update = array();
  103. // Valida si hay cambios en la portada del artículo.
  104. if (!empty($data['cover'])) {
  105. $extension = explode('/', $data['cover']['type'])[1];
  106. if ($extension == 'svg+xml')
  107. $extension = 'svg';
  108. // Valida si el nombre de la portada es único.
  109. do
  110. $filename = bin2hex(random_bytes(32)) . '.' . $extension;
  111. while ($adminModel -> article_id('cover', $filename));
  112. $destination = NABU_DIRECTORY['storage_covers'] . '/' . $filename;
  113. // Guarda la nueva portada en la capeta de almacenamiento de portadas de artículos.
  114. if (move_uploaded_file($data['cover']['tmp_name'], $destination)) {
  115. $update['cover'] = $filename;
  116. // Remueve la portada anterior.
  117. if (!empty($article['cover'])) {
  118. $cover = NABU_DIRECTORY['storage_covers'] . '/' . $article['cover'];
  119. if (file_exists($cover))
  120. unlink($cover);
  121. unset($cover);
  122. }
  123. $messages -> add_message('La portada del artículo se ha actualizado correctamente');
  124. }
  125. else
  126. $messages -> add_message('¡Lo sentimos mucho! &#x1F61E;, por el momento no podemos actualizar la portada del artículo');
  127. unset($extension, $filename, $destination);
  128. }
  129. // Valida si hay cambios en el título del artículo.
  130. if ($data['title'] != $article['title']) {
  131. $slug = utils::url_slug($data['title']);
  132. // Valida la longitud de la URL.
  133. $validations -> validate_form(array('slug' => $slug), array(
  134. array('slug', 'exist' => true)
  135. ));
  136. // Valida si la URL es única.
  137. if ($adminModel -> article_id('slug', $slug))
  138. $messages -> add_message('Por favor define un título diferente o espera máximo un día para actualizar el artículo');
  139. else {
  140. $update['title'] = $data['title'];
  141. $update['slug'] = $slug;
  142. $messages -> add_message('El título del artículo se ha actualizado correctamente');
  143. }
  144. unset($slug);
  145. }
  146. // Valida si hay cambios en el resumen del artículo.
  147. if ($data['synopsis'] != $article['synopsis']) {
  148. $update['synopsis'] = $data['synopsis'];
  149. $messages -> add_message('El resumen del artículo se ha actualizado correctamente');
  150. }
  151. // Valida si hay cambios en el contenido del artículo.
  152. if ($data['content'] != $article['content']) {
  153. $update['content'] = $data['content'];
  154. $messages -> add_message('El contenido del artículo se ha actualizado correctamente');
  155. }
  156. // Actualiza los datos del artículo en la base de datos.
  157. if (!empty($update)) {
  158. $adminModel -> update_article($article['id'], $update);
  159. if (!empty($update['slug']))
  160. $article['slug'] = $update['slug'];
  161. }
  162. $messages -> redirect(NABU_ROUTES['edit_article'] . '&slug=' . $article['slug']);
  163. }
  164. // Autoriza la publicación de un artículo.
  165. private static function authorize_article() {
  166. global $messages;
  167. $view = NABU_ROUTES['authorize_article'] . '&slug=' . $_GET['slug'];
  168. if (empty($_POST['confirm_password_submit'])) {
  169. $head_title = 'Autorizar artículo';
  170. $token = csrf::generate_token();
  171. $messages = $messages -> messages();
  172. $subtitle = 'Escribe tu contraseña para autorizar el artículo';
  173. require_once 'views/layouts/head.php';
  174. require_once 'views/layouts/admin_navbar.php';
  175. require_once 'views/pages/confirm_password.php';
  176. require_once 'views/layouts/footer.php';
  177. }
  178. else {
  179. csrf::validate_token($_POST['csrf']);
  180. $validations = new validations($view);
  181. // Valida los campos del formulario de confirmación de contraseña.
  182. $data = $validations -> validate_form($_POST, array(
  183. array('password', 'exist' => true, 'trim' => true, 'min' => 6, 'equal' => array(true, $_POST['password_confirm']), 'not_spaces' => true)
  184. ));
  185. $adminModel = new adminModel();
  186. // Obtiene el hash de la contraseña del usuario.
  187. $hash = $adminModel -> find_password($_SESSION['user']['id']);
  188. if ($hash === false)
  189. $messages -> redirect(NABU_ROUTES['logout']);
  190. // Valida la contraseña del usuario para completar la operación.
  191. if (!password_verify($data['password'], $hash)) {
  192. $messages -> add_message('La contraseña es incorrecta');
  193. $messages -> redirect($view);
  194. }
  195. // Obtiene el id del artículo.
  196. $id = $adminModel -> article_id('slug', $_GET['slug']);
  197. if ($id === false)
  198. self::default_route();
  199. // Autoriza la publicación del artículo.
  200. $adminModel -> post_article($id);
  201. $messages -> add_message('Artículo publicado con éxito');
  202. self::default_route();
  203. }
  204. }
  205. // Elimina un artículo.
  206. private static function delete_article() {
  207. global $messages;
  208. $view = NABU_ROUTES['delete_article'] . '&slug=' . $_GET['slug'];
  209. if (empty($_POST['confirm_password_submit'])) {
  210. $head_title = 'Eliminar artículo';
  211. $token = csrf::generate_token();
  212. $messages = $messages -> messages();
  213. $subtitle = 'Escribe tu contraseña para eliminar el artículo';
  214. require_once 'views/layouts/head.php';
  215. require_once 'views/layouts/admin_navbar.php';
  216. require_once 'views/pages/confirm_password.php';
  217. require_once 'views/layouts/footer.php';
  218. }
  219. else {
  220. csrf::validate_token($_POST['csrf']);
  221. $validations = new validations($view);
  222. // Valida los campos del formulario de confirmación de contraseña.
  223. $data = $validations -> validate_form($_POST, array(
  224. array('password', 'exist' => true, 'trim' => true, 'min' => 6, 'equal' => array(true, $_POST['password_confirm']), 'not_spaces' => true)
  225. ));
  226. $adminModel = new adminModel();
  227. // Obtiene el hash de la contraseña del usuario.
  228. $hash = $adminModel -> find_password($_SESSION['user']['id']);
  229. if ($hash === false)
  230. $messages -> redirect(NABU_ROUTES['logout']);
  231. // Valida la contraseña del usuario para completar la operación.
  232. if (!password_verify($data['password'], $hash)) {
  233. $messages -> add_message('La contraseña es incorrecta');
  234. $messages -> redirect($view);
  235. }
  236. // Obtiene el id del artículo.
  237. $id = $adminModel -> article_id('slug', $_GET['slug']);
  238. if ($id === false)
  239. self::default_route();
  240. // Elimina el artículo en la base de datos.
  241. $adminModel -> delete_article($id);
  242. $messages -> add_message('El artículo fue eliminado');
  243. self::default_route();
  244. }
  245. }
  246. }