diff --git a/app/Cache/FriendRemark.php b/app/Cache/FriendRemark.php index e8066e2..14c7354 100644 --- a/app/Cache/FriendRemark.php +++ b/app/Cache/FriendRemark.php @@ -3,7 +3,7 @@ namespace App\Cache; use App\Cache\Repository\HashRedis; -use App\Model\UsersFriend; +use App\Model\Contact; /** * 好友备注 - 缓存助手 @@ -55,7 +55,7 @@ class FriendRemark extends HashRedis */ public function reload() { - UsersFriend::select(['id', 'user_id', 'friend_id', 'remark'])->chunk(200, function ($rows) { + Contact::select(['id', 'user_id', 'friend_id', 'remark'])->chunk(200, function ($rows) { foreach ($rows as $row) { $row->remark && $this->save($row->user_id, $row->friend_id, $row->remark); } diff --git a/app/Command/TestCommand.php b/app/Command/TestCommand.php index fe36510..996bfe2 100644 --- a/app/Command/TestCommand.php +++ b/app/Command/TestCommand.php @@ -5,7 +5,7 @@ namespace App\Command; use App\Cache\IpAddressCache; use App\Constants\RobotConstant; -use App\Model\UsersFriend; +use App\Model\Contact; use App\Repository\ExampleRepository; use App\Repository\RobotRepository; use App\Service\RobotService; @@ -55,8 +55,8 @@ class TestCommand extends HyperfCommand // 更新好友表数据 public function updateData() { - $max = UsersFriend::max('id'); - UsersFriend::where('id', '<=', $max)->chunk(1000, function ($rows) { + $max = Contact::max('id'); + Contact::where('id', '<=', $max)->chunk(1000, function ($rows) { $arr = []; foreach ($rows as $row) { $arr[] = [ @@ -69,7 +69,7 @@ class TestCommand extends HyperfCommand ]; } - UsersFriend::insert($arr); + Contact::insert($arr); }); } } diff --git a/app/Constants/FileDriveConstant.php b/app/Constants/FileDriveConstant.php new file mode 100644 index 0000000..b7b8eef --- /dev/null +++ b/app/Constants/FileDriveConstant.php @@ -0,0 +1,10 @@ +request->inputs(['article_id']); + + $this->validate($params, [ + 'article_id' => 'required|integer|min:0' + ]); + + $file = $this->request->file('annex'); + if (!$file || !$file->isValid()) { + return $this->response->fail('上传文件验证失败!'); + } + + $annex = [ + 'suffix' => pathinfo($file->getClientFilename(), PATHINFO_EXTENSION), + 'size' => $file->getSize(), + 'path' => '', + 'drive' => FileDriveConstant::Local, + 'original_name' => $file->getClientFilename() + ]; + + $annex['path'] = 'private/files/notes/' . date('Ymd') . '/' . "[{$annex['suffix']}]" . create_random_filename('tmp'); + + try { + $filesystem->write($annex['path'], file_get_contents($file->getRealPath())); + } catch (\Exception $e) { + return $this->response->fail(); + } + + $annex['id'] = $this->articleService->insertArticleAnnex($this->uid(), (int)$params['article_id'], $annex); + + if (!$annex['id']) { + return $this->response->fail('附件上传失败,请稍后再试!'); + } + + return $this->response->success($annex); + } + + /** + * 删除附件 + * + * @RequestMapping(path="delete", methods="post") + */ + public function delete(): ResponseInterface + { + $params = $this->request->inputs(['annex_id']); + + $this->validate($params, [ + 'annex_id' => 'required|integer|min:0' + ]); + + $isTrue = $this->articleService->updateArticleAnnexStatus($this->uid(), (int)$params['annex_id'], 2); + + return $isTrue ? $this->response->success() : $this->response->fail(); + } + + /** + * 恢复已删除附件 + * + * @RequestMapping(path="recover", methods="post") + */ + public function recover(): ResponseInterface + { + $params = $this->request->inputs(['annex_id']); + + $this->validate($params, [ + 'annex_id' => 'required|integer|min:0' + ]); + + $isTrue = $this->articleService->updateArticleAnnexStatus($this->uid(), (int)$params['annex_id'], 1); + + return $isTrue ? $this->response->success() : $this->response->fail(); + } + + /** + * 附件回收站列表 + * + * @RequestMapping(path="recover/list", methods="get") + * + * @return \Psr\Http\Message\ResponseInterface + */ + public function recoverList(): ResponseInterface + { + $rows = $this->articleService->recoverAnnexList($this->uid()); + + if ($rows) { + $getDay = function ($delete_at) { + $last_time = strtotime('+30 days', strtotime($delete_at)); + return (time() > $last_time) ? 0 : DateHelper::diff(date('Y-m-d', $last_time), date('Y-m-d')); + }; + + array_walk($rows, function (&$item) use ($getDay) { + $item['day'] = $getDay($item['deleted_at']); + $item['visible'] = false; + }); + } + + return $this->response->success(['rows' => $rows]); + } + + /** + * 永久删除附件 + * + * @RequestMapping(path="forever/delete", methods="post") + * + * @return \Psr\Http\Message\ResponseInterface + * @throws \Exception + */ + public function foreverDelete(): ResponseInterface + { + $params = $this->request->inputs(['annex_id']); + + $this->validate($params, [ + 'annex_id' => 'required|integer|min:0' + ]); + + $isTrue = $this->articleService->foreverDelAnnex($this->uid(), (int)$params['annex_id']); + + return $isTrue ? $this->response->success() : $this->response->fail(); + } + + /** + * 下载附件 + * + * @RequestMapping(path="download", methods="get") + */ + public function download(\Hyperf\HttpServer\Contract\ResponseInterface $response, Filesystem $filesystem) + { + $params = $this->request->inputs(['annex_id']); + + $this->validate($params, [ + 'annex_id' => 'required|integer' + ]); + + /** @var ArticleAnnex $info */ + $info = ArticleAnnex::select(['path', 'original_name'])->where('id', $params['annex_id'])->where('user_id', $this->uid())->first(); + + if (!$info || !$filesystem->has($info->path)) { + return $this->response->fail('文件不存在或没有下载权限!'); + } + + switch ($info->drive) { + case FileDriveConstant::Local: + return $response->download($this->getFilePath($info->path), $info->original_name); + case FileDriveConstant::Cos: + // 后期添加 + break; + default: + break; + } + } + + private function getFilePath(string $path) + { + return di()->get(Filesystem::class)->getConfig()->get('root') . '/' . $path; + } +} diff --git a/app/Controller/Api/V1/Article/ArticleController.php b/app/Controller/Api/V1/Article/ArticleController.php new file mode 100644 index 0000000..98e7cf3 --- /dev/null +++ b/app/Controller/Api/V1/Article/ArticleController.php @@ -0,0 +1,275 @@ +request->inputs(['keyword', 'find_type', 'cid', 'page']); + + $this->validate($params1, [ + // 搜索关键词 + 'keyword' => "present", + // 查询类型 $findType 1:获取近期日记 2:获取星标日记 3:获取指定分类文章 4:获取指定标签文章 5:获取已删除文章 6:关键词搜索 + 'find_type' => 'required|in:0,1,2,3,4,5,6', + // 分类ID + 'cid' => 'present|integer|min:-1', + 'page' => 'present|integer|min:1' + ]); + + $params = []; + $params['find_type'] = $params1['find_type']; + if (in_array($params1['find_type'], [3, 4])) { + $params['class_id'] = $params1['cid']; + } + + if (!empty($params1['keyword'])) { + $params['keyword'] = $params1['keyword']; + } + + return $this->response->success( + $this->articleService->getUserArticleList($this->uid(), 1, 10000, $params) + ); + } + + /** + * 获取笔记详情 + * + * @RequestMapping(path="detail", methods="get") + */ + public function detail(): ResponseInterface + { + $params = $this->request->inputs(['article_id']); + + $this->validate($params, [ + 'article_id' => 'required|integer' + ]); + + return $this->response->success( + $this->articleService->getArticleDetail((int)$params['article_id'], $this->uid()) + ); + } + + /** + * 添加或编辑笔记 + * + * @RequestMapping(path="editor", methods="post") + */ + public function editor(): ResponseInterface + { + $params = $this->request->all(); + + $this->validate($params, [ + 'article_id' => 'required|integer|min:0', + 'class_id' => 'required|integer|min:0', + 'title' => 'required|max:255', + 'content' => 'required', + 'md_content' => 'required' + ]); + + $id = $this->articleService->editArticle($this->uid(), (int)$params['article_id'], [ + 'title' => $params['title'], + 'abstract' => mb_substr(strip_tags($params['content']), 0, 200), + 'class_id' => $params['class_id'], + 'image' => StringHelper::getHtmlImage($params['content']), + 'md_content' => htmlspecialchars($params['md_content']), + 'content' => htmlspecialchars($params['content']) + ]); + + return $id ? $this->response->success(['aid' => $id], '笔记编辑成功...') : $this->response->fail(); + } + + /** + * 删除笔记 + * + * @RequestMapping(path="delete", methods="post") + */ + public function delete(): ResponseInterface + { + $params = $this->request->inputs(['article_id']); + + $this->validate($params, [ + 'article_id' => 'required|integer|min:0' + ]); + + $isTrue = $this->articleService->updateArticleStatus($this->uid(), (int)$params['article_id'], 2); + + return $isTrue ? $this->response->success() : $this->response->fail(); + } + + /** + * 恢复删除笔记 + * + * @RequestMapping(path="recover", methods="post") + */ + public function recover(): ResponseInterface + { + $params = $this->request->inputs(['article_id']); + + $this->validate($params, [ + 'article_id' => 'required|integer|min:0' + ]); + + $isTrue = $this->articleService->updateArticleStatus($this->uid(), (int)$params['article_id'], 1); + + return $isTrue ? $this->response->success() : $this->response->fail(); + } + + /** + * 笔记图片上传接口 + * + * @RequestMapping(path="upload/image", methods="post") + * @param Filesystem $filesystem + * @return ResponseInterface + */ + public function upload(Filesystem $filesystem): ResponseInterface + { + $file = $this->request->file('image'); + + if (!$file || !$file->isValid()) { + return $this->response->fail(); + } + + $ext = $file->getExtension(); + if (!in_array($ext, ['jpg', 'png', 'jpeg', 'gif', 'webp'])) { + return $this->response->fail('图片格式错误,目前仅支持jpg、png、jpeg、gif和webp'); + } + + try { + $path = 'public/media/images/notes/' . date('Ymd') . '/' . create_image_name($ext, getimagesize($file->getRealPath())); + $filesystem->write($path, file_get_contents($file->getRealPath())); + } catch (\Exception $e) { + return $this->response->fail(); + } + + return $this->response->success(['url' => get_media_url($path)]); + } + + /** + * 移动笔记至指定分类 + * + * @RequestMapping(path="move", methods="post") + */ + public function move(): ResponseInterface + { + $params = $this->request->inputs(['article_id', 'class_id']); + + $this->validate($params, [ + 'article_id' => 'required|integer|min:0', + 'class_id' => 'required|integer|min:0' + ]); + + $isTrue = $this->articleService->moveArticle($this->uid(), $params['article_id'], $params['class_id']); + + return $isTrue ? $this->response->success() : $this->response->fail(); + } + + /** + * 笔记标记星号接口 + * + * @RequestMapping(path="asterisk", methods="post") + */ + public function asterisk(): ResponseInterface + { + $params = $this->request->inputs(['article_id', 'type']); + + $this->validate($params, [ + 'article_id' => 'required|integer|min:0', + 'type' => 'required|in:1,2' + ]); + + $isTrue = $this->articleService->setAsteriskArticle($this->uid(), (int)$params['article_id'], (int)$params['type']); + + return $isTrue ? $this->response->success() : $this->response->fail(); + } + + /** + * 更新笔记关联标签ID + * + * @RequestMapping(path="tag", methods="post") + */ + public function tag(): ResponseInterface + { + $params = $this->request->inputs(['article_id', 'tags']); + + $this->validate($params, [ + 'article_id' => 'required|integer|min:0', + 'tags' => 'present|array' + ]); + + $isTrue = $this->articleService->updateArticleTag($this->uid(), (int)$params['article_id'], $params['tags']); + + return $isTrue ? $this->response->success() : $this->response->fail(); + } + + /** + * 永久删除笔记文章 + * + * @RequestMapping(path="forever/delete", methods="post") + * @return ResponseInterface + * @throws \Exception + */ + public function foreverDelete(): ResponseInterface + { + $params = $this->request->inputs(['article_id']); + + $this->validate($params, [ + 'article_id' => 'required|integer|min:0' + ]); + + $isTrue = $this->articleService->foreverDelArticle($this->uid(), (int)$params['article_id']); + + return $isTrue ? $this->response->success() : $this->response->fail(); + } + + /** + * 笔记分类合并接口 + * + * @RequestMapping(path="merge", methods="post") + */ + public function merge(): ResponseInterface + { + $params = $this->request->inputs(['class_id', 'toid']); + + $this->validate($params, [ + 'class_id' => 'required|integer', + 'toid' => 'required|integer' + ]); + + $isTrue = $this->articleService->mergeArticleClass($this->uid(), (int)$params['class_id'], (int)$params['toid']); + + return $isTrue ? $this->response->success() : $this->response->fail(); + } +} diff --git a/app/Controller/Api/V1/Article/ClassController.php b/app/Controller/Api/V1/Article/ClassController.php new file mode 100644 index 0000000..e451cf3 --- /dev/null +++ b/app/Controller/Api/V1/Article/ClassController.php @@ -0,0 +1,123 @@ +articleService->getUserClass($this->uid()); + + foreach ($rows as &$row) { + $row['count'] = is_null($row['count']) ? 0 : $row['count']; + } + + return $this->response->success(['rows' => $rows]); + } + + /** + * 编辑分类 + * + * @RequestMapping(path="editor", methods="post") + * + * @return \Psr\Http\Message\ResponseInterface + */ + public function editor(): ResponseInterface + { + $params = $this->request->inputs(['class_id', 'class_name']); + + $this->validate($params, [ + 'class_id' => 'required|integer', + 'class_name' => 'required|max:20' + ]); + + $class_id = $this->articleService->editArticleClass($this->uid(), $params['class_id'], $params['class_name']); + if (!$class_id) { + return $this->response->fail('笔记分类编辑失败!'); + } + + return $this->response->success(['id' => $class_id]); + } + + /** + * 删除分类 + * + * @RequestMapping(path="delete", methods="post") + * + * @return \Psr\Http\Message\ResponseInterface + * @throws \Exception + */ + public function delete(): ResponseInterface + { + $params = $this->request->inputs(['class_id']); + + $this->validate($params, [ + 'class_id' => 'required|integer' + ]); + + $isTrue = $this->articleService->delArticleClass($this->uid(), (int)$params['class_id']); + + return $isTrue ? $this->response->success() : $this->response->fail(); + } + + /** + * 笔记分类列表排序接口 + * + * @RequestMapping(path="sort", methods="post") + * @return ResponseInterface + * @throws \Exception + */ + public function sort(): ResponseInterface + { + $params = $this->request->inputs(['class_id', 'sort_type']); + + $this->validate($params, [ + 'class_id' => 'required|integer', + 'sort_type' => 'required|in:1,2' + ]); + + $lockKey = "article:sort_{$params['class_id']}_{$params['sort_type']}"; + + $lock = LockRedis::getInstance(); + + if ($lock->lock($lockKey, 3, 500)) { + $isTrue = $this->articleService->articleClassSort($this->uid(), (int)$params['class_id'], (int)$params['sort_type']); + + $lock->delete($lockKey); + } else { + $isTrue = false; + } + + return $isTrue ? $this->response->success() : $this->response->fail(); + } +} diff --git a/app/Controller/Api/V1/Article/TagController.php b/app/Controller/Api/V1/Article/TagController.php new file mode 100644 index 0000000..57a1e5b --- /dev/null +++ b/app/Controller/Api/V1/Article/TagController.php @@ -0,0 +1,79 @@ +response->success([ + 'tags' => $this->articleService->getUserTags($this->uid()) + ]); + } + + /** + * 编辑标签 + * + * @RequestMapping(path="editor", methods="post") + */ + public function editor(): ResponseInterface + { + $params = $this->request->inputs(['tag_id', 'tag_name']); + + $this->validate($params, [ + 'tag_id' => 'required|integer|min:0', + 'tag_name' => 'required|max:20' + ]); + + $id = $this->articleService->editArticleTag($this->uid(), (int)$params['tag_id'], $params['tag_name']); + + return $id ? $this->response->success(['id' => $id]) : $this->response->fail(); + } + + /** + * 删除标签 + * + * @RequestMapping(path="delete", methods="post") + */ + public function delete(): ResponseInterface + { + $params = $this->request->inputs(['tag_id']); + + $this->validate($params, [ + 'tag_id' => 'required|integer|min:0' + ]); + + $isTrue = $this->articleService->delArticleTags($this->uid(), (int)$params['tag_id']); + + return $isTrue ? $this->response->success() : $this->response->fail(); + } +} diff --git a/app/Controller/Api/V1/ArticleController.php b/app/Controller/Api/V1/ArticleController.php deleted file mode 100644 index c4b08a4..0000000 --- a/app/Controller/Api/V1/ArticleController.php +++ /dev/null @@ -1,553 +0,0 @@ -articleService->getUserClass($this->uid()); - foreach ($rows as &$row) { - $row['count'] = is_null($row['count']) ? 0 : $row['count']; - } - - return $this->response->success(['rows' => $rows]); - } - - /** - * 获取笔记标签列表 - * - * @RequestMapping(path="tags", methods="get") - */ - public function getArticleTags(): ResponseInterface - { - return $this->response->success([ - 'tags' => $this->articleService->getUserTags($this->uid()) - ]); - } - - /** - * 获取笔记列表 - * - * @RequestMapping(path="search", methods="get") - */ - public function getArticleList(): ResponseInterface - { - $params1 = $this->request->inputs(['keyword', 'find_type', 'cid', 'page']); - $this->validate($params1, [ - // 搜索关键词 - 'keyword' => "present", - // 查询类型 $findType 1:获取近期日记 2:获取星标日记 3:获取指定分类文章 4:获取指定标签文章 5:获取已删除文章 6:关键词搜索 - 'find_type' => 'required|in:0,1,2,3,4,5,6', - // 分类ID - 'cid' => 'present|integer|min:-1', - 'page' => 'present|integer|min:1' - ]); - - $params = []; - $params['find_type'] = $params1['find_type']; - if (in_array($params1['find_type'], [3, 4])) { - $params['class_id'] = $params1['cid']; - } - - if (!empty($params1['keyword'])) { - $params['keyword'] = $params1['keyword']; - } - - return $this->response->success( - $this->articleService->getUserArticleList($this->uid(), 1, 10000, $params) - ); - } - - /** - * 获取笔记详情 - * - * @RequestMapping(path="detail", methods="get") - */ - public function getArticleDetail(): ResponseInterface - { - $params = $this->request->inputs(['article_id']); - $this->validate($params, [ - 'article_id' => 'required|integer' - ]); - - return $this->response->success( - $this->articleService->getArticleDetail((int)$params['article_id'], $this->uid()) - ); - } - - /** - * 添加或编辑笔记分类 - * - * @RequestMapping(path="classify/editor", methods="post") - */ - public function editArticleClass(): ResponseInterface - { - $params = $this->request->inputs(['class_id', 'class_name']); - $this->validate($params, [ - 'class_id' => 'required|integer', - 'class_name' => 'required|max:20' - ]); - - $class_id = $this->articleService->editArticleClass($this->uid(), $params['class_id'], $params['class_name']); - if (!$class_id) { - return $this->response->fail('笔记分类编辑失败!'); - } - - return $this->response->success(['id' => $class_id]); - } - - /** - * 删除笔记分类 - * - * @RequestMapping(path="classify/delete", methods="post") - * @return ResponseInterface - * @throws \Exception - */ - public function delArticleClass(): ResponseInterface - { - $params = $this->request->inputs(['class_id']); - $this->validate($params, [ - 'class_id' => 'required|integer' - ]); - - if (!$this->articleService->delArticleClass($this->uid(), (int)$params['class_id'])) { - return $this->response->fail('笔记分类删除失败!'); - } - - return $this->response->success([], '笔记分类删除成功...'); - } - - /** - * 笔记分类列表排序接口 - * - * @RequestMapping(path="classify/sort", methods="post") - * @return ResponseInterface - * @throws \Exception - */ - public function articleClassSort(): ResponseInterface - { - $params = $this->request->inputs(['class_id', 'sort_type']); - $this->validate($params, [ - 'class_id' => 'required|integer', - 'sort_type' => 'required|in:1,2' - ]); - - $lockKey = "article:sort_{$params['class_id']}_{$params['sort_type']}"; - - $lock = LockRedis::getInstance(); - if ($lock->lock($lockKey, 3, 500)) { - $isTrue = $this->articleService->articleClassSort($this->uid(), (int)$params['class_id'], (int)$params['sort_type']); - - $lock->delete($lockKey); - } else { - $isTrue = false; - } - - return $isTrue - ? $this->response->success([], '排序完成...') - : $this->response->fail('排序失败!'); - } - - /** - * 笔记分类合并接口 - * - * @RequestMapping(path="classify/merge", methods="post") - */ - public function mergeArticleClass(): ResponseInterface - { - $params = $this->request->inputs(['class_id', 'toid']); - $this->validate($params, [ - 'class_id' => 'required|integer', - 'toid' => 'required|integer' - ]); - - $isTrue = $this->articleService->mergeArticleClass($this->uid(), (int)$params['class_id'], (int)$params['toid']); - - return $isTrue - ? $this->response->success([], '合并完成...') - : $this->response->fail('合并失败!'); - } - - /** - * 添加或编辑笔记标签 - * - * @RequestMapping(path="tag/editor", methods="post") - */ - public function editArticleTags(): ResponseInterface - { - $params = $this->request->inputs(['tag_id', 'tag_name']); - $this->validate($params, [ - 'tag_id' => 'required|integer|min:0', - 'tag_name' => 'required|max:20' - ]); - - $id = $this->articleService->editArticleTag($this->uid(), (int)$params['tag_id'], $params['tag_name']); - - return $id - ? $this->response->success(['id' => $id]) - : $this->response->fail('笔记标签编辑失败!'); - } - - /** - * 删除笔记标签 - * - * @RequestMapping(path="del-article-tag", methods="post") - */ - public function delArticleTags(): ResponseInterface - { - $params = $this->request->inputs(['tag_id']); - $this->validate($params, [ - 'tag_id' => 'required|integer|min:0' - ]); - - $isTrue = $this->articleService->delArticleTags($this->uid(), (int)$params['tag_id']); - - return $isTrue - ? $this->response->success([], '笔记标签删除完成...') - : $this->response->fail('笔记标签删除失败!'); - } - - /** - * 添加或编辑笔记 - * - * @RequestMapping(path="editor", methods="post") - */ - public function editArticle(): ResponseInterface - { - $params = $this->request->all(); - $this->validate($params, [ - 'article_id' => 'required|integer|min:0', - 'class_id' => 'required|integer|min:0', - 'title' => 'required|max:255', - 'content' => 'required', - 'md_content' => 'required' - ]); - - $id = $this->articleService->editArticle($this->uid(), (int)$params['article_id'], [ - 'title' => $params['title'], - 'abstract' => mb_substr(strip_tags($params['content']), 0, 200), - 'class_id' => $params['class_id'], - 'image' => StringHelper::getHtmlImage($params['content']), - 'md_content' => htmlspecialchars($params['md_content']), - 'content' => htmlspecialchars($params['content']) - ]); - - return $id - ? $this->response->success(['aid' => $id], '笔记编辑成功...') - : $this->response->fail('笔记编辑失败!', ['id' => null]); - } - - /** - * 删除笔记 - * - * @RequestMapping(path="delete", methods="post") - */ - public function deleteArticle(): ResponseInterface - { - $params = $this->request->inputs(['article_id']); - $this->validate($params, [ - 'article_id' => 'required|integer|min:0' - ]); - - $isTrue = $this->articleService->updateArticleStatus($this->uid(), (int)$params['article_id'], 2); - - return $isTrue - ? $this->response->success([], '笔记删除成功...') - : $this->response->fail('笔记删除失败!'); - } - - /** - * 恢复删除笔记 - * - * @RequestMapping(path="recover", methods="post") - */ - public function recoverArticle(): ResponseInterface - { - $params = $this->request->inputs(['article_id']); - $this->validate($params, [ - 'article_id' => 'required|integer|min:0' - ]); - - $isTrue = $this->articleService->updateArticleStatus($this->uid(), (int)$params['article_id'], 1); - - return $isTrue - ? $this->response->success([], '笔记恢复成功...') - : $this->response->fail('笔记恢复失败!'); - } - - /** - * 笔记图片上传接口 - * - * @RequestMapping(path="upload-image", methods="post") - * @param Filesystem $filesystem - * @return ResponseInterface - */ - public function uploadArticleImage(Filesystem $filesystem): ResponseInterface - { - $file = $this->request->file('image'); - if (!$file || !$file->isValid()) { - return $this->response->fail(); - } - - $ext = $file->getExtension(); - if (!in_array($ext, ['jpg', 'png', 'jpeg', 'gif', 'webp'])) { - return $this->response->fail('图片格式错误,目前仅支持jpg、png、jpeg、gif和webp'); - } - - try { - $path = 'media/images/notes/' . date('Ymd') . '/' . create_image_name($ext, getimagesize($file->getRealPath())); - $filesystem->write($path, file_get_contents($file->getRealPath())); - } catch (\Exception $e) { - return $this->response->fail(); - } - - return $this->response->success([ - 'save_path' => get_media_url($path) - ]); - } - - /** - * 移动笔记至指定分类 - * - * @RequestMapping(path="move", methods="post") - */ - public function moveArticle(): ResponseInterface - { - $params = $this->request->inputs(['article_id', 'class_id']); - $this->validate($params, [ - 'article_id' => 'required|integer|min:0', - 'class_id' => 'required|integer|min:0' - ]); - - $isTrue = $this->articleService->moveArticle( - $this->uid(), - $params['article_id'], - $params['class_id'] - ); - - return $isTrue - ? $this->response->success([], '笔记移动成功...') - : $this->response->fail('笔记移动失败!'); - } - - /** - * 笔记标记星号接口 - * - * @RequestMapping(path="asterisk", methods="post") - */ - public function setAsterisk(): ResponseInterface - { - $params = $this->request->inputs(['article_id', 'type']); - $this->validate($params, [ - 'article_id' => 'required|integer|min:0', - 'type' => 'required|in:1,2' - ]); - - $isTrue = $this->articleService->setAsteriskArticle( - $this->uid(), - (int)$params['article_id'], - (int)$params['type'] - ); - - return $isTrue - ? $this->response->success([], '笔记标记成功...') - : $this->response->fail('笔记标记失败!'); - } - - /** - * 更新笔记关联标签ID - * - * @RequestMapping(path="update-tag", methods="post") - */ - public function updateArticleTag(): ResponseInterface - { - $params = $this->request->inputs(['article_id', 'tags']); - $this->validate($params, [ - 'article_id' => 'required|integer|min:0', - 'tags' => 'present|array' - ]); - - $isTrue = $this->articleService->updateArticleTag($this->uid(), (int)$params['article_id'], $params['tags']); - - return $isTrue - ? $this->response->success([], 'success...') - : $this->response->fail('编辑失败!'); - } - - /** - * 永久删除笔记文章 - * - * @RequestMapping(path="forever-delete", methods="post") - * @return ResponseInterface - * @throws \Exception - */ - public function foreverDelArticle(): ResponseInterface - { - $params = $this->request->inputs(['article_id']); - $this->validate($params, [ - 'article_id' => 'required|integer|min:0' - ]); - - $isTrue = $this->articleService->foreverDelArticle($this->uid(), (int)$params['article_id']); - - return $isTrue - ? $this->response->success([], '笔记删除成功...') - : $this->response->fail('笔记删除失败!'); - } - - /** - * 上传笔记附件 - * - * @RequestMapping(path="annex/upload", methods="post") - * @param Filesystem $filesystem - * @return ResponseInterface - */ - public function uploadArticleAnnex(Filesystem $filesystem): ResponseInterface - { - $params = $this->request->inputs(['article_id']); - $this->validate($params, [ - 'article_id' => 'required|integer|min:0' - ]); - - $file = $this->request->file('annex'); - if (!$file || !$file->isValid()) { - return $this->response->fail('上传文件验证失败!'); - } - - $annex = [ - 'file_suffix' => pathinfo($file->getClientFilename(), PATHINFO_EXTENSION), - 'file_size' => $file->getSize(), - 'save_dir' => '', - 'original_name' => $file->getClientFilename() - ]; - - try { - $path = 'files/notes/' . date('Ymd') . '/' . "[{$annex['file_suffix']}]" . create_random_filename('tmp'); - $filesystem->write($path, file_get_contents($file->getRealPath())); - } catch (\Exception $e) { - return $this->response->fail(); - } - - $annex['save_dir'] = $path; - $annex['id'] = $this->articleService->insertArticleAnnex($this->uid(), (int)$params['article_id'], $annex); - - if (!$annex['id']) { - return $this->response->fail('附件上传失败,请稍后再试!'); - } - - return $this->response->success($annex, '笔记附件上传成功...'); - } - - /** - * 删除笔记附件 - * - * @RequestMapping(path="annex/delete", methods="post") - */ - public function deleteArticleAnnex(): ResponseInterface - { - $params = $this->request->inputs(['annex_id']); - $this->validate($params, [ - 'annex_id' => 'required|integer|min:0' - ]); - - $isTrue = $this->articleService->updateArticleAnnexStatus($this->uid(), (int)$params['annex_id'], 2); - - return $isTrue - ? $this->response->success([], '笔记附件删除成功...') - : $this->response->fail('笔记附件删除失败!'); - } - - /** - * 恢复笔记附件 - * - * @RequestMapping(path="annex/recover", methods="post") - */ - public function recoverArticleAnnex(): ResponseInterface - { - $params = $this->request->inputs(['annex_id']); - $this->validate($params, [ - 'annex_id' => 'required|integer|min:0' - ]); - - $isTrue = $this->articleService->updateArticleAnnexStatus($this->uid(), (int)$params['annex_id'], 1); - - return $isTrue - ? $this->response->success([], '笔记附件恢复成功...') - : $this->response->fail('笔记附件恢复失败!'); - } - - /** - * 获取附件回收站列表 - * - * @RequestMapping(path="annex/recover-list", methods="get") - */ - public function recoverAnnexList(): ResponseInterface - { - $rows = $this->articleService->recoverAnnexList($this->uid()); - if ($rows) { - $getDay = function ($delete_at) { - $last_time = strtotime('+30 days', strtotime($delete_at)); - return (time() > $last_time) ? 0 : DateHelper::diff(date('Y-m-d', $last_time), date('Y-m-d')); - }; - - array_walk($rows, function (&$item) use ($getDay) { - $item['day'] = $getDay($item['deleted_at']); - $item['visible'] = false; - }); - } - - return $this->response->success(['rows' => $rows]); - } - - /** - * 永久删除笔记附件(从已删除附件中永久删除) - * - * @RequestMapping(path="annex/forever-delete", methods="post") - * @return ResponseInterface - * @throws \Exception - */ - public function foreverDelAnnex(): ResponseInterface - { - $params = $this->request->inputs(['annex_id']); - $this->validate($params, [ - 'annex_id' => 'required|integer|min:0' - ]); - - $isTrue = $this->articleService->foreverDelAnnex($this->uid(), (int)$params['annex_id']); - - return $isTrue - ? $this->response->success([], '笔记附件删除成功...') - : $this->response->fail('笔记附件删除失败!'); - } -} diff --git a/app/Controller/Api/V1/AuthController.php b/app/Controller/Api/V1/AuthController.php index c077a21..d6c2563 100644 --- a/app/Controller/Api/V1/AuthController.php +++ b/app/Controller/Api/V1/AuthController.php @@ -58,18 +58,9 @@ class AuthController extends CController event()->dispatch(new LoginEvent($this->request, $user)); return $this->response->success([ - 'authorize' => [ - 'type' => 'Bearer', - 'access_token' => $token, - 'expires_in' => $this->guard()->getJwtManager()->getTtl(), - ], - 'user_info' => [ - 'nickname' => $user->nickname, - 'avatar' => $user->avatar, - 'gender' => $user->gender, - 'motto' => $user->motto, - 'email' => $user->email, - ] + 'type' => 'Bearer', + 'access_token' => $token, + 'expires_in' => $this->guard()->getJwtManager()->getTtl(), ], '账号登录成功...'); } diff --git a/app/Controller/Api/V1/CommonController.php b/app/Controller/Api/V1/CommonController.php new file mode 100644 index 0000000..991cca7 --- /dev/null +++ b/app/Controller/Api/V1/CommonController.php @@ -0,0 +1,28 @@ +service->getApplyRecords($user_id, $page, $page_size) ); } + + /** + * 获取联系人申请未读数 + * + * @RequestMapping(path="unread-num", methods="get") + */ + public function getContactApplyUnreadNum(): ResponseInterface + { + return $this->response->success([ + 'unread_num' => (int)FriendApply::getInstance()->get(strval($this->uid())) + ]); + } } diff --git a/app/Controller/Api/V1/ContactsController.php b/app/Controller/Api/V1/Contact/ContactController.php similarity index 75% rename from app/Controller/Api/V1/ContactsController.php rename to app/Controller/Api/V1/Contact/ContactController.php index b0bde60..71d9c1b 100644 --- a/app/Controller/Api/V1/ContactsController.php +++ b/app/Controller/Api/V1/Contact/ContactController.php @@ -1,8 +1,9 @@ get(TalkListService::class)->deleteByType($user_id, $params['friend_id'], TalkModeConstant::PRIVATE_CHAT); - // TODO 推送消息(待完善) - return $this->response->success([], '好友关系解除成功...'); } - /** - * 获取联系人申请未读数 - * - * @RequestMapping(path="apply-unread-num", methods="get") - */ - public function getContactApplyUnreadNum(): ResponseInterface - { - return $this->response->success([ - 'unread_num' => (int)FriendApply::getInstance()->get(strval($this->uid())) - ]); - } - /** * 搜索联系人 * * @RequestMapping(path="search", methods="get") */ - public function searchContacts(): ResponseInterface + public function search(): ResponseInterface { $params = $this->request->inputs(['mobile']); + $this->validate($params, [ 'mobile' => "present|regex:/^1[3456789][0-9]{9}$/" ]); $result = $this->service->findContact($params['mobile']); + return $this->response->success($result); } @@ -107,9 +101,10 @@ class ContactsController extends CController * * @RequestMapping(path="edit-remark", methods="post") */ - public function editContactRemark(): ResponseInterface + public function editRemark(): ResponseInterface { $params = $this->request->inputs(['friend_id', 'remarks']); + $this->validate($params, [ 'friend_id' => 'required|integer|min:1', 'remarks' => "required|max:20" @@ -125,4 +120,23 @@ class ContactsController extends CController return $this->response->success([], '备注修改成功...'); } + + /** + * 通过用户ID查找用户 + * + * @RequestMapping(path="detail", methods="get") + * + * @return ResponseInterface + */ + public function detail(): ResponseInterface + { + $params = $this->request->inputs(['user_id']); + $this->validate($params, ['user_id' => 'required|integer']); + + if ($data = $this->userService->getUserCard($params['user_id'], $this->uid())) { + return $this->response->success($data); + } + + return $this->response->fail('用户查询失败!'); + } } diff --git a/app/Controller/Api/V1/DownloadController.php b/app/Controller/Api/V1/DownloadController.php index 442416d..9fc0c15 100644 --- a/app/Controller/Api/V1/DownloadController.php +++ b/app/Controller/Api/V1/DownloadController.php @@ -70,31 +70,4 @@ class DownloadController extends CController return $response->download($this->getFilePath($info->save_dir), $info->original_name); } - - /** - * 下载笔记附件 - * @RequestMapping(path="article-annex", methods="get") - * - * @param ResponseInterface $response - * @param Filesystem $filesystem - * @return \Psr\Http\Message\ResponseInterface - */ - public function articleAnnex(ResponseInterface $response, Filesystem $filesystem) - { - $params = $this->request->inputs(['annex_id']); - $this->validate($params, [ - 'annex_id' => 'required|integer' - ]); - - $info = ArticleAnnex::select(['save_dir', 'original_name']) - ->where('id', $params['annex_id']) - ->where('user_id', $this->uid()) - ->first(); - - if (!$info || !$filesystem->has($info->save_dir)) { - return $this->response->fail('文件不存在或没有下载权限!'); - } - - return $response->download($this->getFilePath($info->save_dir), $info->original_name); - } } diff --git a/app/Controller/Api/V1/Group/GroupController.php b/app/Controller/Api/V1/Group/GroupController.php new file mode 100644 index 0000000..e6ae4cc --- /dev/null +++ b/app/Controller/Api/V1/Group/GroupController.php @@ -0,0 +1,78 @@ +response->success([ + "rows" => $this->groupService->getUserGroups($this->uid()), + ]); + } + + // public function Detail() + // { + // + // } + // + // public function Create() + // { + // + // } + // + // public function Dismiss() + // { + // + // } + // + // public function Invite() + // { + // + // } + // + // public function SignOut() + // { + // + // } + // + // public function Setting() + // { + // + // } +} diff --git a/app/Controller/Api/V1/Group/MemberController.php b/app/Controller/Api/V1/Group/MemberController.php new file mode 100644 index 0000000..49ed922 --- /dev/null +++ b/app/Controller/Api/V1/Group/MemberController.php @@ -0,0 +1,142 @@ +uid(); + $group_id = (int)$this->request->input('group_id', 0); + + // 判断用户是否是群成员 + if (!$this->groupMemberService->isMember($group_id, $user_id)) { + return $this->response->fail('非法操作!'); + } + + $members = GroupMember::select([ + 'group_member.id', + 'group_member.leader', + 'group_member.user_card', + 'group_member.user_id', + 'users.avatar', + 'users.nickname', + 'users.gender', + 'users.motto', + ]) + ->leftJoin('users', 'users.id', '=', 'group_member.user_id') + ->where([ + ['group_member.group_id', '=', $group_id], + ['group_member.is_quit', '=', 0], + ])->orderBy('leader', 'desc')->get()->toArray(); + + return $this->response->success($members); + } + + /** + * 获取可邀请加入群组的好友列表 + * + * @RequestMapping(path="invites", methods="get") + */ + public function invites(UserService $service): ResponseInterface + { + $group_id = (int)$this->request->input('group_id', 0); + + $friends = $service->getUserFriends($this->uid()); + + if ($group_id > 0 && $friends) { + if ($ids = $this->groupMemberService->getMemberIds($group_id)) { + foreach ($friends as $k => $item) { + if (in_array($item['id'], $ids)) unset($friends[$k]); + } + } + + $friends = array_values($friends); + } + + return $this->response->success($friends); + } + + + /** + * 移除指定成员(管理员权限) + * + * @RequestMapping(path="remove", methods="post") + */ + public function removeMembers(): ResponseInterface + { + $params = $this->request->inputs(['group_id', 'members_ids']); + $this->validate($params, [ + 'group_id' => 'required|integer', + 'members_ids' => 'required|ids' + ]); + + $params['members_ids'] = parse_ids($params['members_ids']); + + $user_id = $this->uid(); + if (in_array($user_id, $params['members_ids'])) { + return $this->response->fail('群聊用户移除失败!'); + } + + $isTrue = $this->groupService->removeMember(intval($params['group_id']), $user_id, $params['members_ids']); + if (!$isTrue) { + return $this->response->fail('群聊用户移除失败!'); + } + + return $this->response->success([], '已成功退出群组...'); + } + + /** + * 设置群名片 + * @RequestMapping(path="remark", methods="post") + */ + public function remark(): ResponseInterface + { + $params = $this->request->inputs(['group_id', 'visit_card']); + $this->validate($params, [ + 'group_id' => 'required|integer', + 'visit_card' => 'required|max:20' + ]); + + $isTrue = $this->groupService->updateMemberCard(intval($params['group_id']), $this->uid(), $params['visit_card']); + + return $isTrue ? $this->response->success([], '群名片修改成功...') : $this->response->fail('群名片修改失败!'); + } +} diff --git a/app/Controller/Api/V1/Group/NoticeController.php b/app/Controller/Api/V1/Group/NoticeController.php new file mode 100644 index 0000000..8484a82 --- /dev/null +++ b/app/Controller/Api/V1/Group/NoticeController.php @@ -0,0 +1,121 @@ +uid(); + $group_id = (int)$this->request->input('group_id', 0); + + // 判断用户是否是群成员 + if (!$this->groupMemberService->isMember($group_id, $user_id)) { + return $this->response->fail('非管理员禁止操作!'); + } + + return $this->response->success([ + "rows" => $service->lists($group_id) + ]); + } + + /** + * 创建/编辑群公告 + * @RequestMapping(path="edit", methods="post") + */ + public function edit(GroupNoticeService $service): ResponseInterface + { + $params = $this->request->inputs([ + 'group_id', 'notice_id', 'title', 'content', 'is_top', 'is_confirm' + ]); + + $this->validate($params, [ + 'notice_id' => 'required|integer', + 'group_id' => 'required|integer', + 'title' => 'required|max:50', + 'is_top' => 'integer|in:0,1', + 'is_confirm' => 'integer|in:0,1', + 'content' => 'required' + ]); + + $user_id = $this->uid(); + + // 判断用户是否是管理员 + if (!$this->groupMemberService->isAuth(intval($params['group_id']), $user_id)) { + return $this->response->fail('非管理员禁止操作!'); + } + + // 判断是否是新增数据 + if (empty($params['notice_id'])) { + if (!$service->create($user_id, $params)) { + return $this->response->fail('添加群公告信息失败!'); + } + + return $this->response->success([], '添加群公告信息成功...'); + } + + return $service->update($params) + ? $this->response->success([], '修改群公告信息成功...') + : $this->response->fail('修改群公告信息失败!'); + } + + /** + * 删除群公告 + * + * @RequestMapping(path="delete", methods="post") + */ + public function delete(GroupNoticeService $service): ResponseInterface + { + $params = $this->request->inputs(['group_id', 'notice_id']); + + $this->validate($params, [ + 'group_id' => 'required|integer', + 'notice_id' => 'required|integer' + ]); + + try { + $isTrue = $service->delete(intval($params['notice_id']), $this->uid()); + } catch (\Exception $e) { + return $this->response->fail($e->getMessage()); + } + + return $isTrue ? $this->response->success([], '公告删除成功...') : $this->response->fail('公告删除失败!'); + } +} diff --git a/app/Controller/Api/V1/GroupController.php b/app/Controller/Api/V1/GroupController.php index 21c5c43..932d886 100644 --- a/app/Controller/Api/V1/GroupController.php +++ b/app/Controller/Api/V1/GroupController.php @@ -6,17 +6,14 @@ use App\Constants\TalkModeConstant; use App\Service\Group\GroupMemberService; use App\Service\TalkListService; -use App\Service\UserService; use Hyperf\Di\Annotation\Inject; use Hyperf\HttpServer\Annotation\Controller; use Hyperf\HttpServer\Annotation\RequestMapping; use Hyperf\HttpServer\Annotation\Middleware; use App\Middleware\JWTAuthMiddleware; use App\Model\Group\Group; -use App\Model\Group\GroupMember; use App\Model\Group\GroupNotice; use App\Service\Group\GroupService; -use App\Service\Group\GroupNoticeService; use Psr\Http\Message\ResponseInterface; /** @@ -141,33 +138,6 @@ class GroupController extends CController : $this->response->fail('群组信息修改失败!'); } - /** - * 移除指定成员(管理员权限) - * @RequestMapping(path="remove-members", methods="post") - */ - public function removeMembers(): ResponseInterface - { - $params = $this->request->inputs(['group_id', 'members_ids']); - $this->validate($params, [ - 'group_id' => 'required|integer', - 'members_ids' => 'required|ids' - ]); - - $params['members_ids'] = parse_ids($params['members_ids']); - - $user_id = $this->uid(); - if (in_array($user_id, $params['members_ids'])) { - return $this->response->fail('群聊用户移除失败!'); - } - - $isTrue = $this->groupService->removeMember($params['group_id'], $user_id, $params['members_ids']); - if (!$isTrue) { - return $this->response->fail('群聊用户移除失败!'); - } - - return $this->response->success([], '已成功退出群组...'); - } - /** * 获取群信息接口 * @RequestMapping(path="detail", methods="get") @@ -205,168 +175,4 @@ class GroupController extends CController 'notice' => $notice ? $notice->toArray() : [] ]); } - - /** - * 设置群名片 - * @RequestMapping(path="set-group-card", methods="post") - */ - public function editGroupCard(): ResponseInterface - { - $params = $this->request->inputs(['group_id', 'visit_card']); - $this->validate($params, [ - 'group_id' => 'required|integer', - 'visit_card' => 'required|max:20' - ]); - - $isTrue = $this->groupService->updateMemberCard($params['group_id'], $this->uid(), $params['visit_card']); - - return $isTrue - ? $this->response->success([], '群名片修改成功...') - : $this->response->error('群名片修改失败!'); - } - - /** - * 获取可邀请加入群组的好友列表 - * @RequestMapping(path="invite-friends", methods="get") - */ - public function getInviteFriends(UserService $service): ResponseInterface - { - $group_id = $this->request->input('group_id', 0); - $friends = $service->getUserFriends($this->uid()); - if ($group_id > 0 && $friends) { - if ($ids = $this->groupMemberService->getMemberIds($group_id)) { - foreach ($friends as $k => $item) { - if (in_array($item['id'], $ids)) unset($friends[$k]); - } - } - - $friends = array_values($friends); - } - - return $this->response->success($friends); - } - - /** - * 获取群组列表 - * @RequestMapping(path="list", methods="get") - */ - public function getGroups(): ResponseInterface - { - return $this->response->success( - $this->groupService->getUserGroups($this->uid()) - ); - } - - /** - * 获取群组成员列表 - * @RequestMapping(path="members", methods="get") - */ - public function getGroupMembers(): ResponseInterface - { - $user_id = $this->uid(); - $group_id = $this->request->input('group_id', 0); - - // 判断用户是否是群成员 - if (!$this->groupMemberService->isMember($group_id, $user_id)) { - return $this->response->fail('非法操作!'); - } - - $members = GroupMember::select([ - 'group_member.id', - 'group_member.leader', - 'group_member.user_card', - 'group_member.user_id', - 'users.avatar', - 'users.nickname', - 'users.gender', - 'users.motto', - ]) - ->leftJoin('users', 'users.id', '=', 'group_member.user_id') - ->where([ - ['group_member.group_id', '=', $group_id], - ['group_member.is_quit', '=', 0], - ])->orderBy('leader', 'desc')->get()->toArray(); - - return $this->response->success($members); - } - - /** - * 获取群组公告列表 - * @RequestMapping(path="notices", methods="get") - */ - public function getGroupNotice(GroupNoticeService $service): ResponseInterface - { - $user_id = $this->uid(); - $group_id = $this->request->input('group_id', 0); - - // 判断用户是否是群成员 - if (!$this->groupMemberService->isMember($group_id, $user_id)) { - return $this->response->fail('非管理员禁止操作!'); - } - - return $this->response->success($service->lists($group_id)); - } - - /** - * 创建/编辑群公告 - * @RequestMapping(path="edit-notice", methods="post") - */ - public function editNotice(GroupNoticeService $service): ResponseInterface - { - $params = $this->request->inputs([ - 'group_id', 'notice_id', 'title', 'content', 'is_top', 'is_confirm' - ]); - - $this->validate($params, [ - 'notice_id' => 'required|integer', - 'group_id' => 'required|integer', - 'title' => 'required|max:50', - 'is_top' => 'integer|in:0,1', - 'is_confirm' => 'integer|in:0,1', - 'content' => 'required' - ]); - - $user_id = $this->uid(); - - // 判断用户是否是管理员 - if (!$this->groupMemberService->isAuth($params['group_id'], $user_id)) { - return $this->response->fail('非管理员禁止操作!'); - } - - // 判断是否是新增数据 - if (empty($params['notice_id'])) { - if (!$service->create($user_id, $params)) { - return $this->response->fail('添加群公告信息失败!'); - } - - return $this->response->success([], '添加群公告信息成功...'); - } - - return $service->update($params) - ? $this->response->success([], '修改群公告信息成功...') - : $this->response->fail('修改群公告信息失败!'); - } - - /** - * 删除群公告(软删除) - * @RequestMapping(path="delete-notice", methods="post") - */ - public function deleteNotice(GroupNoticeService $service): ResponseInterface - { - $params = $this->request->inputs(['group_id', 'notice_id']); - $this->validate($params, [ - 'group_id' => 'required|integer', - 'notice_id' => 'required|integer' - ]); - - try { - $isTrue = $service->delete($params['notice_id'], $this->uid()); - } catch (\Exception $e) { - return $this->response->fail($e->getMessage()); - } - - return $isTrue - ? $this->response->success([], '公告删除成功...') - : $this->response->fail('公告删除失败!'); - } } diff --git a/app/Controller/Api/V1/UsersController.php b/app/Controller/Api/V1/UsersController.php index 882663c..de28e11 100644 --- a/app/Controller/Api/V1/UsersController.php +++ b/app/Controller/Api/V1/UsersController.php @@ -122,24 +122,6 @@ class UsersController extends CController return $this->response->success([], '头像修改成功...'); } - /** - * 通过用户ID查找用户 - * @RequestMapping(path="search-user", methods="post") - * - * @return ResponseInterface - */ - public function search(): ResponseInterface - { - $params = $this->request->inputs(['user_id']); - $this->validate($params, ['user_id' => 'required|integer']); - - if ($data = $this->userService->getUserCard($params['user_id'], $this->uid())) { - return $this->response->success($data); - } - - return $this->response->fail('用户查询失败!'); - } - /** * 修改我的密码 * @RequestMapping(path="change-password", methods="post") diff --git a/app/Controller/WebSocketController.php b/app/Controller/WebSocketController.php index f09849d..a8addad 100644 --- a/app/Controller/WebSocketController.php +++ b/app/Controller/WebSocketController.php @@ -93,11 +93,14 @@ class WebSocketController implements OnMessageInterface, OnOpenInterface, OnClos */ public function onMessage($server, Frame $frame): void { - // 判断是否为心跳检测 - if ($frame->data == 'PING') return; - $result = json_decode($frame->data, true); + // 判断是否为心跳检测 + if ($result['event'] == 'heartbeat') { + $server->push($frame->fd, json_encode(['event' => "heartbeat", 'content' => "pong"])); + return; + } + if (!isset(ReceiveHandleService::EVENTS[$result['event']])) { return; } diff --git a/app/Model/Article/ArticleAnnex.php b/app/Model/Article/ArticleAnnex.php index 6699977..d54313e 100644 --- a/app/Model/Article/ArticleAnnex.php +++ b/app/Model/Article/ArticleAnnex.php @@ -12,9 +12,10 @@ use App\Model\BaseModel; * @property integer $id 笔记附件ID * @property integer $user_id 用户ID * @property integer $article_id 笔记ID + * @property integer $drive 文件驱动 * @property string $file_suffix 文件后缀名 * @property int $file_size 文件大小 - * @property string $save_dir 文件相对路径 + * @property string $path 文件相对路径 * @property string $original_name 文件原名 * @property integer $status 文件状态 * @property string $created_at 上传时间 @@ -28,20 +29,23 @@ class ArticleAnnex extends BaseModel protected $fillable = [ 'user_id', 'article_id', - 'file_suffix', - 'file_size', - 'save_dir', + 'drive', + 'suffix', + 'size', + 'path', 'original_name', 'status', 'created_at', + 'updated_at', 'deleted_at' ]; protected $casts = [ 'user_id' => 'integer', 'article_id' => 'integer', - 'file_size' => 'integer', + 'size' => 'integer', 'status' => 'integer', - 'created_at' => 'datetime' + 'created_at' => 'datetime', + 'updated_at' => 'datetime', ]; } diff --git a/app/Model/Article/ArticleClass.php b/app/Model/Article/ArticleClass.php index 6842b7f..6cbb804 100644 --- a/app/Model/Article/ArticleClass.php +++ b/app/Model/Article/ArticleClass.php @@ -19,20 +19,26 @@ use App\Model\BaseModel; */ class ArticleClass extends BaseModel { + + protected $table = 'article_class'; + public $timestamps = true; + protected $fillable = [ 'user_id', 'class_name', 'sort', 'is_default', 'created_at', + 'updated_at', ]; protected $casts = [ 'user_id' => 'integer', 'sort' => 'integer', 'is_default' => 'integer', - 'created_at' => 'int' + 'created_at' => 'datetime', + 'updated_at' => 'datetime' ]; } diff --git a/app/Model/Article/ArticleTag.php b/app/Model/Article/ArticleTag.php index feafb53..e4e47b9 100644 --- a/app/Model/Article/ArticleTag.php +++ b/app/Model/Article/ArticleTag.php @@ -17,18 +17,22 @@ use App\Model\BaseModel; */ class ArticleTag extends BaseModel { - protected $table = 'article_tags'; + protected $table = 'article_tag'; + + public $timestamps = true; protected $fillable = [ 'user_id', 'tag_name', 'sort', - 'created_at' + 'created_at', + 'updated_at', ]; protected $casts = [ 'user_id' => 'integer', 'sort' => 'integer', - 'created_at' => 'integer' + 'created_at' => 'datetime', + 'updated_at' => 'datetime' ]; } diff --git a/app/Model/UsersFriend.php b/app/Model/Contact.php similarity index 91% rename from app/Model/UsersFriend.php rename to app/Model/Contact.php index 8ce67e0..846b781 100644 --- a/app/Model/UsersFriend.php +++ b/app/Model/Contact.php @@ -18,9 +18,9 @@ use App\Cache\FriendRemark; * @property string $updated_at 更新时间 * @package App\Model */ -class UsersFriend extends BaseModel +class Contact extends BaseModel { - protected $table = 'users_friends'; + protected $table = 'contact'; protected $fillable = [ 'user_id', diff --git a/app/Model/UsersFriendApply.php b/app/Model/ContactApply.php similarity index 87% rename from app/Model/UsersFriendApply.php rename to app/Model/ContactApply.php index 866409e..4d6d8d5 100644 --- a/app/Model/UsersFriendApply.php +++ b/app/Model/ContactApply.php @@ -14,9 +14,9 @@ namespace App\Model; * @property string $created_at 创建时间 * @package App\ModelÒ */ -class UsersFriendApply extends BaseModel +class ContactApply extends BaseModel { - protected $table = 'users_friends_apply'; + protected $table = 'contact_apply'; protected $fillable = [ 'user_id', diff --git a/app/Model/Talk/TalkList.php b/app/Model/Talk/TalkList.php index 9d698f6..d300b08 100644 --- a/app/Model/Talk/TalkList.php +++ b/app/Model/Talk/TalkList.php @@ -23,7 +23,7 @@ use App\Model\BaseModel; */ class TalkList extends BaseModel { - protected $table = 'talk_list'; + protected $table = 'talk_session'; public $timestamps = true; diff --git a/app/Service/ArticleService.php b/app/Service/ArticleService.php index f6adcb4..7a39b7a 100644 --- a/app/Service/ArticleService.php +++ b/app/Service/ArticleService.php @@ -156,7 +156,7 @@ class ArticleService extends BaseService ['user_id', '=', $user_id], ['article_id', '=', $article_id], ['status', '=', 1] - ])->get(['id', 'file_suffix', 'file_size', 'original_name', 'created_at'])->toArray(); + ])->get(['id', 'suffix', 'size', 'original_name', 'created_at'])->toArray(); } /** @@ -191,12 +191,18 @@ class ArticleService extends BaseService ArticleClass::where('id', $val['id'])->update(['sort' => $val['sort']]); } - $res = ArticleClass::create(['user_id' => $uid, 'class_name' => $class_name, 'sort' => 1, 'created_at' => time()]); + $res = ArticleClass::create(['user_id' => $uid, 'class_name' => $class_name, 'sort' => 1, 'created_at' => date("y-m-d H:i:s")]); Db::commit(); return $res->id; } catch (Exception $e) { Db::rollBack(); + + logger()->info("编辑标签失败", [ + "error" => $e->getMessage(), + "line" => $e->getLine(), + "file" => $e->getFile(), + ]); return false; } } @@ -331,7 +337,7 @@ class ArticleService extends BaseService // 判断新添加的标签名是否存在 if ($id) return false; - $insRes = ArticleTag::create(['user_id' => $uid, 'tag_name' => $tag_name, 'sort' => 1, 'created_at' => time()]); + $insRes = ArticleTag::create(['user_id' => $uid, 'tag_name' => $tag_name, 'sort' => 1]); if (!$insRes) { return false; } @@ -594,7 +600,7 @@ class ArticleService extends BaseService */ public function foreverDelAnnex(int $uid, int $annex_id) { - $info = ArticleAnnex::where('id', $annex_id)->where('user_id', $uid)->where('status', 2)->first(['id', 'save_dir']); + $info = ArticleAnnex::where('id', $annex_id)->where('user_id', $uid)->where('status', 2)->first(['id', 'path']); if (!$info) { return false; } @@ -619,11 +625,13 @@ class ArticleService extends BaseService $result = ArticleAnnex::create([ 'user_id' => $user_id, 'article_id' => $article_id, - 'file_suffix' => $annex['file_suffix'], - 'file_size' => $annex['file_size'], - 'save_dir' => $annex['save_dir'], + 'suffix' => $annex['suffix'], + 'size' => $annex['size'], + 'drive' => $annex['drive'], + 'path' => $annex['path'], 'original_name' => $annex['original_name'], - 'created_at' => date('Y-m-d H:i:s') + 'created_at' => date('Y-m-d H:i:s'), + 'updated_at' => date('Y-m-d H:i:s'), ]); return $result ? $result->id : false; diff --git a/app/Service/ContactApplyService.php b/app/Service/ContactApplyService.php index a3c6b31..27c7550 100644 --- a/app/Service/ContactApplyService.php +++ b/app/Service/ContactApplyService.php @@ -6,8 +6,8 @@ use App\Cache\FriendApply; use App\Constants\TalkEventConstant; use App\Event\TalkEvent; use App\Model\User; -use App\Model\UsersFriend; -use App\Model\UsersFriendApply; +use App\Model\Contact; +use App\Model\ContactApply; use App\Traits\PagingTrait; use Hyperf\DbConnection\Db; @@ -25,13 +25,13 @@ class ContactApplyService */ public function create(int $user_id, int $friend_id, string $remark) { - $result = UsersFriendApply::where([ + $result = ContactApply::where([ ['user_id', '=', $user_id], ['friend_id', '=', $friend_id], ])->orderByDesc('id')->first(); if (!$result) { - $result = UsersFriendApply::create([ + $result = ContactApply::create([ 'user_id' => $user_id, 'friend_id' => $friend_id, 'remark' => $remark, @@ -66,14 +66,14 @@ class ContactApplyService */ public function accept(int $user_id, int $apply_id, string $remarks = '') { - $info = UsersFriendApply::where('id', $apply_id)->first(); + $info = ContactApply::where('id', $apply_id)->first(); if (!$info || $info->friend_id != $user_id) { return false; } Db::beginTransaction(); try { - UsersFriend::updateOrCreate([ + Contact::updateOrCreate([ 'user_id' => $info->user_id, 'friend_id' => $info->friend_id, ], [ @@ -81,7 +81,7 @@ class ContactApplyService 'remark' => $remarks, ]); - UsersFriend::updateOrCreate([ + Contact::updateOrCreate([ 'user_id' => $info->friend_id, 'friend_id' => $info->user_id, ], [ @@ -117,7 +117,7 @@ class ContactApplyService */ public function decline(int $user_id, int $apply_id, string $reason = '') { - $result = UsersFriendApply::where('id', $apply_id)->where('friend_id', $user_id)->delete(); + $result = ContactApply::where('id', $apply_id)->where('friend_id', $user_id)->delete(); if (!$result) return false; @@ -136,24 +136,24 @@ class ContactApplyService */ public function getApplyRecords(int $user_id, $page = 1, $page_size = 30): array { - $rowsSqlObj = UsersFriendApply::select([ - 'users_friends_apply.id', - 'users_friends_apply.remark', + $rowsSqlObj = ContactApply::select([ + 'contact_apply.id', + 'contact_apply.remark', 'users.nickname', 'users.avatar', 'users.mobile', - 'users_friends_apply.user_id', - 'users_friends_apply.friend_id', - 'users_friends_apply.created_at' + 'contact_apply.user_id', + 'contact_apply.friend_id', + 'contact_apply.created_at' ]); - $rowsSqlObj->leftJoin('users', 'users.id', '=', 'users_friends_apply.user_id'); - $rowsSqlObj->where('users_friends_apply.friend_id', $user_id); + $rowsSqlObj->leftJoin('users', 'users.id', '=', 'contact_apply.user_id'); + $rowsSqlObj->where('contact_apply.friend_id', $user_id); $count = $rowsSqlObj->count(); $rows = []; if ($count > 0) { - $rows = $rowsSqlObj->orderBy('users_friends_apply.id', 'desc')->forPage($page, $page_size)->get()->toArray(); + $rows = $rowsSqlObj->orderBy('contact_apply.id', 'desc')->forPage($page, $page_size)->get()->toArray(); } return $this->getPagingRows($rows, $count, $page, $page_size); diff --git a/app/Service/ContactsService.php b/app/Service/ContactsService.php index adaf6af..5a39fa1 100644 --- a/app/Service/ContactsService.php +++ b/app/Service/ContactsService.php @@ -11,7 +11,7 @@ namespace App\Service; use App\Model\User; -use App\Model\UsersFriend; +use App\Model\Contact; use App\Traits\PagingTrait; /** @@ -33,7 +33,7 @@ class ContactsService extends BaseService */ public function delete(int $user_id, int $friend_id): bool { - $res = (bool)UsersFriend::where('user_id', $user_id)->where('friend_id', $friend_id)->where('status', 1)->update([ + $res = (bool)Contact::where('user_id', $user_id)->where('friend_id', $friend_id)->where('status', 1)->update([ 'status' => 0, 'updated_at' => date('Y-m-d H:i:s') ]); @@ -55,7 +55,7 @@ class ContactsService extends BaseService */ public function editRemark(int $user_id, int $friend_id, string $remark): bool { - return (bool)UsersFriend::where('user_id', $user_id)->where('friend_id', $friend_id)->update([ + return (bool)Contact::where('user_id', $user_id)->where('friend_id', $friend_id)->update([ 'remark' => $remark, 'updated_at' => date('Y-m-d H:i:s') ]); diff --git a/app/Service/Group/GroupService.php b/app/Service/Group/GroupService.php index a85da3c..4cf3aad 100644 --- a/app/Service/Group/GroupService.php +++ b/app/Service/Group/GroupService.php @@ -380,7 +380,7 @@ class GroupService extends BaseService */ public function removeMember(int $group_id, int $user_id, array $member_ids) { - if (di()->get(GroupMemberService::class)->isAuth($group_id, $user_id)) { + if (!di()->get(GroupMemberService::class)->isAuth($group_id, $user_id)) { return false; } diff --git a/app/Service/Message/SubscribeHandleService.php b/app/Service/Message/SubscribeHandleService.php index ad5bf5b..b7119a0 100644 --- a/app/Service/Message/SubscribeHandleService.php +++ b/app/Service/Message/SubscribeHandleService.php @@ -9,7 +9,7 @@ use App\Constants\TalkEventConstant; use App\Constants\TalkModeConstant; use App\Model\Talk\TalkRecords; use App\Model\User; -use App\Model\UsersFriendApply; +use App\Model\ContactApply; use App\Service\SocketClientService; use App\Service\UserService; @@ -216,7 +216,7 @@ class SubscribeHandleService { $data = $data['data']; - $applyInfo = UsersFriendApply::where('id', $data['apply_id'])->first(); + $applyInfo = ContactApply::where('id', $data['apply_id'])->first(); if (!$applyInfo) return; $fds = $this->clientService->findUserFds($data['type'] == 1 ? $applyInfo->friend_id : $applyInfo->user_id); diff --git a/app/Service/TalkListService.php b/app/Service/TalkListService.php index b14604a..514fbf6 100644 --- a/app/Service/TalkListService.php +++ b/app/Service/TalkListService.php @@ -114,7 +114,7 @@ class TalkListService 'group.group_name', 'group.avatar as group_avatar' ]; - $rows = TalkList::from('talk_list as list') + $rows = TalkList::from('talk_session as list') ->leftJoin('users', function ($join) { $join->on('users.id', '=', 'list.receiver_id')->where('list.talk_type', '=', TalkModeConstant::PRIVATE_CHAT); }) diff --git a/app/Service/UserFriendService.php b/app/Service/UserFriendService.php index 575aa0e..86ac220 100644 --- a/app/Service/UserFriendService.php +++ b/app/Service/UserFriendService.php @@ -3,7 +3,7 @@ namespace App\Service; use App\Cache\FriendRemark; -use App\Model\UsersFriend; +use App\Model\Contact; class UserFriendService { @@ -19,7 +19,7 @@ class UserFriendService $remark = FriendRemark::getInstance()->read($user_id, $friend_id); if ($remark) return $remark; - $remark = UsersFriend::where('user_id', $user_id)->where('friend_id', $friend_id)->value('remark'); + $remark = Contact::where('user_id', $user_id)->where('friend_id', $friend_id)->value('remark'); if ($remark) FriendRemark::getInstance()->save($user_id, $friend_id, $remark); return (string)$remark; @@ -35,13 +35,13 @@ class UserFriendService */ public function isFriend(int $user_id, int $friend_id, $is_mutual = false): bool { - $isTrue1 = UsersFriend::where('user_id', $user_id)->where('friend_id', $friend_id)->where('status', 1)->exists(); + $isTrue1 = Contact::where('user_id', $user_id)->where('friend_id', $friend_id)->where('status', 1)->exists(); if ($is_mutual === false) { return $isTrue1; } - $isTrue2 = UsersFriend::where('user_id', $friend_id)->where('friend_id', $user_id)->where('status', 1)->exists(); + $isTrue2 = Contact::where('user_id', $friend_id)->where('friend_id', $user_id)->where('status', 1)->exists(); return $isTrue1 && $isTrue2; } diff --git a/app/Service/UserService.php b/app/Service/UserService.php index c3c91c5..2cb9407 100644 --- a/app/Service/UserService.php +++ b/app/Service/UserService.php @@ -5,8 +5,8 @@ namespace App\Service; use App\Helpers\HashHelper; use App\Model\User; use App\Model\Article\ArticleClass; -use App\Model\UsersFriend; -use App\Model\UsersFriendApply; +use App\Model\Contact; +use App\Model\ContactApply; use Hyperf\DbConnection\Db; class UserService extends BaseService @@ -131,7 +131,7 @@ class UserService extends BaseService if ($is_friend) { $info['nickname_remark'] = di()->get(UserFriendService::class)->getFriendRemark($me_user_id, $friend_id); } else { - $res = UsersFriendApply::where('user_id', $me_user_id) + $res = ContactApply::where('user_id', $me_user_id) ->where('friend_id', $friend_id) ->orderBy('id', 'desc') ->exists(); @@ -151,15 +151,15 @@ class UserService extends BaseService */ public function getUserFriends(int $user_id): array { - return UsersFriend::leftJoin('users', 'users.id', '=', 'users_friends.friend_id') - ->where('user_id', $user_id)->where('users_friends.status', 1) + return Contact::Join('users', 'users.id', '=', 'contact.friend_id') + ->where('user_id', $user_id)->where('contact.status', 1) ->get([ 'users.id', 'users.nickname', 'users.avatar', 'users.motto', 'users.gender', - 'users_friends.remark as friend_remark', + 'contact.remark as friend_remark', ])->toArray(); } @@ -171,6 +171,6 @@ class UserService extends BaseService */ public function getFriendIds(int $user_id): array { - return UsersFriend::where('user_id', $user_id)->where('status', 1)->pluck('friend_id')->toArray(); + return Contact::where('user_id', $user_id)->where('status', 1)->pluck('friend_id')->toArray(); } } diff --git a/app/Support/Response.php b/app/Support/Response.php index 39ac7db..f3dbd71 100644 --- a/app/Support/Response.php +++ b/app/Support/Response.php @@ -36,8 +36,14 @@ class Response */ public function success(array $data = [], string $message = 'success'): PsrResponseInterface { - $code = ResponseCode::SUCCESS; - return $this->response->json(compact('code', 'message', 'data')); + $resp = [ + "code" => ResponseCode::SUCCESS, + "message" => $message, + ]; + + if ($data) $resp["data"] = $data; + + return $this->response->json($resp); } /** @@ -50,7 +56,14 @@ class Response */ public function fail(string $message = 'fail', array $data = [], $code = ResponseCode::FAIL): PsrResponseInterface { - return $this->response->json(compact('code', 'message', 'data')); + $resp = [ + "code" => $code, + "message" => $message, + ]; + + if ($data) $resp["data"] = $data; + + return $this->response->json($resp); } /** diff --git a/config/routes/websocket.php b/config/routes/websocket.php index eceedd6..32fcfe8 100644 --- a/config/routes/websocket.php +++ b/config/routes/websocket.php @@ -15,6 +15,6 @@ use Hyperf\HttpServer\Router\Router; // 添加 ws 服务对应的路由 -Router::get('/socket.io', 'App\Controller\WebSocketController', [ +Router::get('/wss/default.io', 'App\Controller\WebSocketController', [ 'middleware' => [\App\Middleware\WebSocketAuthMiddleware::class] -]); \ No newline at end of file +]); diff --git a/seeders/initialize.php b/seeders/initialize.php index 9d59b3f..1a00f85 100644 --- a/seeders/initialize.php +++ b/seeders/initialize.php @@ -7,7 +7,7 @@ use Hyperf\Database\Seeders\Seeder; use App\Model\User; use App\Model\Article\ArticleClass; use Hyperf\DbConnection\Db; -use App\Model\UsersFriend; +use App\Model\Contact; class Initialize extends Seeder { @@ -65,7 +65,7 @@ class Initialize extends Seeder ]; } - UsersFriend::insert($friends); + Contact::insert($friends); $service = new \App\Service\TalkListService(); foreach ($list as $item) {