diff --git a/app/Models/UserBot.php b/app/Models/UserBot.php index 768e1e773..cf5c3c447 100644 --- a/app/Models/UserBot.php +++ b/app/Models/UserBot.php @@ -10,6 +10,8 @@ namespace App\Models; * @property int|null $bot_id 机器人ID * @property int|null $clear_day 消息自动清理天数 * @property string|null $clear_at 下一次清理时间 + * @property string|null $webhook_url 消息webhook地址 + * @property int|null $webhook_num 消息webhook请求次数 * @property \Illuminate\Support\Carbon|null $created_at * @property \Illuminate\Support\Carbon|null $updated_at * @method static \Illuminate\Database\Eloquent\Builder|UserBot newModelQuery() @@ -22,6 +24,8 @@ namespace App\Models; * @method static \Illuminate\Database\Eloquent\Builder|UserBot whereId($value) * @method static \Illuminate\Database\Eloquent\Builder|UserBot whereUpdatedAt($value) * @method static \Illuminate\Database\Eloquent\Builder|UserBot whereUserid($value) + * @method static \Illuminate\Database\Eloquent\Builder|UserBot whereWebhookNum($value) + * @method static \Illuminate\Database\Eloquent\Builder|UserBot whereWebhookUrl($value) * @mixin \Eloquent */ class UserBot extends AbstractModel diff --git a/app/Tasks/BotReceiveMsgTask.php b/app/Tasks/BotReceiveMsgTask.php index e4c56e421..8faf97347 100644 --- a/app/Tasks/BotReceiveMsgTask.php +++ b/app/Tasks/BotReceiveMsgTask.php @@ -7,6 +7,7 @@ use App\Models\UserBot; use App\Models\WebSocketDialog; use App\Models\WebSocketDialogMsg; use App\Module\Base; +use App\Module\Ihttp; use Carbon\Carbon; @error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING); @@ -48,9 +49,7 @@ class BotReceiveMsgTask extends AbstractTask if ($dialog->type !== 'user') { return; } - if ($botUser->email === 'bot-manager@bot.system') { - $this->botManagerReceive($msg); - } + $this->botManagerReceive($msg, $botUser); } public function end() @@ -61,25 +60,46 @@ class BotReceiveMsgTask extends AbstractTask /** * 机器人管理处理消息 * @param WebSocketDialogMsg $msg + * @param User $botUser * @return void */ - private function botManagerReceive(WebSocketDialogMsg $msg) + private function botManagerReceive(WebSocketDialogMsg $msg, User $botUser) { - if ($msg->type === 'text') { - $text = trim(strip_tags($msg->msg['text'])); - if (empty($text)) { + if ($msg->type !== 'text') { + return; + } + $pureText = trim(strip_tags($msg->msg['text'])); + if (str_starts_with($pureText, '/')) { + // 管理机器人 + if ($botUser->email === 'bot-manager@bot.system') { + $isManager = true; + } elseif (UserBot::whereBotId($botUser->userid)->whereUserid($msg->userid)->exists()) { + $isManager = false; + } else { + $text = "非常抱歉,我不是你的机器人,无法完成你的指令。"; + WebSocketDialogMsg::sendMsg(null, $msg->dialog_id, 'text', ['text' => $text], $botUser->userid, false, false, true); // todo 未能在任务end事件来发送任务 return; } - $array = Base::newTrim(explode(" ", "{$text} ")); + // + $array = Base::newTrim(explode(" ", "{$pureText} ")); $type = $array[0]; $data = []; $notice = ""; + if (!$isManager && in_array($type, ['/list', '/newbot'])) { + return; // 这些操作仅支持【机器人管理】机器人 + } switch ($type) { /** * 列表 */ case '/list': - $data = User::select(['users.*']) + $data = User::select([ + 'users.*', + 'user_bots.clear_day', + 'user_bots.clear_at', + 'user_bots.webhook_url', + 'user_bots.webhook_num' + ]) ->join('user_bots', 'users.userid', '=', 'user_bots.bot_id') ->where('users.bot', 1) ->where('user_bots.userid', $msg->userid) @@ -92,6 +112,18 @@ class BotReceiveMsgTask extends AbstractTask } break; + /** + * 详情 + */ + case '/info': + $botId = $isManager ? $array[1] : $botUser->userid; + $data = $this->botManagerOne($botId, $msg->userid); + if (!$data) { + $type = "notice"; + $notice = "机器人不存在。"; + } + break; + /** * 创建 */ @@ -120,7 +152,7 @@ class BotReceiveMsgTask extends AbstractTask } $dialog = WebSocketDialog::checkUserDialog($data->userid, $msg->userid); if ($dialog) { - $text = "你好,我是你的机器人:{$data->nickname}, 我的机器人ID是:{$data->userid}"; + $text = "

您好,我是机器人:{$data->nickname},我的机器人ID是:{$data->userid},

你可以发送 /help 查看我支持什么命令。

"; WebSocketDialogMsg::sendMsg(null, $dialog->id, 'text', ['text' => $text], $data->userid); // todo 未能在任务end事件来发送任务 } break; @@ -129,16 +161,18 @@ class BotReceiveMsgTask extends AbstractTask * 修改名字 */ case '/setname': - if (strlen($array[2]) < 2 || strlen($array[2]) > 20) { + $botId = $isManager ? $array[1] : $botUser->userid; + $nameString = $isManager ? $array[2] : $array[1]; + if (strlen($nameString) < 2 || strlen($nameString) > 20) { $type = "notice"; $notice = "机器人名称由2-20个字符组成。"; break; } - $data = $this->botManagerOne($array[1], $msg->userid); + $data = $this->botManagerOne($botId, $msg->userid); if ($data) { - $data->nickname = $array[2]; - $data->az = Base::getFirstCharter($array[2]); - $data->pinyin = Base::cn2pinyin($array[2]); + $data->nickname = $nameString; + $data->az = Base::getFirstCharter($nameString); + $data->pinyin = Base::cn2pinyin($nameString); $data->save(); } else { $type = "notice"; @@ -151,7 +185,8 @@ class BotReceiveMsgTask extends AbstractTask * 删除 */ case '/deletebot': - $data = $this->botManagerOne($array[1], $msg->userid); + $botId = $isManager ? $array[1] : $botUser->userid; + $data = $this->botManagerOne($botId, $msg->userid); if ($data) { $data->deleteUser('delete bot'); } else { @@ -164,7 +199,8 @@ class BotReceiveMsgTask extends AbstractTask * 获取Token */ case '/token': - $data = $this->botManagerOne($array[1], $msg->userid); + $botId = $isManager ? $array[1] : $botUser->userid; + $data = $this->botManagerOne($botId, $msg->userid); if ($data) { User::token($data); } else { @@ -177,7 +213,8 @@ class BotReceiveMsgTask extends AbstractTask * 更新Token */ case '/revoke': - $data = $this->botManagerOne($array[1], $msg->userid); + $botId = $isManager ? $array[1] : $botUser->userid; + $data = $this->botManagerOne($botId, $msg->userid); if ($data) { $data->encrypt = Base::generatePassword(6); $data->password = Base::md52(Base::generatePassword(32), $data->encrypt); @@ -192,11 +229,13 @@ class BotReceiveMsgTask extends AbstractTask * 设置自动清理消息时间 */ case '/clearday': - $data = $this->botManagerOne($array[1], $msg->userid); + $botId = $isManager ? $array[1] : $botUser->userid; + $clearDay = $isManager ? $array[2] : $array[1]; + $data = $this->botManagerOne($botId, $msg->userid); if ($data) { - $userBot = UserBot::whereBotId($array[1])->whereUserid($msg->userid)->first(); + $userBot = UserBot::whereBotId($botId)->whereUserid($msg->userid)->first(); if ($userBot) { - $userBot->clear_day = min(intval($array[2]) ?: 30, 999); + $userBot->clear_day = min(intval($clearDay) ?: 30, 999); $userBot->clear_at = Carbon::now()->addDays($userBot->clear_day); $userBot->save(); } @@ -208,15 +247,42 @@ class BotReceiveMsgTask extends AbstractTask } break; + /** + * 设置webhook + */ + case '/webhook': + $botId = $isManager ? $array[1] : $botUser->userid; + $webhookUrl = $isManager ? $array[2] : $array[1]; + $data = $this->botManagerOne($botId, $msg->userid); + if (strlen($webhookUrl) > 255) { + $type = "notice"; + $notice = "webhook地址最长仅支持255个字符。"; + } elseif ($data) { + $userBot = UserBot::whereBotId($botId)->whereUserid($msg->userid)->first(); + if ($userBot) { + $userBot->webhook_url = $webhookUrl ?: ""; + $userBot->webhook_num = 0; + $userBot->save(); + } + $data->webhook_url = $userBot->webhook_url ?: '-'; + $data->webhook_num = $userBot->webhook_num; // 这两个参数只是作为输出,所以不保存 + } else { + $type = "notice"; + $notice = "机器人不存在。"; + } + break; + /** * 会话搜索 */ case '/dialog': - $data = $this->botManagerOne($array[1], $msg->userid); + $botId = $isManager ? $array[1] : $botUser->userid; + $nameKey = $isManager ? $array[2] : $array[1]; + $data = $this->botManagerOne($botId, $msg->userid); if ($data) { $list = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.mark_unread', 'u.silence']) ->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id') - ->where('web_socket_dialogs.name', 'LIKE', "%{$array[2]}%") + ->where('web_socket_dialogs.name', 'LIKE', "%{$nameKey}%") ->where('u.userid', $data->userid) ->orderByDesc('u.top_at') ->orderByDesc('web_socket_dialogs.last_at') @@ -229,7 +295,7 @@ class BotReceiveMsgTask extends AbstractTask $list->transform(function (WebSocketDialog $item) use ($data) { return $item->formatData($data->userid); }); - $data->list = $list; + $data->list = $list; // 这个参数只是作为输出,所以不保存 } } else { $type = "notice"; @@ -242,11 +308,26 @@ class BotReceiveMsgTask extends AbstractTask 'type' => $type, 'data' => $data, 'notice' => $notice, + 'manager' => $isManager, 'version' => Base::getVersion() ])->render(); + if (!$isManager) { + $text = preg_replace("/\s*\{机器人ID\}/", "", $text); + } $text = preg_replace("/^\x20+/", "", $text); $text = preg_replace("/\n\x20+/", "\n", $text); - WebSocketDialogMsg::sendMsg(null, $msg->dialog_id, 'text', ['text' => $text], $this->userid, false, false, true); // todo 未能在任务end事件来发送任务 + WebSocketDialogMsg::sendMsg(null, $msg->dialog_id, 'text', ['text' => $text], $botUser->userid, false, false, true); // todo 未能在任务end事件来发送任务 + } elseif ($pureText) { + // 推送Webhook + $userBot = UserBot::whereBotId($botUser->userid)->first(); + if ($userBot && preg_match("/^https*:\/\//", $userBot->webhook_url)) { + Ihttp::ihttp_post($userBot->webhook_url, [ + 'text' => $pureText, + 'token' => User::token($botUser), + 'msg_id' => $msg->id, + 'dialog_id' => $msg->dialog_id, + ], 10); + } } } @@ -260,7 +341,13 @@ class BotReceiveMsgTask extends AbstractTask $botId = intval($botId); $userid = intval($userid); if ($botId > 0) { - return User::select(['users.*']) + return User::select([ + 'users.*', + 'user_bots.clear_day', + 'user_bots.clear_at', + 'user_bots.webhook_url', + 'user_bots.webhook_num' + ]) ->join('user_bots', 'users.userid', '=', 'user_bots.bot_id') ->where('users.bot', 1) ->where('user_bots.bot_id', $botId) diff --git a/database/migrations/2023_02_14_121233_add_user_bots_webhook.php b/database/migrations/2023_02_14_121233_add_user_bots_webhook.php new file mode 100644 index 000000000..d3f8313ee --- /dev/null +++ b/database/migrations/2023_02_14_121233_add_user_bots_webhook.php @@ -0,0 +1,36 @@ +string('webhook_url', 255)->nullable()->default('')->after('clear_at')->comment('消息webhook地址'); + $table->integer('webhook_num')->nullable()->default(0)->after('webhook_url')->comment('消息webhook请求次数'); + } + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('user_bots', function (Blueprint $table) { + $table->dropColumn("webhook_url"); + $table->dropColumn("webhook_num"); + }); + } +} diff --git a/resources/views/push/bot.blade.php b/resources/views/push/bot.blade.php index 0618d694f..727d679b7 100755 --- a/resources/views/push/bot.blade.php +++ b/resources/views/push/bot.blade.php @@ -1,17 +1,22 @@ @if ($type === '/help') 您可以通过发送以下命令来控制我: - /list - 机器人列表 - /newbot {机器人名称} - 创建机器人 + @if ($manager) + /list - 机器人列表 + /newbot {机器人名称} - 创建机器人 + @else + /info - 查看机器人详情 + @endif 修改机器人 /setname {机器人ID} {机器人名称} - 修改机器人名称 /deletebot {机器人ID} - 删除机器人 + /clearday {机器人ID} {天数} - 设置自动清理消息时间(默认30天) + /webhook {机器人ID} [url] - 设置消息Webhook(详细说明看 /api机器人设置 /token {机器人ID} - 生成Token令牌 /revoke {机器人ID} - 撤销机器人Token令牌 - /clearday {机器人ID} {天数} - 设置自动清理消息时间(默认30天) 会话管理 /dialog {机器人ID} [搜索关键词] - 查看会话ID @@ -21,10 +26,19 @@ @elseif ($type === '/list') 我的机器人。 - 机器人ID | 机器人名称 + ID | 名称 | 清理时间 | Webhook @foreach($data as $item) - {{$item->userid}} | {{$item->nickname}} + {{$item->userid}} | {{$item->nickname}} | {{$item->clear_day}} | {{$item->webhook_url ?: '-'}} @endforeach +@elseif ($type === '/info') + 机器人详情。 + + 机器人ID:{{$data->userid}} + 机器人名称:{{$data->nickname}} + 自动清理消息时间:{{$data->clear_day}} + 最后一次清理时间:{{$data->clear_at ?: '-'}} + Webhook地址:{{$data->webhook_url ?: '-'}} + Webhook请求次数:{{$data->webhook_num}} @elseif ($type === '/newbot') 创建成功。 @@ -51,6 +65,12 @@ 机器人ID:{{$data->userid}} 机器人名称:{{$data->nickname}} +@elseif ($type === '/webhook') + 设置Webhook地址。 + + 机器人ID:{{$data->userid}} + 机器人名称:{{$data->nickname}} + Webhook地址:{{$data->webhook_url}} @elseif ($type === '/clearday') 设置自动清理消息时间。 @@ -68,13 +88,20 @@ @elseif ($type === '/api') 你可以通过执行以下命令来请求我: - 发送文本消息 + 发送文本消息: curl --request POST '{{url('api/dialog/msg/sendtext')}}' \ --header 'version: {{ $version }}' \ --header 'token: {机器人Token}' \ --form 'dialog_id="{对话ID}"' \ --form 'text="{消息内容}"' --form 'silence="[yes|no]"' + + Webhook说明: + 机器人收到个人对话消息后会将消息POST推送到Webhook地址,请求超时为10秒,请求参数如下: + text: 消息文本 + token: 机器人Token + msg_id: 消息ID + dialog_id: 对话ID @elseif ($type === 'notice') {{$notice}} @else