chat.php 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346
  1. <?php
  2. class imChat extends model
  3. {
  4. /**
  5. * Get a chat by gid.
  6. *
  7. * @param string $gid
  8. * @param bool $getMembers
  9. * @param bool $format format the chat or return its data as is.
  10. * @param bool $getLastMessage
  11. * @access public
  12. * @return object
  13. */
  14. public function getByGid($gid = '', $getMembers = false, $format = true, $getLastMessage = false)
  15. {
  16. $chat = $this->dao->select('*')->from(TABLE_IM_CHAT)->where('gid')->eq($gid)->fetch();
  17. if($chat && $format)
  18. {
  19. $chat = $this->format($chat, $getLastMessage);
  20. if($getMembers) $chat->members = $this->getMembers($gid);
  21. }
  22. return $chat;
  23. }
  24. /**
  25. * Get public chat list that user not join.
  26. *
  27. * @param int $userID
  28. * @access public
  29. * @return array
  30. */
  31. public function getPublicList($userID)
  32. {
  33. $joinedChats = $this->dao->select('cgid')->from(TABLE_IM_CHATUSER)
  34. ->where('user')->eq($userID)
  35. ->andWhere("(quit is null or quit = null)")
  36. ->fetchAll();
  37. $joinedChats = array_map(function($chat) { return $chat->cgid; }, $joinedChats);
  38. $chats = $this->dao->select('*')->from(TABLE_IM_CHAT)
  39. ->where('public')->eq(true)
  40. ->andWhere("(dismissDate is null or dismissDate = null)")
  41. ->andWhere("(mergedDate is null or mergedDate = null)")
  42. ->andWhere("(archiveDate is null or archiveDate = null)")
  43. ->andWhere('gid')->notin($joinedChats)
  44. ->fetchAll();
  45. return $this->format($chats);
  46. }
  47. /**
  48. * Get chat gid list by userID.
  49. *
  50. * @param int $userID
  51. * @param bool $includeMerged
  52. * @access public
  53. * @return array
  54. */
  55. public function getGidListByUserID($userID = 0, $includeMerged = false)
  56. {
  57. $systemChatGidList = $this->dao->select('gid')->from(TABLE_IM_CHAT)
  58. ->where('type')->eq('system')
  59. ->fetchPairs('gid');
  60. $gidList = $this->dao->select('t1.gid')->from(TABLE_IM_CHAT)->alias('t1')
  61. ->leftJoin(TABLE_IM_CHATUSER)->alias('t2')->on('t2.cgid=t1.gid')
  62. ->where('t2.user')->eq($userID)
  63. ->andWhere("(t2.quit is null or t2.quit = null)", $includeMerged)
  64. ->beginIF($includeMerged)->orWhere("(t1.mergedDate is not null and t1.mergedDate != null)")->markRight()->fi()
  65. ->fetchPairs('gid');
  66. return array_merge($systemChatGidList, $gidList);
  67. }
  68. /**
  69. * Get chat list by userID.
  70. *
  71. * @param int $userID
  72. * @access public
  73. * @return array
  74. */
  75. public function getListByUserID($userID = 0)
  76. {
  77. $limit = isset($this->config->dismissedGroupLife) ? $this->config->dismissedGroupLife : 90;
  78. $chats = $this->dao->select('chat.*, cu.star, cu.hide, cu.mute, cu.freeze, cu.category, cu.lastReadMessage, cu.lastReadMessageIndex')
  79. ->from(TABLE_IM_CHAT)->alias('chat')
  80. ->leftJoin(TABLE_IM_CHATUSER)->alias('cu')->on('chat.gid=cu.cgid')
  81. ->where('cu.user')->eq($userID)
  82. ->andWhere("(cu.quit is null or cu.quit = null)")
  83. ->andWhere("(chat.dismissDate is null or chat.dismissDate = null)", true)
  84. ->orWhere('chat.dismissDate')->gt(date(DT_DATETIME1, strtotime("-{$limit} day")))
  85. ->markRight(1)
  86. ->fetchAll();
  87. if(!isset($this->config->xuanxuan->disableSystemGroupChat) || $this->config->xuanxuan->disableSystemGroupChat == 'off')
  88. {
  89. $this->loadModel('setting');
  90. $account = $this->dao->select('account')->from(TABLE_USER)->where('id')->eq($userID)->fetch('account');
  91. $lastReadMessage = $this->setting->getItem("owner=$account&module=chat&section=system&key=lastreadid");
  92. if(empty($lastReadMessage)) $lastReadMessage = 0;
  93. $lastReadMessageIndex = $this->setting->getItem("owner=$account&module=chat&section=system&key=lastreadindex");
  94. if(empty($lastReadMessageIndex)) $lastReadMessageIndex = 0;
  95. $systemChat = $this->dao->select("*, 1 as star, 0 as hide, 0 as mute, 0 as freeze, 0 as category, $lastReadMessage as lastReadMessage, $lastReadMessageIndex as lastReadMessageIndex")
  96. ->from(TABLE_IM_CHAT)
  97. ->where('type')->eq('system')
  98. ->fetch();
  99. if($systemChat->lastReadMessage == 0) $systemChat->lastReadMessage = $systemChat->lastMessage;
  100. if($systemChat->lastReadMessageIndex == 0) $systemChat->lastReadMessageIndex = $systemChat->lastMessageIndex;
  101. $chats[] = $systemChat;
  102. }
  103. return $this->format($chats, true);
  104. }
  105. /**
  106. * Get chat by gid and verify if user is in the chat.
  107. *
  108. * @param string $gid
  109. * @param int $userID
  110. * @access public
  111. * @return object|bool
  112. */
  113. public function getByGidForUser($gid, $userID)
  114. {
  115. $chat = $this->getByGid($gid, true);
  116. if(empty($chat)) return false;
  117. if(!in_array($userID, $chat->members)) return false;
  118. return $chat;
  119. }
  120. /**
  121. * Get chats owned by given user.
  122. *
  123. * @param int $userID
  124. * @param bool $format
  125. * @access public
  126. * @return array
  127. */
  128. public function getOwnedListForUser($userID, $format = true)
  129. {
  130. $account = $this->dao->select('account')->from(TABLE_USER)->where('id')->eq($userID)->fetch('account');
  131. $chats = $this->dao->select('*')->from(TABLE_IM_CHAT)
  132. ->where('type')->eq('group')
  133. ->andWhere("(dismissDate is null or dismissDate = null)")
  134. ->andWhere("(mergedDate is null or mergedDate = null)")
  135. ->andWhere('ownedBy', true)->eq($account)
  136. ->orWhere('ownedBy')->eq('')
  137. ->andWhere('createdBy')->eq($account)
  138. ->markRight(1)
  139. ->fetchAll();
  140. return $format ? $this->format($chats) : $chats;
  141. }
  142. /**
  143. * Check if user is committer of a chat.
  144. *
  145. * @param object $message
  146. * @param int $userID
  147. * @param object $chat
  148. * @access public
  149. * @return object|bool $output | true
  150. */
  151. public function isCommitter($message, $userID, $chat)
  152. {
  153. $members = explode('&', $message->cgid);
  154. $output = new stdclass();
  155. $output->result = 'fail';
  156. $output->users = $userID;
  157. if(!$chat)
  158. {
  159. $output->data = new stdclass();
  160. $output->data->gid = $message->cgid;
  161. $output->data->messages = $this->lang->im->notExist;
  162. return $output;
  163. }
  164. if(count($members) == 2 and !in_array($userID, $members))
  165. {
  166. $output->message = $this->lang->im->notInChat;
  167. return $output;
  168. }
  169. if(!empty($chat->dismissDate))
  170. {
  171. $output->data = new stdclass();
  172. $output->data->gid = $message->cgid;
  173. $output->data->messages = $this->lang->im->chatHasDismissed;
  174. return $output;
  175. }
  176. /* Check if user is in the group. */
  177. if($chat->type == 'group' and $message->type == 'normal')
  178. {
  179. $members = $this->getMembers($chat->gid);
  180. if(!in_array($message->user, $members))
  181. {
  182. $output->data = new stdclass();
  183. $output->data->gid = $message->cgid;
  184. $output->data->messages = $this->lang->im->notInGroup;
  185. return $output;
  186. }
  187. }
  188. /* Check if user is in committers. */
  189. if(!empty($chat->committers))
  190. {
  191. if($chat->committers == '$ADMINS')
  192. {
  193. if(!$this->isAdmin($chat, $userID))
  194. {
  195. $output->data = new stdclass();
  196. $output->data->gid = $message->cgid;
  197. $output->data->messages = $this->lang->im->cantChat;
  198. return $output;
  199. }
  200. }
  201. else
  202. {
  203. $committers = explode(',', $chat->committers);
  204. if(!in_array($userID, $committers))
  205. {
  206. $output->data = new stdclass();
  207. $output->data->gid = $message->cgid;
  208. $output->data->messages = $this->lang->im->cantChat;
  209. return $output;
  210. }
  211. }
  212. }
  213. return true;
  214. }
  215. /**
  216. * Check if user is admin in a chat.
  217. *
  218. * @param string|object $chat
  219. * @param int $userID
  220. * @access public
  221. * @return boolean
  222. */
  223. public function isAdmin($chat, $userID)
  224. {
  225. if(strpos(is_string($chat) ? $chat : $chat->gid, '&') !== false) return true;
  226. if(is_string($chat)) $chat = $this->getByGid($chat, false, false);
  227. if(isset($chat->admins) && (is_array($chat->admins) ? in_array($userID, $chat->admins) : strpos($chat->admins, ",$userID,")) !== false) return true;
  228. if($chat->createdBy === 'system')
  229. {
  230. $account = $this->loadModel('user')->getById($userID);
  231. $admins = $this->dao->select('admins')->from(TABLE_COMPANY)->where('id')->eq($this->app->company->id)->fetch('admins');
  232. $adminArray = explode(',', $admins);
  233. return in_array($account, $adminArray);
  234. return in_array($userID, $sysAdmins);
  235. }
  236. $creatorID = $this->dao->select('id')->from(TABLE_USER)
  237. ->where('account')->eq(empty($chat->ownedBy) ? $chat->createdBy : $chat->ownedBy)
  238. ->fetch('id');
  239. return $userID == $creatorID;
  240. }
  241. /**
  242. * Get group pairs of all chat.
  243. *
  244. * @access public
  245. * @return array
  246. */
  247. public function getGroupPairs()
  248. {
  249. return $this->dao->select('gid, name')->from(TABLE_IM_CHAT)
  250. ->where('type')->eq('group')
  251. ->andWhere("(dismissDate is null or dismissDate = null)")
  252. ->fetchPairs();
  253. }
  254. /**
  255. * Get user pairs of one chat group.
  256. *
  257. * @param string $gid
  258. * @access public
  259. * @return array
  260. */
  261. public function getUserPairs($gid = '')
  262. {
  263. $userIdList = $this->dao->select('user')->from(TABLE_IM_CHATUSER)
  264. ->where("(quit is null or quit = null)")
  265. ->beginIF($gid)->andWhere('cgid')->eq($gid)->fi()
  266. ->fetchPairs();
  267. return $this->dao->select('id, realname')->from(TABLE_USER)->where('id')->in($userIdList)->fetchPairs();
  268. }
  269. /**
  270. * Create a chat.
  271. *
  272. * @param string $gid
  273. * @param string $name
  274. * @param string $type
  275. * @param array $members
  276. * @param int $subjectID
  277. * @param bool $public
  278. * @param int $userID
  279. * @access public
  280. * @return object
  281. */
  282. public function create($gid = '', $name = '', $type = '', $members = array(), $subjectID = 0, $public = false, $userID = 0)
  283. {
  284. $user = $this->loadModel('im')->user->getByID($userID);
  285. $chat = new stdclass();
  286. $chat->gid = $gid;
  287. $chat->name = $name;
  288. if($type == 'bot' || ($type == 'one2one' && in_array('xuanbot', $members)))
  289. {
  290. $type = 'bot';
  291. $avatar = new stdclass();
  292. $avatar->type = 'image';
  293. $avatar->data = new stdclass();
  294. $avatar->data->imgUrl = $this->config->webRoot . 'data/image/xuanbot.png';
  295. $chat->avatar = json_encode($avatar);
  296. $chat->name = $this->lang->im->bot->commonName;
  297. }
  298. $chat->type = $type;
  299. $chat->subject = $subjectID;
  300. $chat->createdBy = !empty($user->account) ? $user->account : '';
  301. $chat->ownedBy = $chat->createdBy;
  302. $chat->createdDate = helper::now();
  303. if($public) $chat->public = 1;
  304. $this->dao->insert(TABLE_IM_CHAT)->data($chat)->exec();
  305. /* Add members to chat. */
  306. foreach($members as $member) $this->join($gid, $member);
  307. return $this->getByGid($gid, true);
  308. }
  309. /**
  310. * Update a chat.
  311. *
  312. * @param object $chat
  313. * @param int $userID
  314. * @access public
  315. * @return object
  316. */
  317. public function update($chat = null, $userID = 0)
  318. {
  319. if(isset($chat))
  320. {
  321. $user = $this->loadModel('im')->user->getByID($userID);
  322. $chat->editedBy = !empty($user->account) ? $user->account : '';
  323. $chat->editedDate = helper::now();
  324. if(is_array($chat->admins)) $chat->admins = implode(',', $chat->admins);
  325. if(is_array($chat->pinnedMessages)) $chat->pinnedMessages = implode(',', $chat->pinnedMessages);
  326. if(is_array($chat->mergedChats)) $chat->mergedChats = implode(',', $chat->mergedChats);
  327. if(is_bool($chat->public))
  328. {
  329. $chat->public = $chat->public ? '1' : '0';
  330. }
  331. if(is_bool($chat->adminInvite))
  332. {
  333. $chat->adminInvite = $chat->adminInvite ? '1' : '0';
  334. }
  335. foreach(array('createdDate', 'lastMessageInfo', 'avatar') as $dropProp) unset($chat->$dropProp);
  336. foreach(array('dismissDate', 'mergedDate', 'archiveDate') as $nullable) if(isset($chat->$nullable) && empty($chat->$nullable)) $chat->$nullable = null;
  337. $this->dao->update(TABLE_IM_CHAT)->data($chat)->where('gid')->eq($chat->gid)->batchCheck($this->config->im->require->edit, 'notempty')->exec();
  338. }
  339. /* Return the changed chat. */
  340. return $this->getByGid($chat->gid, true);
  341. }
  342. /**
  343. * Touch a chat (as on Linux), changes its editedDate to now.
  344. *
  345. * This method is currently meant to track members' join/leave events, which will not get synced during login.
  346. *
  347. * @param string $gid
  348. * @return boolean
  349. */
  350. public function touch($gid)
  351. {
  352. $this->dao->update(TABLE_IM_CHAT)->set('editedDate')->eq(helper::now())->where('gid')->eq($gid)->exec();
  353. return !dao::isError();
  354. }
  355. /**
  356. * Init the system chat.
  357. *
  358. * @access public
  359. * @return bool
  360. */
  361. public function initSystemChat()
  362. {
  363. if(!isset($this->config->disableSystemGroupChat) || !$this->config->disableSystemGroupChat)
  364. {
  365. $chat = $this->dao->select('*')->from(TABLE_IM_CHAT)->where('type')->eq('system')->fetch();
  366. if(!$chat)
  367. {
  368. $chat = new stdclass();
  369. $chat->gid = imModel::createGID();
  370. $chat->name = $this->lang->im->systemGroup;
  371. $chat->type = 'system';
  372. $chat->createdBy = 'system';
  373. $chat->createdDate = helper::now();
  374. $this->dao->insert(TABLE_IM_CHAT)->data($chat)->exec();
  375. }
  376. return !dao::isError();
  377. }
  378. return true;
  379. }
  380. /**
  381. * Join a chat.
  382. *
  383. * @param string $gid
  384. * @param int $userID
  385. * @access public
  386. * @return bool|int return userID if already joined, else return result.
  387. */
  388. public function join($gid = '', $userID = 0)
  389. {
  390. $this->touch($gid);
  391. $lastMessageInfo = $this->dao->select('lastMessage, lastMessageIndex')->from(TABLE_IM_CHAT)->where('gid')->eq($gid)->fetch();
  392. $data = $this->dao->select('*')->from(TABLE_IM_CHATUSER)->where('cgid')->eq($gid)->andWhere('user')->eq($userID)->fetch();
  393. if($data)
  394. {
  395. /* If user hasn't quit the chat then return. */
  396. if($data->quit == null || empty($data->quit)) return $userID;
  397. /* If user has quited the chat then update the record. */
  398. $data = new stdclass();
  399. $data->join = helper::now();
  400. $data->quit = null;
  401. $data->lastReadMessage = $lastMessageInfo->lastMessage;
  402. $data->lastReadMessageIndex = $lastMessageInfo->lastMessageIndex;
  403. $this->dao->update(TABLE_IM_CHATUSER)->data($data)->where('cgid')->eq($gid)->andWhere('user')->eq($userID)->exec();
  404. return !dao::isError();
  405. }
  406. /* Create a new record of user's chat info. */
  407. $data = new stdclass();
  408. $data->cgid = $gid;
  409. $data->user = $userID;
  410. $data->join = helper::now();
  411. $data->lastReadMessage = $lastMessageInfo->lastMessage;
  412. $data->lastReadMessageIndex = $lastMessageInfo->lastMessageIndex;
  413. $this->dao->insert(TABLE_IM_CHATUSER)->data($data)->exec();
  414. /* Update order field. */
  415. $id = $this->dao->lastInsertID();
  416. $this->dao->update(TABLE_IM_CHATUSER)->set('`order`')->eq($id)->where('id')->eq($id)->exec();
  417. return !dao::isError();
  418. }
  419. /**
  420. * leave a chat.
  421. *
  422. * @param int $gid
  423. * @param int $userID
  424. * @access public
  425. * @return bool
  426. */
  427. public function leave($gid, $userID)
  428. {
  429. $this->dao->update(TABLE_IM_CHATUSER)->set('quit')->eq(helper::now())->where('cgid')->eq($gid)->andWhere('user')->eq($userID)->exec();
  430. $this->removeAdmins($gid, array($userID));
  431. $this->loadModel('im')->conferenceRemoveUserFromChat($gid, $userID);
  432. $this->touch($gid);
  433. return !dao::isError();
  434. }
  435. /**
  436. * Format chats.
  437. *
  438. * @param mixed $chats object | array
  439. * @access public
  440. * @return object | array
  441. */
  442. public function format($chats, $getLastMessage = false)
  443. {
  444. $isObject = false;
  445. if(is_object($chats))
  446. {
  447. $isObject = true;
  448. $chats = array($chats);
  449. }
  450. $userID = $this->app->session->userID;
  451. foreach($chats as $chat)
  452. {
  453. if(!$chat) continue;
  454. $chat->id = (int)$chat->id;
  455. $chat->subject = (int)$chat->subject;
  456. $chat->createdDate = empty($chat->createdDate) || $chat->createdDate == null ? 0 : strtotime($chat->createdDate);
  457. $chat->editedDate = empty($chat->editedDate) || $chat->editedDate == null ? 0 : strtotime($chat->editedDate);
  458. $chat->lastActiveTime = empty($chat->lastActiveTime) || $chat->lastActiveTime == null ? 0 : strtotime($chat->lastActiveTime);
  459. $chat->dismissDate = empty($chat->dismissDate) || $chat->dismissDate == null ? 0 : strtotime($chat->dismissDate);
  460. $chat->mergedDate = empty($chat->mergedDate) || $chat->mergedDate == null ? 0 : strtotime($chat->mergedDate);
  461. $chat->archiveDate = empty($chat->archiveDate) || $chat->archiveDate == null ? 0 : strtotime($chat->archiveDate);
  462. $chat->lastMessage = (int)$chat->lastMessage;
  463. $chat->admins = array_values(array_map('intval', array_filter(explode(',', $chat->admins))));
  464. $chat->pinnedMessages = array_values(array_map('intval', array_filter(explode(',', $chat->pinnedMessages))));
  465. $chat->mergedChats = array_values(array_filter(explode(',', $chat->mergedChats)));
  466. $chat->avatar = json_decode($chat->avatar);
  467. if(isset($chat->avatar) && $chat->avatar->type === 'image')
  468. {
  469. $chat->avatar->data->imgUrl = $this->loadModel('im')->getServer() . $chat->avatar->data->imgUrl;
  470. }
  471. if($getLastMessage && isset($chat->lastMessage)) $chat->lastMessageInfo = current($this->loadModel('im')->messageGetList($chat->gid, array($chat->lastMessage)));
  472. if(empty($chat->lastMessageInfo)) $chat->lastMessageInfo = null;
  473. if(!empty($chat->lastMessageInfo)) $chat->lastMessageInfo->senderId = intval($chat->lastMessageInfo->user);
  474. if(isset($chat->lastReadMessageIndex)) $chat->lastReadMessageIndex = (int)$chat->lastReadMessageIndex;
  475. if($chat->type == 'one2one' && $chat->gid != "$userID&$userID") $chat->name = '';
  476. if(isset($chat->star)) $chat->star = (bool)$chat->star;
  477. if(isset($chat->hide)) $chat->hide = (bool)$chat->hide;
  478. if(isset($chat->mute)) $chat->mute = (bool)$chat->mute;
  479. if(isset($chat->public)) $chat->public = (bool)$chat->public;
  480. if(isset($chat->freeze)) $chat->freeze = (bool)$chat->freeze;
  481. if(isset($chat->lastReadMessage)) $chat->lastReadMessage = (int)$chat->lastReadMessage;
  482. if(isset($chat->adminInvite)) $chat->adminInvite = (bool)$chat->adminInvite;
  483. if($chat->archiveDate) {
  484. $chat->star = false;
  485. $chat->hide = false;
  486. $chat->mute = false;
  487. $chat->freeze = false;
  488. }
  489. }
  490. if($isObject) return reset($chats);
  491. return $chats;
  492. }
  493. /**
  494. * Add admins of a chat.
  495. *
  496. * @param string $gid
  497. * @param array $admins
  498. * @param int $userID
  499. * @access public
  500. * @return object
  501. */
  502. public function addAdmins($gid = '', $admins = array())
  503. {
  504. $chat = $this->getByGid($gid);
  505. $adminList = $chat->admins;
  506. $adminList = array_filter(array_unique(array_merge($adminList, $admins)));
  507. $adminList = implode(',', $adminList);
  508. $this->dao->update(TABLE_IM_CHAT)->set('admins')->eq(',' . $adminList . ',')->where('gid')->eq($gid)->exec();
  509. return $this->getByGid($gid, true);
  510. }
  511. /**
  512. * Remove admins of a chat.
  513. *
  514. * @param string $gid
  515. * @param array $users
  516. * @access public
  517. * @return object
  518. */
  519. public function removeAdmins($gid = '', $users = array())
  520. {
  521. $chat = $this->getByGid($gid);
  522. $adminList = $chat->admins;
  523. $adminList = array_filter(array_diff($adminList, $users));
  524. $adminList = implode(',', $adminList);
  525. $this->dao->update(TABLE_IM_CHAT)->set('admins')->eq(',' . $adminList . ',')->where('gid')->eq($gid)->exec();
  526. return $this->getByGid($gid, true);
  527. }
  528. /**
  529. * Pin messages of a chat.
  530. *
  531. * @param string|object $chat
  532. * @param array $messageIds
  533. * @access public
  534. * @return object
  535. */
  536. public function pinMessages($chat, $messageIds)
  537. {
  538. if(is_string($chat)) $chat = $this->getByGid($chat);
  539. $pinnedMessages = $chat->pinnedMessages;
  540. if(!empty($pinnedMessages))
  541. {
  542. $pinnedMessagesData = $this->loadModel('im')->messageGetList('', $pinnedMessages);
  543. foreach($pinnedMessagesData as $msg) if($msg->deleted) $pinnedMessages = array_diff($pinnedMessages, array($msg->id));
  544. }
  545. $pinnedMessagesLimit = isset($this->config->pinnedMessagesLimit) ? $this->config->pinnedMessagesLimit : 10;
  546. if(count($pinnedMessages) >= $pinnedMessagesLimit) $pinnedMessages = array_slice($pinnedMessages, $pinnedMessagesLimit - count($pinnedMessages) + count($messageIds));
  547. $pinnedMessages = array_filter(array_unique(array_merge($pinnedMessages, $messageIds)));
  548. $pinnedMessages = implode(',', $pinnedMessages);
  549. $this->dao->update(TABLE_IM_CHAT)->set('pinnedMessages')->eq(',' . $pinnedMessages . ',')->where('gid')->eq($chat->gid)->exec();
  550. return $this->getByGid($chat->gid, true);
  551. }
  552. /**
  553. * Unpin messages of a chat.
  554. *
  555. * @param string|object $chat
  556. * @param array $messageIDs
  557. * @access public
  558. * @return object
  559. */
  560. public function unpinMessages($chat, $messageIds)
  561. {
  562. if(is_string($chat)) $chat = $this->getByGid($chat);
  563. $pinnedMessages = $chat->pinnedMessages;
  564. $pinnedMessages = array_filter(array_diff($pinnedMessages, $messageIds));
  565. $pinnedMessages = implode(',', $pinnedMessages);
  566. $this->dao->update(TABLE_IM_CHAT)->set('pinnedMessages')->eq(',' . $pinnedMessages . ',')->where('gid')->eq($chat->gid)->exec();
  567. return $this->getByGid($chat->gid, true);
  568. }
  569. /**
  570. * Star or unstar a chat.
  571. *
  572. * @param string $star
  573. * @param string $gid
  574. * @param int $userID
  575. * @access public
  576. * @return object
  577. */
  578. public function star($star = '1', $gid = '', $userID = 0)
  579. {
  580. $this->dao->update(TABLE_IM_CHATUSER)
  581. ->set('star')->eq($star)
  582. ->where('cgid')->eq($gid)
  583. ->andWhere('user')->eq($userID)
  584. ->exec();
  585. return $this->getByGid($gid, true);
  586. }
  587. /**
  588. * Hide or display a chat.
  589. *
  590. * @param string $hide
  591. * @param string $gid
  592. * @param int $userID
  593. * @access public
  594. * @return bool
  595. */
  596. public function hide($hide = '1', $gid = '', $userID = 0)
  597. {
  598. $this->dao->update(TABLE_IM_CHATUSER)
  599. ->set('hide')->eq($hide)
  600. ->where('cgid')->eq($gid)
  601. ->andWhere('user')->eq($userID)
  602. ->exec();
  603. return !dao::isError();
  604. }
  605. /**
  606. * Mute or unmute a chat.
  607. *
  608. * @param string $mute
  609. * @param string $gid
  610. * @param int $userID
  611. * @access public
  612. * @return bool
  613. */
  614. public function mute($mute = '1', $gid = '', $userID = 0)
  615. {
  616. $this->dao->update(TABLE_IM_CHATUSER)
  617. ->set('mute')->eq($mute)
  618. ->where('cgid')->eq($gid)
  619. ->andWhere('user')->eq($userID)
  620. ->exec();
  621. return !dao::isError();
  622. }
  623. /**
  624. * Freeze or unfreeze a chat.
  625. *
  626. * @param string $freeze
  627. * @param string $gid
  628. * @param int $userID
  629. * @access public
  630. * @return bool
  631. */
  632. public function freeze($freeze = '1', $gid = '', $userID = 0)
  633. {
  634. $this->dao->update(TABLE_IM_CHATUSER)
  635. ->set('freeze')->eq($freeze)
  636. ->where('cgid')->eq($gid)
  637. ->andWhere('user')->eq($userID)
  638. ->exec();
  639. return !dao::isError();
  640. }
  641. /**
  642. * Set category for a chat
  643. *
  644. * @param array $gids
  645. * @param string $category
  646. * @param int $userID
  647. * @access public
  648. * @return boolean
  649. */
  650. public function setCategory($gids = array(), $category = '', $userID = 0)
  651. {
  652. $this->dao->update(TABLE_IM_CHATUSER)
  653. ->set('category')->eq($category)
  654. ->where('cgid')->in($gids)
  655. ->andWhere('user')->eq($userID)
  656. ->exec();
  657. return !dao::isError();
  658. }
  659. /**
  660. * Get member list of one chat.
  661. *
  662. * @param string|object $chat chat gid or chat object.
  663. * @param bool $trueOnSystemChat return true if chat type is system.
  664. * @access public
  665. * @return array
  666. */
  667. public function getMembers($chat, $trueOnSystemChat = false)
  668. {
  669. if(is_string($chat)) $chat = $this->getByGid($chat);
  670. if(!$chat) return array();
  671. if($chat->type == 'system')
  672. {
  673. if($trueOnSystemChat) return true;
  674. $memberList = $this->dao->select('id')->from(TABLE_USER)->where('deleted')->eq('0')->fetchPairs();
  675. }
  676. else
  677. {
  678. $memberList = $this->dao->select('user')->from(TABLE_IM_CHATUSER)->alias('tcu')
  679. ->leftJoin(TABLE_USER)->alias('tu')->on('tcu.user = tu.id')
  680. ->where("(tcu.quit is null or tcu.quit = null)")
  681. ->andWhere('tu.deleted')->eq('0')
  682. ->andWhere('cgid')->eq($chat->gid)
  683. ->fetchPairs();
  684. }
  685. $members = array();
  686. foreach($memberList as $member) $members[] = (int)$member;
  687. return $members;
  688. }
  689. /**
  690. * Get detailed member list of chat.
  691. *
  692. * @param string $chat chat gid
  693. * @param object $pager
  694. * @param string $orderBy order by owner, admin, join date by default
  695. * @param array $memberIDs only get details for members in memberIDs if provided
  696. * @access public
  697. * @return array
  698. */
  699. public function getMemberDetails($cgid, $pager = null, $orderBy = '', $memberIDs = array())
  700. {
  701. $chat = $this->getByGid($cgid);
  702. if(!$chat || $chat->type == 'system') return array();
  703. /* Get join and last seen date of members, with some values which will be filled in later. */
  704. $memberList = $this->dao->select('user as id, account, tcu.`join`, last as lastSeen, null as lastPost, 0 as isOwner, 0 as isAdmin')->from(TABLE_IM_CHATUSER)->alias('tcu')
  705. ->leftJoin(TABLE_USER)->alias('tu')->on('tcu.user = tu.id')
  706. ->where("(tcu.quit is null or tcu.quit = null)")
  707. ->andWhere('tu.deleted')->eq('0')
  708. ->andWhere('cgid')->eq($cgid)
  709. ->fetchAll('id');
  710. if(empty($memberList)) return array();
  711. /* Filter members. */
  712. if(!empty($memberIDs))
  713. {
  714. $memberList = array_filter($memberList, function($member) use ($memberIDs)
  715. {
  716. return in_array($member->id, $memberIDs);
  717. });
  718. }
  719. /* Get date of members' last message in chat. */
  720. $members = array_keys($memberList);
  721. $lastMessageDates = $this->dao->select('user, MAX(date)')->from(TABLE_IM_MESSAGE)
  722. ->where('cgid')->eq($cgid)
  723. ->andWhere('user')->in($members)
  724. ->groupBy('user')
  725. ->fetchAll();
  726. foreach($lastMessageDates as $messageDate) $memberList[$messageDate->user]->lastPost = $messageDate->{'MAX(date)'};
  727. /* Set isAdmin for members. */
  728. foreach($chat->admins as $admin)
  729. {
  730. if(isset($memberList[$admin])) $memberList[$admin]->isAdmin = 1;
  731. }
  732. /* Set isOwner. */
  733. $ownerAccount = !empty($chat->ownedBy) ? $chat->ownedBy : $chat->createdBy;
  734. $ownerIndex = false; // For reorder later.
  735. foreach($memberList as $index => $member)
  736. {
  737. if($member->account == $ownerAccount)
  738. {
  739. $memberList[$index]->isOwner = 1;
  740. $ownerIndex = $index;
  741. break;
  742. }
  743. }
  744. /* Format data. */
  745. $memberList = array_map(function($member)
  746. {
  747. $member->id = (int)$member->id;
  748. $member->isOwner = (int)$member->isOwner;
  749. $member->isAdmin = (int)$member->isAdmin;
  750. $member->join = empty($member->join) || $member->join == null ? 0 : strtotime($member->join);
  751. $member->lastSeen = empty($member->lastSeen) || $member->lastSeen == null ? 0 : strtotime($member->lastSeen);
  752. $member->lastPost = empty($member->lastPost) || $member->lastPost == null ? 0 : strtotime($member->lastPost);
  753. return $member;
  754. }, $memberList);
  755. /* Reorder data. */
  756. $orderedMemberList = array();
  757. if(empty($orderBy) || stripos($orderBy, 'member') === 0) // Default order: owner, admin, join date. Might reverse.
  758. {
  759. if($ownerIndex !== false) $orderedMemberList[] = $memberList[$ownerIndex];
  760. if(!empty($chat->admins))
  761. {
  762. $adminList = array_filter($memberList, function($member)
  763. {
  764. return $member->isAdmin && !$member->isOwner;
  765. });
  766. usort($adminList, function($a, $b)
  767. {
  768. return ($a->join < $b->join) ? -1 : 1;
  769. });
  770. $orderedMemberList = array_merge($orderedMemberList, $adminList);
  771. }
  772. $normalMemberList = array_filter($memberList, function($member)
  773. {
  774. return !$member->isOwner && !$member->isAdmin;
  775. });
  776. usort($normalMemberList, function($a, $b)
  777. {
  778. return ($a->join < $b->join) ? -1 : 1;
  779. });
  780. $orderedMemberList = array_merge($orderedMemberList, $normalMemberList);
  781. if(stripos($orderBy, 'desc') !== false) $orderedMemberList = array_reverse($orderedMemberList);
  782. }
  783. else
  784. {
  785. $orderByArgs = explode('_', $orderBy);
  786. $property = $orderByArgs[0];
  787. $direction = $orderByArgs[1] == 'asc' ? 1 : -1;
  788. usort($memberList, function($a, $b) use ($property, $direction)
  789. {
  790. return ($a->$property < $b->$property) ? (-1 * $direction) : $direction;
  791. });
  792. $orderedMemberList = $memberList;
  793. }
  794. /* Slice data with pager. */
  795. $recTotal = count($memberList);
  796. if($pager->recPerPage * ($pager->pageID - 1) >= $recTotal)
  797. {
  798. $pager->pageID = ceil($recTotal / $pager->recPerPage);
  799. }
  800. $startIndex = $pager->recPerPage * ($pager->pageID - 1);
  801. if($startIndex >= $recTotal || $startIndex < 0) return array();
  802. $memberSlice = array_slice($orderedMemberList , $startIndex, $pager->recPerPage);
  803. /* Assemble data. */
  804. $details = new stdclass();
  805. $details->data = $memberSlice;
  806. $details->pager = new stdclass();
  807. $details->pager->gid = $cgid;
  808. $details->pager->recTotal = $recTotal;
  809. $details->pager->recPerPage = $pager->recPerPage;
  810. $details->pager->pageID = $pager->pageID;
  811. $details->pager->data = array('orderBy' => $orderBy);
  812. return $details;
  813. }
  814. /**
  815. * Get count of messages for a chat.
  816. *
  817. * @param string $gid
  818. * @access public
  819. * @return int
  820. */
  821. public function getMessageCount($gid)
  822. {
  823. $masterTableCount = $this->dao->select('count(*)')->from(TABLE_IM_MESSAGE)->where('cgid')->eq($gid)->fetch('count(*)');
  824. $partitionsMessageCount = $this->dao->select('sum(`count`)')->from(TABLE_IM_CHAT_MESSAGE_INDEX)->where('gid')->eq($gid)->fetch('sum(`count`)');
  825. return $masterTableCount + ($partitionsMessageCount ?: 0);
  826. }
  827. /**
  828. * Add chat action.
  829. *
  830. * @param int $chatId
  831. * @param string $action
  832. * @param int $actionId
  833. * @param string $result
  834. * @param string $comment
  835. */
  836. public function addAction($chatId, $action, $actorId, $result, $comment = '')
  837. {
  838. if(!$this->loadModel('action')->checkLogLevel('chat', $action)) return;
  839. $account = $this->dao->select('account')
  840. ->from(TABLE_USER)
  841. ->where('id')->eq($actorId)
  842. ->fetch('account');
  843. $actor = !empty($account) ? $account : '';
  844. $extra = json_encode(array('actorId' => $actorId));
  845. $this->loadModel('action')->create('chat', $chatId, $action, $result, $comment, $extra, $actor);
  846. }
  847. /**
  848. * Set last read message for a chat.
  849. *
  850. * @param string $gid
  851. * @param int $lastReadMessageID
  852. * @param int $userID
  853. * @access public
  854. * @return bool
  855. */
  856. public function setLastReadMessage($gid, $lastReadMessageID, $userID)
  857. {
  858. $messageIndex = $this->dao->select('`index`')->from(TABLE_IM_MESSAGE)
  859. ->where('id')->eq($lastReadMessageID)
  860. ->andWhere('cgid')->eq($gid)
  861. ->fetch('index');
  862. $this->dao->update(TABLE_IM_CHATUSER)
  863. ->set('lastReadMessage')->eq($lastReadMessageID)
  864. ->set('lastReadMessageIndex')->eq($messageIndex)
  865. ->where('cgid')->eq($gid)
  866. ->andWhere('lastReadMessage')->lt($lastReadMessageID)
  867. ->andWhere('user')->eq($userID)
  868. ->exec();
  869. return !dao::isError();
  870. }
  871. /**
  872. * Set last read message for a chat.
  873. *
  874. * @param string $gid
  875. * @param int $lastReadMessageIndex
  876. * @param int $userID
  877. * @access public
  878. * @return bool
  879. */
  880. public function setLastReadMessageByIndex($gid, $lastReadMessageIndex, $userID)
  881. {
  882. $messageID = $this->dao->select('id')->from(TABLE_IM_MESSAGE)
  883. ->where('`index`')->eq($lastReadMessageIndex)
  884. ->andWhere('cgid')->eq($gid)
  885. ->fetch('id');
  886. $affected = $this->dao->update(TABLE_IM_CHATUSER)
  887. ->set('lastReadMessageIndex')->eq($lastReadMessageIndex)
  888. ->set('lastReadMessage')->eq($messageID)
  889. ->where('cgid')->eq($gid)
  890. ->andWhere('user')->eq($userID)
  891. ->exec();
  892. if($affected === 0)
  893. {
  894. $systemChatGidList = $this->dao->select('gid')->from(TABLE_IM_CHAT)
  895. ->where('type')->eq('system')
  896. ->fetchPairs('gid');
  897. if(in_array($gid, array_keys($systemChatGidList)))
  898. {
  899. $this->loadModel('setting');
  900. $account = $this->dao->select('account')->from(TABLE_USER)->where('id')->eq($userID)->fetch('account');
  901. if(!isset($this->app->user)) $this->app->user = new stdclass();
  902. $this->app->user->account = $account;
  903. $this->setting->setItem("$account.chat.system.lastreadid", $messageID);
  904. $this->setting->setItem("$account.chat.system.lastreadindex", $lastReadMessageIndex);
  905. }
  906. }
  907. return !dao::isError();
  908. }
  909. /**
  910. * Change ownership of chat.
  911. *
  912. * @param object $chat
  913. * @param int $ownerUserID new owner id
  914. * @param int $userID
  915. * @param bool $byAdmin true if is request by an admin, will bypass owner checking.
  916. * @access public
  917. * @return bool|object returns chat on success, returns false on fail
  918. */
  919. public function changeOwnership($chat, $ownerUserID, $userID, $byAdmin = false)
  920. {
  921. if(!$byAdmin)
  922. {
  923. if($ownerUserID == $userID) return false;
  924. $currentUserAccount = $this->dao->select('account')->from(TABLE_USER)->where('id')->eq($userID)->fetch('account');
  925. if(empty($currentUserAccount) || (!empty($chat->ownedBy) && $chat->ownedBy != $currentUserAccount) || (empty($chat->ownedBy) && $chat->createdBy != $currentUserAccount)) return false;
  926. }
  927. $ownerAccount = $this->dao->select('account')->from(TABLE_USER)->where('id')->eq($ownerUserID)->fetch('account');
  928. if(empty($ownerAccount)) return false;
  929. $this->dao->update(TABLE_IM_CHAT)
  930. ->set('ownedBy')->eq($ownerAccount)
  931. ->where('gid')->eq($chat->gid)
  932. ->exec();
  933. return dao::isError() ? false : $this->getByGid($chat->gid, true);
  934. }
  935. /**
  936. * Merge chat into targetChat.
  937. *
  938. * @param object $chat
  939. * @param object $targetChat
  940. * @param int $userID
  941. * @access public
  942. * @return bool
  943. */
  944. public function merge($chat, $targetChat, $userID)
  945. {
  946. /* Check if user is owner of both chats, and chat has not been merged. */
  947. $accountAdmin = $this->dao->select('account')->from(TABLE_USER)->where('id')->eq($userID)->fetch();
  948. $sysAdmins = $this->dao->select('admins')->from(TABLE_COMPANY)->where('id')->eq($this->app->company->id)->fetch('admins');
  949. $sysAdminArray = explode(',', $sysAdmins);
  950. $accountAdmin->admin = in_array($accountAdmin->account, $sysAdminArray) ? 'super' : '';
  951. if((empty($accountAdmin) || (!empty($chat->ownedBy) && $chat->ownedBy != $accountAdmin->account) || (!empty($targetChat->ownedBy) && $targetChat->ownedBy != $accountAdmin->account) || (empty($chat->ownedBy) && $chat->createdBy != $accountAdmin->account) || (empty($targetChat->ownedBy) && $targetChat->createdBy != $accountAdmin->account)) && $accountAdmin->admin != 'super') return false;
  952. if($chat->mergedDate != null && !empty($chat->mergedDate)) return false;
  953. /* Mark chat as merged. */
  954. $this->dao->update(TABLE_IM_CHAT)
  955. ->set('mergedDate')->eq(helper::now())
  956. ->where('gid')->eq($chat->gid)
  957. ->exec();
  958. /* Merge previously merged chats. */
  959. $prevMergedChats = $chat->mergedChats;
  960. $currMergedChats = $targetChat->mergedChats;
  961. $mergedChats = array_merge(array($chat->gid), $prevMergedChats, $currMergedChats);
  962. $mergedChats = join(',', array_filter($mergedChats));
  963. $this->dao->update(TABLE_IM_CHAT)
  964. ->set('mergedChats')->eq($mergedChats)
  965. ->where('gid')->eq($targetChat->gid)
  966. ->exec();
  967. /* Merge members. */
  968. foreach($chat->members as $memberID)
  969. {
  970. $this->leave($chat->gid, $memberID);
  971. $this->join($targetChat->gid, $memberID);
  972. }
  973. return dao::isError() ? false : $this->getByGid($targetChat->gid, true);
  974. }
  975. /**
  976. * Get next owner candidate for chat. (Seniormost user other than current owner)
  977. *
  978. * @param object $chat
  979. * @param int $userID current owner user id
  980. * @param bool $asAccount will return id if set to false
  981. * @access public
  982. * @return int|string
  983. */
  984. public function getNextOwnerCandidate($chat, $userID, $asAccount = true)
  985. {
  986. if(!empty($chat->admins))
  987. {
  988. $seniormostAdmin = $this->dao->select($asAccount ? 'account' : 'user')->from(TABLE_IM_CHATUSER)->alias('tcu')
  989. ->leftJoin(TABLE_USER)->alias('tu')->on('tcu.user=tu.id')
  990. ->where('tcu.cgid')->eq($chat->gid)
  991. ->andWhere("(tcu.quit is null or tcu.quit = null)")
  992. ->andWhere('tcu.user')->in($chat->admins)
  993. ->andWhere('tcu.user')->ne($userID)
  994. ->andWhere('tu.deleted')->eq('0')
  995. ->orderBy('tcu.join_asc')
  996. ->limit(1)
  997. ->fetch($asAccount ? 'account' : 'user');
  998. if(!empty($seniormostAdmin)) return $seniormostAdmin;
  999. }
  1000. return $this->dao->select($asAccount ? 'account' : 'user')->from(TABLE_IM_CHATUSER)->alias('tcu')
  1001. ->leftJoin(TABLE_USER)->alias('tu')->on('tcu.user=tu.id')
  1002. ->where('tcu.cgid')->eq($chat->gid)
  1003. ->andWhere("(tcu.quit is null or tcu.quit = null)")
  1004. ->andWhere('tcu.user')->ne($userID)
  1005. ->andWhere('tu.deleted')->eq('0')
  1006. ->orderBy('tcu.join_asc')
  1007. ->limit(1)
  1008. ->fetch($asAccount ? 'account' : 'user');
  1009. }
  1010. /**
  1011. * Transfer all chats from user to next candidate if possible.
  1012. *
  1013. * @param int $userID
  1014. * @access public
  1015. * @return bool
  1016. */
  1017. public function transferAllFromUser($userID)
  1018. {
  1019. $userChats = $this->getOwnedListForUser($userID);
  1020. $chatOwnerPairs = array();
  1021. foreach($userChats as $chat) $chatOwnerPairs[$chat->gid] = $this->getNextOwnerCandidate($chat, $userID);
  1022. $chatOwnerPairs = array_filter($chatOwnerPairs);
  1023. if(empty($chatOwnerPairs)) return true;
  1024. $queryData = array();
  1025. foreach($chatOwnerPairs as $cgid => $owner) $queryData[] = "WHEN '$cgid' THEN '$owner'";
  1026. $cgids = array_keys($chatOwnerPairs);
  1027. $query = "UPDATE " . TABLE_IM_CHAT . " SET `ownedBy` = (CASE `gid` " . join(' ', $queryData) . " END) WHERE `gid` IN('" . join('\',\'', $cgids) . "');";
  1028. $this->dao->query($query); $this->dao->setCache(trim(TABLE_IM_CHAT, "`"));
  1029. return !!dao::isError();
  1030. }
  1031. /**
  1032. * Prune group data of the expired, including group information, group messages, group files, etc.
  1033. *
  1034. * @access public
  1035. * @return bool
  1036. */
  1037. public function pruneExpired()
  1038. {
  1039. $groupLife = isset($this->config->dismissedGroupLife) ? $this->config->dismissedGroupLife : 90;
  1040. $expiredGroups = $this->dao->select('gid')
  1041. ->from(TABLE_IM_CHAT)
  1042. ->where('type')->eq('group')
  1043. ->andWhere("(dismissDate is not null and dismissDate != null)")
  1044. ->andWhere('dismissDate')->lt(date(DT_DATETIME1, strtotime("-{$groupLife} day")))
  1045. ->fetchPairs();
  1046. $expiredGroups = array_keys($expiredGroups);
  1047. if(empty($expiredGroups)) return true;
  1048. $messageTables = $this->loadModel('im')->message->getAllTables();
  1049. foreach($messageTables as $table) $this->dao->delete()->from($table->tableName)->where('cgid')->in($expiredGroups)->exec();
  1050. $this->dao->delete()->from(TABLE_IM_CHAT_MESSAGE_INDEX)->where('gid')->in($expiredGroups)->exec();
  1051. $this->dao->delete()->from(TABLE_IM_CHAT)->where('gid')->in($expiredGroups)->exec();
  1052. $this->dao->delete()->from(TABLE_IM_CHATUSER)->where('cgid')->in($expiredGroups)->exec();
  1053. $this->dao->delete()->from(TABLE_IM_CONFERENCE)->where('cgid')->in($expiredGroups)->exec();
  1054. $this->dao->delete()->from(TABLE_IM_CONFERENCEACTION)->where('rid')->in($expiredGroups)->exec();
  1055. return !dao::isError();
  1056. }
  1057. /**
  1058. * Search chats with chat name or groupOwner's realname/account/pinyin.
  1059. *
  1060. * @param string $searchField
  1061. * @param object $pager
  1062. * @param string $orderBy
  1063. * @access public
  1064. * @return array
  1065. */
  1066. public function search($searchField, $pager, $orderBy)
  1067. {
  1068. $accounts = array();
  1069. if(isset($searchField) && !empty($searchField))
  1070. {
  1071. $accounts = $this->dao->select('account')->from(TABLE_USER)
  1072. ->beginIF($searchField)
  1073. ->where('account')->like("%$searchField%")
  1074. ->andWhere('deleted')->eq(0)
  1075. ->orWhere('pinyin')->like("%$searchField%")
  1076. ->orWhere('realname')->like("%$searchField%")
  1077. ->fi()
  1078. ->fetchPairs('account');
  1079. $accounts = array_keys($accounts);
  1080. }
  1081. $chatMemberCounts = $this->dao->select('tc.gid, COUNT(*) AS memberCount')
  1082. ->from(TABLE_IM_CHATUSER)->alias('tcu')
  1083. ->leftJoin(TABLE_IM_CHAT)->alias('tc')
  1084. ->on('tcu.cgid=tc.gid')
  1085. ->where('tc.type')->eq('group')
  1086. ->andWhere("(tc.dismissDate is null or tc.dismissDate = null)")
  1087. ->andWhere("(tc.mergedDate is null or tc.mergedDate = null)")
  1088. ->andWhere("(tcu.quit is null or tcu.quit = null)")
  1089. ->beginIF($searchField)->andWhere('tc.name', true)->like("%$searchField%")
  1090. ->orWhere('tc.ownedBy')->in($accounts)->markRight(1)
  1091. ->fi()
  1092. ->groupBy('tcu.cgid')
  1093. ->fetchPairs();
  1094. $pagerGids = array();
  1095. if($orderBy == 'userCount_asc' || $orderBy == 'userCount_desc')
  1096. {
  1097. if($orderBy == 'userCount_asc')
  1098. {
  1099. asort($chatMemberCounts);
  1100. }
  1101. else
  1102. {
  1103. arsort($chatMemberCounts);
  1104. }
  1105. $pagerGids = array_slice(array_keys($chatMemberCounts), ($pager->pageID-1)*$pager->recPerPage, $pager->recPerPage);
  1106. }
  1107. $chats = $this->dao->select('tc.gid, tc.id, tc.name, tc.public, tu.id as groupOwner, tc.createdDate, tc.lastActiveTime, tc.archiveDate')
  1108. ->from(TABLE_IM_CHAT)->alias('tc')
  1109. ->leftJoin(TABLE_USER)->alias('tu')
  1110. ->on('tc.ownedBy=tu.account')
  1111. ->where('tc.type')->eq('group')
  1112. ->andWhere("(dismissDate is null or dismissDate = null)")
  1113. ->andWhere("(mergedDate is null or mergedDate = null)")
  1114. ->beginIF($searchField)->andWhere('tc.name', true)->like("%$searchField%")
  1115. ->orWhere('tc.ownedBy')->in($accounts)->markRight(1)
  1116. ->fi()
  1117. ->beginIF(!empty($pagerGids))->andWhere('tc.gid')->in($pagerGids)
  1118. ->fi()
  1119. ->beginIF(empty($pagerGids))
  1120. ->orderBy($orderBy)
  1121. ->fi()
  1122. ->beginIF($pager)->page($pager, 'tc.gid')->fi()
  1123. ->fetchAll();
  1124. foreach($chats as $chat) $chat->userCount = isset($chatMemberCounts[$chat->gid]) ? $chatMemberCounts[$chat->gid] : 0;
  1125. $sortedChats = array();
  1126. if($orderBy == 'userCount_asc' || $orderBy == 'userCount_desc')
  1127. {
  1128. foreach($pagerGids as $key => $gid)
  1129. {
  1130. foreach($chats as $key => $chat)
  1131. {
  1132. if($chat->gid == $gid)
  1133. {
  1134. $sortedChats[] = $chat;
  1135. break;
  1136. }
  1137. }
  1138. }
  1139. }
  1140. $chats = $sortedChats ? $sortedChats : $chats;
  1141. /* Format data. */
  1142. $chats = array_map(function($chat)
  1143. {
  1144. $chat->id = (int)$chat->id;
  1145. $chat->groupOwner = (int)$chat->groupOwner;
  1146. $chat->userCount = (int)$chat->userCount;
  1147. $chat->createdDate = empty($chat->createdDate) || $chat->createdDate == null ? 0 : strtotime($chat->createdDate);
  1148. $chat->lastActiveTime = empty($chat->lastActiveTime) || $chat->lastActiveTime == null ? 0 : strtotime($chat->lastActiveTime);
  1149. $chat->public = empty($chat->public) ? 0 : 1;
  1150. $chat->archiveDate = empty($chat->archiveDate) || $chat->archiveDate == null ? 0 : strtotime($chat->archiveDate);
  1151. return $chat;
  1152. }, $chats);
  1153. return dao::isError() ? array() : $chats;
  1154. }
  1155. /**
  1156. * Update chat avatar.
  1157. *
  1158. * @param string $gid
  1159. * @param object $avatarData
  1160. * @access public
  1161. * @return object
  1162. */
  1163. public function updateAvatar($gid, $avatarData)
  1164. {
  1165. $this->dao->update(TABLE_IM_CHAT)->set('avatar')->eq($avatarData)->where('gid')->eq($gid)->exec();
  1166. return $this->getByGid($gid, true);
  1167. }
  1168. /**
  1169. * Super admin get all chatGroups.
  1170. *
  1171. * @access public
  1172. * @return array
  1173. */
  1174. public function adminGetChatGroups()
  1175. {
  1176. $chats = $this->dao->select('*')->from(TABLE_IM_CHAT)
  1177. ->where('type')->eq('group')
  1178. ->andWhere("(mergedDate is null or mergedDate = null)")
  1179. ->andWhere("(dismissDate is null or dismissDate = null)")
  1180. ->fetchAll();
  1181. return dao::isError() ? array() : $chats;
  1182. }
  1183. /**
  1184. * Filter out users not in chat.
  1185. *
  1186. * @param string $chatID
  1187. * @param array $userIDs
  1188. * @access public
  1189. * @return array
  1190. */
  1191. public function filterUsers($chatID, $userIDs)
  1192. {
  1193. $chat = $this->getByGid($chatID);
  1194. if($chat->type == 'group')
  1195. {
  1196. $members = $this->getMembers($chatID);
  1197. return array_intersect($members, $userIDs);
  1198. }
  1199. elseif($chat->type == 'one2one')
  1200. {
  1201. $members = explode('&', $chatID);
  1202. return array_intersect($members, $userIDs);
  1203. }
  1204. return $userIDs;
  1205. }
  1206. }