Просмотр файла app/Controllers/AjaxController.php

Размер файла: 12.14Kb
  1. <?php
  2.  
  3. declare(strict_types=1);
  4.  
  5. namespace App\Controllers;
  6.  
  7. use App\Classes\Validator;
  8. use App\Models\Article;
  9. use App\Models\BaseModel;
  10. use App\Models\Comment;
  11. use App\Models\Down;
  12. use App\Models\File;
  13. use App\Models\Guestbook;
  14. use App\Models\Item;
  15. use App\Models\Message;
  16. use App\Models\News;
  17. use App\Models\Offer;
  18. use App\Models\Photo;
  19. use App\Models\Post;
  20. use App\Models\Spam;
  21. use App\Models\Wall;
  22. use Exception;
  23. use Illuminate\Database\Eloquent\Relations\Relation;
  24. use Illuminate\Http\Request;
  25.  
  26. class AjaxController extends BaseController
  27. {
  28. /**
  29. * Конструктор
  30. *
  31. * @param Request $request
  32. */
  33. public function __construct(Request $request)
  34. {
  35. parent::__construct();
  36. $this->checkAjax($request);
  37. $this->checkAuthorize();
  38. }
  39.  
  40. /**
  41. * Возвращает bbCode для предпросмотра
  42. *
  43. * @param Request $request
  44. *
  45. * @return string
  46. */
  47. public function bbCode(Request $request): string
  48. {
  49. $message = $request->input('data');
  50.  
  51. return view('app/_bbcode', compact('message'));
  52. }
  53.  
  54. /**
  55. * Отправляет жалобу на сообщение
  56. *
  57. * @param Request $request
  58. * @param Validator $validator
  59. *
  60. * @return string
  61. */
  62. public function complaint(Request $request, Validator $validator): string
  63. {
  64. $path = null;
  65. $model = false;
  66. $id = int($request->input('id'));
  67. $type = $request->input('type');
  68. $page = $request->input('page');
  69.  
  70. switch ($type) :
  71. case Guestbook::$morphName:
  72. $model = Guestbook::query()->find($id);
  73. $path = '/guestbook?page='.$page;
  74. break;
  75.  
  76. case Post::$morphName:
  77. $model = Post::query()->find($id);
  78. $path = '/topics/' . $model->topic_id . '?page='.$page;
  79. break;
  80.  
  81. case Message::$morphName:
  82. $model = Message::query()->find($id);
  83. break;
  84.  
  85. case Wall::$morphName:
  86. $model = Wall::query()->find($id);
  87. $path = '/walls/' . $model->user->login . '?page='.$page;
  88. break;
  89.  
  90. case News::$morphName:
  91. case Article::$morphName:
  92. case Photo::$morphName:
  93. case Offer::$morphName:
  94. case Down::$morphName:
  95. $model = Comment::query()->find($id);
  96. $path = '/' . $model->relate_type . '/comments/' . $model->relate_id . '?page='.$page;
  97. $type = 'comments';
  98. break;
  99. endswitch;
  100.  
  101. $spam = Spam::query()->where(['relate_type' => $type, 'relate_id' => $id])->first();
  102.  
  103. $validator
  104. ->equal($request->input('token'), $_SESSION['token'], __('validator.token'))
  105. ->true($model, __('main.message_not_found'))
  106. ->false($spam, __('ajax.complaint_already_sent'));
  107.  
  108. if ($validator->isValid()) {
  109. Spam::query()->create([
  110. 'relate_type' => $type,
  111. 'relate_id' => $model->id,
  112. 'user_id' => getUser('id'),
  113. 'path' => $path,
  114. 'created_at' => SITETIME,
  115. ]);
  116.  
  117. return json_encode(['status' => 'success']);
  118. }
  119.  
  120. return json_encode([
  121. 'status' => 'error',
  122. 'message' => current($validator->getErrors()),
  123. ]);
  124. }
  125.  
  126. /**
  127. * Удаляет комментарии
  128. *
  129. * @param Request $request
  130. * @param Validator $validator
  131. *
  132. * @return string
  133. */
  134. public function delComment(Request $request, Validator $validator): string
  135. {
  136. if (! isAdmin()) {
  137. return json_encode([
  138. 'status' => 'error',
  139. 'message' => __('main.not_authorized'),
  140. ]);
  141. }
  142.  
  143. $type = $request->input('type');
  144. $rid = int($request->input('rid'));
  145. $id = int($request->input('id'));
  146.  
  147. $validator->equal($request->input('token'), $_SESSION['token'], __('validator.token'));
  148.  
  149. if ($validator->isValid()) {
  150. $delComments = Comment::query()
  151. ->where('relate_type', $type)
  152. ->where('relate_id', $rid)
  153. ->where('id', $id)
  154. ->delete();
  155.  
  156. if ($delComments) {
  157. /** @var BaseModel $class */
  158. $class = Relation::getMorphedModel($type);
  159. $model = $class::query()->find($rid);
  160.  
  161. if ($model) {
  162. $model->decrement('count_comments');
  163. }
  164. }
  165.  
  166. return json_encode(['status' => 'success']);
  167. }
  168.  
  169. return json_encode([
  170. 'status' => 'error',
  171. 'message' => current($validator->getErrors())
  172. ]);
  173. }
  174.  
  175. /**
  176. * Изменяет рейтинг
  177. *
  178. * @param Request $request
  179. *
  180. * @return string
  181. * @throws Exception
  182. */
  183. public function rating(Request $request): string
  184. {
  185. $types = [
  186. Post::$morphName,
  187. Article::$morphName,
  188. Photo::$morphName,
  189. Offer::$morphName,
  190. News::$morphName,
  191. ];
  192.  
  193. $id = int($request->input('id'));
  194. $type = $request->input('type');
  195. $vote = $request->input('vote');
  196.  
  197. if ($request->input('token') !== $_SESSION['token']) {
  198. return json_encode(['status' => 'error', 'message' => 'Invalid token']);
  199. }
  200.  
  201. if (! in_array($vote, ['+', '-'], true)) {
  202. return json_encode(['status' => 'error', 'message' => 'Invalid rating']);
  203. }
  204.  
  205. if (! in_array($type, $types, true)) {
  206. return json_encode(['status' => 'error', 'message' => 'Type invalid']);
  207. }
  208.  
  209. /** @var BaseModel $model */
  210. $model = Relation::getMorphedModel($type);
  211.  
  212. $post = $model::query()
  213. ->where('id', $id)
  214. ->where('user_id', '<>', getUser('id'))
  215. ->first();
  216.  
  217. if (! $post) {
  218. return json_encode(['status' => 'error', 'message' => 'Record not found']);
  219. }
  220.  
  221. $polling = $post->polling()->first();
  222. $cancel = false;
  223.  
  224. if ($polling) {
  225. if ($polling->vote === $vote) {
  226. return json_encode(['status' => 'error']);
  227. }
  228.  
  229. $polling->delete();
  230. $cancel = true;
  231. } else {
  232. $post->polling()->create([
  233. 'user_id' => getUser('id'),
  234. 'vote' => $vote,
  235. 'created_at' => SITETIME,
  236. ]);
  237. }
  238.  
  239. if ($vote === '+') {
  240. $post->increment('rating');
  241. } else {
  242. $post->decrement('rating');
  243. }
  244.  
  245. return json_encode([
  246. 'status' => 'success',
  247. 'cancel' => $cancel,
  248. 'rating' => formatNum($post['rating'])->toHtml(),
  249. ]);
  250. }
  251.  
  252. /**
  253. * Загружает изображение
  254. *
  255. * @param Request $request
  256. * @param Validator $validator
  257. *
  258. * @return string
  259. */
  260. public function uploadFile(Request $request, Validator $validator): string
  261. {
  262. $imageTypes = [
  263. Article::$morphName,
  264. Item::$morphName,
  265. Photo::$morphName,
  266. ];
  267.  
  268. $fileTypes = [
  269. Message::$morphName,
  270. ];
  271.  
  272. $id = int($request->input('id'));
  273. $file = $request->file('file');
  274. $type = $request->input('type');
  275.  
  276. if (! in_array($type, array_merge($imageTypes, $fileTypes), true)) {
  277. return json_encode(['status' => 'error', 'message' => 'Type invalid']);
  278. }
  279.  
  280. /** @var BaseModel $class */
  281. $class = Relation::getMorphedModel($type);
  282. $isImageType = in_array($type, $imageTypes, true);
  283.  
  284. if ($id) {
  285. $model = $class::query()->where('user_id', getUser('id'))->find($id);
  286.  
  287. if (! $model) {
  288. return json_encode([
  289. 'status' => 'error',
  290. 'message' => 'Service not found'
  291. ]);
  292. }
  293. } else {
  294. $model = new $class();
  295. }
  296.  
  297. $countFiles = File::query()
  298. ->where('relate_type', $type)
  299. ->where('relate_id', $id)
  300. ->where('user_id', getUser('id'))
  301. ->count();
  302.  
  303. $validator
  304. ->equal($request->input('token'), $_SESSION['token'], __('validator.token'))
  305. ->lt($countFiles, setting('maxfiles'), __('validator.files_max', ['max' => setting('maxfiles')]));
  306.  
  307. if ($validator->isValid()) {
  308. $rules = [
  309. 'minweight' => 100,
  310. 'maxsize' => setting('filesize'),
  311. 'extensions' => explode(',', setting('file_extensions')),
  312. ];
  313.  
  314. $validator->file($file, $rules, ['files' => __('validator.file_upload_failed')]);
  315. }
  316.  
  317. if ($validator->isValid()) {
  318. $fileData = $model->uploadFile($file);
  319. $fileType = $fileData['is_image'] ? 'image' : 'file';
  320.  
  321. if ($isImageType) {
  322. $imageData = resizeProcess($fileData['path'], ['size' => 100]);
  323. $data = [
  324. 'status' => 'success',
  325. 'id' => $fileData['id'],
  326. 'path' => $imageData['path'],
  327. 'source' => $imageData['source'],
  328. 'type' => $fileType,
  329. ];
  330. } else {
  331. $data = [
  332. 'status' => 'success',
  333. 'id' => $fileData['id'],
  334. 'path' => $fileData['path'],
  335. 'name' => $fileData['name'],
  336. 'size' => $fileData['size'],
  337. 'type' => $fileType,
  338. ];
  339. }
  340.  
  341. return json_encode($data);
  342. }
  343.  
  344. return json_encode([
  345. 'status' => 'error',
  346. 'message' => current($validator->getErrors())
  347. ]);
  348. }
  349.  
  350. /**
  351. * Удаляет изображение
  352. *
  353. * @param Request $request
  354. * @param Validator $validator
  355. *
  356. * @return string
  357. * @throws Exception
  358. */
  359. public function deleteFile(Request $request, Validator $validator): string
  360. {
  361. $types = [
  362. Article::$morphName,
  363. Item::$morphName,
  364. Photo::$morphName,
  365. Message::$morphName,
  366. ];
  367.  
  368. $id = int($request->input('id'));
  369. $type = $request->input('type');
  370.  
  371. if (! in_array($type, $types, true)) {
  372. return json_encode(['status' => 'error', 'message' => 'Type invalid']);
  373. }
  374.  
  375. /** @var File $file */
  376. $file = File::query()
  377. ->where('relate_type', $type)
  378. ->find($id);
  379.  
  380. if (! $file) {
  381. return json_encode([
  382. 'status' => 'error',
  383. 'message' => 'File not found'
  384. ]);
  385. }
  386.  
  387. $validator->equal($request->input('token'), $_SESSION['token'], __('validator.token'))
  388. ->true(getUser('id') === $file->user_id || isAdmin(), __('ajax.file_not_author'));
  389.  
  390. if ($validator->isValid()) {
  391. $file->delete();
  392.  
  393. return json_encode([
  394. 'status' => 'success',
  395. 'path' => $file->hash,
  396. ]);
  397. }
  398.  
  399. return json_encode([
  400. 'status' => 'error',
  401. 'message' => current($validator->getErrors())
  402. ]);
  403. }
  404.  
  405. /**
  406. * Возвращает является ли запрос ajax
  407. *
  408. * @param Request $request
  409. *
  410. * @return mixed
  411. */
  412. private function checkAjax(Request $request)
  413. {
  414. if (! $request->ajax()) {
  415. exit(json_encode([
  416. 'status' => 'error',
  417. 'message' => __('validator.not_ajax')
  418. ]));
  419. }
  420.  
  421. return true;
  422. }
  423.  
  424. /**
  425. * Возвращает авторизован ли пользователь
  426. *
  427. * @return mixed
  428. */
  429. private function checkAuthorize()
  430. {
  431. if (! getUser()) {
  432. exit(json_encode([
  433. 'status' => 'error',
  434. 'message' => __('main.not_authorized')
  435. ]));
  436. }
  437.  
  438. return true;
  439. }
  440. }