MqDiscussion.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. <?php
  2. namespace App\Console\Commands;
  3. use Illuminate\Console\Command;
  4. use Illuminate\Support\Facades\Log;
  5. use Illuminate\Support\Str;
  6. use App\Models\Sentence;
  7. use App\Models\WebHook;
  8. use App\Models\Discussion;
  9. use App\Models\Article;
  10. use App\Models\DhammaTerm;
  11. use App\Models\Wbw;
  12. use App\Models\WbwBlock;
  13. use App\Http\Api\Mq;
  14. use App\Tools\WebHook as WebHookSend;
  15. use App\Http\Api\MdRender;
  16. use App\Http\Api\UserApi;
  17. use App\Http\Controllers\NotificationController;
  18. class MqDiscussion extends Command
  19. {
  20. /**
  21. * The name and signature of the console command.
  22. * php artisan mq:discussion
  23. * @var string
  24. */
  25. protected $signature = 'mq:discussion';
  26. /**
  27. * The console command description.
  28. *
  29. * @var string
  30. */
  31. protected $description = 'Command description';
  32. /**
  33. * Create a new command instance.
  34. *
  35. * @return void
  36. */
  37. public function __construct()
  38. {
  39. parent::__construct();
  40. }
  41. /**
  42. * Execute the console command.
  43. *
  44. * @return int
  45. */
  46. public function handle()
  47. {
  48. if (\App\Tools\Tools::isStop()) {
  49. return 0;
  50. }
  51. $exchange = 'router';
  52. $queue = 'discussion';
  53. $this->info(" [*] Waiting for {$queue}. To exit press CTRL+C");
  54. Log::info("discussion worker start .");
  55. Mq::worker($exchange, $queue, function ($message) {
  56. Log::info('mq discussion receive {message}', ['message' => json_encode($message, JSON_UNESCAPED_UNICODE)]);
  57. $result = 0;
  58. $msgParam = array();
  59. $msgParam['nickname'] = $message->editor->nickName;
  60. $link = config('app.url') . "/pcd/discussion/topic/";
  61. if ($message->parent) {
  62. $msgParam['topic-title'] = Discussion::where('id', $message->parent)->value('title');
  63. $id = $message->id;
  64. $msgParam['link'] = $link . $message->parent . '#' . $id;
  65. $msgParam['card_title'] = "回复讨论";
  66. $type = 'reply';
  67. } else {
  68. $msgParam['title'] = $message->title;
  69. $msgParam['link'] = $link . $message->id;
  70. $msgParam['card_title'] = "创建讨论";
  71. $type = 'create';
  72. }
  73. if ($message->content) {
  74. $msgParam['content'] = $message->content;
  75. }
  76. switch ($message->res_type) {
  77. case 'sentence':
  78. $sentence = Sentence::where('uid', $message->res_id)->first();
  79. if (!$sentence) {
  80. Log::error('invalid sentence id ' . $message->res_id);
  81. $result = 1;
  82. break;
  83. }
  84. //站内信
  85. try {
  86. $sendTo = array();
  87. //句子的channel拥有者
  88. //$sendTo[] = $prData->channel->studio_id;
  89. //句子的作者
  90. if (!in_array($sentence->editor_uid, $sendTo)) {
  91. $sendTo[] = $sentence->editor_uid;
  92. }
  93. //句子的采纳者
  94. if (!empty($sentence->acceptor_uid) && !in_array($sentence->acceptor_uid, $sendTo)) {
  95. $sendTo[] = $sentence->acceptor_uid;
  96. }
  97. $this->notification(
  98. $message->editor->uid,
  99. $sendTo,
  100. 'discussion',
  101. $message->id,
  102. $sentence->channel_uid
  103. );
  104. } catch (\Exception $e) {
  105. Log::error('send notification failed', ['exception' => $e]);
  106. }
  107. //webhook
  108. $contentHtml = MdRender::render(
  109. $sentence->content,
  110. [$sentence->channel_uid],
  111. null,
  112. 'read',
  113. 'translation',
  114. $sentence->content_type
  115. );
  116. $contentTxt = strip_tags($contentHtml);
  117. /**生成消息内容 */
  118. $msgParam['anchor-content'] = $contentTxt;
  119. $WebHookResId = $sentence->channel_uid;
  120. $this->WebHook($msgParam, $type, $WebHookResId);
  121. break;
  122. case 'wbw':
  123. $wbw = Wbw::where('uid', $message->res_id)->first();
  124. if (!$wbw) {
  125. Log::error('invalid wbw id ' . $message->res_id);
  126. $result = 1;
  127. break;
  128. }
  129. $wbwBlock = WbwBlock::where('uid', $wbw->block_uid)->first();
  130. if (!$wbwBlock) {
  131. Log::error('invalid wbw-block id ' . $message->res_id);
  132. $result = 1;
  133. break;
  134. }
  135. //站内信
  136. try {
  137. $sendTo = array();
  138. //channel拥有者
  139. //$sendTo[] = $prData->channel->studio_id;
  140. //作者
  141. if (!in_array($wbw->creator_uid, $sendTo)) {
  142. $sendTo[] = $wbw->creator_uid;
  143. }
  144. //提问者
  145. if (!empty($message->parent)) {
  146. $topicEditor = Discussion::where('id', $message->parent)
  147. ->value('editor_uid');
  148. if (!empty($topicEditor) && !in_array($topicEditor, $sendTo)) {
  149. $sendTo[] = $topicEditor;
  150. Log::debug('发送给提问者', ['data' => $topicEditor]);
  151. }
  152. }
  153. $this->notification(
  154. $message->editor->id,
  155. $sendTo,
  156. 'discussion',
  157. $message->id,
  158. $wbwBlock->channel_uid
  159. );
  160. } catch (\Exception $e) {
  161. Log::error('send notification failed', ['exception' => $e]);
  162. }
  163. $msgParam['anchor-content'] = $wbw->word;
  164. $WebHookResId = $wbwBlock->channel_uid;
  165. $this->WebHook($msgParam, $type, $WebHookResId);
  166. break;
  167. case 'term':
  168. $term = DhammaTerm::where('guid', $message->res_id)->first();
  169. if (!$term) {
  170. Log::error('invalid term id ' . $message->res_id);
  171. $result = 1;
  172. break;
  173. }
  174. if (empty($term->channal) || !Str::isUuid($term->channal)) {
  175. break;
  176. }
  177. //站内信
  178. try {
  179. $sendTo = array();
  180. //拥有者
  181. $sendTo[] = $term->term;
  182. //作者
  183. $editor = UserApi::getById($term->editor_id);
  184. if ($editor['id'] !== 0 && !in_array($editor['uid'], $sendTo)) {
  185. $sendTo[] = $editor['uid'];
  186. }
  187. $this->notification(
  188. $message->editor->uid,
  189. $sendTo,
  190. 'discussion',
  191. $message->id,
  192. $term->channal
  193. );
  194. } catch (\Exception $e) {
  195. Log::error('send notification failed', ['exception' => $e]);
  196. }
  197. //webhook
  198. $msgParam['anchor-content'] = $term->meaning . '(' . $term->word . ')';
  199. $WebHookResId = $term->channal;
  200. $this->WebHook($msgParam, 'term', $WebHookResId);
  201. break;
  202. default:
  203. # code...
  204. break;
  205. }
  206. return $result;
  207. });
  208. return 0;
  209. }
  210. private function WebHook($msgParam, $type, $resId)
  211. {
  212. $rootId = UserApi::getById(0)['uid'];
  213. $articleTitle = "webhook://discussion/{$type}/zh-hans";
  214. $tpl = Article::where('owner', $rootId)
  215. ->where('title', $articleTitle)
  216. ->value('content');
  217. if (empty($tpl)) {
  218. Log::error('mq:discussion 模版不能为空', ['tpl_title' => $articleTitle]);
  219. return 1;
  220. }
  221. $m = new \Mustache_Engine(array(
  222. 'entity_flags' => ENT_QUOTES,
  223. 'delimiters' => '{% %}',
  224. ));
  225. $msgContent = $m->render($tpl, $msgParam);
  226. $webhooks = WebHook::where('res_id', $resId)
  227. ->where('status', 'active')
  228. ->get();
  229. $result = 0;
  230. foreach ($webhooks as $key => $hook) {
  231. $event = json_decode($hook->event);
  232. if (is_array($event)) {
  233. if (!in_array('discussion', $event)) {
  234. continue;
  235. }
  236. } else {
  237. continue;
  238. }
  239. $command = '';
  240. $whSend = new WebHookSend;
  241. $ok = 0;
  242. switch ($hook->receiver) {
  243. case 'dingtalk':
  244. $ok = $whSend->dingtalk($hook->url, $msgParam['card_title'], $msgContent);
  245. break;
  246. case 'wechat':
  247. $ok = $whSend->wechat($hook->url, null, $msgContent);
  248. break;
  249. default:
  250. $ok = 2;
  251. break;
  252. }
  253. $result += $ok;
  254. $logMsg = "{$command} ok={$ok}";
  255. if ($ok === 0) {
  256. $this->info($logMsg);
  257. } else {
  258. $this->error($logMsg);
  259. }
  260. if ($ok === 0) {
  261. Log::debug('mq:discussion: send success {url}', ['url' => $hook->url]);
  262. WebHook::where('id', $hook->id)->increment('success');
  263. } else {
  264. Log::error('mq:discussion: send fail {url}', ['url' => $hook->url]);
  265. WebHook::where('id', $hook->id)->increment('fail');
  266. }
  267. }
  268. }
  269. private function notification($from, $to, $resType, $resId, $channel)
  270. {
  271. //发送站内信
  272. try {
  273. $sendCount = NotificationController::insert(
  274. $from,
  275. $to,
  276. $resType,
  277. $resId,
  278. $channel
  279. );
  280. $this->info("send notification success to [" . $sendCount . '] users');
  281. } catch (\Exception $e) {
  282. Log::error('send notification failed', ['exception' => $e]);
  283. }
  284. return;
  285. }
  286. }