diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e12433a1..ce81c6b44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,31 @@ All notable changes to this project will be documented in this file. +## [0.24.53] + +### Bug Fixes + +- 重命名别人共享的文件后不见了 + +### Features + +- 搜索会话消息 + +### Performance + +- 优化数据同步 +- 重写更新和删除方法 +- 重写项目和会话接口数据 +- 搜索消息禁止右键 +- 优化搜索 +- 子任务允许多个负责人 +- 文件名称显示两行 +- 隐藏共享文件改为仅显示我的 +- 优化链接识别 +- 文件消息新增显示文件菜单 +- 会员选择框支持搜索拼音 +- 可以通过ID搜索任务 + ## [0.24.30] ### Bug Fixes diff --git a/app/Http/Controllers/Api/SystemController.php b/app/Http/Controllers/Api/SystemController.php index 6d8e7b7cd..8cc09fbb0 100755 --- a/app/Http/Controllers/Api/SystemController.php +++ b/app/Http/Controllers/Api/SystemController.php @@ -2,20 +2,17 @@ namespace App\Http\Controllers\Api; -use App\Ldap\LdapUser; use App\Models\Setting; use App\Models\User; use App\Models\UserCheckinRecord; use App\Module\Base; use App\Module\BillExport; use App\Module\BillMultipleExport; +use App\Module\Extranet; use Arr; use Carbon\Carbon; -use Config; use Guanguans\Notify\Factory; use Guanguans\Notify\Messages\EmailMessage; -use LdapRecord\Auth\PasswordRequiredException; -use LdapRecord\Auth\UsernameRequiredException; use LdapRecord\Container; use LdapRecord\LdapRecordException; use Madzipper; @@ -535,8 +532,8 @@ class SystemController extends AbstractController } return Base::retSuccess('success', [ 'ip' => Base::getIp(), - 'ip-info' => Base::getIpInfo(Base::getIp()), - 'ip-gcj02' => Base::getIpGcj02(Base::getIp()), + 'ip-info' => Extranet::getIpInfo(Base::getIp()), + 'ip-gcj02' => Extranet::getIpGcj02(Base::getIp()), 'ip-iscn' => Base::isCnIp(Base::getIp()), 'header' => Request::header(), 'token' => Base::getToken(), @@ -590,7 +587,7 @@ class SystemController extends AbstractController * @apiSuccess {Object} data 返回数据 */ public function get__ipgcj02() { - return Base::getIpGcj02(Request::input("ip")); + return Extranet::getIpGcj02(Request::input("ip")); } /** @@ -607,7 +604,7 @@ class SystemController extends AbstractController * @apiSuccess {Object} data 返回数据 */ public function get__ipinfo() { - return Base::getIpInfo(Request::input("ip")); + return Extranet::getIpInfo(Request::input("ip")); } /** diff --git a/app/Http/Controllers/IndexController.php b/app/Http/Controllers/IndexController.php index a4c2ad6e5..602220925 100755 --- a/app/Http/Controllers/IndexController.php +++ b/app/Http/Controllers/IndexController.php @@ -4,7 +4,7 @@ namespace App\Http\Controllers; use App\Models\File; use App\Module\Base; -use App\Module\Ihttp; +use App\Module\Extranet; use App\Module\RandomColor; use App\Tasks\AppPushTask; use App\Tasks\AutoArchivedTask; @@ -295,20 +295,10 @@ class IndexController extends InvokeController */ public function drawio__iconsearch() { - $query = Request::input('q'); - $page = Request::input('p'); - $size = Request::input('c'); - $url = "https://app.diagrams.net/iconSearch?q={$query}&p={$page}&c={$size}"; - $result = Cache::remember("drawioIconsearch::" . md5($url), now()->addDays(15), function () use ($url) { - return Ihttp::ihttp_get($url); - }); - if (Base::isSuccess($result)) { - return $result['data']; - } - return [ - 'icons' => [], - 'total_count' => 0 - ]; + $query = trim(Request::input('q')); + $page = trim(Request::input('p')); + $size = trim(Request::input('c')); + return Extranet::drawioIconSearch($query, $page, $size); } /** diff --git a/app/Models/UserBot.php b/app/Models/UserBot.php index cf5c3c447..e79f47112 100644 --- a/app/Models/UserBot.php +++ b/app/Models/UserBot.php @@ -2,6 +2,11 @@ namespace App\Models; +use App\Module\Base; +use App\Module\Extranet; +use Cache; +use Carbon\Carbon; + /** * App\Models\UserBot * @@ -31,4 +36,61 @@ namespace App\Models; class UserBot extends AbstractModel { + /** + * 机器人菜单 + * @param $email + * @return array|array[] + */ + public static function quickMsgs($email) + { + if ($email === 'check-in@bot.system') { + return [ + [ + 'key' => 'checkin', + 'label' => Base::Lang('我要签到') + ], [ + 'key' => 'it', + 'label' => Base::Lang('IT资讯') + ], [ + 'key' => '36ke', + 'label' => Base::Lang('36氪') + ], [ + 'key' => '60s', + 'label' => Base::Lang('60s读世界') + ], [ + 'key' => 'joke', + 'label' => Base::Lang('一个笑话') + ], [ + 'key' => 'soup', + 'label' => Base::Lang('一碗鸡汤') + ] + ]; + } + return []; + } + + /** + * 签到机器人 + * @param $type + * @param $userid + * @return string + */ + public static function checkinBotQuickMsg($type, $userid) + { + if (Cache::get("UserBot::checkinBotQuickMsg:{$userid}") === "yes") { + return "操作频繁!"; + } + Cache::put("UserBot::checkinBotQuickMsg:{$userid}", "yes", Carbon::now()->addSecond()); + // + switch ($type) { + case "checkin": + $text = "暂未开放手动签到。"; + break; + + default: + $text = Extranet::checkinBotQuickMsg($type); + break; + } + return $text ?: '维护中...'; + } } diff --git a/app/Models/WebSocketDialog.php b/app/Models/WebSocketDialog.php index 8c02cd8ca..337934209 100644 --- a/app/Models/WebSocketDialog.php +++ b/app/Models/WebSocketDialog.php @@ -119,14 +119,7 @@ class WebSocketDialog extends AbstractModel if ($basic) { $this->name = $basic->nickname; $this->bot = $basic->bot; - if ($basic->email === 'check-in@bot.system') { - $this->quick_msgs = [ - [ - 'key' => 'checkin', - 'label' => Base::Lang('我要签到') - ] - ]; - } + $this->quick_msgs = UserBot::quickMsgs($basic->email); } else { $this->name = 'non-existent'; $this->dialog_delete = 1; diff --git a/app/Module/Base.php b/app/Module/Base.php index 4a3e03ee0..dc16657e2 100755 --- a/app/Module/Base.php +++ b/app/Module/Base.php @@ -6,8 +6,6 @@ use App\Exceptions\ApiException; use App\Models\Setting; use App\Models\Tmp; use Cache; -use Illuminate\Support\Arr; -use Illuminate\Support\Facades\Config; use Overtrue\Pinyin\Pinyin; use Redirect; use Request; @@ -1916,111 +1914,6 @@ class Base return $_A["__static_ip"]; } - /** - * 获取IP地址经纬度 - * @param string $ip - * @return array|mixed - */ - public static function getIpGcj02($ip = '') - { - if (empty($ip)) { - $ip = self::getIp(); - } - $cacheKey = "getIpPoint::" . md5($ip); - $result = Cache::rememberForever($cacheKey, function () use ($ip) { - return Ihttp::ihttp_request("https://www.ifreesite.com/ipaddress/address.php?q=" . $ip, [], [], 12); - }); - if (Base::isError($result)) { - Cache::forget($cacheKey); - return $result; - } - $data = $result['data']; - $lastPos = strrpos($data, ','); - $long = floatval(Base::getMiddle(substr($data, $lastPos + 1), null, ')')); - $lat = floatval(Base::getMiddle(substr($data, strrpos(substr($data, 0, $lastPos), ',') + 1), null, ',')); - return Base::retSuccess("success", [ - 'long' => $long, - 'lat' => $lat, - ]); - } - - /** - * 百度接口:根据ip获取经纬度 - * @param string $ip - * @return array|mixed - */ - public static function getIpGcj02ByBaidu($ip = ''): array - { - if (empty($ip)) { - $ip = self::getIp(); - } - - $cacheKey = "getIpPoint::" . md5($ip); - $result = Cache::rememberForever($cacheKey, function () use ($ip) { - $ak = Config::get('app.baidu_app_key'); - $url = 'http://api.map.baidu.com/location/ip?ak=' . $ak . '&ip=' . $ip . '&coor=bd09ll'; - return Ihttp::ihttp_request($url, [], [], 12); - }); - - if (Base::isError($result)) { - Cache::forget($cacheKey); - return $result; - } - $data = json_decode($result['data'], true); - - // x坐标纬度, y坐标经度 - $long = Arr::get($data, 'content.point.x'); - $lat = Arr::get($data, 'content.point.y'); - return Base::retSuccess("success", [ - 'long' => $long, - 'lat' => $lat, - ]); - } - - /** - * 获取IP地址详情 - * @param string $ip - * @return array|mixed - */ - public static function getIpInfo($ip = '') - { - if (empty($ip)) { - $ip = self::getIp(); - } - $cacheKey = "getIpInfo::" . md5($ip); - $result = Cache::rememberForever($cacheKey, function () use ($ip) { - return Ihttp::ihttp_request("http://ip.taobao.com/service/getIpInfo.php?accessKey=alibaba-inc&ip=" . $ip, [], [], 12); - }); - if (Base::isError($result)) { - Cache::forget($cacheKey); - return $result; - } - $data = json_decode($result['data'], true); - if (!is_array($data) || intval($data['code']) != 0) { - Cache::forget($cacheKey); - return Base::retError("error ip: -1"); - } - $data = $data['data']; - if (!is_array($data) || !isset($data['country'])) { - return Base::retError("error ip: -2"); - } - $data['text'] = $data['country']; - $data['textSmall'] = $data['country']; - if ($data['region'] && $data['region'] != $data['country'] && $data['region'] != "XX") { - $data['text'] .= " " . $data['region']; - $data['textSmall'] = $data['region']; - } - if ($data['city'] && $data['city'] != $data['region'] && $data['city'] != "XX") { - $data['text'] .= " " . $data['city']; - $data['textSmall'] .= " " . $data['city']; - } - if ($data['county'] && $data['county'] != $data['city'] && $data['county'] != "XX") { - $data['text'] .= " " . $data['county']; - $data['textSmall'] .= " " . $data['county']; - } - return Base::retSuccess("success", $data); - } - /** * 是否是中国IP:-1错误、1是、0否 * @param string $ip @@ -3194,39 +3087,4 @@ class Base } return Response::streamDownload($callback, $name); } - - /** - * 判断是否工作日 - * @param string $Ymd 年月日(如:20220102) - * @return int - * 0: 工作日 - * 1: 非工作日 - * 2: 获取不到远程数据的非工作日(周六、日) - * 所以可以用>0来判断是否工作日 - */ - public static function isHoliday($Ymd) { - $time = strtotime($Ymd . " 00:00:00"); - $holidayKey = "holiday::" . date("Ym", $time); - $holidayData = Cache::remember($holidayKey, now()->addMonth(), function () use ($time) { - $apiMonth = date("Ym", $time); - $apiResult = Ihttp::ihttp_request("https://api.apihubs.cn/holiday/get?field=date&month={$apiMonth}&workday=2&size=31", [], [], 20); - if (Base::isError($apiResult)) { - info('[holiday] get error'); - return []; - } - $apiResult = Base::json2array($apiResult['data']); - if ($apiResult['code'] !== 0) { - info('[holiday] result error'); - return []; - } - return array_map(function ($item) { - return $item['date']; - }, $apiResult['data']['list']); - }); - if (empty($holidayData)) { - Cache::forget($holidayKey); - return in_array(date("w", $time), [0, 6]) ? 2 : 0; - } - return in_array($Ymd, $holidayData) ? 1 : 0; - } } diff --git a/app/Module/Extranet.php b/app/Module/Extranet.php new file mode 100644 index 000000000..aca6b26eb --- /dev/null +++ b/app/Module/Extranet.php @@ -0,0 +1,300 @@ + $long, + 'lat' => $lat, + ]); + } + + /** + * 百度接口:根据ip获取经纬度 + * @param string $ip + * @return array + */ + public static function getIpGcj02ByBaidu(string $ip = ''): array + { + if (empty($ip)) { + $ip = Base::getIp(); + } + + $cacheKey = "getIpPoint::" . md5($ip); + $result = Cache::rememberForever($cacheKey, function () use ($ip) { + $ak = Config::get('app.baidu_app_key'); + $url = 'http://api.map.baidu.com/location/ip?ak=' . $ak . '&ip=' . $ip . '&coor=bd09ll'; + return Ihttp::ihttp_request($url, [], [], 12); + }); + + if (Base::isError($result)) { + Cache::forget($cacheKey); + return $result; + } + $data = json_decode($result['data'], true); + + // x坐标纬度, y坐标经度 + $long = Arr::get($data, 'content.point.x'); + $lat = Arr::get($data, 'content.point.y'); + return Base::retSuccess("success", [ + 'long' => $long, + 'lat' => $lat, + ]); + } + + /** + * 获取IP地址详情 + * @param string $ip + * @return array + */ + public static function getIpInfo(string $ip = ''): array + { + if (empty($ip)) { + $ip = Base::getIp(); + } + $cacheKey = "getIpInfo::" . md5($ip); + $result = Cache::rememberForever($cacheKey, function () use ($ip) { + return Ihttp::ihttp_request("http://ip.taobao.com/service/getIpInfo.php?accessKey=alibaba-inc&ip=" . $ip, [], [], 12); + }); + if (Base::isError($result)) { + Cache::forget($cacheKey); + return $result; + } + $data = json_decode($result['data'], true); + if (!is_array($data) || intval($data['code']) != 0) { + Cache::forget($cacheKey); + return Base::retError("error ip: -1"); + } + $data = $data['data']; + if (!is_array($data) || !isset($data['country'])) { + return Base::retError("error ip: -2"); + } + $data['text'] = $data['country']; + $data['textSmall'] = $data['country']; + if ($data['region'] && $data['region'] != $data['country'] && $data['region'] != "XX") { + $data['text'] .= " " . $data['region']; + $data['textSmall'] = $data['region']; + } + if ($data['city'] && $data['city'] != $data['region'] && $data['city'] != "XX") { + $data['text'] .= " " . $data['city']; + $data['textSmall'] .= " " . $data['city']; + } + if ($data['county'] && $data['county'] != $data['city'] && $data['county'] != "XX") { + $data['text'] .= " " . $data['county']; + $data['textSmall'] .= " " . $data['county']; + } + return Base::retSuccess("success", $data); + } + + /** + * 判断是否工作日 + * @param string $Ymd 年月日(如:20220102) + * @return int + * 0: 工作日 + * 1: 非工作日 + * 2: 获取不到远程数据的非工作日(周六、日) + * 所以可以用>0来判断是否工作日 + */ + public static function isHoliday(string $Ymd): int + { + $time = strtotime($Ymd . " 00:00:00"); + $holidayKey = "holiday::" . date("Ym", $time); + $holidayData = Cache::remember($holidayKey, now()->addMonth(), function () use ($time) { + $apiMonth = date("Ym", $time); + $apiResult = Ihttp::ihttp_request("https://api.apihubs.cn/holiday/get?field=date&month={$apiMonth}&workday=2&size=31", [], [], 20); + if (Base::isError($apiResult)) { + info('[holiday] get error'); + return []; + } + $apiResult = Base::json2array($apiResult['data']); + if ($apiResult['code'] !== 0) { + info('[holiday] result error'); + return []; + } + return array_map(function ($item) { + return $item['date']; + }, $apiResult['data']['list']); + }); + if (empty($holidayData)) { + Cache::forget($holidayKey); + return in_array(date("w", $time), [0, 6]) ? 2 : 0; + } + return in_array($Ymd, $holidayData) ? 1 : 0; + } + + /** + * Drawio 图标搜索 + * @param $query + * @param $page + * @param $size + * @return array + */ + public static function drawioIconSearch($query, $page, $size): array + { + $result = self::curl("https://app.diagrams.net/iconSearch?q={$query}&p={$page}&c={$size}", 15 * 86400); + if ($result = Base::json2array($result)) { + return $result; + } + return [ + 'icons' => [], + 'total_count' => 0 + ]; + } + + /** + * 随机笑话接口 + * @return array + */ + public static function randJoke(): array + { + $jokeKey = env("JUKE_KEY_JOKE"); + if ($jokeKey) { + $data = self::curl("http://v.juhe.cn/joke/randJoke.php?key=" . $jokeKey); + $data = Base::json2array($data); + if ($data['reason'] === 'success') { + return $data['result']; + } + } + return []; + } + + /** + * 心灵鸡汤 + * @return string + */ + public static function soups(): string + { + $soupKey = env("JUKE_KEY_SOUP"); + if ($soupKey) { + $data = self::curl("https://apis.juhe.cn/fapig/soup/query?key=" . $soupKey); + $data = Base::json2array($data); + if ($data['reason'] === 'success' && $text = trim($data['result']['text'])) { + return $text; + } + } + return ""; + } + + /** + * 签到机器人网络内容 + * @param $type + * @return string + */ + public static function checkinBotQuickMsg($type): string + { + $text = ''; + switch ($type) { + case "it": + $data = self::curl('https://api.vvhan.com/api/hotlist?type=itNews', 3600); + if ($data = Base::json2array($data)) { + $array = array_map(function ($item, $key) { + $content = "
" . ($key + 1) . ". {$item['title']}
"; + if ($item['desc']) { + $content .= "{$item['desc']}
"; + } + return $content; + }, $data['data'], array_keys($data['data'])); + if ($array) { + array_unshift($array, "{$data['title']}({$data['update_time']})
"); + } + $text = implode("", $array); + } + break; + + case "36ke": + $data = self::curl('https://api.vvhan.com/api/hotlist?type=36Ke', 3600); + if ($data = Base::json2array($data)) { + $array = array_map(function ($item, $key) { + $content = "
" . ($key + 1) . ". {$item['title']}
"; + if ($item['desc']) { + $content .= "{$item['desc']}
"; + } + return $content; + }, $data['data'], array_keys($data['data'])); + if ($array) { + array_unshift($array, "{$data['title']}({$data['update_time']})
"); + } + $text = implode("", $array); + } + break; + + case "60s": + $data = self::curl('https://api.vvhan.com/api/60s?type=json', 3600); + if ($data = Base::json2array($data)) { + $array = array_map(function ($item, $key) { + return "
" . ($key + 1) . ". {$item}
"; + }, $data['data'], array_keys($data['data'])); + if ($array) { + array_unshift($array, "{$data['name']}({$data['time'][0]})
"); + } + $text = implode("", $array); + } + break; + + case "joke": + $data = self::curl('https://api.vvhan.com/api/joke?type=json', 5); + if ($data = Base::json2array($data)) { + $text = $data['joke'] ?: '笑话被掏空'; + } + break; + + case "soup": + $data = self::curl('https://api.ayfre.com/jt/?type=bot', 5); + $text = trim($data) ?: "鸡汤分完了"; + break; + } + return $text; + } + + /** + * @param $url + * @param int $cacheSecond + * @param int $timeout + * @return string + */ + private static function curl($url, int $cacheSecond = 0, int $timeout = 15): string + { + if ($cacheSecond > 0) { + $res = Cache::remember("curlCache::" . md5($url), Carbon::now()->addSeconds($cacheSecond), function () use ($timeout, $url) { + return Ihttp::ihttp_request($url, [], [], $timeout); + }); + } else { + $res = Ihttp::ihttp_request($url, [], [], $timeout); + } + if (Base::isSuccess($res)) { + return $res['data']; + } + return ''; + } +} diff --git a/app/Tasks/BotReceiveMsgTask.php b/app/Tasks/BotReceiveMsgTask.php index 095b769a2..ba8b1872b 100644 --- a/app/Tasks/BotReceiveMsgTask.php +++ b/app/Tasks/BotReceiveMsgTask.php @@ -73,11 +73,11 @@ class BotReceiveMsgTask extends AbstractTask // 签到机器人 if ($botUser->email === 'check-in@bot.system') { if (preg_match("/]*?data-quick-key=([\"'])(.*?)\\1[^>]*?>(.*?)<\/span>/is", $original, $match)) { - if ($match[2] === 'checkin') { - $text = "暂未开放手动签到。"; + $text = UserBot::checkinBotQuickMsg($match[2], $msg->userid); + if ($text) { WebSocketDialogMsg::sendMsg(null, $msg->dialog_id, 'text', ['text' => $text], $botUser->userid, false, false, true); // todo 未能在任务end事件来发送任务 - return; } + return; } } // 管理机器人 diff --git a/app/Tasks/CheckinRemindTask.php b/app/Tasks/CheckinRemindTask.php index ba2b1eac6..beca1a978 100644 --- a/app/Tasks/CheckinRemindTask.php +++ b/app/Tasks/CheckinRemindTask.php @@ -7,7 +7,7 @@ use App\Models\UserCheckinRecord; use App\Models\WebSocketDialog; use App\Models\WebSocketDialogMsg; use App\Module\Base; -use App\Module\Ihttp; +use App\Module\Extranet; use Cache; use Carbon\Carbon; @@ -27,7 +27,7 @@ class CheckinRemindTask extends AbstractTask return; } // 判断非工作日 - if (Base::isHoliday(date("Ymd")) > 0) { + if (Extranet::isHoliday(date("Ymd")) > 0) { return; } // diff --git a/app/Tasks/JokeSoupTask.php b/app/Tasks/JokeSoupTask.php index dd79c1230..8d0b8d909 100644 --- a/app/Tasks/JokeSoupTask.php +++ b/app/Tasks/JokeSoupTask.php @@ -3,7 +3,7 @@ namespace App\Tasks; use App\Module\Base; -use App\Module\Ihttp; +use App\Module\Extranet; use Cache; use Carbon\Carbon; @@ -33,35 +33,21 @@ class JokeSoupTask extends AbstractTask } Cache::put("JokeSoupTask:YmdH", date("YmdH"), Carbon::now()->addDay()); // - $jokeKey = env("JUKE_KEY_JOKE"); - if ($jokeKey) { - $array = Base::json2array(Cache::get("JokeSoupTask:jokes")); - $res = Ihttp::ihttp_get("http://v.juhe.cn/joke/randJoke.php?key=" . $jokeKey); - if (Base::isSuccess($res)) { - $data = Base::json2array($res['data']); - if ($data['reason'] === 'success') { - foreach ($data['result'] as $item) { - if ($text = trim($item['content'])) { - $array[] = $text; - } - } - } + $array = Base::json2array(Cache::get("JokeSoupTask:jokes")); + $data = Extranet::randJoke(); + foreach ($data as $item) { + if ($text = trim($item['content'])) { + $array[] = $text; } - Cache::forever("JokeSoupTask:jokes", Base::array2json(array_slice($array, -100))); } + Cache::forever("JokeSoupTask:jokes", Base::array2json(array_slice($array, -100))); // - $soupKey = env("JUKE_KEY_SOUP"); - if ($soupKey) { - $array = Base::json2array(Cache::get("JokeSoupTask:soups")); - $res = Ihttp::ihttp_get("https://apis.juhe.cn/fapig/soup/query?key=" . $soupKey); - if (Base::isSuccess($res)) { - $data = Base::json2array($res['data']); - if ($data['reason'] === 'success' && $text = trim($data['result']['text'])) { - $array[] = $text; - } - } - Cache::forever("JokeSoupTask:soups", Base::array2json(array_slice($array, -24))); + $array = Base::json2array(Cache::get("JokeSoupTask:soups")); + $data = Extranet::soups(); + if ($data) { + $array[] = $data; } + Cache::forever("JokeSoupTask:soups", Base::array2json(array_slice($array, -24))); } public function end() diff --git a/package.json b/package.json index 34ebc26ac..0f58b28a8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "DooTask", - "version": "0.24.30", + "version": "0.24.53", "description": "DooTask is task management system.", "scripts": { "start": "./cmd dev",