From 5bd716169cc7f145f3ba1ec5930836ca6fb4e543 Mon Sep 17 00:00:00 2001 From: xiaochong0302 Date: Thu, 2 Jul 2020 20:52:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9EImUser?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Http/Admin/Services/Student.php | 20 ++- app/Http/Web/Controllers/ImController.php | 6 +- app/Http/Web/Controllers/PublicController.php | 22 +-- app/Http/Web/Controllers/SearchController.php | 4 + app/Http/Web/Services/Im.php | 166 ++++++++---------- app/Library/CsrfToken.php | 2 +- app/Library/Security.php | 92 ---------- app/Models/Account.php | 5 + app/Models/ImUser.php | 135 ++++++++++++++ app/Models/User.php | 44 ++--- app/Repos/ImGroup.php | 6 +- app/Repos/ImUser.php | 164 +++++++++++++++++ app/Repos/User.php | 91 ---------- app/Validators/Category.php | 6 +- app/Validators/Chapter.php | 20 +-- app/Validators/Consult.php | 13 +- app/Validators/CourseUser.php | 32 +--- app/Validators/ImGroupUser.php | 19 +- app/Validators/ImUser.php | 55 ++++++ app/Validators/Review.php | 13 +- app/Validators/User.php | 22 --- config/config.default.php | 14 +- config/errors.php | 30 ++-- public/static/admin/js/common.js | 14 +- public/static/web/js/common.js | 13 +- public/static/web/js/im.js | 6 +- 26 files changed, 555 insertions(+), 459 deletions(-) delete mode 100644 app/Library/Security.php create mode 100644 app/Models/ImUser.php create mode 100644 app/Repos/ImUser.php create mode 100644 app/Validators/ImUser.php diff --git a/app/Http/Admin/Services/Student.php b/app/Http/Admin/Services/Student.php index 1b77f702..af0598d4 100644 --- a/app/Http/Admin/Services/Student.php +++ b/app/Http/Admin/Services/Student.php @@ -16,18 +16,18 @@ use App\Validators\CourseUser as CourseUserValidator; class Student extends Service { - public function getCourse($courseId) + public function getCourse($id) { $repo = new CourseRepo(); - return $repo->findById($courseId); + return $repo->findById($id); } - public function getStudent($userId) + public function getStudent($id) { $repo = new UserRepo(); - return $repo->findById($userId); + return $repo->findById($id); } public function getRelations() @@ -85,9 +85,13 @@ class Student extends Service 'source_type' => CourseUserModel::SOURCE_IMPORT, ]; - $data['course_id'] = $validator->checkCourseId($post['course_id']); - $data['user_id'] = $validator->checkUserId($post['user_id']); - $data['expiry_time'] = $validator->checkExpiryTime($post['expiry_time']); + $course = $validator->checkCourse($post['course_id']); + $user = $validator->checkUser($post['user_id']); + $expiryTime = $validator->checkExpiryTime($post['expiry_time']); + + $data['course_id'] = $course->id; + $data['user_id'] = $user->id; + $data['expiry_time'] = $expiryTime; $validator->checkIfJoined($post['course_id'], $post['user_id']); @@ -134,7 +138,7 @@ class Student extends Service { $validator = new CourseUserValidator(); - return $validator->checkCourseUser($id); + return $validator->checkRelation($id); } protected function handleRelations($pager) diff --git a/app/Http/Web/Controllers/ImController.php b/app/Http/Web/Controllers/ImController.php index e96af78d..895970ec 100644 --- a/app/Http/Web/Controllers/ImController.php +++ b/app/Http/Web/Controllers/ImController.php @@ -226,13 +226,13 @@ class ImController extends LayerController } /** - * @Post("/online/update", name="web.im.update_online") + * @Post("/status/update", name="web.im.update_status") */ - public function updateOnlineAction() + public function updateStatusAction() { $service = new ImService(); - $service->updateOnline(); + $service->updateStatus(); return $this->jsonSuccess(); } diff --git a/app/Http/Web/Controllers/PublicController.php b/app/Http/Web/Controllers/PublicController.php index 799f074d..989e44b6 100644 --- a/app/Http/Web/Controllers/PublicController.php +++ b/app/Http/Web/Controllers/PublicController.php @@ -2,17 +2,17 @@ namespace App\Http\Web\Controllers; -use App\Library\Security; +use App\Library\CsrfToken as CsrfTokenService; use App\Models\ContentImage as ContentImageModel; -use App\Services\Frontend\Chapter\Learning as LearningService; use App\Services\Storage as StorageService; use App\Traits\Response as ResponseTrait; +use App\Traits\Security as SecurityTrait; use PHPQRCode\QRcode as PHPQRCode; class PublicController extends \Phalcon\Mvc\Controller { - use ResponseTrait; + use ResponseTrait, SecurityTrait; /** * @Get("/content/img/{id:[0-9]+}", name="web.content_img") @@ -58,21 +58,13 @@ class PublicController extends \Phalcon\Mvc\Controller */ public function refreshTokenAction() { - $security = new Security(); + $this->checkCsrfToken(); - return $this->jsonSuccess(); - } + $service = new CsrfTokenService(); - /** - * @Post("/{id:[0-9]+}/learning", name="web.learning") - */ - public function learningAction($id) - { - $service = new LearningService(); + $token = $service->getToken(); - $service->handle($id); - - return $this->jsonSuccess(); + return $this->jsonSuccess(['token' => $token]); } } diff --git a/app/Http/Web/Controllers/SearchController.php b/app/Http/Web/Controllers/SearchController.php index 160d8a9b..22a34bed 100644 --- a/app/Http/Web/Controllers/SearchController.php +++ b/app/Http/Web/Controllers/SearchController.php @@ -22,6 +22,10 @@ class SearchController extends Controller { $query = $this->request->get('query', ['trim']); + if (empty($query)) { + return $this->response->redirect(['for' => 'web.course.list']); + } + $service = new CourseHotQueryService(); $hotQueries = $service->handle(); diff --git a/app/Http/Web/Services/Im.php b/app/Http/Web/Services/Im.php index d84fe9cd..d1ab3807 100644 --- a/app/Http/Web/Services/Im.php +++ b/app/Http/Web/Services/Im.php @@ -8,18 +8,18 @@ use App\Caches\ImNewUserList as ImNewUserListCache; use App\Library\Paginator\Query as PagerQuery; use App\Models\ImFriendMessage as ImFriendMessageModel; use App\Models\ImGroupMessage as ImGroupMessageModel; -use App\Models\User as UserModel; +use App\Models\ImUser as ImUserModel; use App\Repos\ImFriendMessage as ImFriendMessageRepo; use App\Repos\ImFriendUser as ImFriendUserRepo; use App\Repos\ImGroup as ImGroupRepo; use App\Repos\ImGroupMessage as ImGroupMessageRepo; use App\Repos\ImSystemMessage as ImSystemMessageRepo; -use App\Repos\User as UserRepo; +use App\Repos\ImUser as ImUserRepo; use App\Validators\ImFriendUser as ImFriendUserValidator; use App\Validators\ImGroup as ImGroupValidator; use App\Validators\ImGroupUser as ImGroupUserValidator; use App\Validators\ImMessage as ImMessageValidator; -use App\Validators\User as UserValidator; +use App\Validators\ImUser as ImUserValidator; use GatewayClient\Gateway; /** @@ -36,18 +36,18 @@ class Im extends Service { $user = $this->getLoginUser(); - $user->afterFetch(); + $imUser = $this->getImUser($user->id); $mine = [ - 'id' => $user->id, - 'username' => $user->name, - 'avatar' => $user->avatar, - 'sign' => $user->im['sign'] ?? '', - 'status' => $user->im['online']['status'] ?? 'online', + 'id' => $imUser->id, + 'username' => $imUser->name, + 'avatar' => $imUser->avatar, + 'sign' => $imUser->sign, + 'status' => $imUser->status, ]; - $friend = $this->handleFriendList($user); - $group = $this->handleGroupList($user); + $friend = $this->handleFriendList($imUser); + $group = $this->handleGroupList($imUser); return [ 'mine' => $mine, @@ -68,7 +68,7 @@ class Im extends Service $page = $pagerQuery->getPage(); $limit = $pagerQuery->getLimit(); - $userRepo = new UserRepo(); + $userRepo = new ImUserRepo(); $pager = $userRepo->paginate($params, $sort, $page, $limit); @@ -163,11 +163,11 @@ class Im extends Service $id = $this->request->getQuery('id'); - $validator = new UserValidator(); + $validator = new ImUserValidator(); $friend = $validator->checkUser($id); - $userRepo = new UserRepo(); + $userRepo = new ImUserRepo(); $messages = $userRepo->findUnreadImFriendMessages($friend->id, $user->id); @@ -209,7 +209,7 @@ class Im extends Service { $user = $this->getLoginUser(); - $userRepo = new UserRepo(); + $userRepo = new ImUserRepo(); return $userRepo->countUnreadImSystemMessages($user->id); } @@ -273,37 +273,29 @@ class Im extends Service public function getFriendStatus() { - $user = $this->getLoginUser(); - - $user->afterFetch(); - $id = $this->request->getQuery('id'); - $validator = new UserValidator(); + $validator = new ImUserValidator(); $friend = $validator->checkUser($id); - $status = $friend->im['online']['status'] ?? 'unknown'; - /** * 对方设置隐身,不返回真实情况 */ - if ($status == 'hide') { + if ($friend->status == 'hide') { return 'unknown'; } Gateway::$registerAddress = $this->getRegisterAddress(); - $status = Gateway::isUidOnline($friend->id) ? 'online' : 'offline'; - - return $status; + return Gateway::isUidOnline($friend->id) ? 'online' : 'offline'; } public function bindUser() { $user = $this->getLoginUser(); - $user->afterFetch(); + $imUser = $this->getImUser($user->id); $clientId = $this->request->getPost('client_id'); @@ -311,7 +303,7 @@ class Im extends Service Gateway::bindUid($clientId, $user->id); - $userRepo = new UserRepo(); + $userRepo = new ImUserRepo(); $chatGroups = $userRepo->findImGroups($user->id); @@ -321,12 +313,7 @@ class Im extends Service } } - /** - * 保持上次的在线状态 - */ - $status = $user->im['online']['status'] ?? 'online'; - - $this->pushFriendOnlineTips($user, $status); + $this->pushOnlineTips($imUser); } public function sendMessage() @@ -433,7 +420,7 @@ class Im extends Service { $user = $this->getLoginUser(); - $userRepo = new UserRepo(); + $userRepo = new ImUserRepo(); $messages = $userRepo->findUnreadImSystemMessages($user->id); @@ -445,91 +432,80 @@ class Im extends Service } } - public function updateOnline() + public function updateStatus() { $user = $this->getLoginUser(); - $user->afterFetch(); + $imUser = $this->getImUser($user->id); $status = $this->request->getPost('status'); - $im = $user->im ?: []; + $validator = new ImUserValidator(); - $im['online']['status'] = $status; + $validator->checkSign($status); - $user->update(['im' => $im]); + $imUser->update(['status' => $status]); - $this->pushFriendOnlineTips($user, $status); - - return $user; + $this->pushOnlineTips($imUser); } public function updateSignature() { $user = $this->getLoginUser(); - $user->afterFetch(); + $imUser = $this->getImUser($user->id); $sign = $this->request->getPost('sign'); - $validator = new UserValidator(); + $validator = new ImUserValidator(); - $sign = $validator->checkImSign($sign); + $sign = $validator->checkSign($sign); - $im = $user->im ?? []; + $imUser->update(['sign' => $sign]); - $im['sign'] = $sign; - - $user->update(['im' => $im]); - - return $user; + return $imUser; } public function updateSkin() { $user = $this->getLoginUser(); - $user->afterFetch(); + $imUser = $this->getImUser($user->id); $skin = $this->request->getPost('skin'); - $validator = new UserValidator(); + $validator = new ImUserValidator(); - $skin = $validator->checkImSkin($skin); + $skin = $validator->checkSkin($skin); - $im = $user->im ?? []; + $imUser->update(['skin' => $skin]); - $im['skin'] = $skin; - - $user->update(['im' => $im]); - - return $user; + return $imUser; } - protected function pushFriendOnlineTips(UserModel $user, $status) + protected function pushOnlineTips(ImUserModel $user) { - $user->afterFetch(); - - $time = $user->im['online']['time'] ?? 0; - $expired = time() - $time > 600; - /** - * 检查间隔,避免频繁提醒干扰 + * 隐身状态不推送消息 */ - if ($time > 0 && !$expired) { + if ($user->status == 'hide') { return; } - $im = $user->im ?: []; + $onlinePushTime = $this->persistent->online_push_time; - $im['online']['status'] = $status; - $im['online']['time'] = time(); + /** + * 避免频繁推送消息 + */ + if ($onlinePushTime && time() - $onlinePushTime > 600) { + return; + } - $user->update(['im' => $im]); + $this->persistent->online_push_time = time(); - $userRepo = new UserRepo(); + $imUserRepo = new ImUserRepo(); - $friendUsers = $userRepo->findImFriendUsers($user->id); + $friendUsers = $imUserRepo->findImFriendUsers($user->id); if ($friendUsers->count() == 0) { return; @@ -546,16 +522,16 @@ class Im extends Service 'name' => $user->name, 'avatar' => $user->avatar, ], - 'status' => $status == 'online' ? 'online' : 'offline', + 'status' => $user->status == 'online' ? 'online' : 'offline', ]); Gateway::sendToUid($friendUser->friend_id, $content); } } } - protected function handleFriendList(UserModel $user) + protected function handleFriendList(ImUserModel $user) { - $userRepo = new UserRepo(); + $userRepo = new ImUserRepo(); $friendGroups = $userRepo->findImFriendGroups($user->id); $friendUsers = $userRepo->findImFriendUsers($user->id); @@ -583,31 +559,30 @@ class Im extends Service return $items; } - $userIds = kg_array_column($friendUsers->toArray(), 'friend_id'); + $ids = kg_array_column($friendUsers->toArray(), 'friend_id'); - $users = $userRepo->findByIds($userIds); + $users = $userRepo->findByIds($ids); - $userMappings = []; + $mappings = []; /** * 用户可以设置状态为 ['online', 'hide'] * 列表在线状态识别为 ['online', 'offline'] */ foreach ($users as $user) { - $status = $user->im['online']['status'] ?? 'offline'; - $status = in_array($status, ['online', 'offline']) ? $status : 'offline'; - $userMappings[$user->id] = [ + $status = in_array($user->status, ['online', 'offline']) ? $user->status : 'offline'; + $mappings[$user->id] = [ 'id' => $user->id, 'username' => $user->name, 'avatar' => $user->avatar, - 'sign' => $user->im['sign'] ?? '', + 'sign' => $user->sign, 'status' => $status, ]; } foreach ($items as $key => $item) { foreach ($friendUsers as $friendUser) { - $friend = $userMappings[$friendUser->friend_id]; + $friend = $mappings[$friendUser->friend_id]; if ($item['id'] == $friendUser->group_id) { $friend['msg_count'] = $friendUser->msg_count; $items[$key]['list'][] = $friend; @@ -620,9 +595,9 @@ class Im extends Service return $items; } - protected function handleGroupList(UserModel $user) + protected function handleGroupList(ImUserModel $user) { - $userRepo = new UserRepo(); + $userRepo = new ImUserRepo(); $groups = $userRepo->findImGroups($user->id); @@ -730,14 +705,23 @@ class Im extends Service return $pager; } - protected function getGroupName($groupId) + protected function getImUser($id) { - return "group_{$groupId}"; + $repo = new ImUserRepo(); + + return $repo->findById($id); + } + + protected function getGroupName($id) + { + return "group_{$id}"; } protected function getRegisterAddress() { - return '127.0.0.1:1238'; + $config = $this->getDI()->get('config'); + + return $config->websocket->register_address; } } diff --git a/app/Library/CsrfToken.php b/app/Library/CsrfToken.php index f9877eb6..099450cb 100644 --- a/app/Library/CsrfToken.php +++ b/app/Library/CsrfToken.php @@ -14,7 +14,7 @@ class CsrfToken */ protected $crypt; - protected $lifetime = 60 * 60; + protected $lifetime = 600; protected $delimiter = '@@'; diff --git a/app/Library/Security.php b/app/Library/Security.php deleted file mode 100644 index 33e5e44f..00000000 --- a/app/Library/Security.php +++ /dev/null @@ -1,92 +0,0 @@ -options['lifetime'] = $options['lifetime'] ?? 3600; - - $this->cache = Di::getDefault()->get('cache'); - $this->session = Di::getDefault()->get('session'); - - $this->generateToken(); - } - - public function generateToken() - { - $this->tokenKey = $this->session->getId(); - - $key = $this->getCacheKey($this->tokenKey); - - $lifetime = $this->options['lifetime']; - - $content = [ - 'hash' => Text::random(Text::RANDOM_ALNUM, 32), - 'expire' => time() + $lifetime, - ]; - - $cacheContent = $this->cache->get($key); - - if ($cacheContent) { - $this->tokenValue = $cacheContent['hash']; - if ($cacheContent['expire'] < time() + $lifetime / 2) { - $this->cache->save($key, $content, $lifetime); - $this->tokenValue = $content['hash']; - } - } else { - $this->cache->save($key, $content, $lifetime); - $this->tokenValue = $content['hash']; - } - } - - protected function getCacheKey($tokenKey) - { - return "csrf_token:{$tokenKey}"; - } - - public function getTokenKey() - { - return $this->tokenKey; - } - - public function getTokenValue() - { - return $this->tokenValue; - } - - public function checkToken($tokenKey, $tokenValue) - { - $key = $this->getCacheKey($tokenKey); - - $content = $this->cache->get($key); - - if (!$content) return false; - - return $tokenValue == $content['hash']; - } - -} diff --git a/app/Models/Account.php b/app/Models/Account.php index becf92e8..1aff0846 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -96,6 +96,11 @@ class Account extends Model $user->id = $this->id; $user->name = "user_{$this->id}"; $user->create(); + + $imUser = new ImUser(); + $imUser->id = $this->id; + $imUser->name = "user_{$this->id}"; + $imUser->create(); } } diff --git a/app/Models/ImUser.php b/app/Models/ImUser.php new file mode 100644 index 00000000..e1b25a39 --- /dev/null +++ b/app/Models/ImUser.php @@ -0,0 +1,135 @@ +addBehavior( + new SoftDelete([ + 'field' => 'deleted', + 'value' => 1, + ]) + ); + } + + public function beforeCreate() + { + $this->create_time = time(); + + if (Text::startsWith($this->avatar, 'http')) { + $this->avatar = self::getAvatarPath($this->avatar); + } elseif (empty($this->avatar)) { + $this->avatar = kg_default_avatar_path(); + } + } + + public function beforeUpdate() + { + $this->update_time = time(); + + if (Text::startsWith($this->avatar, 'http')) { + $this->avatar = self::getAvatarPath($this->avatar); + } + } + + public function afterFetch() + { + if (!Text::startsWith($this->avatar, 'http')) { + $this->avatar = kg_ci_avatar_img_url($this->avatar); + } + } + + public static function getAvatarPath($url) + { + if (Text::startsWith($url, 'http')) { + return parse_url($url, PHP_URL_PATH); + } + + return $url; + } + +} diff --git a/app/Models/User.php b/app/Models/User.php index 8cec91e8..dbc3b996 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -22,20 +22,6 @@ class User extends Model const EDU_ROLE_STUDENT = 1; // 学员 const EDU_ROLE_TEACHER = 2; // 讲师 - /** - * @var array - * - * 即时通讯设置 - */ - protected $_im = [ - 'sign' => '', - 'skin' => '', - 'online' => [ - 'status' => 'online', - 'time' => 0, - ], - ]; - /** * 主键编号 * @@ -71,13 +57,6 @@ class User extends Model */ public $about; - /** - * im设置 - * - * @var string|array - */ - public $im; - /** * 所在地 * @@ -199,10 +178,6 @@ class User extends Model if (Text::startsWith($this->avatar, 'http')) { $this->avatar = self::getAvatarPath($this->avatar); } - - if (is_array($this->im)) { - $this->im = kg_json_encode($this->im); - } } public function afterCreate() @@ -212,15 +187,21 @@ class User extends Model $cache->rebuild(); } + public function afterUpdate() + { + $imUser = ImUser::findFirst($this->id); + + $imUser->update([ + 'name' => $this->name, + 'avatar' => $this->avatar, + ]); + } + public function afterFetch() { if (!Text::startsWith($this->avatar, 'http')) { $this->avatar = kg_ci_avatar_img_url($this->avatar); } - - if (!empty($this->im) && is_string($this->im)) { - $this->im = json_decode($this->im, true); - } } public static function getAvatarPath($url) @@ -249,9 +230,4 @@ class User extends Model ]; } - public function setAvatar($avatar) - { - $this->avatar = $avatar; - } - } diff --git a/app/Repos/ImGroup.php b/app/Repos/ImGroup.php index fc11a6c9..d281ad0e 100644 --- a/app/Repos/ImGroup.php +++ b/app/Repos/ImGroup.php @@ -5,7 +5,7 @@ namespace App\Repos; use App\Library\Paginator\Adapter\QueryBuilder as PagerQueryBuilder; use App\Models\ImGroup as ImGroupModel; use App\Models\ImGroupUser as ImGroupUserModel; -use App\Models\User as UserModel; +use App\Models\ImUser as ImUserModel; use Phalcon\Mvc\Model; use Phalcon\Mvc\Model\Resultset; use Phalcon\Mvc\Model\ResultsetInterface; @@ -77,13 +77,13 @@ class ImGroup extends Repository /** * @param int $groupId - * @return ResultsetInterface|Resultset|UserModel[] + * @return ResultsetInterface|Resultset|ImUserModel[] */ public function findGroupUsers($groupId) { return $this->modelsManager->createBuilder() ->columns('u.*') - ->addFrom(UserModel::class, 'u') + ->addFrom(ImUserModel::class, 'u') ->join(ImGroupUserModel::class, 'u.id = gu.user_id', 'gu') ->where('gu.group_id = :group_id:', ['group_id' => $groupId]) ->andWhere('u.deleted = 0') diff --git a/app/Repos/ImUser.php b/app/Repos/ImUser.php new file mode 100644 index 00000000..03af51a1 --- /dev/null +++ b/app/Repos/ImUser.php @@ -0,0 +1,164 @@ +modelsManager->createBuilder(); + + $builder->from(ImUserModel::class); + + $builder->where('1 = 1'); + + if (!empty($where['id'])) { + $builder->andWhere('id = :id:', ['id' => $where['id']]); + } + + if (!empty($where['name'])) { + $builder->andWhere('name LIKE :name:', ['name' => "%{$where['name']}%"]); + } + + if (isset($where['deleted'])) { + $builder->andWhere('deleted = :deleted:', ['deleted' => $where['deleted']]); + } + + switch ($sort) { + default: + $orderBy = 'id DESC'; + break; + } + + $builder->orderBy($orderBy); + + $pager = new PagerQueryBuilder([ + 'builder' => $builder, + 'page' => $page, + 'limit' => $limit, + ]); + + return $pager->paginate(); + } + + /** + * @param int $id + * @return ImUserModel|Model|bool + */ + public function findById($id) + { + return ImUserModel::findFirst($id); + } + + /** + * @param array $ids + * @param array|string $columns + * @return ResultsetInterface|Resultset|ImUserModel[] + */ + public function findByIds($ids, $columns = '*') + { + return ImUserModel::query() + ->columns($columns) + ->inWhere('id', $ids) + ->execute(); + } + + /** + * @param int $userId + * @return ResultsetInterface|Resultset|ImFriendUserModel[] + */ + public function findImFriendUsers($userId) + { + return ImFriendUserModel::query() + ->where('user_id = :user_id:', ['user_id' => $userId]) + ->execute(); + } + + /** + * @param int $userId + * @return ResultsetInterface|Resultset|ImFriendGroupModel[] + */ + public function findImFriendGroups($userId) + { + return ImFriendGroupModel::query() + ->where('user_id = :user_id:', ['user_id' => $userId]) + ->andWhere('deleted = 0') + ->execute(); + } + + /** + * @param int $userId + * @return ResultsetInterface|Resultset|ImGroupModel[] + */ + public function findImGroups($userId) + { + return $this->modelsManager->createBuilder() + ->columns('g.*') + ->addFrom(ImGroupModel::class, 'g') + ->join(ImGroupUserModel::class, 'g.id = gu.group_id', 'gu') + ->where('gu.user_id = :user_id:', ['user_id' => $userId]) + ->andWhere('g.deleted = 0') + ->getQuery()->execute(); + } + + /** + * @param int $friendId + * @param int $userId + * @return ResultsetInterface|Resultset|ImFriendMessageModel[] + */ + public function findUnreadImFriendMessages($friendId, $userId) + { + return ImFriendMessageModel::find([ + 'conditions' => 'sender_id = ?1 AND receiver_id = ?2 AND viewed = ?3', + 'bind' => [1 => $friendId, 2 => $userId, 3 => 0], + ]); + } + + /** + * @param int $userId + * @param int $itemType + * @return Model|bool|ImSystemMessageModel + */ + public function findImSystemMessage($userId, $itemType) + { + return ImSystemMessageModel::findFirst([ + 'conditions' => 'receiver_id = ?1 AND item_type = ?2', + 'bind' => [1 => $userId, 2 => $itemType], + 'order' => 'id DESC', + ]); + } + + /** + * @param int $userId + * @return ResultsetInterface|Resultset|ImFriendMessageModel[] + */ + public function findUnreadImSystemMessages($userId) + { + return ImSystemMessageModel::find([ + 'conditions' => 'receiver_id = ?1 AND viewed = ?2', + 'bind' => [1 => $userId, 2 => 0], + ]); + } + + public function countUnreadImSystemMessages($userId) + { + return ImSystemMessageModel::count([ + 'conditions' => 'receiver_id = ?1 AND viewed = ?2', + 'bind' => [1 => $userId, 2 => 0], + ]); + } + +} diff --git a/app/Repos/User.php b/app/Repos/User.php index d1c007b7..0b80136c 100644 --- a/app/Repos/User.php +++ b/app/Repos/User.php @@ -3,12 +3,6 @@ namespace App\Repos; use App\Library\Paginator\Adapter\QueryBuilder as PagerQueryBuilder; -use App\Models\ImFriendGroup as ImFriendGroupModel; -use App\Models\ImFriendMessage as ImFriendMessageModel; -use App\Models\ImFriendUser as ImFriendUserModel; -use App\Models\ImGroup as ImGroupModel; -use App\Models\ImGroupUser as ImGroupUserModel; -use App\Models\ImSystemMessage as ImSystemMessageModel; use App\Models\User as UserModel; use Phalcon\Mvc\Model; use Phalcon\Mvc\Model\Resultset; @@ -117,89 +111,4 @@ class User extends Repository ->execute(); } - /** - * @param int $userId - * @return ResultsetInterface|Resultset|ImFriendUserModel[] - */ - public function findImFriendUsers($userId) - { - return ImFriendUserModel::query() - ->where('user_id = :user_id:', ['user_id' => $userId]) - ->execute(); - } - - /** - * @param int $userId - * @return ResultsetInterface|Resultset|ImFriendGroupModel[] - */ - public function findImFriendGroups($userId) - { - return ImFriendGroupModel::query() - ->where('user_id = :user_id:', ['user_id' => $userId]) - ->andWhere('deleted = 0') - ->execute(); - } - - /** - * @param int $userId - * @return ResultsetInterface|Resultset|ImGroupModel[] - */ - public function findImGroups($userId) - { - return $this->modelsManager->createBuilder() - ->columns('g.*') - ->addFrom(ImGroupModel::class, 'g') - ->join(ImGroupUserModel::class, 'g.id = gu.group_id', 'gu') - ->where('gu.user_id = :user_id:', ['user_id' => $userId]) - ->andWhere('g.deleted = 0') - ->getQuery()->execute(); - } - - /** - * @param int $friendId - * @param int $userId - * @return ResultsetInterface|Resultset|ImFriendMessageModel[] - */ - public function findUnreadImFriendMessages($friendId, $userId) - { - return ImFriendMessageModel::find([ - 'conditions' => 'sender_id = ?1 AND receiver_id = ?2 AND viewed = ?3', - 'bind' => [1 => $friendId, 2 => $userId, 3 => 0], - ]); - } - - /** - * @param int $userId - * @param int $itemType - * @return Model|bool|ImSystemMessageModel - */ - public function findImSystemMessage($userId, $itemType) - { - return ImSystemMessageModel::findFirst([ - 'conditions' => 'receiver_id = ?1 AND item_type = ?2', - 'bind' => [1 => $userId, 2 => $itemType], - 'order' => 'id DESC', - ]); - } - - /** - * @param int $userId - * @return ResultsetInterface|Resultset|ImFriendMessageModel[] - */ - public function findUnreadImSystemMessages($userId) - { - return ImSystemMessageModel::find([ - 'conditions' => 'receiver_id = ?1 AND viewed = ?2', - 'bind' => [1 => $userId, 2 => 0], - ]); - } - - public function countUnreadImSystemMessages($userId) - { - return ImSystemMessageModel::count([ - 'conditions' => 'receiver_id = ?1 AND viewed = ?2', - 'bind' => [1 => $userId, 2 => 0], - ]); - } - } diff --git a/app/Validators/Category.php b/app/Validators/Category.php index 34e608fd..a787bca5 100644 --- a/app/Validators/Category.php +++ b/app/Validators/Category.php @@ -55,13 +55,13 @@ class Category extends Validator return $category; } - public function checkParent($parentId) + public function checkParent($id) { $categoryRepo = new CategoryRepo(); - $category = $categoryRepo->findById($parentId); + $category = $categoryRepo->findById($id); - if (!$category || $category->deleted == 1) { + if (!$category) { throw new BadRequestException('category.parent_not_found'); } diff --git a/app/Validators/Chapter.php b/app/Validators/Chapter.php index e1b7f5fc..5e8cb9a7 100644 --- a/app/Validators/Chapter.php +++ b/app/Validators/Chapter.php @@ -57,27 +57,21 @@ class Chapter extends Validator return $chapter; } - public function checkCourse($courseId) + public function checkCourse($id) { - $courseRepo = new CourseRepo(); + $validator = new Course(); - $course = $courseRepo->findById($courseId); - - if (!$course) { - throw new BadRequestException('chapter.invalid_course_id'); - } - - return $course; + return $validator->checkCourse($id); } - public function checkParent($parentId) + public function checkParent($id) { $chapterRepo = new ChapterRepo(); - $chapter = $chapterRepo->findById($parentId); + $chapter = $chapterRepo->findById($id); if (!$chapter) { - throw new BadRequestException('chapter.invalid_parent_id'); + throw new BadRequestException('chapter.parent_not_found'); } return $chapter; @@ -175,7 +169,7 @@ class Chapter extends Validator ]); if ($chapters->count() > 0) { - throw new BadRequestException('chapter.has_child_node'); + throw new BadRequestException('chapter.child_existed'); } } diff --git a/app/Validators/Consult.php b/app/Validators/Consult.php index 17059d16..01dcc6bc 100644 --- a/app/Validators/Consult.php +++ b/app/Validators/Consult.php @@ -4,7 +4,6 @@ namespace App\Validators; use App\Exceptions\BadRequest as BadRequestException; use App\Repos\Consult as ConsultRepo; -use App\Repos\Course as CourseRepo; class Consult extends Validator { @@ -22,17 +21,11 @@ class Consult extends Validator return $consult; } - public function checkCourse($courseId) + public function checkCourse($id) { - $courseRepo = new CourseRepo(); + $validator = new Course(); - $course = $courseRepo->findById($courseId); - - if (!$course) { - throw new BadRequestException('consult.invalid_course_id'); - } - - return $course; + return $validator->checkCourse($id); } public function checkQuestion($question) diff --git a/app/Validators/CourseUser.php b/app/Validators/CourseUser.php index b92071d1..8951dd7f 100644 --- a/app/Validators/CourseUser.php +++ b/app/Validators/CourseUser.php @@ -4,14 +4,12 @@ namespace App\Validators; use App\Exceptions\BadRequest as BadRequestException; use App\Library\Validators\Common as CommonValidator; -use App\Repos\Course as CourseRepo; use App\Repos\CourseUser as CourseUserRepo; -use App\Repos\User as UserRepo; class CourseUser extends Validator { - public function checkCourseUser($id) + public function checkRelation($id) { $courseUserRepo = new CourseUserRepo(); @@ -24,34 +22,18 @@ class CourseUser extends Validator return $courseUser; } - public function checkCourseId($courseId) + public function checkCourse($id) { - $value = $this->filter->sanitize($courseId, ['trim', 'int']); + $validator = new Course(); - $courseRepo = new CourseRepo(); - - $course = $courseRepo->findById($value); - - if (!$course) { - throw new BadRequestException('course_user.course_not_found'); - } - - return $course->id; + return $validator->checkCourse($id); } - public function checkUserId($userId) + public function checkUser($id) { - $value = $this->filter->sanitize($userId, ['trim', 'int']); + $validator = new User(); - $userRepo = new UserRepo(); - - $user = $userRepo->findById($value); - - if (!$user) { - throw new BadRequestException('course_user.user_not_found'); - } - - return $user->id; + return $validator->checkUser($id); } public function checkExpiryTime($expiryTime) diff --git a/app/Validators/ImGroupUser.php b/app/Validators/ImGroupUser.php index c1a55918..d9f003f1 100644 --- a/app/Validators/ImGroupUser.php +++ b/app/Validators/ImGroupUser.php @@ -8,11 +8,18 @@ use App\Repos\ImGroupUser as ImGroupUserRepo; class ImGroupUser extends Validator { - public function checkGroup($groupId) + public function checkGroup($id) { $validator = new ImGroup(); - return $validator->checkGroup($groupId); + return $validator->checkGroup($id); + } + + public function checkUser($id) + { + $validator = new User(); + + return $validator->checkUser($id); } public function checkRemark($remark) @@ -22,7 +29,7 @@ class ImGroupUser extends Validator $length = kg_strlen($value); if ($length > 30) { - throw new BadRequestException('im_chat_group_user.remark_too_long'); + throw new BadRequestException('im_group_user.remark_too_long'); } return $remark; @@ -35,7 +42,7 @@ class ImGroupUser extends Validator $record = $repo->findGroupUser($userId, $groupId); if (!$record) { - throw new BadRequestException('im_chat_group_user.not_found'); + throw new BadRequestException('im_group_user.not_found'); } return $record; @@ -48,7 +55,7 @@ class ImGroupUser extends Validator $record = $repo->findGroupUser($userId, $groupId); if ($record && $record->blocked == 0) { - throw new BadRequestException('im_chat_group_user.has_joined'); + throw new BadRequestException('im_group_user.has_joined'); } } @@ -59,7 +66,7 @@ class ImGroupUser extends Validator $record = $repo->findGroupUser($userId, $groupId); if ($record && $record->blocked == 1) { - throw new BadRequestException('im_chat_group_user.blocked'); + throw new BadRequestException('im_group_user.blocked'); } } diff --git a/app/Validators/ImUser.php b/app/Validators/ImUser.php new file mode 100644 index 00000000..32dbdffe --- /dev/null +++ b/app/Validators/ImUser.php @@ -0,0 +1,55 @@ +findById($id); + + if (!$user) { + throw new BadRequestException('im_user.not_found'); + } + + return $user; + } + + public function checkSign($sign) + { + $value = $this->filter->sanitize($sign, ['trim', 'string']); + + $length = kg_strlen($value); + + if ($length > 30) { + throw new BadRequestException('im_user.sign_too_long'); + } + + return $value; + } + + public function checkSkin($url) + { + if (empty($url)) { + throw new BadRequestException('im_user.invalid_skin'); + } + + return $url; + } + + public function checkStatus($status) + { + if (!in_array($status, ['online', 'hide'])) { + throw new BadRequestException('im_user.invalid_status'); + } + + return $status; + } + +} diff --git a/app/Validators/Review.php b/app/Validators/Review.php index 18e8c2e2..92355106 100644 --- a/app/Validators/Review.php +++ b/app/Validators/Review.php @@ -4,7 +4,6 @@ namespace App\Validators; use App\Exceptions\BadRequest; use App\Exceptions\BadRequest as BadRequestException; -use App\Repos\Course as CourseRepo; use App\Repos\Review as ReviewRepo; class Review extends Validator @@ -23,17 +22,11 @@ class Review extends Validator return $review; } - public function checkCourse($courseId) + public function checkCourse($id) { - $courseRepo = new CourseRepo(); + $validator = new Course(); - $course = $courseRepo->findById($courseId); - - if (!$course) { - throw new BadRequestException('review.course_not_found'); - } - - return $course; + return $validator->checkCourse($id); } public function checkContent($content) diff --git a/app/Validators/User.php b/app/Validators/User.php index bb745222..6b6a216f 100644 --- a/app/Validators/User.php +++ b/app/Validators/User.php @@ -101,28 +101,6 @@ class User extends Validator return $value; } - public function checkImSign($sign) - { - $value = $this->filter->sanitize($sign, ['trim', 'string']); - - $length = kg_strlen($value); - - if ($length > 50) { - throw new BadRequestException('user.im_sign_too_long'); - } - - return $value; - } - - public function checkImSkin($url) - { - if (empty($url)) { - throw new BadRequestException('user.invalid_im_skin'); - } - - return $url; - } - public function checkGender($value) { $list = UserModel::genderTypes(); diff --git a/config/config.default.php b/config/config.default.php index 870109ad..70ad4f74 100644 --- a/config/config.default.php +++ b/config/config.default.php @@ -17,6 +17,11 @@ $config['key'] = 'mlq7jQ1Py8kTdW9m'; */ $config['timezone'] = 'Asia/Shanghai'; +/** + * 日志级别 + */ +$config['log']['level'] = Phalcon\Logger::INFO; + /** * 网站根地址,必须以"/"结尾 */ @@ -118,8 +123,13 @@ $config['throttle']['lifetime'] = 60; $config['throttle']['rate_limit'] = 60; /** - * 日志级别 + * 客户端连接地址 */ -$config['log']['level'] = Phalcon\Logger::INFO; +$config['websocket']['url'] = 'ws://127.0.0.1:8282'; + +/** + * gateway和worker注册地址 + */ +$config['websocket']['register_address'] = '127.0.0.1:1238'; return $config; diff --git a/config/errors.php b/config/errors.php index 5d8cfe84..96ff1b10 100644 --- a/config/errors.php +++ b/config/errors.php @@ -137,8 +137,6 @@ $error['package.invalid_publish_status'] = '无效的发布状态'; * 课程成员 */ $error['course_user.not_found'] = '课程学员不存在'; -$error['course_user.course_not_found'] = '课程不存在'; -$error['course_user.user_not_found'] = '用户不存在'; $error['course_user.apply_not_allowed'] = '当前不允许申请课程'; $error['course_user.has_joined_course'] = '已经加入当前课程'; $error['course_user.invalid_expiry_time'] = '无效的过期时间'; @@ -147,19 +145,18 @@ $error['course_user.invalid_expiry_time'] = '无效的过期时间'; * 章节相关 */ $error['chapter.not_found'] = '章节不存在'; -$error['chapter.invalid_free_status'] = '无效的免费状态'; -$error['chapter.invalid_course_id'] = '无效的课程编号'; -$error['chapter.invalid_parent_id'] = '无效的父级编号'; +$error['chapter.parent_not_found'] = '父级章节不存在'; $error['chapter.invalid_priority'] = '无效的排序值(范围:1-255)'; +$error['chapter.invalid_free_status'] = '无效的免费状态'; $error['chapter.invalid_publish_status'] = '无效的发布状态'; $error['chapter.title_too_short'] = '标题太短(少于2个字符)'; $error['chapter.title_too_long'] = '标题太长(多于30个字符)'; $error['chapter.summary_too_long'] = '简介太长(多于255个字符)'; $error['chapter.vod_not_ready'] = '点播资源尚未就绪'; +$error['chapter.read_not_ready'] = '文章内容尚未就绪'; $error['chapter.live_not_start'] = '直播尚未开始'; $error['chapter.live_time_empty'] = '直播时间尚未设置'; -$error['chapter.read_not_ready'] = '文章内容尚未就绪'; -$error['chapter.has_child_node'] = '不允许相关操作(存在子节点)'; +$error['chapter.child_existed'] = '不允许相关操作(存在子章节)'; /** * 点播相关 @@ -189,7 +186,6 @@ $error['chapter_read.content_too_long'] = '文章内容太长(多于65535个 * 评价相关 */ $error['review.not_found'] = '评价不存在'; -$error['review.course_not_found'] = '课程不存在'; $error['review.invalid_rating'] = '无效的评分(范围:1-5)'; $error['review.invalid_publish_status'] = '无效的发布状态'; $error['review.content_too_short'] = '评价内容太短(少于5个字符)'; @@ -329,21 +325,21 @@ $error['learning.invalid_interval'] = '无效的间隔时间'; /** * 即时通讯 */ - $error['im_friend_group.not_found'] = '分组不存在'; $error['im_friend_group.name_too_short'] = '分组名太短(少于2字符)'; $error['im_friend_group.name_too_long'] = '分组名太长(超过15字符)'; -$error['im_chat_group.not_found'] = '群组不存在'; -$error['im_chat_group.name_too_short'] = '群组名太短(少于2字符)'; -$error['im_chat_group.name_too_long'] = '群组名太长(超过30字符)'; -$error['im_chat_group.about_too_long'] = '群组简介太长(超过255字符)'; +$error['im_group.not_found'] = '群组不存在'; +$error['im_group.name_too_short'] = '群组名太短(少于2字符)'; +$error['im_group.name_too_long'] = '群组名太长(超过30字符)'; +$error['im_group.about_too_long'] = '群组简介太长(超过255字符)'; -$error['im_chat_group_user.has_joined'] = '已经加入过群组'; -$error['im_chat_group_user.blocked'] = '对方拒绝接收消息'; -$error['im_chat_group_user.remark_too_long'] = '验证信息太长(超过30字符)'; +$error['im_group_user.not_found'] = '群组关系不存在'; +$error['im_group_user.remark_too_long'] = '验证信息太长(超过30字符)'; +$error['im_group_user.has_joined'] = '已经加入过群组'; +$error['im_group_user.blocked'] = '对方拒绝接收消息'; -$error['im_friend_user.user_not_found'] = '用户不存在'; +$error['im_friend_user.not_found'] = '好友关系不存在'; $error['im_friend_user.remark_too_long'] = '验证信息太长(超过30字符)'; $error['im_friend_user.self_apply'] = '不能添加自己为好友'; $error['im_friend_user.has_joined'] = '已经是好友啦'; diff --git a/public/static/admin/js/common.js b/public/static/admin/js/common.js index 2c5629c6..35afe27f 100644 --- a/public/static/admin/js/common.js +++ b/public/static/admin/js/common.js @@ -10,12 +10,24 @@ layui.use(['jquery', 'form', 'element', 'layer', 'dropdown'], function () { var form = layui.form; var layer = layui.layer; + var $token = $('meta[name="csrf-token"]'); + $.ajaxSetup({ beforeSend: function (xhr) { - xhr.setRequestHeader('X-Csrf-Token', $('meta[name="csrf-token"]').attr('content')); + xhr.setRequestHeader('X-Csrf-Token', $token.attr('content')); } }); + setInterval(function () { + $.ajax({ + type: 'POST', + url: '/token/refresh', + success: function (res) { + $token.attr('content', res.token); + } + }); + }, 300000); + form.on('submit(go)', function (data) { var submit = $(this); submit.attr('disabled', 'disabled').addClass('layui-btn-disabled'); diff --git a/public/static/web/js/common.js b/public/static/web/js/common.js index cfd081c8..63f6b2cb 100644 --- a/public/static/web/js/common.js +++ b/public/static/web/js/common.js @@ -11,28 +11,23 @@ layui.use(['jquery', 'form', 'element', 'layer', 'helper'], function () { var layer = layui.layer; var helper = layui.helper; + var $token = $('meta[name="csrf-token"]'); + $.ajaxSetup({ beforeSend: function (xhr) { - xhr.setRequestHeader('X-Csrf-Token', $('meta[name="csrf-token"]').attr('content')); + xhr.setRequestHeader('X-Csrf-Token', $token.attr('content')); } }); - /** - * @todo 定时刷新token - */ - /** - setInterval(function () { - var $token = $('meta[name="csrf-token"]'); + setInterval(function () { $.ajax({ type: 'POST', url: '/token/refresh', - data: {token: $token.val()}, success: function (res) { $token.attr('content', res.token); } }); }, 300000); - */ form.on('submit(go)', function (data) { var submit = $(this); diff --git a/public/static/web/js/im.js b/public/static/web/js/im.js index d55be50a..11294d8f 100644 --- a/public/static/web/js/im.js +++ b/public/static/web/js/im.js @@ -89,7 +89,7 @@ layui.use(['jquery', 'layim'], function () { layim.on('online', function (status) { $.ajax({ type: 'POST', - url: '/im/online/update', + url: '/im/status/update', data: {status: status} }); }); @@ -102,11 +102,11 @@ layui.use(['jquery', 'layim'], function () { }); }); - layim.on('setSkin', function (file, src) { + layim.on('setSkin', function (filename, src) { $.ajax({ type: 'POST', url: '/im/skin/update', - data: {skin: src} + data: {skin: filename} }); });