CommentController.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. <?php
  2. namespace App\Http\Controllers\Api;
  3. use App\Http\Controllers\Api\Repositories\WxCommentRepositores;
  4. use App\Jobs\CalculateCommentLikesNumJob;
  5. use App\Jobs\ImitateCircleJoinStepJob;
  6. use App\Jobs\SubscribeMessageJob;
  7. use App\Jobs\UserInputSafeCheckJob;
  8. use App\Lib\WeApp\WeApp;
  9. use App\Models\Posts\WxComment;
  10. use App\Models\Posts\WxPost;
  11. use App\Models\User\WxUserStudentCertify;
  12. use App\Models\WxCommentLike;
  13. use App\Models\User\WxUser;
  14. use App\Wen\Utils\BaiduUtils;
  15. use App\Wen\Utils\CommentUtils;
  16. use App\Wen\Utils\FieldUtils;
  17. use App\Wen\Utils\Settings;
  18. use App\Wen\Utils\UserUtils;
  19. use App\Wen\Utils\Utils;
  20. use Illuminate\Http\Request;
  21. use Illuminate\Support\Facades\Cache;
  22. use Illuminate\Support\Facades\Redis;
  23. use Intervention\Image\Facades\Image;
  24. use SimpleSoftwareIO\QrCode\Facades\QrCode;
  25. class CommentController extends BaseController
  26. {
  27. /**
  28. * $posts_id 文章id
  29. * $comment_id 评论id
  30. * $user_id 评论的用户id
  31. * $comment_content 评论内容
  32. * @param Request $request
  33. */
  34. public function add(Request $request)
  35. {
  36. global $__MINI_GLOBAL_CURRENT_PLAYER_ID__;
  37. $posts_id = (int)(_empty_default_($request->posts_id, 0));
  38. $user_id = $request->uid;
  39. if(_empty_($posts_id) || _empty_($user_id)){
  40. return $this->fail(200001);
  41. }
  42. $posts_id = _abs($posts_id);
  43. if(!UserUtils::is_user_can_speak($user_id)){
  44. return $this->fail(200043, [
  45. 'title' => '禁言中,无法言论',
  46. 'content' => '是否前往解除限制',
  47. 'confirmText' => '去解除',
  48. 'target_type' => 6,
  49. 'target_id' => '/pagesA/mine/unlock/unlock?user_id='.$user_id
  50. ], '您当前处于禁言期间,无法言论');
  51. }
  52. $user = WxUser::find($user_id);
  53. if(_empty_($user)){
  54. return $this->fail(200000, [], '用户不存在');
  55. }
  56. // if(mb_strlen( str_replace( [Settings::get('default_user_name', '微信用户'), '微信用户', '普通用户'], '', $user->user_name )) != mb_strlen($user->user_name)){
  57. // return $this->fail(200041);
  58. // }
  59. if(Settings::get('sticky_comment_force_bind_phone', 0, true) == 1){
  60. if(_empty_($user->phone) && _empty_($__MINI_GLOBAL_CURRENT_PLAYER_ID__)){
  61. return $this->fail(200043, [
  62. 'title' => '未绑定手机号',
  63. 'content' => '前往绑定',
  64. 'confirmText' => '去绑定',
  65. 'target_type' => 6,
  66. 'target_id' => '/pagesA/mine/editmine/editmine?phone=1'
  67. ], '未绑定手机号');
  68. }
  69. }
  70. if(Settings::get('sticky_comment_force_real_name', 0, true) == 1){
  71. if(_empty_($user->real_name) && _empty_($__MINI_GLOBAL_CURRENT_PLAYER_ID__)){
  72. return $this->fail(200043, [
  73. 'title' => '未实名认证',
  74. 'content' => '您还没有实名认证,是否前往认证',
  75. 'confirmText' => '去认证',
  76. 'target_type' => 6,
  77. 'target_id' => '/pagesA/mine/realname/realname'
  78. ], '未实名认证');
  79. }
  80. }
  81. $force_university = Settings::get('sticky_comment_force_university', [], true);
  82. if(!_empty_($force_university)){
  83. if(_empty_($user->university)){
  84. return $this->fail(200043, [
  85. 'title' => '未学生认证',
  86. 'content' => '您还没有学生认证,是否前往认证',
  87. 'confirmText' => '去认证',
  88. 'target_type' => 6,
  89. 'target_id' => '/pagesA/attestation/attestation'
  90. ], '未学生认证');
  91. }else{
  92. if(!in_array('-1', $force_university)){
  93. $student_certify = WxUserStudentCertify::find($user->id);
  94. if($student_certify){
  95. if(!in_array($student_certify->sid, $force_university)){
  96. return $this->fail(200000, [], '仅“'.Settings::get('sticky_comment_force_university_tip', '', true).'”可发布');
  97. }
  98. }
  99. }
  100. }
  101. }
  102. if(Settings::get('sticky_comment_force_subscribe_mp', 0, true) == 1){
  103. if(_empty_($user->weixin_mp_openid) && _empty_($__MINI_GLOBAL_CURRENT_PLAYER_ID__)){
  104. $weapp = new WeApp('mp');
  105. $mpServicer = $weapp->getMpServicer();
  106. try {
  107. $url = $mpServicer->getQrCodeWithPara(0, 'user:bind:'.$user->id);
  108. }catch (\Exception $e){
  109. return $this->fail(200006, [], '生成公众号二维码失败,请检查[全局配置-支付-微信-公众号]');
  110. }
  111. if($url){
  112. $qrCode = QrCode::format('png')->size(300)->generate($url);
  113. $image = Image::make($qrCode);
  114. $image->resizeCanvas(300, 300 + 60, 'bottom', false, '#ffffff'); // 增加高度,保持宽高比,背景色为白色
  115. $mp_app_name = Settings::get('mp_app_name', '');
  116. $text_tip = '关注'.$mp_app_name.'公众号,可以更方便通知到您';
  117. if(mb_strlen($mp_app_name) > 4){
  118. $text_tip = '关注'.$mp_app_name.'公众号';
  119. }
  120. $image->text($text_tip, 150, 40, function($font){
  121. $font->file(public_path('storage/font/DingTalk_JinBuTi_Regular.ttf')); // 字体文件路径
  122. $font->size(13); // 字体大小
  123. $font->color('#000000'); // 字体颜色
  124. $font->align('center'); // 水平对齐
  125. $font->valign('top'); // 垂直对齐
  126. });
  127. $base64 = 'data:image/png;base64,' . base64_encode($image->encode('png')->getEncoded());
  128. return $this->fail(200043, [
  129. 'title' => '未关注公众号,无法实时获取通知',
  130. 'content' => '前往关注',
  131. 'confirmText' => '去关注',
  132. 'target_type' => 26,
  133. 'target_id' => $base64
  134. ], '未关注公众号');
  135. }
  136. }
  137. }
  138. if(Cache::has('user:comment:cahce:'.$user_id)){
  139. return $this->fail(200027);
  140. }
  141. _limit_user('add:comment', $user_id, 16);
  142. $reply_user_id = $request->input('reply_user_id', 0);
  143. $comment_id = $request->input('comment_id', '');
  144. $comment_content = trim($request->comment_content ?? '');
  145. $comment_img_url = trim($request->comment_img_url);
  146. if(_empty_($request->giveCoin)){
  147. $giveCoin = 0;
  148. }else{
  149. $giveCoin = (int)($request->giveCoin);
  150. }
  151. $is_anonymous = _empty_default_($request->input('is_anonymous', 0), 0) == 1 ? 1 : 0;
  152. if($is_anonymous == 1 && Settings::get('app_vip_anonymous_only', 0) == 1){
  153. if($user->is_member){
  154. }else{
  155. return $this->fail(200043, [
  156. 'title' => '仅会员可用',
  157. 'content' => '匿名属于会员特权,是否前往开通',
  158. 'confirmText' => '前往开通',
  159. 'target_type' => 6,
  160. 'target_id' => '/pagesA/mine/members/members'
  161. ], '仅会员可用');
  162. }
  163. }
  164. $device = in_array($request->header('device',''), ['app', 'h5', 'mp', 'pc']) ? $request->header('device','') : '';
  165. if($giveCoin == 0){
  166. if(_empty_($comment_content) && _empty_($comment_img_url)){
  167. return $this->fail(200001, [], '评论没有文字及图片');
  168. }
  169. if(UserUtils::user_permissions_check_by_config($user_id, 'audit_comment_white_list')){
  170. $need_manual_review = false;
  171. }else{
  172. // 百度审核
  173. $need_manual_review = true;
  174. $is_audit_comment = Settings::get('is_audit_comment', 0);
  175. if ($is_audit_comment == 2) {
  176. $filter_result = BaiduUtils::text_filter($comment_content);
  177. if($filter_result){
  178. if($filter_result['hit_level'] == 2){
  179. // 不合规
  180. return $this->fail(200016, ['tip'=>$filter_result['tip_list'], 'hit_word'=>$filter_result['hit_word']]);
  181. }else if($filter_result['hit_level'] == 0){
  182. // 审核通过
  183. $need_manual_review = false;
  184. }
  185. }
  186. }else if($is_audit_comment == 0){
  187. $need_manual_review = true;
  188. }else{
  189. $need_manual_review = false;
  190. }
  191. }
  192. // 0:审核中,1:审核通过,2:驳回
  193. $comment_state = 1;
  194. if($need_manual_review){
  195. $comment_state = 0;
  196. }
  197. }else{
  198. $res_arr = UserUtils::give_coins($user_id, $giveCoin, $posts_id, $comment_id, $reply_user_id);
  199. if($res_arr['code'] != 200){
  200. return $this->fail($res_arr['code'], [], $res_arr['msg']);
  201. }
  202. $comment_state = 1;
  203. $comment_content = '<mini-icon name="mini-icon mini-jinbi2 gold-color"></mini-icon> 投了'.$giveCoin.'枚'.Settings::get('app_coin_name', '硬币'). '<mini-aite uid="'.$res_arr['to_user'].'" name="'.UserUtils::get_cached_user_name($res_arr['to_user'], true).'"></mini-aite>';
  204. }
  205. $r = WxCommentRepositores::add($posts_id, $comment_id,$reply_user_id, $user_id, $comment_content, $comment_img_url, $comment_state, $device, $is_anonymous);
  206. if($r){
  207. if($comment_img_url){
  208. Utils::image_state_change([$comment_img_url], 1);
  209. }
  210. Redis::sadd('realtime:post:set', $posts_id);
  211. Redis::sadd('post:popular:comment:set', $posts_id);
  212. Cache::put('user:comment:cahce:'.$user_id, 1, 10);
  213. UserInputSafeCheckJob::dispatch($user_id, $comment_content);
  214. $tmplIds = [];
  215. if($device == 'mp'){
  216. $comment_reply_id = Settings::get('mini_template_message_comment_reply', '');
  217. if(!_empty_($comment_reply_id)){
  218. $tmplIds[] = $comment_reply_id;
  219. }
  220. }
  221. if($comment_state == 1){
  222. if($giveCoin > 0){
  223. SubscribeMessageJob::dispatch('gicecoin', $r);
  224. return $this->success(['comment_id'=>$r, 'tip'=>$res_arr['msg']]);
  225. }else{
  226. CalculateCommentLikesNumJob::dispatch($r);
  227. if($comment_id && $comment_id > 0){
  228. CalculateCommentLikesNumJob::dispatch($comment_id);
  229. }
  230. $circle_id = WxPost::where('id', $posts_id)->value('circle_id');
  231. if($circle_id && $circle_id > 0){
  232. ImitateCircleJoinStepJob::dispatch($circle_id, mini_rand(1, 100) <= 30 ? mini_rand(1, 2) : 0)->delay(now()->addMinutes(mini_rand(1, 20)));
  233. }
  234. SubscribeMessageJob::dispatch('comment_add', $r);
  235. if($comment_id > 0){
  236. SubscribeMessageJob::dispatch('comment_reply', $r);
  237. }
  238. $msg = UserUtils::reward_user_coin($user_id, 'comment');
  239. if($msg){
  240. UserUtils::assistant_notice($user_id, '您的评论(id:<a href="/pages/sticky/sticky?id='.$posts_id.'">'.$r.'</a>)审核已通过,并获得评论奖励:'.$msg);
  241. return $this->success(['comment_id'=>$r, 'tip'=>'您的评论审核已通过,并获得评论奖励:'.$msg, 'tmplIds'=>$tmplIds]);
  242. }else{
  243. return $this->success(['comment_id'=>$r, 'tip'=>'您的评论审核已通过', 'tmplIds'=>$tmplIds]);
  244. }
  245. }
  246. }else{
  247. // UserUtils::assistant_notice('admin', '有新发布的评论待审核,(id:<a href="/pages/sticky/sticky?id='.$posts_id.'">进入笔记</a>)');
  248. UserUtils::assistant_notice_review(102, $r);
  249. }
  250. return $this->success(['comment_id'=>$r, 'tip'=>'评论成功,我们将尽快为您审核', 'tmplIds'=>$tmplIds]);
  251. }else{
  252. return $this->fail(200002);
  253. }
  254. }
  255. /**
  256. * 通过笔记获取评论列表
  257. * @param Request $request
  258. * @return \Illuminate\Http\JsonResponse
  259. */
  260. public function getCommentByPostsId(Request $request)
  261. {
  262. $posts_id = $request->posts_id;
  263. $uid = $request->uid;
  264. $comments = WxCommentRepositores::getCommentByPostsId($posts_id, $uid);
  265. return $this->success($comments);
  266. }
  267. /**
  268. * 通过评论id获取评论列表
  269. * @param Request $request
  270. * @return \Illuminate\Http\JsonResponse
  271. */
  272. public function getCommentByCommentId(Request $request)
  273. {
  274. $uid = $request->uid;
  275. $comment_id = $request->comment_id;
  276. $begin_id = $request->begin_id;
  277. if(_empty_($begin_id)){
  278. $begin_id = 0;
  279. }
  280. $childData = WxComment::where('comment_id', $comment_id)->where('comment_state', 1)->where('id', '>', $begin_id)
  281. ->orderBy('id', 'asc')->simplePaginate(10, FieldUtils::commentInfoColums());
  282. if($childData){
  283. $childData->map(function ($item) use ($uid) {
  284. $imgList = array();
  285. $item->comment_img_url = Utils::imgWithStyle($item->comment_img_url);
  286. if($item->comment_img_url){
  287. array_push($imgList, ['img_url' => $item->comment_img_url]);
  288. }
  289. $item->is_like = WxCommentLike::where('comment_id', $item->id)->where('user_id', $uid)->exists();
  290. $item->like_count = WxCommentLike::where('comment_id', $item->id)->count();
  291. $item->imgList = $imgList;
  292. $item->user = UserUtils::get_cached_user($item->user_id);
  293. $item->comment_content_raw = strip_tags(_mini_phone(_mini_emoji(_mini_aite_replace($item->comment_content, true), true), true));
  294. $sub_allowable = [];
  295. if($uid > 0){
  296. if($uid != $item->user_id) {
  297. $sub_allowable[] = [
  298. 'text' => '举报',
  299. 'type' => 'report',
  300. 'id' => $item->id,
  301. 'icon' => 'mini-icon mini-jinggao'
  302. ];
  303. }
  304. if($uid == $item->user_id || UserUtils::is_mini_admin($uid)){
  305. $sub_allowable[] = [
  306. 'text' => '删除',
  307. 'type' => 'delete',
  308. 'id' => $item->id,
  309. 'icon' => 'mini-icon2 mini-shanchu'
  310. ];
  311. }
  312. }
  313. $sub_allowable[] = [
  314. 'text' => '复制',
  315. 'type' => 'copy',
  316. 'id' => $item->id,
  317. 'raw' => $item->comment_content_raw,
  318. 'icon' => 'mini-icon mini-fuzhi'
  319. ];
  320. $item->allowable = $sub_allowable;
  321. CommentUtils::anonymousProcess($item);
  322. });
  323. $childData->append(['format_time', 'ip_address']);
  324. return $this->success($childData);
  325. }
  326. return $this->fail(200003, [], '没有更多回复了');
  327. }
  328. /**
  329. * 点赞评论
  330. * @param Request $request
  331. * @return \Illuminate\Http\JsonResponse
  332. */
  333. public function commentAddLike(Request $request)
  334. {
  335. $uid = $request->uid;
  336. $comment_id = $request->comment_id;
  337. if(_empty_($comment_id)){
  338. return $this->fail(200001);
  339. }
  340. $res = CommentUtils::comment_like($uid, $comment_id);
  341. if($res > 0){
  342. return $this->success([],416003);
  343. }
  344. return $this->fail(200006);
  345. }
  346. /**
  347. * 删除评论
  348. * @param Request $request
  349. */
  350. public function delComment(Request $request)
  351. {
  352. $commentId = $request->id;
  353. $uid = $request->uid;
  354. $WxComment = WxComment::where('id',$commentId)->first();
  355. $posts_id = $WxComment->posts_id;
  356. if(_empty_($WxComment)){
  357. return $this->fail(200003);
  358. }
  359. $comment_user_id = $WxComment->user_id;
  360. // 权限验证
  361. if(!UserUtils::is_mini_admin($uid) && !($uid == $comment_user_id)){
  362. return $this->fail(200000, [], '删个屁啊,你都没有权限删除');
  363. }
  364. $comment_img_url = $WxComment->value('comment_img_url');
  365. if(false && $uid == $comment_user_id){
  366. WxComment::where('id', $commentId)
  367. ->update(['comment_content' => '(该评论已被自己删除)','comment_img_url' => '']);
  368. }else{
  369. WxComment::where('id',$commentId)->forceDelete();
  370. Cache::forget('post:commentCount:'.$posts_id);
  371. }
  372. // WxComment::where('comment_id',$commentId)->delete();
  373. if($comment_img_url){
  374. Utils::image_state_change([$comment_img_url], 0);
  375. }
  376. $popular_comment = json_decode(Cache::get('post:popular:comment:'.$posts_id, '[]'), true);
  377. if(_array_key($popular_comment, 'id', 0) == $WxComment->id){
  378. Cache::forget('post:popular:comment:'.$posts_id);
  379. Redis::sadd('post:popular:comment:set', $posts_id);
  380. }
  381. return $this->success();
  382. }
  383. /**
  384. * 置顶评论
  385. * @param Request $request
  386. */
  387. public function stickyComment(Request $request)
  388. {
  389. $commentId = $request->id;
  390. $uid = $request->uid;
  391. // 权限验证 管理员+文章作者
  392. if(!UserUtils::is_mini_admin($uid) && !(CommentUtils::get_comment_post_author($commentId) == $uid)){
  393. return $this->fail(200000, [], '你既不是管理员,也不是文章作者,你置顶个什么劲');
  394. }
  395. $comment = WxComment::find($commentId);
  396. if($comment){
  397. if($comment->is_sticky){
  398. $comment->is_sticky = 0;
  399. $r = $comment->save();
  400. }else{
  401. $comment->is_sticky = 1;
  402. $r = $comment->save();
  403. }
  404. }else{
  405. return $this->fail(200003);
  406. }
  407. if($r){
  408. return $this->success();
  409. }else{
  410. return $this->fail(200002);
  411. }
  412. }
  413. }