123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602 |
- <?php
- /**
- * 群组相关
- * @author solu
- */
- class GroupInfo extends Model {
- protected $tableName = 'group_info';
- protected $dbKey = 'dw_chat';
- const OFFICIAL_ID = 10000; // 官方群id
- const MAX_ADMIN_COUNT = 6; // 最多管理员数量
- const REDIS_GROUP_ID_HASH = 'globals:group_id_hash';
- const STATE_USE = 1;
- const STATE_DISCARD = 0;
- /**
- * 加入群组
- * @author solu
- * @param $userId
- * @param $groupId
- * @param $group
- * @return bool
- * @throws Exception
- */
- public function joinGroup($userId, $groupId, $group = []) {
- $where = ['group_id' => $groupId];
- !$group && $group = $this->objTable->getRow($where);
- if (!$group || $group['state'] != self::STATE_USE) {
- throw new Exception('group not exists', CODE_PARAM_ERROR);
- }
- $objSession = new Session();
- $objUserGroup = new TableHelper('user_group', 'dw_chat');
- $row = $objUserGroup->getRow(['user_id' => $userId, 'group_id' => $groupId, 'state' => UserGroup::STATE_IN_GROUP]);
- if (!$row) {
- $data = [
- 'user_id' => $userId,
- 'group_id' => $groupId,
- 'join_time' => NOW,
- 'state' => UserGroup::STATE_IN_GROUP,
- ];
- if (!$objUserGroup->replaceObject($data)) {
- throw new Exception('join fail', CODE_DB_ERROR);
- }
- $memberNum = $group['member_num'] + 1;
- $where['member_num'] = $group['member_num'];
- if (!$this->objTable->updateObject(['member_num' => $memberNum], $where)) {
- throw new Exception('update group info fail', CODE_DB_ERROR);
- }
- // 给自己发消息订阅新群组
- ThirdApi::pushPersonEvent($userId, [
- 'type' => 'join_group',
- 'group_id' => $groupId,
- ]);
- // 发群消息
- try {
- $objSession->sendGroupMsg($userId, $groupId, Session::MSG_TYPE_EVENT, '', false, true, ['event_type' => 'join']);
- } catch (Exception $e) {
- var_log($e->getMessage());
- }
- // $user_info = User::getUserInfoById($userId);
- // // 给群组发消息有人加入了
- // ThirdApi::pushGroupEvent($groupId, [
- // 'type' => 'join',
- // 'group_id' => $groupId,
- // 'user_info' => $user_info,
- // ]);
- }
- $where = [
- 'user_id' => $userId,
- 'session_id' => $groupId,
- ];
- // 有可能删除了会话
- if (!$objSession->objTable->getCount($where)) {
- $sessData = $where;
- $sessData['is_group'] = 1;
- $objSession->objTable->replaceObject($sessData);
- }
- return true;
- }
- /**
- * 加入群组
- * @author solu
- * @param $userId
- * @param $groupId
- * @param $group
- * @param $memberNum
- * @return bool
- * @throws Exception
- */
- public function appendToGroup($userIds, $groupId, $memberNum = 0) {
- $userGroupDatas = [];
- $sessDatas = [];
- foreach ($userIds as $userId) {
- $userGroupDatas[] = [
- 'user_id' => $userId,
- 'group_id' => $groupId,
- 'join_time' => NOW,
- 'state' => UserGroup::STATE_IN_GROUP,
- ];
- $sessDatas[] = [
- 'user_id' => $userId,
- 'session_id' => $groupId,
- 'is_group' => 1,
- ];
- }
- $objUserGroup = new UserGroup();
- $objUserGroup->objTable->replaceObjects2($userGroupDatas);
- $objSession = new Session();
- $objSession->objTable->replaceObjects2($sessDatas);
- $where = ['group_id' => $groupId];
- $newData = [
- 'member_num' => count($userIds) + $memberNum,
- 'group_name' => $groupId,
- ];
- $this->objTable->updateObject($newData, $where);
- }
- /**
- * 离开群组
- * @author solu
- * @param $userId
- * @param $groupId
- * @param $group
- * @return bool
- * @throws Exception
- */
- public function leaveGroup($userId, $groupId, $group = []) {
- $groupId = (int) $groupId;
- $where = ['group_id' => $groupId];
- !$group && $group = $this->objTable->getRow($where);
- if (!$group) {
- throw new Exception('group not exists', CODE_PARAM_ERROR);
- }
- $objUserGroup = new UserGroup();
- if (!$objUserGroup->inGroup($groupId, $userId)) {
- throw new Exception('not in group', CODE_PARAM_ERROR);
- }
- $groupUserIds = $objUserGroup->getUserIdListSortByAdminAndJoinTime($groupId);
- $isCreator = $this->isCreator($groupId, $userId);
- $objSession = new Session();
- $objUserGroup->objTable->autoCommit(false);
- $ugWhere = [
- 'user_id' => $userId,
- 'group_id' => $groupId,
- ];
- if (!$objUserGroup->objTable->updateObject(['state' => UserGroup::STATE_LEAVE, 'is_admin' => 0], $ugWhere)) {
- throw new Exception('leave fail', CODE_DB_ERROR);
- }
- $creatorField = '';
- if (count($groupUserIds) == 1) { // 最后一个人离开,去掉群主,群解散
- $creatorField = ' , creator=0';
- } elseif ($isCreator) { // 群主离开, 群主顺移给下一位
- $newCreator = 0;
- for ($i = 0; $i < count($groupUserIds); $i++) {
- if ($groupUserIds[$i] == $userId) {
- continue;
- }
- $newCreator = $groupUserIds[$i];
- break;
- }
- $creatorField = " , creator={$newCreator}";
- // 新群主设置成管理员
- $objUserGroup->setData($groupId, $newCreator, ['is_admin' => 1]);
- }
- $sql = "UPDATE group_info SET member_num = member_num - 1 {$creatorField} WHERE group_id = {$groupId}";
- $this->objDb->update($sql);
- $sessWhere = [
- 'user_id' => $userId,
- 'session_id' => $groupId,
- ];
- if (!$objSession->objTable->delObject($sessWhere)) {
- throw new Exception('delete session error', CODE_DB_ERROR);
- }
- $objUserGroup->objTable->commit();
- // 发群消息
- try {
- $objSession->sendGroupMsg($userId, $groupId, Session::MSG_TYPE_EVENT, '', false, true, ['event_type' => 'leave_group']);
- } catch (Exception $e) {
- var_log($e->getMessage());
- }
- // 给自己发消息订阅新群组
- ThirdApi::pushPersonEvent($userId, [
- 'type' => 'leave_group',
- 'group_id' => $groupId,
- ]);
- // $user_info = User::getUserInfoById($userId);
- //
- // // 给群组发消息有人离开了
- // ThirdApi::pushGroupEvent($groupId, [
- // 'type' => 'leave',
- // 'group_id' => $groupId,
- // 'user_id' => $userId,
- // 'user_info' => $user_info,
- // ]);
- return true;
- }
- /**
- * 更新信息
- * @author solu
- * @param $userId
- * @param $groupId
- * @param array $data
- * @return bool|int
- * @throws Exception
- */
- public function setData($userId, $groupId, array $data) {
- if (!(new UserGroup())->isAdmin($groupId, $userId)) {
- throw new Exception('no permission', CODE_NO_PERMITION);
- }
- $data['update_time'] = NOW;
- return $this->objTable->updateObject($data, ['group_id' => $groupId]);
- }
- /**
- * 分享连接
- * @author solu
- * @param string $name
- * @return string
- */
- public static function genInviteUrl($name) {
- if (!$name) {
- return '';
- }
- return sprintf('%s/s/%s', URL_SELF, $name);
- }
- /**
- * 是否群主
- * @author solu
- * @param $groupId
- * @param $userId
- * @return bool
- */
- public function isCreator($groupId, $userId) {
- $creator = $this->objTable->getOne(['group_id' => $groupId], ['_field' => 'creator']);
- return intval($creator) == $userId;
- }
- /**
- * 设置群管理
- * @author solu
- * @param $groupId
- * @param $creator
- * @param $userIds
- * @return bool
- * @throws Exception
- */
- public function addAdmin($groupId, $creator, $userIds) {
- if (!$this->isCreator($groupId, $creator)) {
- throw new Exception('no permission', CODE_NO_PERMITION);
- }
- $objUserGroup = new UserGroup();
- $c = $objUserGroup->objTable->getCount(['group_id' => $groupId, 'is_admin' => 1]);
- $c += count($userIds);
- if ($c > self::MAX_ADMIN_COUNT) {
- throw new Exception('too many admins', CODE_NORMAL_ERROR);
- }
- if (!$objUserGroup->setData($groupId, $userIds, ['is_admin' => 1])) {
- throw new Exception('set admin fail', CODE_NORMAL_ERROR);
- }
- return true;
- }
- /**
- * 移除管理员
- * @author solu
- * @param $groupId
- * @param $creator
- * @param $userId
- * @return bool
- * @throws Exception
- */
- public function removeAdmin($groupId, $creator, $userId) {
- if (!$this->isCreator($groupId, $creator)) {
- throw new Exception('no permission', CODE_NO_PERMITION);
- }
- if ($userId == $creator) {
- throw new Exception('can not remove creator', CODE_NORMAL_ERROR);
- }
- $objUserGroup = new UserGroup();
- if (!$objUserGroup->setData($groupId, $userId, ['is_admin' => 0])) {
- throw new Exception('set admin fail', CODE_NORMAL_ERROR);
- }
- return true;
- }
- /**
- * 搜索群用户信息
- * @author solu
- * @param $groupId
- * @param $keyword
- * @return array
- */
- public function memberSearch($groupId, $keyword) {
- $objUserGroup = new UserGroup();
- $userIds = $objUserGroup->objTable->getCol(['group_id' => $groupId], ['_field' => 'user_id']);
- if (!$userIds) {
- return [];
- }
- $objUserInfo = new TableHelper('user_info', 'dw_chat');
- // $keyword 是外部传来的参数,会有注入攻击
- $keyword = $objUserInfo->escape($keyword);
- $userInfo = $objUserInfo->getAll(['user_id' => $userIds], [
- '_where' => "(user_name like '{$keyword}%' || nick_name like '{$keyword}%')",
- '_field' => 'user_id, user_name, nick_name, cover_photo',
- '_sortKey' => 'last_login_time DESC',
- // '_debug' => true,
- ]);
- coverReplaceArrImage($userInfo, 'cover_photo');
- return $userInfo;
- }
- /**
- * 获取用户名
- * @author solu
- * @param $groupId
- * @return string
- */
- public static function getGroupNameById($groupId) {
- $objRedis = dwRedis::init();
- $userName = $objRedis->hGet(self::REDIS_GROUP_ID_HASH, $groupId);
- if (!$userName) {
- $obj = new GroupInfo();
- $userName = $obj->objTable->getOne(['group_id' => $groupId], ['_field' => 'group_title']);
- if ($userName) {
- self::setGroupNameById($groupId, $userName, $objRedis);
- }
- }
- return $userName;
- }
- public static function setGroupNameById($groupId, $user_name, $objRedis = null) {
- !$objRedis && $objRedis = dwRedis::init();
- $objRedis->hSet(self::REDIS_GROUP_ID_HASH, $groupId, $user_name);
- }
- /**
- * 转移群主
- * @author solu
- * @param $groupId
- * @param $old
- * @param $new
- * @return bool
- * @throws Exception
- */
- public function changeCreator($groupId, $old, $new) {
- if (!$this->isCreator($groupId, $old)) {
- throw new Exception('no permission', CODE_NO_PERMITION);
- }
- if ($old == $new) {
- throw new Exception('same creator', CODE_NORMAL_ERROR);
- }
- $this->objTable->updateObject(['creator' => $new], ['group_id' => $groupId]);
- (new UserGroup())->setData($groupId, $old, ['is_admin' => 0]);
- return true;
- }
- /**
- * 获取客服id
- * @author solu
- * @param $userIds
- * @return array
- */
- public function getGroupServerFromUserIds($userIds) {
- $items = $this->objTable->getAll(['server_id' => $userIds], ['_field' => 'group_id, server_id']);
- return arrayFormatKey($items, 'server_id', 'group_id');
- }
- public function checkPermission($group_id, $user_id) {
- $_field = 'is_public';
- $objGroupInfo = new GroupInfo();
- $is_public = (int) $objGroupInfo->objTable->getOne(['group_id' => $group_id], compact('_field'));
- if (!$is_public) {
- // 私有群要判断用户是否存在
- if ($user_id) {
- $objUserGroup = new UserGroup();
- $state = 1;
- $count = $objUserGroup->objTable->getCount(compact('group_id', 'user_id', 'state'));
- if (!$count) {
- Response::error(CODE_NO_PERMITION, 'the group is private');
- }
- } else {
- Response::error(CODE_NO_PERMITION, 'the group is private');
- }
- }
- }
- public function getGroupIdFromTgGroupId($tgGroupId) {
- $groupId = $this->objTable->getOne(['tg_group_id' => $tgGroupId], ['_field' => 'group_id']);
- return intval($groupId);
- }
- /**
- * 热门群组
- * @return array
- */
- public function getHotList() {
- $list = $this->objTable->getAll(['is_auth' => 1, 'is_public' => 1], ['_limit' => 100]);
- $fillNum = 24 - count($list);
- if ($fillNum > 0) {
- // 找用户自发来补充
- $keyWord = ['_limit' => 200, '_sortKey' => 'member_num DESC'];
- $list2 = $this->objTable->getAll(['is_auth' => 0, 'is_public' => 1], $keyWord);
- // 随机取10个
- $list2 = $this->array_random_assoc($list2, 24 - count($list));
- $list = array_merge($list, $list2);
- }
- $group_ids = array_column($list, 'group_id');
- $existList = [];
- $userId = User::getUserId();
- if ($userId) {
- $_field = 'group_id';
- $objUserGroup = new UserGroup();
- $where = ['group_id' => $group_ids, 'state' => 1, 'user_id' => $userId];
- $existList = $objUserGroup->objTable->getCol($where, ['_field' => $_field]);
- }
- foreach ($list as $i => $value) {
- $value['is_join'] = in_array($value['group_id'], $existList) ? 1 : 0;
- $value['cover_photo'] = awsReplaceImg($value['cover_photo']);
- $list[$i] = $value;
- }
- return $list;
- }
- private function array_random_assoc($arr, $num = 1) {
- $keys = array_keys($arr);
- shuffle($keys);
- $r = array();
- for ($i = 0; $i < $num; $i++) {
- $r[$keys[$i]] = $arr[$keys[$i]];
- }
- return $r;
- }
- /**
- * 创建群
- * @param $args
- * @return array|null
- * @throws Exception
- */
- public function create($args) {
- $creator = $args['creator'];
- $user_id_list = arrayPop($args, 'user_id_list');
- if (!$creator) {
- throw new Exception("miss creator", CODE_PARAM_ERROR);
- }
- $state = self::STATE_USE;
- $num = $this->objTable->getCount(compact('creator', 'state'));
- if ($num >= 100) {
- throw new Exception("create group num >= {$num}", CODE_NO_PERMITION);
- }
- $args['server_id'] = $args['creator'];
- $memberNum = 0;
- $args['member_num'] = $memberNum;
- $args['create_time'] = $args['update_time'] = NOW;
- $this->objTable->addObject($args);
- $group_id = $this->objTable->getInsertId();
- // 设置group_name
- $this->objTable->updateObject(['group_name' => $group_id], ['group_id' => $group_id]);
- // 默认加群
- $this->joinGroup($creator, $group_id);
- $memberNum++;
- // 设置为管理员
- $objUserGroup = new UserGroup();
- $data = [
- 'is_admin' => 1,
- 'state' => UserGroup::STATE_IN_GROUP,
- ];
- $objUserGroup->setData($group_id, $creator, $data);
- $friend_ids = $this->_getFriendList($creator, $user_id_list);
- if ($friend_ids) {
- $this->appendToGroup($friend_ids, $group_id, $memberNum);
- }
- $objSession = new Session();
- $_field = 'session_id, is_group, read_hash, is_pin, pin_time_int, is_mute';
- $sesion = $objSession->objTable->getRow(['session_id' => $group_id], compact('_field'));
- $sesion['name'] = $args['group_title'];
- $sesion['cover_photo'] = $args['cover_photo'];
- return $sesion;
- }
- // 只过滤出真正的朋友
- private function _getFriendList($userId, $friend_id_list) {
- $friend_ids = explode(',', $friend_id_list);
- $map = [];
- foreach ($friend_ids as $friend_id) {
- $friend_id = (int) $friend_id;
- $sessionId = Session::getPersonSessionId($userId, $friend_id);
- $map[$sessionId] = $friend_id;
- }
- if (!$map) {
- return [];
- }
- $where = [
- 'user_id' => $userId,
- 'session_id' => array_keys($map),
- ];
- $_field = 'session_id';
- $objSession = new Session();
- $sessionIds = $objSession->objTable->getCol($where, compact('_field'));
- if (!$sessionIds) return [];
- $friend_ids = [];
- foreach ($sessionIds as $sessionId) {
- $friend_ids[] = $map[$sessionId];
- }
- return $friend_ids;
- }
- /**
- * 删除群
- * @author solu
- * @param $creator
- * @param $groupId
- * @return bool
- * @throws Exception
- */
- public function discard($creator, $groupId) {
- if (!$this->objTable->getRow(['group_id' => $groupId, 'creator' => $creator])) {
- throw new Exception('group not found', CODE_PARAM_ERROR);
- }
- $objUserGroup = new UserGroup();
- $objSession = new Session();
- $this->objTable->autoCommit(false);
- $this->objTable->updateObject(['member_num' => 0, 'state' => self::STATE_DISCARD], ['group_id' => $groupId]);
- $objUserGroup->objTable->updateObject(['state' => UserGroup::STATE_LEAVE], ['group_id' => $groupId]);
- $objSession->objTable->delObject(['session_id' => $groupId, 'is_group' => 1]);
- $this->objTable->commit();
- return true;
- }
- }
|