From 93a50abb3abde3e8e70c280c13eabb0959fb6049 Mon Sep 17 00:00:00 2001 From: gzydong <837215079@qq.com> Date: Mon, 9 Nov 2020 17:41:22 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Amqp/Consumer/ChatMessageConsumer.php | 2 +- app/Controller/Api/V1/UsersController.php | 345 ++++++++++++++++++++-- app/Controller/WebSocketController.php | 11 +- app/Helper/Hash.php | 4 +- app/Model/UsersChatList.php | 95 ++++++ app/Model/UsersFriendsApply.php | 10 +- app/Service/FriendService.php | 198 +++++++++++++ app/Service/SocketFDService.php | 2 +- app/Service/UserService.php | 141 ++++++++- app/Support/SendEmailCode.php | 100 +++++++ config/autoload/server.php | 9 +- test.php | 10 - 12 files changed, 883 insertions(+), 44 deletions(-) create mode 100644 app/Support/SendEmailCode.php delete mode 100644 test.php diff --git a/app/Amqp/Consumer/ChatMessageConsumer.php b/app/Amqp/Consumer/ChatMessageConsumer.php index 9acf1c6..a35c956 100644 --- a/app/Amqp/Consumer/ChatMessageConsumer.php +++ b/app/Amqp/Consumer/ChatMessageConsumer.php @@ -77,7 +77,7 @@ class ChatMessageConsumer extends ConsumerMessage $server = server(); foreach ($server->connections as $fd) { - if ($server->isEstablished($fd)) { + if ($server->exist($fd) && $server->isEstablished($fd)) { $server->push($fd, "Recv: 我是后台进程 [{$data['message']}]"); } } diff --git a/app/Controller/Api/V1/UsersController.php b/app/Controller/Api/V1/UsersController.php index 177c876..650b424 100644 --- a/app/Controller/Api/V1/UsersController.php +++ b/app/Controller/Api/V1/UsersController.php @@ -7,9 +7,25 @@ use Hyperf\HttpServer\Annotation\Controller; use Hyperf\HttpServer\Annotation\RequestMapping; use Hyperf\HttpServer\Annotation\Middleware; use Phper666\JWTAuth\Middleware\JWTAuthMiddleware; +use App\Constants\ResponseCode; +use App\Helper\Hash; +use App\Model\User; +use App\Model\UsersChatList; +use App\Model\UsersFriend; +use App\Service\SmsCodeService; +use App\Support\SendEmailCode; use App\Service\FriendService; use App\Service\UserService; +use App\Service\SocketFDService; +/** + * Class UsersController + * + * @Controller(path="/api/v1/users") + * @Middleware(JWTAuthMiddleware::class) + * + * @package App\Controller\Api\V1 + */ class UsersController extends CController { /** @@ -25,107 +41,284 @@ class UsersController extends CController protected $userService; /** + * @inject + * @var SocketFDService + */ + private $socketFDService; + + /** + * 获取我的好友列表 + * * @RequestMapping(path="friends", methods="get") */ public function getUserFriends() { + $rows = UsersFriend::getUserFriends($this->uid()); + $runArr = $this->socketFDService->getServerRunIdAll(); + foreach ($rows as $k => $row) { + $rows[$k]['online'] = $this->socketFDService->isOnlineAll($row['id'], $runArr); + } + + return $this->response->success($rows); } /** - * @RequestMapping(path="remove-friend", methods="get") + * 解除好友关系 + * + * @RequestMapping(path="remove-friend", methods="post") */ public function removeFriend() { + $params = $this->request->all(); + $this->validate($params, [ + 'friend_id' => 'required|integer' + ]); + $user_id = $this->uid(); + if (!$this->friendService->removeFriend($user_id, $params['friend_id'])) { + return $this->response->fail('好友关系解除成功...'); + } + + //删除好友会话列表 + UsersChatList::delItem($user_id, $params['friend_id'], 2); + UsersChatList::delItem($params['friend_id'], $user_id, 2); + + return $this->response->success([], '好友关系解除成功...'); } /** + * 获取用户群聊列表 + * * @RequestMapping(path="user-groups", methods="get") */ public function getUserGroups() { - + return $this->response->success( + $this->userService->getUserChatGroups($this->uid()) + ); } /** + * 获取我的信息 + * * @RequestMapping(path="detail", methods="get") */ public function getUserDetail() { - + $userInfo = $this->userService->findById($this->uid(), ['mobile', 'nickname', 'avatar', 'motto', 'email', 'gender']); + return $this->response->success([ + 'mobile' => $userInfo->mobile, + 'nickname' => $userInfo->nickname, + 'avatar' => $userInfo->avatar, + 'motto' => $userInfo->motto, + 'email' => $userInfo->email, + 'gender' => $userInfo->gender + ]); } /** + * 用户相关设置 + * * @RequestMapping(path="setting", methods="get") */ public function getUserSetting() { - + $userInfo = $this->userService->findById($this->uid(), ['id', 'nickname', 'avatar', 'motto', 'gender']); + return $this->response->success([ + 'user_info' => [ + 'uid' => $userInfo->id, + 'nickname' => $userInfo->nickname, + 'avatar' => $userInfo->avatar, + 'motto' => $userInfo->motto, + 'gender' => $userInfo->gender, + ], + 'setting' => [ + 'theme_mode' => '', + 'theme_bag_img' => '', + 'theme_color' => '', + 'notify_cue_tone' => '', + 'keyboard_event_notify' => '' + ] + ]); } /** - * @RequestMapping(path="edit-user-detail", methods="get") + * 编辑我的信息 + * + * @RequestMapping(path="edit-user-detail", methods="post") */ public function editUserDetail() { + $params = $this->request->inputs(['nickname', 'avatar', 'motto', 'gender']); + $this->validate($params, [ + 'nickname' => 'required', + 'motto' => 'present|integer', + 'gender' => 'required|integer', + 'avatar' => 'url' + ]); + $isTrue = User::where('id', $this->uid())->update($params); + + return $isTrue + ? $this->response->success([], '个人信息修改成功...') + : $this->response->fail('个人信息修改失败...'); } /** - * @RequestMapping(path="edit-avatar", methods="get") + * 修改用户头像 + * + * @RequestMapping(path="edit-avatar", methods="post") */ public function editAvatar() { + $params = $this->request->inputs(['avatar']); + $this->validate($params, [ + 'avatar' => 'required|url' + ]); + $isTrue = User::where('id', $this->uid())->update(['avatar' => $params['avatar']]); + return $isTrue + ? $this->response->success([], '头像修改成功...') + : $this->response->fail('头像修改失败...'); } /** + * 通过手机号查找用户 + * * @RequestMapping(path="search-user", methods="get") */ public function searchUserInfo() { + $params = $this->request->inputs(['user_id', 'mobile']); + $this->validate($params, [ + 'user_id' => 'present|integer', + 'mobile' => "present|regex:/^1[345789][0-9]{9}$/", + ]); + if (!empty($params['user_id'])) { + $where['uid'] = $params['user_id']; + } else if (!empty($params['mobile'])) { + $where['mobile'] = $params['mobile']; + } else { + return $this->response->fail('请求参数不正确...', [], ResponseCode::VALIDATION_ERROR); + } + + if ($data = $this->userService->searchUserInfo($where, $this->uid())) { + return $this->response->success($data); + } + + return $this->response->fail('查询失败...'); } /** - * @RequestMapping(path="edit-friend-remark", methods="get") + * 编辑好友备注信息 + * + * @RequestMapping(path="edit-friend-remark", methods="post") */ public function editFriendRemark() { + $params = $this->request->inputs(['friend_id', 'remarks']); + $this->validate($params, [ + 'friend_id' => 'required|integer', + 'remarks' => "required", + ]); + $isTrue = $this->friendService->editFriendRemark($this->uid(), $params['friend_id'], $params['remarks']); + return $isTrue + ? $this->response->success([], '备注修改成功...') + : $this->response->fail('备注修改失败...'); } /** - * @RequestMapping(path="send-friend-apply", methods="get") + * 发送添加好友申请 + * + * @RequestMapping(path="send-friend-apply", methods="post") */ public function sendFriendApply() { + $params = $this->request->inputs(['friend_id', 'remarks']); + $this->validate($params, [ + 'friend_id' => 'required|integer', + 'remarks' => 'present', + ]); + $user = $this->userService->findById($params['friend_id']); + if (!$user) { + return $this->response->fail('用户不存在...'); + } + + if (!$this->friendService->addFriendApply($this->uid(), $params['friend_id'], $params['remarks'])) { + return $this->response->fail('发送好友申请失败...'); + } + + //判断对方是否在线。如果在线发送消息通知 + // ... + + return $this->response->success([], '发送好友申请成功...'); } /** - * @RequestMapping(path="handle-friend-apply", methods="get") + * 处理好友的申请 + * + * @RequestMapping(path="handle-friend-apply", methods="post") */ public function handleFriendApply() { + $params = $this->request->inputs(['apply_id', 'remarks']); + $this->validate($params, [ + 'apply_id' => 'required|integer', + 'remarks' => 'present', + ]); + $isTrue = $this->friendService->handleFriendApply($this->uid(), $params['apply_id'], $params['remarks']); + //判断是否是同意添加好友 + if ($isTrue) { + //... 推送处理消息 + } + + return $isTrue + ? $this->response->success([], '处理成功...') + : $this->response->fail('处理失败...'); } /** - * @RequestMapping(path="delete-friend-apply", methods="get") + * 删除好友申请记录 + * + * @RequestMapping(path="delete-friend-apply", methods="post") */ public function deleteFriendApply() { + $params = $this->request->inputs(['apply_id']); + $this->validate($params, [ + 'apply_id' => 'required|integer', + ]); + $isTrue = $this->friendService->delFriendApply($this->uid(), $params['apply_id']); + return $isTrue + ? $this->response->success([], '删除成功...') + : $this->response->fail('删除失败...'); } /** + * 获取我的好友申请记录 + * * @RequestMapping(path="friend-apply-records", methods="get") */ public function getFriendApplyRecords() { + $params = $this->request->inputs(['page', 'page_size']); + $this->validate($params, [ + 'page' => 'present|integer', + 'page_size' => 'present|integer', + ]); + $page = $this->request->input('page', 1); + $page_size = $this->request->input('page_size', 10); + $user_id = $this->uid(); + + $data = $this->friendService->findApplyRecords($user_id, $page, $page_size); + return $this->response->success($data); } /** @@ -137,42 +330,156 @@ class UsersController extends CController } /** - * @RequestMapping(path="change-password", methods="get") + * 修改我的密码 + * + * @RequestMapping(path="change-password", methods="post") */ public function editUserPassword() { + $params = $this->request->inputs(['old_password', 'new_password']); + $this->validate($params, [ + 'old_password' => 'required', + 'new_password' => 'required', + ]); + $userInfo = $this->userService->findById($this->uid(), ['id', 'password', 'mobile']); + + // 验证密码是否正确 + if (!Hash::check($this->request->post('old_password'), $userInfo->password)) { + return $this->response->fail('旧密码验证失败...'); + } + + $isTrue = $this->userService->resetPassword($userInfo->mobile, $params['new_password']); + return $isTrue + ? $this->response->success([], '密码修改成功...') + : $this->response->fail('密码修改失败...'); } /** - * @RequestMapping(path="change-mobile", methods="get") + * 更换用户手机号 + * + * @RequestMapping(path="change-mobile", methods="post") + * + * @param SmsCodeService $smsCodeService + * @return \Psr\Http\Message\ResponseInterface */ - public function editUserMobile() + public function editUserMobile(SmsCodeService $smsCodeService) { + $params = $this->request->inputs(['mobile', 'password', 'sms_code']); + $this->validate($params, [ + 'mobile' => 'required', + 'password' => 'required', + 'sms_code' => 'required|integer', + ]); + if (!$smsCodeService->check('change_mobile', $params['mobile'], $params['sms_code'])) { + return $this->response->fail('验证码填写错误...'); + } + + $user_id = $this->uid(); + if (!Hash::check($params['password'], User::where('id', $user_id)->value('password'))) { + return $this->response->fail('账号密码验证失败...'); + } + + [$isTrue,] = $this->userService->changeMobile($user_id, $params['mobile']); + if (!$isTrue) { + return $this->response->fail('手机号更换失败...'); + } + + // 清除缓存信息 + $smsCodeService->delCode('change_mobile', $params['mobile']); + return $this->response->success([], '手机号更换成功...'); } /** - * @RequestMapping(path="change-email", methods="get") + * 修改用户邮箱接口 + * + * @RequestMapping(path="change-email", methods="post") */ public function editUserEmail() { + $params = $this->request->inputs(['email', 'password', 'email_code']); + $this->validate($params, [ + 'email' => 'required', + 'password' => 'required', + 'email_code' => 'required|integer', + ]); + $sendEmailCode = new SendEmailCode(); + if (!$sendEmailCode->check(SendEmailCode::CHANGE_EMAIL, $params['email'], $params['email_code'])) { + return $this->response->fail('验证码填写错误...'); + } + + $uid = $this->uid(); + $user_password = User::where('id', $uid)->value('password'); + if (!Hash::check($params['password'], $user_password)) { + return $this->response->fail('账号密码验证失败...'); + } + + $isTrue = User::where('id', $uid)->update(['email' => $params['email']]); + if (!$isTrue) { + return $this->response->fail('邮箱设置失败...'); + } + + $sendEmailCode->delCode(SendEmailCode::CHANGE_EMAIL, $params['email']); + return $this->response->success([], '邮箱设置成功...'); } /** - * @RequestMapping(path="send-mobile-code", methods="get") + * 修改手机号发送验证码 + * + * @RequestMapping(path="send-mobile-code", methods="post") + * + * @param SmsCodeService $smsCodeService + * @return \Psr\Http\Message\ResponseInterface */ - public function sendMobileCode() + public function sendMobileCode(SmsCodeService $smsCodeService) { + $params = $this->request->inputs(['mobile']); + $this->validate($params, [ + 'mobile' => "present|regex:/^1[345789][0-9]{9}$/", + ]); + $user_id = $this->uid(); + if (in_array($user_id, [2054, 2055])) { + return $this->response->fail('测试账号不支持修改手机号...'); + } + + if (User::where('mobile', $params['mobile'])->exists()) { + return $this->response->fail('手机号已被他人注册...'); + } + + $data = ['is_debug' => true]; + [$isTrue, $result] = $smsCodeService->send('change_mobile', $params['mobile']); + if ($isTrue) { + $data['sms_code'] = $result['data']['code']; + } else { + // ... 处理发送失败逻辑,当前默认发送成功 + } + + return $this->response->success($data, '验证码发送成功...'); } /** - * @RequestMapping(path="send-change-email-code", methods="get") + * 发送绑定邮箱的验证码 + * + * @RequestMapping(path="send-change-email-code", methods="post") + * + * @param SendEmailCode $sendEmailCode + * @return \Psr\Http\Message\ResponseInterface */ - public function sendChangeEmailCode() + public function sendChangeEmailCode(SendEmailCode $sendEmailCode) { + $params = $this->request->inputs(['email']); + $this->validate($params, [ + 'email' => "required|email", + ]); + $isTrue = $sendEmailCode->send(SendEmailCode::CHANGE_EMAIL, '绑定邮箱', $params['email']); + if (!$isTrue) { + return $this->response->fail('验证码发送失败...'); + } + + return $this->response->success([], '验证码发送成功...'); } -} \ No newline at end of file +} diff --git a/app/Controller/WebSocketController.php b/app/Controller/WebSocketController.php index 9999d0c..1e67a5b 100644 --- a/app/Controller/WebSocketController.php +++ b/app/Controller/WebSocketController.php @@ -49,6 +49,7 @@ class WebSocketController implements OnMessageInterface, OnOpenInterface, OnClos $token = $request->get['token'] ?? ''; $userInfo = $this->jwt->getParserData($token); stdout_log()->notice("用户连接信息 : user_id:{$userInfo['user_id']} | fd:{$request->fd} | data:" . Json::encode($userInfo)); + stdout_log()->notice('连接时间:' . date('Y-m-d H:i:s')); // 绑定fd与用户关系 $this->socketFDService->bindRelation($request->fd, $userInfo['user_id']); @@ -85,10 +86,18 @@ class WebSocketController implements OnMessageInterface, OnOpenInterface, OnClos $user_id = $this->socketFDService->findFdUserId($fd); stdout_log()->notice("客户端FD:{$fd} 已关闭连接,用户ID为【{$user_id}】"); + stdout_log()->notice('关闭时间:' . date('Y-m-d H:i:s')); // 解除fd关系 $this->socketFDService->removeRelation($fd); - // ... 包装推送消息至队列 + // 判断是否存在异地登录 + $isOnline = $this->socketFDService->isOnlineAll(intval($user_id)); + if (!$isOnline) { + // ... 不存在异地登录,推送下线通知消息 + // ... 包装推送消息至队列 + } else { + stdout_log()->notice("用户:{$user_id} 存在异地登录..."); + } } } diff --git a/app/Helper/Hash.php b/app/Helper/Hash.php index 0d0df84..bdf85ae 100644 --- a/app/Helper/Hash.php +++ b/app/Helper/Hash.php @@ -10,7 +10,7 @@ class Hash * @param string $value * @return string */ - public function make($value) + public static function make($value) { return password_hash($value, PASSWORD_DEFAULT); } @@ -22,7 +22,7 @@ class Hash * @param string $hashedValue * @return bool */ - public function check($value, $hashedValue) + public static function check($value, $hashedValue) { return password_verify($value, $hashedValue); } diff --git a/app/Model/UsersChatList.php b/app/Model/UsersChatList.php index 9192128..3b00e03 100644 --- a/app/Model/UsersChatList.php +++ b/app/Model/UsersChatList.php @@ -48,4 +48,99 @@ class UsersChatList extends BaseModel 'created_at' => 'datetime', 'updated_at' => 'datetime' ]; + + /** + * 创建聊天列表记录 + * + * @param int $user_id 用户ID + * @param int $receive_id 接收者ID + * @param int $type 创建类型 1:私聊 2:群聊 + * @return array + */ + public static function addItem(int $user_id, int $receive_id, int $type) + { + $result = self::where('uid', $user_id)->where('type', $type)->where($type == 1 ? 'friend_id' : 'group_id', $receive_id)->first(); + if ($result) { + $result->status = 1; + $result->updated_at = date('Y-m-d H:i:s'); + $result->save(); + + return [ + 'id'=>$result->id, + 'type'=>$result->type, + 'friend_id'=>$result->friend_id, + 'group_id'=>$result->group_id, + ]; + } + + if (!$result = self::create([ + 'type' => $type, + 'uid' => $user_id, + 'status' => 1, + 'friend_id' => $type == 1 ? $receive_id : 0, + 'group_id' => $type == 2 ? $receive_id : 0, + 'created_at' => date('Y-m-d H:i:s'), + 'updated_at' => date('Y-m-d H:i:s'), + ])) { + return []; + } + + return [ + 'id'=>$result->id, + 'type'=>$result->type, + 'friend_id'=>$result->friend_id, + 'group_id'=>$result->group_id, + ]; + } + + /** + * 聊天对话列表置顶操作 + * + * @param int $user_id 用户ID + * @param int $list_id 对话列表ID + * @param bool $is_top 是否置顶(true:是 false:否) + * @return bool + */ + public static function topItem(int $user_id, int $list_id, $is_top = true) + { + return (bool)self::where('id', $list_id)->where('uid', $user_id)->update(['is_top' => $is_top ? 1 : 0, 'updated_at' => date('Y-m-d H:i:s')]); + } + + /** + * 删除聊天列表 + * + * @param int $user_id 用户ID + * @param int $id 聊天列表ID、好友ID或群聊ID + * @param int $type ID类型 (1:聊天列表ID 2:好友ID 3:群聊ID) + * @return bool + */ + public static function delItem(int $user_id, int $id, $type = 1) + { + if ($type == 1) { + return (bool)self::where('id', $id)->where('uid', $user_id)->update(['status' => 0, 'updated_at' => date('Y-m-d H:i:s')]); + } else if ($type == 2) { + return (bool)self::where('uid', $user_id)->where('friend_id', $id)->update(['status' => 0, 'updated_at' => date('Y-m-d H:i:s')]); + } else { + return (bool)self::where('uid', $user_id)->where('group_id', $id)->update(['status' => 0, 'updated_at' => date('Y-m-d H:i:s')]); + } + } + + /** + * 设置消息免打扰 + * + * @param int $user_id 用户ID + * @param int $receive_id 接收者ID + * @param int $type 接收者类型(1:好友 2:群组) + * @param int $not_disturb 是否免打扰 + * @return boolean + */ + public static function notDisturbItem(int $user_id, int $receive_id, int $type, int $not_disturb) + { + $result = self::where('uid', $user_id)->where($type == 1 ? 'friend_id' : 'group_id', $receive_id)->where('status', 1)->first(['id', 'not_disturb']); + if (!$result || $not_disturb == $result->not_disturb) { + return false; + } + + return (bool)self::where('id', $result->id)->update(['not_disturb' => $not_disturb]); + } } diff --git a/app/Model/UsersFriendsApply.php b/app/Model/UsersFriendsApply.php index 15eaf96..4a2664d 100644 --- a/app/Model/UsersFriendsApply.php +++ b/app/Model/UsersFriendsApply.php @@ -1,6 +1,7 @@ where('friend_id', $friend_id)->orderBy('id', 'desc')->first(); + if (!$result) { + $result = UsersFriendsApply::create([ + 'user_id' => $user_id, + 'friend_id' => $friend_id, + 'status' => 0, + 'remarks' => $remarks, + 'created_at' => date('Y-m-d H:i:s'), + 'updated_at' => date('Y-m-d H:i:s') + ]); + + return $result ? true : false; + } else if ($result->status == 0) { + $result->remarks = $remarks; + $result->updated_at = date('Y-m-d H:i:s'); + $result->save(); + + return true; + } + + return false; + } + + /** + * 删除好友申请记录 + * + * @param int $user_id 用户ID + * @param int $apply_id 好友申请ID + * @return mixed + */ + public function delFriendApply(int $user_id, int $apply_id) + { + return (bool)UsersFriendsApply::where('id', $apply_id)->where('friend_id', $user_id)->delete(); + } + + /** + * 处理好友的申请 + * + * @param int $user_id 当前用户ID + * @param int $apply_id 申请记录ID + * @param string $remarks 备注信息 + * @return bool + */ + public function handleFriendApply(int $user_id, int $apply_id, $remarks = '') + { + $info = UsersFriendsApply::where('id', $apply_id)->where('friend_id', $user_id)->where('status', 0)->orderBy('id', 'desc')->first(['user_id', 'friend_id']); + if (!$info) { + return false; + } + + Db::beginTransaction(); + try { + $res = UsersFriendsApply::where('id', $apply_id)->update(['status' => 1, 'updated_at' => date('Y-m-d H:i:s')]); + if (!$res) { + throw new \Exception('更新好友申请表信息失败'); + } + + $user1 = $info->user_id; + $user2 = $info->friend_id; + if ($info->user_id > $info->friend_id) { + [$user1, $user2] = [$info->friend_id, $info->user_id]; + } + + //查询是否存在好友记录 + $friendResult = UsersFriend::select('id', 'user1', 'user2', 'active', 'status')->where('user1', '=', $user1)->where('user2', '=', $user2)->first(); + if ($friendResult) { + $active = ($friendResult->user1 == $info->user_id && $friendResult->user2 == $info->friend_id) ? 1 : 2; + if (!UsersFriend::where('id', $friendResult->id)->update(['active' => $active, 'status' => 1])) { + throw new \Exception('更新好友关系信息失败'); + } + } else { + //好友昵称 + $friend_nickname = User::where('id', $info->friend_id)->value('nickname'); + $insRes = UsersFriend::create([ + 'user1' => $user1, + 'user2' => $user2, + 'user1_remark' => $user1 == $user_id ? $remarks : $friend_nickname, + 'user2_remark' => $user2 == $user_id ? $remarks : $friend_nickname, + 'active' => $user1 == $user_id ? 2 : 1, + 'status' => 1, + 'agree_time' => date('Y-m-d H:i:s'), + 'created_at' => date('Y-m-d H:i:s') + ]); + + if (!$insRes) { + throw new \Exception('创建好友关系失败'); + } + } + + Db::commit(); + } catch (\Exception $e) { + Db::rollBack(); + return false; + } + + return true; + } + + /** + * 解除好友关系 + * + * @param int $user_id 用户ID + * @param int $friend_id 好友ID + * @return bool + */ + public function removeFriend(int $user_id, int $friend_id) + { + if (!UsersFriend::isFriend($user_id, $friend_id)) { + return false; + } + + $data = ['status' => 0]; + + // 用户ID比大小交换位置 + if ($user_id > $friend_id) { + [$user_id, $friend_id] = [$friend_id, $user_id]; + } + + return (bool)UsersFriend::where('user1', $user_id)->where('user2', $friend_id)->update($data); + } + + /** + * 获取用户好友申请记录 + * + * @param int $user_id 用户ID + * @param int $page 分页数 + * @param int $page_size 分页大小 + * @return array + */ + public function findApplyRecords(int $user_id, $page = 1, $page_size = 30) + { + $rowsSqlObj = UsersFriendsApply::select([ + 'users_friends_apply.id', + 'users_friends_apply.status', + 'users_friends_apply.remarks', + 'users.nickname', + 'users.avatar', + 'users.mobile', + 'users_friends_apply.user_id', + 'users_friends_apply.friend_id', + 'users_friends_apply.created_at' + ]); + + $rowsSqlObj->leftJoin('users', 'users.id', '=', 'users_friends_apply.user_id'); + $rowsSqlObj->where('users_friends_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(); + } + + return $this->getPagingRows($rows, $count, $page, $page_size); + } + + /** + * 编辑好友备注信息 + * + * @param int $user_id 用户ID + * @param int $friend_id 朋友ID + * @param string $remarks 好友备注名称 + * @return bool + */ + public function editFriendRemark(int $user_id, int $friend_id, string $remarks) + { + $data = []; + if ($user_id > $friend_id) { + [$user_id, $friend_id] = [$friend_id, $user_id]; + $data['user2_remark'] = $remarks; + } else { + $data['user1_remark'] = $remarks; + } + + return (bool)UsersFriend::where('user1', $user_id)->where('user2', $friend_id)->update($data); + } } diff --git a/app/Service/SocketFDService.php b/app/Service/SocketFDService.php index a4e5dd0..35c6e31 100644 --- a/app/Service/SocketFDService.php +++ b/app/Service/SocketFDService.php @@ -89,7 +89,7 @@ class SocketFDService { if (empty($run_ids)) $run_ids = $this->getServerRunIdAll(); - foreach ($run_ids as $run_id) { + foreach ($run_ids as $run_id => $time) { if ($this->isOnline($user_id, $run_id)) return true; } diff --git a/app/Service/UserService.php b/app/Service/UserService.php index e4a1d3f..dff6c73 100644 --- a/app/Service/UserService.php +++ b/app/Service/UserService.php @@ -2,12 +2,29 @@ namespace App\Service; +use App\Helper\Hash; +use App\Model\Group\UsersGroupMember; use App\Model\User; -use App\Model\ArticleClass; +use App\Model\Article\ArticleClass; +use App\Model\UsersChatList; +use App\Model\UsersFriend; +use App\Model\UsersFriendsApply; use Hyperf\DbConnection\Db; class UserService extends BaseService { + /** + * 获取用户信息 + * + * @param int $user_id 用户ID + * @param array $field 查询字段 + * @return mixed + */ + public function findById(int $user_id, $field = ['*']) + { + return User::where('id', $user_id)->first($field); + } + /** * 登录逻辑 * @@ -15,14 +32,15 @@ class UserService extends BaseService * @param string $password 登录密码 * @return array|bool */ - public function login(string $mobile,string $password){ - $user = User::where('mobile',$mobile)->first(); + public function login(string $mobile, string $password) + { + $user = User::where('mobile', $mobile)->first(); - if(!$user){ + if (!$user) { return false; } - if(!password_verify($password,$user->password)){ + if (!password_verify($password, $user->password)) { return false; } @@ -43,6 +61,7 @@ class UserService extends BaseService $result = User::create($data); + // 创建用户的默认笔记分类 ArticleClass::create([ 'user_id' => $result->id, @@ -57,4 +76,116 @@ class UserService extends BaseService return $result ? true : false; } + + /** + * 账号重置密码 + * + * @param string $mobile 用户手机好 + * @param string $password 新密码 + * @return mixed + */ + public function resetPassword(string $mobile, string $password) + { + return User::where('mobile', $mobile)->update(['password' => Hash::make($password)]); + } + + /** + * 修改绑定的手机号 + * + * @param int $user_id 用户ID + * @param string $mobile 换绑手机号 + * @return array|bool + */ + public function changeMobile(int $user_id, string $mobile) + { + $uid = User::where('mobile', $mobile)->value('id'); + if ($uid) { + return [false, '手机号已被他人绑定']; + } + + $isTrue = (bool)User::where('id', $user_id)->update(['mobile' => $mobile]); + return [$isTrue, null]; + } + + /** + * 获取用户所在的群聊 + * + * @param int $user_id 用户ID + * @return mixed + */ + public function getUserChatGroups(int $user_id) + { + $items = UsersGroupMember::select(['users_group.id', 'users_group.group_name', 'users_group.avatar', 'users_group.group_profile', 'users_group.user_id as group_user_id']) + ->join('users_group', 'users_group.id', '=', 'users_group_member.group_id') + ->where([ + ['users_group_member.user_id', '=', $user_id], + ['users_group_member.status', '=', 0] + ]) + ->orderBy('id', 'desc')->get()->toarray(); + + foreach ($items as $key => $item) { + // 判断当前用户是否是群主 + $items[$key]['isGroupLeader'] = $item['group_user_id'] == $user_id; + + //删除无关字段 + unset($items[$key]['group_user_id']); + + // 是否消息免打扰 + $items[$key]['not_disturb'] = UsersChatList::where([ + ['uid', '=', $user_id], + ['type', '=', 2], + ['group_id', '=', $item['id']] + ])->value('not_disturb'); + } + + return $items; + } + + /** + * 通过手机号查找用户 + * + * @param array $where 查询条件 + * @param int $user_id 当前登录用户的ID + * @return array + */ + public function searchUserInfo(array $where, int $user_id) + { + $info = User::select(['id', 'mobile', 'nickname', 'avatar', 'gender', 'motto']); + if (isset($where['uid'])) { + $info->where('id', $where['uid']); + } + + if (isset($where['mobile'])) { + $info->where('mobile', $where['mobile']); + } + + $info = $info->first(); + $info = $info ? $info->toArray() : []; + if ($info) { + $info['friend_status'] = 0;//朋友关系状态 0:本人 1:陌生人 2:朋友 + $info['nickname_remark'] = ''; + $info['friend_apply'] = 0; + + // 判断查询信息是否是自己 + if ($info['id'] != $user_id) { + $friend_id = $info['id']; + + $friendInfo = UsersFriend::select('id', 'user1', 'user2', 'active', 'user1_remark', 'user2_remark')->where(function ($query) use ($friend_id, $user_id) { + $query->where('user1', '=', $user_id)->where('user2', '=', $friend_id)->where('status', 1); + })->orWhere(function ($query) use ($friend_id, $user_id) { + $query->where('user1', '=', $friend_id)->where('user2', '=', $user_id)->where('status', 1); + })->first(); + + $info['friend_status'] = $friendInfo ? 2 : 1; + if ($friendInfo) { + $info['nickname_remark'] = ($friendInfo->user1 == $friend_id) ? $friendInfo->user2_remark : $friendInfo->user1_remark; + } else { + $res = UsersFriendsApply::where('user_id', $user_id)->where('friend_id', $info['id'])->where('status', 0)->orderBy('id', 'desc')->exists(); + $info['friend_apply'] = $res ? 1 : 0; + } + } + } + + return $info; + } } diff --git a/app/Support/SendEmailCode.php b/app/Support/SendEmailCode.php new file mode 100644 index 0000000..08d4b6c --- /dev/null +++ b/app/Support/SendEmailCode.php @@ -0,0 +1,100 @@ +get($this->getKey($type, $email)); + if (!$sms_code) { + return false; + } + + return $sms_code == $code; + } + + /** + * 发送邮件验证码 + * + * @param string $type 类型 + * @param string $title 邮件标题 + * @param string $email 邮箱地址 + * @return boolean + */ + public function send(string $type, string $title, string $email) + { + $key = $this->getKey($type, $email); + if (!$sms_code = $this->getCode($key)) { + $sms_code = mt_rand(100000, 999999); + } + + $this->setCode($key, $sms_code); + + // ...执行发送 + + return true; + } + + /** + * 获取缓存的验证码 + * + * @param string $key + * @return mixed + */ + public function getCode(string $key) + { + return redis()->get($key); + } + + /** + * 设置验证码缓存 + * + * @param string $key 缓存key + * @param string $sms_code 验证码 + * @param float|int $exp 过期时间 + * @return mixed + */ + public function setCode(string $key, string $sms_code, $exp = 60 * 15) + { + return redis()->setex($key, $exp, $sms_code); + } + + /** + * 删除验证码缓存 + * + * @param string $type 类型 + * @param string $email 邮箱地址 + * @return mixed + */ + public function delCode(string $type, string $email) + { + return redis()->del($this->getKey($type, $email)); + } +} diff --git a/config/autoload/server.php b/config/autoload/server.php index e7c254e..3e3f3cd 100644 --- a/config/autoload/server.php +++ b/config/autoload/server.php @@ -37,6 +37,11 @@ return [ SwooleEvent::ON_MESSAGE => [Hyperf\WebSocketServer\Server::class, 'onMessage'], SwooleEvent::ON_CLOSE => [Hyperf\WebSocketServer\Server::class, 'onClose'], ], + 'settings'=>[ + //设置心跳检测 + 'heartbeat_idle_time' => 70, + 'heartbeat_check_interval' => 30, + ] ], ], 'settings' => [ @@ -50,10 +55,6 @@ return [ 'socket_buffer_size' => 3 * 1024 * 1024, 'buffer_output_size' => 3 * 1024 * 1024, 'package_max_length'=> 10 * 1024 * 1024, - - //设置心跳检测 - 'heartbeat_idle_time' => 150, - 'heartbeat_check_interval' => 60, ], 'callbacks' => [ //自定义启动前事件 diff --git a/test.php b/test.php deleted file mode 100644 index 462102d..0000000 --- a/test.php +++ /dev/null @@ -1,10 +0,0 @@ -