GroupInfo.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. <?php
  2. /**
  3. * 群组相关
  4. * @author solu
  5. */
  6. class GroupInfo extends Model {
  7. protected $tableName = 'group_info';
  8. protected $dbKey = 'dw_chat';
  9. const OFFICIAL_ID = 10000; // 官方群id
  10. const MAX_ADMIN_COUNT = 6; // 最多管理员数量
  11. const REDIS_GROUP_ID_HASH = 'globals:group_id_hash';
  12. /**
  13. * 加入群组
  14. * @author solu
  15. * @param $userId
  16. * @param $groupId
  17. * @param $group
  18. * @return bool
  19. * @throws Exception
  20. */
  21. public function joinGroup($userId, $groupId, $group = []) {
  22. $where = ['group_id' => $groupId];
  23. !$group && $group = $this->objTable->getRow($where);
  24. if (!$group) {
  25. throw new Exception('group not exists', CODE_PARAM_ERROR);
  26. }
  27. $objUserGroup = new TableHelper('user_group', 'dw_chat');
  28. $row = $objUserGroup->getRow(['user_id' => $userId, 'group_id' => $groupId, 'state' => UserGroup::STATE_IN_GROUP]);
  29. if (!$row) {
  30. $data = [
  31. 'user_id' => $userId,
  32. 'group_id' => $groupId,
  33. 'join_time' => NOW,
  34. 'state' => UserGroup::STATE_IN_GROUP,
  35. ];
  36. if (!$objUserGroup->replaceObject($data)) {
  37. throw new Exception('join fail', CODE_DB_ERROR);
  38. }
  39. $memberNum = $group['member_num'] + 1;
  40. $where['member_num'] = $group['member_num'];
  41. if (!$this->objTable->updateObject(['member_num' => $memberNum], $where)) {
  42. throw new Exception('update group info fail', CODE_DB_ERROR);
  43. }
  44. // 给自己发消息订阅新群组
  45. ThirdApi::pushPersonEvent($userId, [
  46. 'type' => 'join_group',
  47. 'group_id' => $groupId,
  48. ]);
  49. $user_info = User::getUserInfoById($userId);
  50. // 给群组发消息有人加入了
  51. ThirdApi::pushGroupEvent($groupId, [
  52. 'type' => 'join',
  53. 'group_id' => $groupId,
  54. 'user_info' => $user_info,
  55. ]);
  56. }
  57. $objSession = new Session();
  58. $where = [
  59. 'user_id' => $userId,
  60. 'session_id' => $groupId,
  61. ];
  62. // 有可能删除了会话
  63. if (!$objSession->objTable->getCount($where)) {
  64. $sessData = $where;
  65. $sessData['is_group'] = 1;
  66. $objSession->objTable->replaceObject($sessData);
  67. }
  68. return true;
  69. }
  70. /**
  71. * 加入群组
  72. * @author solu
  73. * @param $userId
  74. * @param $groupId
  75. * @param $group
  76. * @param $memberNum
  77. * @return bool
  78. * @throws Exception
  79. */
  80. public function appendToGroup($userIds, $groupId, $memberNum = 0) {
  81. $userGroupDatas = [];
  82. $sessDatas = [];
  83. foreach ($userIds as $userId) {
  84. $userGroupDatas[] = [
  85. 'user_id' => $userId,
  86. 'group_id' => $groupId,
  87. 'join_time' => NOW,
  88. 'state' => UserGroup::STATE_IN_GROUP,
  89. ];
  90. $sessDatas[] = [
  91. 'user_id' => $userId,
  92. 'session_id' => $groupId,
  93. 'is_group' => 1,
  94. ];
  95. }
  96. $objUserGroup = new UserGroup();
  97. $objUserGroup->objTable->replaceObjects2($userGroupDatas);
  98. $objSession = new Session();
  99. $objSession->objTable->replaceObjects2($sessDatas);
  100. $where = ['group_id' => $groupId];
  101. $newData = [
  102. 'member_num' => count($userIds) + $memberNum,
  103. 'group_name' => $groupId,
  104. ];
  105. $this->objTable->updateObject($newData, $where);
  106. }
  107. /**
  108. * 离开群组
  109. * @author solu
  110. * @param $userId
  111. * @param $groupId
  112. * @param $group
  113. * @return bool
  114. * @throws Exception
  115. */
  116. public function leaveGroup($userId, $groupId, $group = []) {
  117. $groupId = (int) $groupId;
  118. $where = ['group_id' => $groupId];
  119. !$group && $group = $this->objTable->getRow($where);
  120. if (!$group) {
  121. throw new Exception('group not exists', CODE_PARAM_ERROR);
  122. }
  123. $objUserGroup = new UserGroup();
  124. if (!$objUserGroup->inGroup($groupId, $userId)) {
  125. throw new Exception('not in group', CODE_PARAM_ERROR);
  126. }
  127. $groupUserIds = $objUserGroup->getUserIdListSortByAdminAndJoinTime($groupId);
  128. $isCreator = $this->isCreator($groupId, $userId);
  129. $objSession = new Session();
  130. $objUserGroup->objTable->autoCommit(false);
  131. $ugWhere = [
  132. 'user_id' => $userId,
  133. 'group_id' => $groupId,
  134. ];
  135. if (!$objUserGroup->objTable->updateObject(['state' => UserGroup::STATE_LEAVE, 'is_admin' => 0], $ugWhere)) {
  136. throw new Exception('leave fail', CODE_DB_ERROR);
  137. }
  138. $creatorField = '';
  139. if (count($groupUserIds) == 1) { // 最后一个人离开,去掉群主,群解散
  140. $creatorField = ' , creator=0';
  141. } elseif ($isCreator) { // 群主离开, 群主顺移给下一位
  142. $newCreator = 0;
  143. for ($i = 0; $i < count($groupUserIds); $i++) {
  144. if ($groupUserIds[$i] == $userId) {
  145. continue;
  146. }
  147. $newCreator = $groupUserIds[$i];
  148. break;
  149. }
  150. $creatorField = " , creator={$newCreator}";
  151. // 新群主设置成管理员
  152. $objUserGroup->setData($groupId, $newCreator, ['is_admin' => 1]);
  153. }
  154. $sql = "UPDATE group_info SET member_num = member_num - 1 {$creatorField} WHERE group_id = {$groupId}";
  155. $this->objDb->update($sql);
  156. $sessWhere = [
  157. 'user_id' => $userId,
  158. 'session_id' => $groupId,
  159. ];
  160. if (!$objSession->objTable->delObject($sessWhere)) {
  161. throw new Exception('delete session error', CODE_DB_ERROR);
  162. }
  163. $objUserGroup->objTable->commit();
  164. // 给自己发消息订阅新群组
  165. ThirdApi::pushPersonEvent($userId, [
  166. 'type' => 'leave_group',
  167. 'group_id' => $groupId,
  168. ]);
  169. $user_info = User::getUserInfoById($userId);
  170. // 给群组发消息有人离开了
  171. ThirdApi::pushGroupEvent($groupId, [
  172. 'type' => 'leave',
  173. 'group_id' => $groupId,
  174. 'user_id' => $userId,
  175. 'user_info' => $user_info,
  176. ]);
  177. return true;
  178. }
  179. /**
  180. * 更新信息
  181. * @author solu
  182. * @param $userId
  183. * @param $groupId
  184. * @param array $data
  185. * @return bool|int
  186. * @throws Exception
  187. */
  188. public function setData($userId, $groupId, array $data) {
  189. if (!(new UserGroup())->isAdmin($groupId, $userId)) {
  190. throw new Exception('no permission', CODE_NO_PERMITION);
  191. }
  192. $data['update_time'] = NOW;
  193. return $this->objTable->updateObject($data, ['group_id' => $groupId]);
  194. }
  195. /**
  196. * 分享连接
  197. * @author solu
  198. * @param string $name
  199. * @return string
  200. */
  201. public static function genInviteUrl($name) {
  202. if (!$name) {
  203. return '';
  204. }
  205. return sprintf('%s/s/%s', URL_SELF, $name);
  206. }
  207. /**
  208. * 是否群主
  209. * @author solu
  210. * @param $groupId
  211. * @param $userId
  212. * @return bool
  213. */
  214. public function isCreator($groupId, $userId) {
  215. $creator = $this->objTable->getOne(['group_id' => $groupId], ['_field' => 'creator']);
  216. return intval($creator) == $userId;
  217. }
  218. /**
  219. * 设置群管理
  220. * @author solu
  221. * @param $groupId
  222. * @param $creator
  223. * @param $userIds
  224. * @return bool
  225. * @throws Exception
  226. */
  227. public function addAdmin($groupId, $creator, $userIds) {
  228. if (!$this->isCreator($groupId, $creator)) {
  229. throw new Exception('no permission', CODE_NO_PERMITION);
  230. }
  231. $objUserGroup = new UserGroup();
  232. $c = $objUserGroup->objTable->getCount(['group_id' => $groupId, 'is_admin' => 1]);
  233. $c += count($userIds);
  234. if ($c > self::MAX_ADMIN_COUNT) {
  235. throw new Exception('too many admins', CODE_NORMAL_ERROR);
  236. }
  237. if (!$objUserGroup->setData($groupId, $userIds, ['is_admin' => 1])) {
  238. throw new Exception('set admin fail', CODE_NORMAL_ERROR);
  239. }
  240. return true;
  241. }
  242. /**
  243. * 移除管理员
  244. * @author solu
  245. * @param $groupId
  246. * @param $creator
  247. * @param $userId
  248. * @return bool
  249. * @throws Exception
  250. */
  251. public function removeAdmin($groupId, $creator, $userId) {
  252. if (!$this->isCreator($groupId, $creator)) {
  253. throw new Exception('no permission', CODE_NO_PERMITION);
  254. }
  255. if ($userId == $creator) {
  256. throw new Exception('can not remove creator', CODE_NORMAL_ERROR);
  257. }
  258. $objUserGroup = new UserGroup();
  259. if (!$objUserGroup->setData($groupId, $userId, ['is_admin' => 0])) {
  260. throw new Exception('set admin fail', CODE_NORMAL_ERROR);
  261. }
  262. return true;
  263. }
  264. /**
  265. * 搜索群用户信息
  266. * @author solu
  267. * @param $groupId
  268. * @param $keyword
  269. * @return array
  270. */
  271. public function memberSearch($groupId, $keyword) {
  272. $objUserGroup = new UserGroup();
  273. $userIds = $objUserGroup->objTable->getCol(['group_id' => $groupId], ['_field' => 'user_id']);
  274. if (!$userIds) {
  275. return [];
  276. }
  277. $objUserInfo = new TableHelper('user_info', 'dw_chat');
  278. // $keyword 是外部传来的参数,会有注入攻击
  279. $keyword = $objUserInfo->escape($keyword);
  280. $userInfo = $objUserInfo->getAll(['user_id' => $userIds], [
  281. '_where' => "(user_name like '{$keyword}%' || nick_name like '{$keyword}%')",
  282. '_field' => 'user_id, user_name, nick_name, cover_photo',
  283. '_sortKey' => 'last_login_time DESC',
  284. // '_debug' => true,
  285. ]);
  286. coverReplaceArrImage($userInfo, 'cover_photo');
  287. return $userInfo;
  288. }
  289. /**
  290. * 获取用户名
  291. * @author solu
  292. * @param $groupId
  293. * @return string
  294. */
  295. public static function getGroupNameById($groupId) {
  296. $objRedis = dwRedis::init();
  297. $userName = $objRedis->hGet(self::REDIS_GROUP_ID_HASH, $groupId);
  298. if (!$userName) {
  299. $obj = new GroupInfo();
  300. $userName = $obj->objTable->getOne(['group_id' => $groupId], ['_field' => 'group_title']);
  301. if ($userName) {
  302. self::setGroupNameById($groupId, $userName, $objRedis);
  303. }
  304. }
  305. return $userName;
  306. }
  307. public static function setGroupNameById($groupId, $user_name, $objRedis = null) {
  308. !$objRedis && $objRedis = dwRedis::init();
  309. $objRedis->hSet(self::REDIS_GROUP_ID_HASH, $groupId, $user_name);
  310. }
  311. /**
  312. * 转移群主
  313. * @author solu
  314. * @param $groupId
  315. * @param $old
  316. * @param $new
  317. * @return bool
  318. * @throws Exception
  319. */
  320. public function changeCreator($groupId, $old, $new) {
  321. if (!$this->isCreator($groupId, $old)) {
  322. throw new Exception('no permission', CODE_NO_PERMITION);
  323. }
  324. if ($old == $new) {
  325. throw new Exception('same creator', CODE_NORMAL_ERROR);
  326. }
  327. $this->objTable->updateObject(['creator' => $new], ['group_id' => $groupId]);
  328. (new UserGroup())->setData($groupId, $old, ['is_admin' => 0]);
  329. return true;
  330. }
  331. /**
  332. * 获取客服id
  333. * @author solu
  334. * @param $userIds
  335. * @return array
  336. */
  337. public function getGroupServerFromUserIds($userIds) {
  338. $items = $this->objTable->getAll(['server_id' => $userIds], ['_field' => 'group_id, server_id']);
  339. return arrayFormatKey($items, 'server_id', 'group_id');
  340. }
  341. public function checkPermission($group_id, $user_id) {
  342. $_field = 'is_public';
  343. $objGroupInfo = new GroupInfo();
  344. $is_public = (int) $objGroupInfo->objTable->getOne(['group_id' => $group_id], compact('_field'));
  345. if (!$is_public) {
  346. // 私有群要判断用户是否存在
  347. if ($user_id) {
  348. $objUserGroup = new UserGroup();
  349. $state = 1;
  350. $count = $objUserGroup->objTable->getCount(compact('group_id', 'user_id', 'state'));
  351. if (!$count) {
  352. Response::error(CODE_NO_PERMITION, 'the group is private');
  353. }
  354. } else {
  355. Response::error(CODE_NO_PERMITION, 'the group is private');
  356. }
  357. }
  358. }
  359. public function getGroupIdFromTgGroupId($tgGroupId) {
  360. $groupId = $this->objTable->getOne(['tg_group_id' => $tgGroupId], ['_field' => 'group_id']);
  361. return intval($groupId);
  362. }
  363. }