control.php 164 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296
  1. <?php
  2. class im extends control
  3. { public function __construct($moduleName = "", $methodName = "") { parent::__construct($moduleName, $methodName); $this->dao->exec("SET @@sql_mode=''"); }
  4. /**
  5. * @var imModel
  6. */
  7. public $im;
  8. /**
  9. * @var restrictionModel
  10. */
  11. public $restriction;
  12. /**
  13. * @var conferenceModel
  14. */
  15. public $conference;
  16. /**
  17. * Server start.
  18. *
  19. * @access public
  20. * @return void
  21. */
  22. public function sysServerStart()
  23. {
  24. $this->im->setXxdStartTime();
  25. $this->im->userResetStatus();
  26. $this->im->userReindexPinyin();
  27. $this->im->chatInitSystemChat();
  28. $this->im->conferenceResetStatus();
  29. $this->im->updateLastPoll();
  30. $output = new stdClass();
  31. $output->result = 'success';
  32. $output->version = $this->config->version;
  33. if(isset($this->config->fileEncryptionKey) && commonModel::isLicensedMethod('im', 'fileEncrypt')) $output->fileKey = $this->config->fileEncryptionKey;
  34. return $this->app->output($this->app->encrypt($output));
  35. }
  36. /**
  37. * Get serverInfo api.
  38. *
  39. * @param string $account
  40. * @param string $password
  41. * @param string $apiVersion
  42. * @param int $userID
  43. * @param string $version
  44. * @param string $device
  45. * @access public
  46. * @return void
  47. */
  48. public function sysGetServerInfo($account, $password, $apiVersion = '', $userID = 0, $version = '', $device = 'desktop')
  49. {
  50. $this->app->loadLang('user');
  51. if($this->loadModel('restriction') !== false)
  52. {
  53. $IPRestriction = $this->restriction->getConfiguration();
  54. if(isset($IPRestriction->enabled) && $IPRestriction->enabled == 'open')
  55. {
  56. if(!$this->im->checkIPInCIDRs(helper::getRemoteIp(), $IPRestriction->cidrs))
  57. {
  58. $output = new stdclass();
  59. $output->result = 'fail';
  60. $output->data = 'Illegal Request.';
  61. $output->message = $this->lang->im->IPInvalid;
  62. return $this->app->output($this->app->encrypt($output));
  63. }
  64. }
  65. }
  66. if($device == 'mobile' && isset($this->config->xuanxuan->mobileClient) && $this->config->xuanxuan->mobileClient == 'off')
  67. {
  68. $output = new stdclass();
  69. $output->result = 'fail';
  70. $output->data = 'Illegal Request.';
  71. $output->message = $this->lang->im->mobileLimited;
  72. return $this->app->output($this->app->encrypt($output));
  73. }
  74. $this->app->input['device'] = $device; // set device into input for further uses.
  75. $user = $this->im->userIdentify($account, $password);
  76. if(!is_array($user) || $user->account != $account) $this->im->userAddAction($account, 'loginXuanxuan', 'fail');
  77. if(!$user || (is_object($user) && $user->account != $account))
  78. {
  79. $output = new stdclass();
  80. $output->result = 'fail';
  81. $output->data = 'Illegal Request.';
  82. $output->message = $this->lang->user->loginFailed;
  83. return $this->app->output($this->app->encrypt($output));
  84. }
  85. if(is_string($user) && in_array($user, array('locked', 'banned')))
  86. {
  87. $output = new stdclass();
  88. $output->result = 'fail';
  89. $output->data = $user;
  90. return $this->app->output($this->app->encrypt($output));
  91. }
  92. if($user == 'invalid_token')
  93. {
  94. $output = new stdclass();
  95. $output->result = 'fail';
  96. $output->data = 'Invalid Token.';
  97. $output->message = $this->lang->user->tokenInvalid;
  98. return $this->app->output($this->app->encrypt($output));
  99. }
  100. if (isset($user->cidrs)) {
  101. if(!$this->im->checkIPInCIDRs(helper::getRemoteIp(), $user->cidrs))
  102. {
  103. $output = new stdclass();
  104. $output->result = 'fail';
  105. $output->data = 'Illegal Request.';
  106. $output->message = $this->lang->im->IPInvalid;
  107. return $this->app->output($this->app->encrypt($output));
  108. }
  109. }
  110. $upgradeInfo = $this->loadModel('client')->getUpgrade($version);
  111. if((empty($upgradeInfo) || $upgradeInfo->strategy == 'optional') && version_compare($version, $this->config->minClientVerson, '<'))
  112. {
  113. $output = new stdclass();
  114. $output->result = 'fail';
  115. $output->data = 'Illegal Request.';
  116. $output->message = sprintf($this->lang->im->errorClientVersionNotSupport, $version);
  117. return $this->app->output($this->app->encrypt($output));
  118. }
  119. $outputData = new stdclass();
  120. $outputData->clientUpdate = empty($upgradeInfo) ? null : $upgradeInfo;
  121. $outputData->backend = $this->config->xuanxuan->backend;
  122. $outputData->permissions = extCommonModel::getLicensePropertyValue('permissions');
  123. $outputData->backendURL = $this->im->getServer() . $this->config->webRoot;
  124. $outputData->dismissedGroupLife = isset($this->config->dismissedGroupLife) ? $this->config->dismissedGroupLife : 90; // Unit: Day
  125. $outputData->requestType = $this->config->requestType;
  126. $outputData->requestFix = $this->config->requestFix;
  127. /* Send ice servers configuration. */
  128. if(isset($this->config->xuanxuan->iceServers)) $outputData->iceServers = $this->config->xuanxuan->iceServers;
  129. /* Send conference configuration if available. */
  130. $conferenceConfig = $this->loadModel('conference')->getConfiguration('client');
  131. $isConferenceEnable = $this->conference->isEnabled();
  132. if($isConferenceEnable && !empty($conferenceConfig))
  133. {
  134. $outputData->conference = $conferenceConfig;
  135. $outputData->conference->enableSystem = isset($this->config->xuanxuan->enableSystemConference) ? (int)$this->config->xuanxuan->enableSystemConference : 1;
  136. /* Remove conference config if detached conferences are enabled and the client version is lower than 7.2. */
  137. if($device != 'mobile' && version_compare($version, '9.0', 'lt')) unset($outputData->conference);
  138. }
  139. /* Pushing related information for mobile devices.*/
  140. /* Send api scheme if client api version mismatch server api version. */
  141. $currentApiVersion = $this->config->maps['$version'];
  142. if($currentApiVersion != $apiVersion) $outputData->apiScheme = $this->im->getApiScheme();
  143. /* Send server local timestamp to client. */
  144. $outputData->serverTime = (double)(microtime(true) * 1000);
  145. /* Include generated token if there is one. (user was logon using password) */
  146. if(isset($user->token)) $outputData->authToken = $user->token;
  147. $outputData->authTokenLifetime = (int)zget($this->config->xuanxuan, 'tokenLifetime', 30);
  148. $outputData->authTokenAuthWindow = (int)zget($this->config->xuanxuan, 'tokenAuthWindow', 20);
  149. if(isset($user->tokenNeedRenew)) $outputData->tokenNeedRenew = $user->tokenNeedRenew;
  150. /* Integration related stuff. */
  151. if(isset($this->config->integration))
  152. {
  153. $integratedFeatures = array();
  154. if(zget($this->config->integration->office, 'officeEnabled')) $integratedFeatures[] = 'collaboraOffice';
  155. $outputData->integration = $integratedFeatures;
  156. }
  157. $watermarkConfig = $this->loadModel('watermark')->getConfig();
  158. if(isset($watermarkConfig)) $outputData->watermark = $watermarkConfig;
  159. $outputData->readStatus = zget($this->config->xuanxuan, 'readStatus', 'off');
  160. /* Store referer URL if provided, otherwise clear stored URL. (Will be used when assembling server URLs.) */
  161. $this->loadModel('setting')->setItem("system.im.loginurl.$user->id", empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER']);
  162. $output = new stdclass();
  163. $output->result = 'success';
  164. $output->users = array($user->id);
  165. $output->userID = $user->id;
  166. $output->method = 'sysgetserverinfo';
  167. $output->device = $device;
  168. $output->lang = zget($this->app->input, 'lang');
  169. $output->rid = zget($this->app->input, 'rid');
  170. $output->version = $this->config->version;
  171. $output->data = $outputData;
  172. return $this->app->output($this->app->encrypt($output));
  173. }
  174. /**
  175. * Get depts dept and roles list
  176. *
  177. * @param int $userID
  178. * @access public
  179. * @return void
  180. */
  181. public function sysGetDepts($userID)
  182. {
  183. $this->app->loadLang('user');
  184. $allDepts = $this->loadModel('dept')->getListByType('dept');
  185. if(dao::isError()) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Get depts fail'), 'messageResponsePack');
  186. $depts = array();
  187. foreach($allDepts as $id => $dept)
  188. {
  189. $depts[$id] = array('name' => $dept->name, 'order' => (int)$dept->order, 'parent' => (int)$dept->parent);
  190. }
  191. $data = new stdclass();
  192. $data->depts = $depts;
  193. $data->roles = $this->lang->user->roleList;
  194. unset($data->roles['']);
  195. $output = new stdclass();
  196. $output->result = 'success';
  197. $output->users = array($userID);
  198. $output->data = $data;
  199. return $this->im->sendOutput($output, 'sysgetdeptsResponse');
  200. }
  201. /**
  202. * Login.
  203. *
  204. * @param string $account user account
  205. * @param string $password encrypted password
  206. * @param object $options { simple: 0 | 1, status: 'online' | 'busy' | 'away', oidc: bool} oidc: OpenID Connect from XXD
  207. * @param int $userID
  208. * @param string $version
  209. * @param string $device desktop | mobile
  210. * @access public
  211. * @return void
  212. */
  213. public function userLogin($account = '', $password = '', $options = array(), $userID = 0, $version = '', $device = 'desktop')
  214. {
  215. $this->app->loadLang('user');
  216. if($this->loadModel('restriction') !== false)
  217. {
  218. $IPRestriction = $this->restriction->getConfiguration();
  219. if(isset($IPRestriction->enabled) && $IPRestriction->enabled == 'open' && !$this->im->checkIPInCIDRs(helper::getRemoteIp(), $IPRestriction->cidrs))
  220. {
  221. return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->IPInvalid, 'messageResponsePack'));
  222. }
  223. }
  224. $this->app->input['device'] = $device; // set device into input for further uses.
  225. $user = $this->im->userIdentify($account, $password);
  226. /* Handle OIDC auth request from XXD. */
  227. if(!empty($options->oidc))
  228. {
  229. if(empty($user) || !is_object($user)) return $this->app->output($this->app->encrypt(array('result' => 'fail', 'data' => $user)));
  230. /* Format user, send only necessary props back. */
  231. $userData = new stdclass();
  232. $userData->id = (int)$user->id;
  233. $userData->account = $user->account;
  234. $userData->realname = $user->realname;
  235. $userData->email = $user->email;
  236. return $this->app->output($this->app->encrypt(array('result' => 'success', 'data' => $userData)));
  237. }
  238. if(!$user) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->user->loginFailed), 'messageResponsePack');
  239. $lang = $this->app->input['lang'];
  240. $simple = !empty($options->simple);
  241. $status = !empty($options->status) ? $options->status : 'online';
  242. $comment = json_encode(array('version' => 'xuanxuan-v' . (empty($version) ? '?' : $version)));
  243. if(is_string($user) && in_array($user, array('locked', 'banned', 'invalid_token')))
  244. {
  245. $this->im->userAddAction($account, $simple ? 'reconnectXuanxuan' : 'loginXuanxuan', 'fail', $comment);
  246. return $this->im->sendOutput(array('result' => 'fail', 'data' => $user));
  247. }
  248. if (isset($user->cidrs) && !$this->im->checkIPInCIDRs(helper::getRemoteIp(), $user->cidrs)) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->IPInvalid, 'messageResponsePack'));
  249. $loginInfo = new stdclass();
  250. $loginInfo->result = 'success';
  251. $loginInfo->users = $user->id;
  252. $loginInfo->userID = (int)$user->id;
  253. $loginInfo->method = 'userlogin';
  254. $loginInfo->device = $device;
  255. $loginInfo->lang = $lang;
  256. /* Save client status and client lang of the user.*/
  257. $userData = new stdclass();
  258. $userData->id = $user->id;
  259. $userData->clientStatus = $status;
  260. $userData->clientLang = $this->session->clientLang;
  261. $user = $this->im->userUpdate($userData);
  262. $this->im->userAddAction($user->id, $simple ? 'reconnectXuanxuan' : 'loginXuanxuan', 'success', $comment);
  263. /* Append signed time, backendUrl and status to user. */
  264. $user->status = $status;
  265. $loginInfo->data = $user;
  266. $userChatList = $this->im->chatGetListByUserID($user->id);
  267. $cgids = array_map(function($chat) {return $chat->gid;}, $userChatList);
  268. $hasBotChat = in_array("$user->id&xuanbot", $cgids);
  269. if(!$hasBotChat)
  270. {
  271. $this->im->chatCreate("$user->id&xuanbot", '', 'bot', array($user->id), 0, false, $user->id);
  272. $this->im->messageCreateXuanbotWelcomeNotify($user->id, version_compare($version, '7.0', 'lt'));
  273. $userChatList = $this->im->chatGetListByUserID($user->id);
  274. }
  275. $outputs = array($loginInfo);
  276. $outputs[] = array('result' => 'success', 'method' => 'chatgetlist', 'data' => $userChatList, 'users' => array($user->id));
  277. $this->im->userUpdateDevice($user->id, $device, 'login', $version);
  278. // invite user to join conferences.
  279. $conferences = $this->im->conference->getPendingInvites($userID);
  280. foreach($conferences as $conference)
  281. {
  282. $conference = $this->im->conference->format($conference);
  283. $inviteOutput = new stdClass();
  284. $inviteOutput->method = 'conferenceinvite';
  285. $inviteOutput->result = 'success';
  286. $inviteOutput->users = array($userID);
  287. $inviteOutput->data = $conference;
  288. $outputs[] = $inviteOutput;
  289. }
  290. return $this->im->sendOutputGroup($outputs);
  291. }
  292. /**
  293. * Logout.
  294. *
  295. * @param bool $normal
  296. * @param int $userID
  297. * @access public
  298. * @return void
  299. */
  300. public function userLogout($normal = false, $userID = 0)
  301. {
  302. $output = new stdClass();
  303. $onlineUserIdList = array_keys($this->im->userGetList($status = 'online'));
  304. if(!in_array($userID, $onlineUserIdList))
  305. {
  306. $this->im->userAddAction($userID, $normal ? 'logoutXuanxuan' : 'disconnectXuanxuan', 'fail');
  307. $output->result = 'fail';
  308. $output->data = $this->im->userGetByID($userID);
  309. $output->users = $onlineUserIdList;
  310. return $this->app->output($this->app->encrypt($output));
  311. }
  312. // 先处理会议关闭,确保用户还在线时发送消息
  313. $closedConference = $this->im->conference->removeUserFromConferences($userID);
  314. $conferenceOutputs = array();
  315. foreach($closedConference as $conferenceNumber)
  316. {
  317. $conferenceOutputs = array_merge($conferenceOutputs, $this->getConferenceCloseOutput($conferenceNumber, $userID));
  318. }
  319. // 更新用户状态为离线
  320. $userData = new stdclass();
  321. $userData->id = $userID;
  322. $userData->clientStatus = 'offline';
  323. $updatedUser = $this->im->userUpdate($userData);
  324. // 处理用户更新失败的情况
  325. if(empty($updatedUser))
  326. {
  327. $user = $this->im->userGetByID($userID);
  328. $user->status = $user->clientStatus;
  329. }
  330. else
  331. {
  332. $user = $updatedUser;
  333. $user->status = $user->clientStatus;
  334. }
  335. $this->im->userAddAction($userID, $normal ? 'logoutXuanxuan' : 'disconnectXuanxuan', 'success');
  336. $this->im->userUpdateDevice($userID, isset($this->app->input['device']) ? $this->app->input['device'] : 'default');
  337. session_destroy();
  338. $onlineUsers = $this->im->userGetList($status = 'online');
  339. $onlineUserIdList = array_keys($onlineUsers);
  340. $output->result = 'success';
  341. $output->method = 'userlogout';
  342. $output->data = $user;
  343. $output->users = $onlineUserIdList;
  344. if(count($conferenceOutputs) > 0) return $this->im->sendOutputGroup(array_merge($conferenceOutputs, array($output)));
  345. return $this->im->sendOutput($output, 'userlogoutResponse');
  346. }
  347. /**
  348. * Close a conference in a chat.
  349. *
  350. * @param string $conferenceNumber
  351. * @param int $userID
  352. * @access private
  353. * @return void
  354. */
  355. private function getConferenceCloseOutput($conferenceNumber, $userID)
  356. {
  357. $conference = $this->im->conference->getByNumber($conferenceNumber);
  358. $result = $this->im->conference->close($conference->id);
  359. $outputs = array();
  360. if(!empty($conference->cgid))
  361. {
  362. $chat = $this->im->chatGetByGidForUser($conference->cgid, $userID);
  363. $chatMembers = $this->im->chat->getMembers($conference->cgid);
  364. // conference status change event for xxc chat header button.
  365. $statusChangeOutput = new stdClass();
  366. $statusChangeOutput->method = 'chatConferenceStatusChange';
  367. $statusChangeOutput->users = $chatMembers;
  368. $statusChangeOutput->result = 'success';
  369. $statusChangeOutput->data = array('number' => $conferenceNumber, 'cgid' => $conference->cgid);
  370. $outputs[] = $statusChangeOutput;
  371. $subscribers = explode(',', $conference->subscribers);
  372. $subscribers = array_filter($subscribers);
  373. if ($conference->isPrivate === '0')
  374. {
  375. $broadcastOutput = $this->im->message->createBroadcast('closeConference', $chat, $chat->members, $userID, $subscribers, true);
  376. if($broadcastOutput) $outputs[] = $broadcastOutput;
  377. }
  378. }
  379. $users = explode(',', $conference->participants . $conference->subscribers . $conference->invitee);
  380. $users = array_filter($users);
  381. $users = array_values($users);
  382. $users = array_map(function($v){
  383. return (int)$v;
  384. }, $users);
  385. // send close event for disabling the invitation.
  386. $conferenceCloseOutput = new stdClass();
  387. $conferenceCloseOutput->method = 'conferenceclose';
  388. $conferenceCloseOutput->users = $users;
  389. $conferenceCloseOutput->result ='success';
  390. $conferenceCloseOutput->data = array('number' => $conferenceNumber);
  391. $outputs[] = $conferenceCloseOutput;
  392. return $outputs;
  393. }
  394. /**
  395. * Get user list.
  396. *
  397. * @param array $identities array of userIDs or accounts.
  398. * @param int $userID
  399. * @access public
  400. * @return void
  401. */
  402. public function userGetList($identities, $userID = 0)
  403. {
  404. $output = $this->im->getUserListOutput($identities, $userID, $returnRaw = false);
  405. return $this->app->output($this->app->encrypt($output));
  406. }
  407. /**
  408. * Get user id list by dept with pager and sort rule
  409. *
  410. * @param string $deptID
  411. * @param object $pager
  412. * @param string $orderBy
  413. * @param array $exclude
  414. * @param int $userID
  415. * @access public
  416. * @return array
  417. */
  418. public function userGetListByDept($deptID, $pager, $orderBy, $exclude = array(), $onlySelf = false, $userID = 0)
  419. {
  420. if(empty($pager)) $pager = new stdclass();
  421. if(empty($orderBy)) $orderBy = 'id_asc';
  422. if(!isset($pager->pageID)) $pager->pageID = 1;
  423. if(!isset($pager->recPerPage)) $pager->recPerPage = 50;
  424. if(!isset($pager->recTotal)) $pager->recTotal = 0;
  425. $this->app->loadClass('pager', $static = true);
  426. $pager = new pager($pager->recTotal, $pager->recPerPage, $pager->pageID);
  427. $list = $this->im->userGetIDListByDept($deptID, $exclude, $pager, $orderBy, $onlySelf);
  428. $idList = array();
  429. foreach($list as $id) $idList[] = (int)$id;
  430. $output = new stdclass();
  431. $output->result = 'success';
  432. $output->users = array($userID);
  433. $output->data = $idList;
  434. $output->pager = new stdclass();
  435. $output->pager->recPerPage = $pager->recPerPage;
  436. $output->pager->pageID = $pager->pageID;
  437. $output->pager->recTotal = $pager->recTotal;
  438. $output->pager->data = array('dept' => $deptID, 'orderBy' => $orderBy);
  439. return $this->im->sendOutput($output, 'usergetlistbydeptResponse');
  440. }
  441. /**
  442. * Get deleted users with their user ids.
  443. *
  444. * @param array $idList
  445. * @param int $userID
  446. * @return void
  447. * @deprecated Use "userGetList" instead
  448. */
  449. public function userGetDeleted($idList, $userID)
  450. {
  451. $output = $this->im->getUserListOutput($idList, $userID);
  452. return $this->app->output($this->app->encrypt($output));
  453. }
  454. /**
  455. * Search for user with account / realname / pinyin in group / dept.
  456. *
  457. * @param string $search
  458. * @param object $options {"chat": "3b320201-52e1-4061-90b2-23e750e8b6e0", "dept": 5, "limit": 51, "exclude": [3, 5, 7], "pager": {"pageID": 1, "recPerPage": 50, "recTotal": 0}}
  459. * @param boolean $returnID
  460. * @param integer $userID
  461. * @access public
  462. * @return void
  463. */
  464. public function userSearch($search, $options = array(), $returnID = false, $userID = 0)
  465. {
  466. $pager = null;
  467. if(property_exists($options, 'pager'))
  468. {
  469. $this->app->loadClass('pager', $static = true);
  470. $pager = pager::init(isset($options->pager->recTotal) ? $options->pager->recTotal : 0, isset($options->pager->recPerPage) ? $options->pager->recPerPage : 50, isset($options->pager->pageID) ? $options->pager->pageID : 1);
  471. unset($options->pager);
  472. }
  473. $output = new stdclass();
  474. $output->result = 'success';
  475. $output->users = array($userID);
  476. $output->data = $this->im->userSearch($search, $options, $returnID, $pager);
  477. $output->pager = $pager;
  478. return $this->im->sendOutput($output, $returnID ? 'usersearchidResponse' : 'usersearchResponse');
  479. }
  480. /**
  481. * Change a user.
  482. *
  483. * @param array $user
  484. * @param int $userID
  485. * @access public
  486. * @return void
  487. */
  488. public function userUpdate($user = array(), $userID = 0)
  489. {
  490. $user = (object)$user;
  491. $user->id = $userID;
  492. if(isset($user->status) && !empty($user->status))
  493. {
  494. $user->clientStatus = $user->status;
  495. unset($user->status);
  496. }
  497. $user = $this->im->userUpdate($user);
  498. if(dao::isError())
  499. {
  500. $this->im->userAddAction($userID, 'edit', 'fail');
  501. return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Update user fail'), 'messageResponsePack');
  502. }
  503. $users = $this->im->userGetList($status = 'online');
  504. $this->im->userAddAction($userID, 'edit', 'success');
  505. $output = new stdclass();
  506. $output->result = 'success';
  507. $output->users = array_keys($users);
  508. $output->data = $user;
  509. return $this->im->sendOutput($output, 'userupdateResponse');
  510. }
  511. /**
  512. * Upload or download settings.
  513. *
  514. * @param string $account
  515. * @param string|array|object $settings
  516. * @param int $userID
  517. * @access public
  518. * @return void
  519. */
  520. public function userSyncSettings($account = '', $settings = '', $userID = 0)
  521. {
  522. /* Ignore $account param and use current user account */
  523. if(empty($account)) $account = $this->dao->select('account')->from(TABLE_USER)->where('id')->eq($userID)->fetch('account');
  524. $settingsObj = new stdclass();
  525. $userSettings = json_decode($this->loadModel('setting')->getItem("owner=$account&module=chat&section=clientSettings&key=settings")) ?: new stdClass();
  526. if(is_object($settings))
  527. {
  528. /* Upload the specified settings. */
  529. $settingsObj = $settings;
  530. foreach($settings as $key => $value) $userSettings->$key = $value;
  531. $this->app->user = (object)array("account" => $account); $this->setting->setItem("$account.chat.clientSettings.settings", helper::jsonEncode($userSettings));
  532. }
  533. elseif(is_array($settings))
  534. {
  535. /* Download the specified settings. */
  536. foreach($settings as $key) $settingsObj->$key = zget($userSettings, $key, '');
  537. }
  538. else
  539. {
  540. $isReset = $this->setting->getItem("owner=$account&module=user&section=clientSettings&key=reset");
  541. if($isReset)
  542. {
  543. /* User setting has been reset */
  544. $settingsObj->hash = '';
  545. $settingsObj->reset = true;
  546. $settingsObj->isReset = $isReset;
  547. $this->loadModel('setting')->deleteItems("owner=$account&module=chat&section=clientSettings&key=settings");
  548. $this->loadModel('setting')->deleteItems("owner=$account&module=user&section=clientSettings&key=reset");
  549. }
  550. elseif(isset($userSettings->hash) && $settings == $userSettings->hash)
  551. {
  552. /* User settings not change, only return hash */
  553. $settingsObj->hash = $userSettings->hash;
  554. }
  555. else
  556. {
  557. /* Download all settings. */
  558. $settingsObj = $userSettings;
  559. }
  560. }
  561. if(dao::isError()) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Save settings fail'), 'messageResponsePack');
  562. $output = new stdclass();
  563. $output->result = 'success';
  564. $output->users = array($userID);
  565. $output->data = $settingsObj;
  566. return $this->im->sendOutput($output, 'usersyncsettingsResponse');
  567. }
  568. /**
  569. * Set push device token to user table.
  570. *
  571. * @param string $deviceToken
  572. * @param string $deviceType android|ios
  573. * @param int $userID
  574. * @access public
  575. * @return void
  576. */
  577. public function userSetDeviceToken($deviceToken = '', $deviceType = 'android', $userID = 0)
  578. {
  579. $result = $this->loadModel('user')->setDeviceToken($deviceToken, $deviceType, $userID);
  580. return $this->im->sendOutput(array('result' => $result, 'users' => array($userID)), 'usersetdevicetokenResponse');
  581. }
  582. /**
  583. * Get a new auth token for user's device.
  584. *
  585. * @param string $deviceType desktop|mobile|android|ios, optional
  586. * @param string $deviceID
  587. * @param int $userID
  588. * @access public
  589. * @return string|bool
  590. */
  591. public function userGetAuthToken($deviceType = '', $deviceID = '', $userID = 0)
  592. {
  593. $tokenObj = $this->im->userGetAuthToken($userID, $deviceType, $deviceID);
  594. $output = new stdclass();
  595. $output->result = empty($tokenObj) ? 'fail' : 'success';
  596. $output->users = array($userID);
  597. $output->data = !empty($tokenObj) ? $tokenObj->token : '';
  598. return $this->im->sendOutput($output, 'usergetauthtokenResponse');
  599. }
  600. /**
  601. * Renew or just generate auth token for user's device.
  602. *
  603. * @param int $userID
  604. * @param string $deviceType
  605. * @param string $deviceID
  606. * @access public
  607. * @return object|bool
  608. */
  609. public function userRenewAuthToken($deviceType = '', $deviceID = '', $userID = 0)
  610. {
  611. $tokenObj = $this->im->userRenewAuthToken($userID, $deviceType, $deviceID);
  612. $output = new stdClass();
  613. $output->result = empty($tokenObj) ? 'fail' : 'success';
  614. $output->users = array($userID);
  615. $output->data = !empty($tokenObj) ? $tokenObj->token : '';
  616. return $this->im->sendOutput($output, 'usergetauthtokenResponse');
  617. }
  618. /**
  619. * Get public chat list that user not join.
  620. *
  621. * @param int $userID
  622. * @access public
  623. * @return void
  624. */
  625. public function chatGetPublicList($userID = 0)
  626. {
  627. $chatList = $this->im->chatGetPublicList($userID);
  628. if(dao::isError()) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Get public chat list fail'), 'messageResponsePack');
  629. $output = new stdclass();
  630. $output->result = 'success';
  631. $output->users = $userID;
  632. $output->data = $chatList;
  633. return $this->im->sendOutput($output, 'chatgetpubliclistResponse');
  634. }
  635. /**
  636. * Get chat list of a user.
  637. *
  638. * @param int $userID
  639. * @access public
  640. * @return void
  641. */
  642. public function chatGetList($userID = 0)
  643. {
  644. $chats = $this->im->chatGetListByUserID($userID);
  645. $output = new stdclass();
  646. $output->result = 'success';
  647. $output->users = array($userID);
  648. $output->data = $chats;
  649. return $this->im->sendOutput($output, "chatgetlistResponse");
  650. }
  651. /**
  652. * Get message count and last message id of chat.
  653. *
  654. * @param string $gid
  655. * @param int $userID
  656. * @access public
  657. * @return void
  658. */
  659. public function chatGetMessageInfo($gid, $userID = 0)
  660. {
  661. $chat = $this->im->chatGetByGid($gid, true);
  662. if(is_array($chat->members) && !in_array($userID, $chat->members) && (empty($chat->mergedDate) || $chat->mergedDate == null)) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'No such chat, or you are not in the chat.'), 'messageResponsePack');
  663. $chatInfo = new stdclass();
  664. $chatInfo->lastMessage = intval($chat->lastMessage);
  665. $chatInfo->messageCount = $this->im->chatgetMessageCount($gid);
  666. $output = new stdclass();
  667. $output->result = 'success';
  668. $output->users = array($userID);
  669. $output->data = $chatInfo;
  670. return $this->im->sendOutput($output, 'chatgetmessageinfoResponse');
  671. }
  672. /**
  673. * Get last messages of chats by gids.
  674. *
  675. * @param string|array $cgids
  676. * @param int $userID
  677. * @access public
  678. * @return void
  679. */
  680. public function chatGetLastMessage($cgids, $userID)
  681. {
  682. if(is_string($cgids)) $cgids = array($cgids);
  683. /* Check if user is in those chats. */
  684. $userChatList = $this->im->chatGetGidListByUserID($userID);
  685. $cgids = array_intersect($cgids, $userChatList);
  686. $output = new stdclass();
  687. $output->result = 'success';
  688. $output->users = array($userID);
  689. $output->data = $this->im->messageGetLast($cgids);
  690. return $this->im->sendOutput($output, 'chatgetlastmessageResponse');
  691. }
  692. /**
  693. * Get members of a chat.
  694. *
  695. * @param string $gid
  696. * @param int $userID
  697. * @access public
  698. * @return void
  699. */
  700. public function chatGetMembers($gid = '', $userID = 0)
  701. {
  702. $chat = $this->im->chatGetByGid($gid, true, true);
  703. if(dao::isError()) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Get member list fail'));
  704. $output = new stdclass();
  705. $output->result = 'success';
  706. $output->users = array($userID);
  707. $data = new stdclass();
  708. $data->gid = $gid;
  709. $data->members = (empty($chat->mergedDate) || $chat->mergedDate == null) ? $chat->members : array($userID);
  710. $output->data = $data;
  711. return $this->im->sendOutput($output, 'chatgetmembersResponse');
  712. }
  713. /**
  714. * Get detailed member list of a chat.
  715. *
  716. * @param string $gid
  717. * @param object $pager
  718. * @param string $orderBy
  719. * @param string $search
  720. * @param int $userID
  721. * @access public
  722. * @return void
  723. */
  724. public function chatGetMemberDetails($gid, $pager = null, $orderBy = '', $search = '', $userID = 0)
  725. {
  726. $user = $this->im->userGetByID($userID);
  727. if(empty($user->admin) || $user->admin != 'super') return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Unauthorized to get member details.'));
  728. if(empty($pager)) $pager = new stdclass();
  729. if(!isset($pager->pageID)) $pager->pageID = 1;
  730. if(!isset($pager->recPerPage)) $pager->recPerPage = 10;
  731. if(!isset($pager->recTotal)) $pager->recTotal = 0;
  732. $this->app->loadClass('pager', $static = true);
  733. $pager = new pager($pager->recTotal, $pager->recPerPage, $pager->pageID);
  734. /* Search for members in chat. */
  735. $memberIDs = array();
  736. if(!empty($search))
  737. {
  738. $userSearchPager = pager::init(0, $pager->recPerPage, 1);
  739. $memberIDs = $this->im->userSearch($search, array('chat' => $gid), true, $userSearchPager);
  740. }
  741. $details = $this->im->chatGetMemberDetails($gid, $pager, $orderBy, $memberIDs);
  742. if(dao::isError()) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Get chat details fail'));
  743. $output = new stdclass();
  744. $output->result = 'success';
  745. $output->users = array($userID);
  746. $output->data = $details->data;
  747. $output->pager = $details->pager;
  748. return $this->im->sendOutput($output, 'chatgetmemberdetailsResponse');
  749. }
  750. /**
  751. * Create a chat.
  752. *
  753. * @param string $gid
  754. * @param string $name
  755. * @param string $type
  756. * @param array $members
  757. * @param int $subjectID
  758. * @param bool $public true: the chat is public | false: the chat isn't public.
  759. * @param int $userID
  760. * @access public
  761. * @return void
  762. */
  763. public function chatCreate($gid = '', $name = '', $type = 'group', $members = array(), $subjectID = 0, $public = false, $userID = 0)
  764. {
  765. if($gid == 'notification' or $gid == 'littlexx') return $this->im->sendOutput(array('result' => 'success', 'users' =>$userID));
  766. $chat = $this->im->chat->getByGid($gid, true);
  767. if(!$chat)
  768. {
  769. $name = strip_tags($name);
  770. $chat = $this->im->chat->create($gid, $name, $type, $members, $subjectID, $public, $userID);
  771. }
  772. $users = $this->im->userGetList($status = 'online', $chat->members);
  773. if(dao::isError())
  774. {
  775. if($type == 'group') $this->im->chatAddAction(0, 'create', $userID, 'fail');
  776. return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Create chat fail'), 'messageResponsePack');
  777. }
  778. $output = new stdclass();
  779. $output->result = 'success';
  780. $output->method = $this->app->getMethodName();
  781. $output->users = array_keys($users);
  782. $output->data = $chat;
  783. if($type == 'group')
  784. {
  785. $this->im->chatAddAction($chat->id, 'create', $userID, 'success');
  786. $broadcast = $this->im->messageCreateBroadcast('createChat', $chat, array_keys($users), $userID);
  787. if($broadcast) $output = array($output, $broadcast);
  788. return $this->im->sendOutputGroup($output);
  789. }
  790. return $this->im->sendOutput($output, 'chatcreateResponse');
  791. }
  792. /**
  793. * Set admins of a chat.
  794. *
  795. * @param string $gid
  796. * @param array $admins
  797. * @param int $userID
  798. * @access public
  799. * @return void
  800. */
  801. public function chatAddAdmins($gid = '', $admins = array(), $userID = 0)
  802. {
  803. $chat = $this->im->chat->getByGid($gid);
  804. if(!$chat) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notExist), 'messageResponsePack');
  805. $account = $this->dao->select('account')->from(TABLE_USER)->where('id')->eq($userID)->fetch('account');
  806. if((empty($chat->ownedBy) && $chat->createdBy != $account) || (!empty($chat->ownedBy) && $chat->ownedBy != $account))
  807. {
  808. $user = $this->im->userGetByID($userID);
  809. if(empty($user->admin) || $user->admin != 'super') return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notGroupCreator), 'messageResponsePack');
  810. }
  811. $account = $this->dao->select('account')->from(TABLE_USER)->where('id')->eq($userID)->fetch('account');
  812. $sysAdmins = $this->dao->select('admins')->from(TABLE_COMPANY)->where('id')->eq($this->app->company->id)->fetch('admins');
  813. $sysAdminArray = explode(',', $sysAdmins);
  814. $super = in_array($account, $sysAdminArray) ? 'super' : '';
  815. if($chat->archiveDate && $super != 'super')
  816. {
  817. $chat = $this->im->chat->getByGid($gid, true);
  818. $output = new stdclass();
  819. $output->result = 'success';
  820. $output->users = array($userID);
  821. $output->data = $chat;
  822. return $this->im->sendOutput($output, 'chataddadminsResponse');
  823. }
  824. $chat = $this->im->chatAddAdmins($gid, $admins, $userID);
  825. $users = $this->im->userGetList($status = 'online', $chat->members);
  826. $comment = json_encode(array('admins' => $admins));
  827. $this->im->chatAddAction($chat->id, 'addAdmins', $userID, 'success', $comment);
  828. $users = array_keys($users);
  829. $users[] = $userID;
  830. $users = array_unique($users);
  831. $output = new stdclass();
  832. $output->result = 'success';
  833. $output->users = $users;
  834. $output->data = $chat;
  835. return $this->im->sendOutput($output, 'chataddadminsResponse');
  836. }
  837. /**
  838. * Remove admins of a chat.
  839. *
  840. * @param string $gid
  841. * @param array $users
  842. * @param int $userID
  843. * @access public
  844. * @return void
  845. */
  846. public function chatRemoveAdmins($gid = '', $admins = array(), $userID = 0)
  847. {
  848. $chat = $this->im->chat->getByGid($gid);
  849. if(!$chat) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notExist), 'messageResponsePack');
  850. $account = $this->dao->select('account')->from(TABLE_USER)->where('id')->eq($userID)->fetch('account');
  851. if((empty($chat->ownedBy) && $chat->createdBy != $account) || (!empty($chat->ownedBy) && $chat->ownedBy != $account))
  852. {
  853. $user = $this->im->userGetByID($userID);
  854. if(empty($user->admin) || $user->admin != 'super') return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notGroupCreator), 'messageResponsePack');
  855. }
  856. $account = $this->dao->select('account')->from(TABLE_USER)->where('id')->eq($userID)->fetch('account');
  857. $sysAdmins = $this->dao->select('admins')->from(TABLE_COMPANY)->where('id')->eq($this->app->company->id)->fetch('admins');
  858. $sysAdminArray = explode(',', $sysAdmins);
  859. $super = in_array($account, $sysAdminArray) ? 'super' : '';
  860. if($chat->archiveDate && $super != 'super')
  861. {
  862. $chat = $this->im->chat->getByGid($gid, true);
  863. $output = new stdclass();
  864. $output->result = 'success';
  865. $output->users = array($userID);
  866. $output->data = $chat;
  867. return $this->im->sendOutput($output, 'chatremoveadminsResponse');
  868. }
  869. $chat = $this->im->chatRemoveAdmins($gid, $admins, $userID);
  870. $users = $this->im->userGetList($status = 'online', $chat->members);
  871. $comment = json_encode(array('admins' => $admins));
  872. $this->im->chatAddAction($chat->id, 'removeAdmins', $userID, 'success', $comment);
  873. $users = array_keys($users);
  874. $users[] = $userID;
  875. $users = array_unique($users);
  876. $output = new stdclass();
  877. $output->result = 'success';
  878. $output->users = $users;
  879. $output->data = $chat;
  880. return $this->im->sendOutput($output, 'chatremoveadminsResponse');
  881. }
  882. /**
  883. * Pin messages of a chat.
  884. *
  885. * @param string $gid
  886. * @param array $messageIds
  887. * @param int $userID
  888. * @access public
  889. * @return void
  890. */
  891. public function chatPinMessages($gid = '', $messageIds = array(), $userID = 0)
  892. {
  893. $chat = $this->im->chat->getByGid($gid);
  894. if(!$chat) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notExist), 'messageResponsePack');
  895. if(!$this->im->chatIsAdmin($chat, $userID)) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notAdmin), 'messageResponsePack');
  896. if(!$chat->archiveDate)
  897. {
  898. $chat = $this->im->chatPinMessages($chat, $messageIds);
  899. }
  900. $users = $this->im->userGetList($status = 'online', $chat->members);
  901. $output = new stdclass();
  902. $output->result = 'success';
  903. $output->users = array_keys($users);
  904. $output->data = array('cgid' => $gid, 'pinned' => $messageIds, 'allPinned' => $chat->pinnedMessages);
  905. return $this->im->sendOutput($output, 'chatpinmessagesResponse');
  906. }
  907. /**
  908. * Unpin messages of a chat.
  909. *
  910. * @param string $gid
  911. * @param array $messageIds
  912. * @param int $userID
  913. * @access public
  914. * @return void
  915. */
  916. public function chatUnpinMessages($gid = '', $messageIds = array(), $userID = 0)
  917. {
  918. $chat = $this->im->chat->getByGid($gid);
  919. if(!$chat) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notExist), 'messageResponsePack');
  920. if(!$this->im->chatIsAdmin($chat, $userID)) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notAdmin), 'messageResponsePack');
  921. if(!$chat->archiveDate)
  922. {
  923. $chat = $this->im->chatUnpinMessages($chat, $messageIds);
  924. }
  925. $users = $this->im->userGetList($status = 'online', $chat->members);
  926. $output = new stdclass();
  927. $output->result = 'success';
  928. $output->users = array_keys($users);
  929. $output->data = array('cgid' => $gid, 'unpinned' => $messageIds, 'allPinned' => $chat->pinnedMessages);
  930. return $this->im->sendOutput($output, 'chatunpinmessagesResponse');
  931. }
  932. /**
  933. * Join a chat.
  934. *
  935. * @param string $gid
  936. * @param int $userID
  937. * @access public
  938. * @return void
  939. */
  940. public function chatJoin($gid = '', $userID = 0)
  941. {
  942. $chat = $this->im->chat->getByGid($gid);
  943. if(!$chat) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notExist), 'messageResponsePack');
  944. if($chat->type != 'group') return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notGroupChat), 'messageResponsePack');
  945. if($chat->public == '0') return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notPublic), 'messageResponsePack');
  946. $result = $this->im->chatJoin($gid, $userID);
  947. $this->im->chat->addAction($chat->id, 'join', $userID, $result ? 'success' : 'fail');
  948. $chat = $this->im->chat->getByGid($gid, true);
  949. $users = $this->im->userGetList($status = 'online', $chat->members);
  950. $users = array_keys($users);
  951. $users[] = $userID;
  952. if(dao::isError()) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Join chat failed.'), 'messageResponsePack');
  953. $output = new stdclass();
  954. $output->result = 'success';
  955. $output->method = $this->app->getMethodName();
  956. $output->users = $users;
  957. $output->data = $chat;
  958. $broadcast = $this->im->messageCreateBroadcast('joinChat', $chat, $users, $userID);
  959. if($broadcast)
  960. {
  961. $output = array($output, $broadcast);
  962. return $this->im->sendOutputGroup($output);
  963. }
  964. return $this->im->sendOutput($output);
  965. }
  966. /**
  967. * Leave a chat.
  968. *
  969. * @param string $gid
  970. * @param int $userID
  971. * @access public
  972. * @return void
  973. */
  974. public function chatLeave($gid = '', $userID = 0)
  975. {
  976. $chat = $this->im->chat->getByGid($gid);
  977. if(!$chat) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notExist), 'messageResponsePack');
  978. if($chat->type != 'group') return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notGroupChat), 'messageResponsePack');
  979. $result = $this->im->chatLeave($gid, $userID);
  980. if(!$result)
  981. {
  982. $this->im->chat->addAction($chat->id, 'leave', $userID, 'fail');
  983. return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Leave chat failed.'), 'messageResponsePack');
  984. }
  985. $this->im->chat->addAction($chat->id, 'leave', $userID, 'success');
  986. $chat = $this->im->chat->getByGid($gid, true);
  987. $users = $this->im->userGetList($status = 'online', $chat->members);
  988. $users = array_keys($users);
  989. $users[] = $userID;
  990. $output = new stdclass();
  991. $output->result = 'success';
  992. $output->method = $this->app->getMethodName();
  993. $output->users = $users;
  994. $output->data = $chat;
  995. if(empty($chat->dismissDate))
  996. {
  997. $broadcast = $this->im->messageCreateBroadcast('leaveChat', $chat, $users, $userID);
  998. if($broadcast)
  999. {
  1000. $output = array($output, $broadcast);
  1001. return $this->im->sendOutputGroup($output);
  1002. }
  1003. }
  1004. return $this->im->sendOutput($output, 'chatleaveResponse');
  1005. }
  1006. /**
  1007. * Change the name of a chat.
  1008. *
  1009. * @param string $gid
  1010. * @param string $name
  1011. * @param int $userID
  1012. * @access public
  1013. * @return void
  1014. */
  1015. public function chatRename($gid = '', $name = '', $userID = 0)
  1016. {
  1017. $chat = $this->im->chat->getByGid($gid);
  1018. if(!$chat) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notExist), 'messageResponsePack');
  1019. if($chat->archiveDate) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->operationNotSupportedOnArchivedChat), 'messageResponsePack');
  1020. $account = $this->dao->select('account')->from(TABLE_USER)->where('id')->eq($userID)->fetch('account');
  1021. $sysAdmins = $this->dao->select('admins')->from(TABLE_COMPANY)->where('id')->eq($this->app->company->id)->fetch('admins');
  1022. $sysAdminArray = explode(',', $sysAdmins);
  1023. $super = in_array($account, $sysAdminArray) ? 'super' : '';
  1024. if(!$this->im->chatIsAdmin($chat, $userID) && $super != 'super') return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notAdmin), 'messageResponsePack');
  1025. $isPrivateChat = $gid == "$userID&$userID";
  1026. if($chat->type != 'group' && $chat->type != 'system' && !$isPrivateChat) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notGroupChat), 'messageResponsePack');
  1027. if(mb_strlen($name, 'utf8') > 16) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->chatNameTooLong), 'messageResponsePack');
  1028. $chat->name = strip_tags($name);
  1029. $chatID = $chat->id;
  1030. $comment = json_encode(array('name' => $name));
  1031. $chat = $this->im->chatUpdate($chat, $userID);
  1032. if(dao::isError())
  1033. {
  1034. $this->im->chatAddAction($chatID, 'rename', $userID, 'fail', $comment);
  1035. return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Rename chat fail.'), 'messageResponsePack');
  1036. }
  1037. $this->im->chatAddAction($chatID, 'rename', $userID, 'success', $comment);
  1038. $users = $this->im->userGetList($status = 'online', $chat->members);
  1039. $output = new stdclass();
  1040. $output->result = 'success';
  1041. $output->method = $this->app->getMethodName();
  1042. $output->users = array_keys($users);
  1043. $output->data = $chat;
  1044. $broadcast = $this->im->messageCreateBroadcast($isPrivateChat ? 'renamePrivate' : 'renameChat', $chat, array_keys($users), $userID);
  1045. if($broadcast)
  1046. {
  1047. $output = array($output, $broadcast);
  1048. return $this->im->sendOutputGroup($output);
  1049. }
  1050. return $this->im->sendOutput($output);
  1051. }
  1052. /**
  1053. * Dismiss a chat
  1054. *
  1055. * @param string $gid
  1056. * @param int $userID
  1057. * @access public
  1058. * @return void
  1059. */
  1060. public function chatDismiss($gid = '', $userID = 0)
  1061. {
  1062. $chat = $this->im->chat->getByGid($gid);
  1063. if(!$chat) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notExist), 'messageResponsePack');
  1064. if($chat->type != 'group') return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notGroupChat), 'messageResponsePack');
  1065. $account = $this->dao->select('account')->from(TABLE_USER)->where('id')->eq($userID)->fetch('account');
  1066. if(empty($chat->ownedBy) && $chat->createdBy != $account) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notGroupCreator), 'messageResponsePack');
  1067. if(!empty($chat->ownedBy) && $chat->ownedBy != $account) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notGroupCreator), 'messageResponsePack');
  1068. $chat->dismissDate = helper::now();
  1069. $chatID = $chat->id;
  1070. $chat = $this->im->chatUpdate($chat, $userID);
  1071. if(dao::isError())
  1072. {
  1073. $this->im->chatAddAction($chatID, 'dismiss', $userID, 'fail');
  1074. return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Dismiss chat fail.'), 'messageResponsePack');
  1075. }
  1076. $this->im->chatAddAction($chatID, 'dismiss', $userID, 'success');
  1077. $users = $this->im->userGetList($status = 'online', $chat->members);
  1078. $output = new stdclass();
  1079. $output->result = 'success';
  1080. $output->method = $this->app->getMethodName();
  1081. $output->users = array_keys($users);
  1082. $output->data = $chat;
  1083. $broadcast = $this->im->messageCreateBroadcast('dismissChat', $chat, array_keys($users), $userID);
  1084. if($broadcast)
  1085. {
  1086. $output = array($output, $broadcast);
  1087. return $this->im->sendOutputGroup($output);
  1088. }
  1089. return $this->im->sendOutput($output);
  1090. }
  1091. /**
  1092. * Change the committers of a chat
  1093. *
  1094. * @param string $gid
  1095. * @param string $committers
  1096. * @param int $userID
  1097. * @access public
  1098. * @return void
  1099. */
  1100. public function chatSetCommitters($gid = '', $committers = '', $userID = 0)
  1101. {
  1102. $chat = $this->im->chat->getByGid($gid);
  1103. if(!$chat) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notExist), 'messageResponsePack');
  1104. if($chat->type != 'group' && $chat->type != 'system') return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notGroupChat), 'messageResponsePack');
  1105. $chat->committers = $committers;
  1106. $chat = $this->im->chatUpdate($chat, $userID);
  1107. if(dao::isError()) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Set chat committers fail.'), 'messageResponsePack');
  1108. $users = $this->im->userGetList($status = 'online', $chat->members);
  1109. $output = new stdclass();
  1110. $output->result = 'success';
  1111. $output->users = array_keys($users);
  1112. $output->data = $chat;
  1113. return $this->im->sendOutput($output, 'chatsetcommittersResponse');
  1114. }
  1115. /**
  1116. * Change a chat to be public or not.
  1117. *
  1118. * @param string $gid
  1119. * @param string $visible 0|1
  1120. * @param int $userID
  1121. * @access public
  1122. * @return void
  1123. */
  1124. public function chatSetVisibility($gid = '', $visible = '1', $userID = 0)
  1125. {
  1126. $chat = $this->im->chat->getByGid($gid);
  1127. if(!$chat) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notExist), 'messageResponsePack');
  1128. if($chat->type != 'group') return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notGroupChat), 'messageResponsePack');
  1129. if($chat->archiveDate) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->operationNotSupportedOnArchivedChat), 'messageResponsePack');
  1130. $chatID = $chat->id;
  1131. $chat->public = $visible ? '1' : '0';
  1132. $chat->lastActiveTime = empty($chat->lastActiveTime) ? null : date('Y-m-d H:i:s', $chat->lastActiveTime);
  1133. $chat = $this->im->chatUpdate($chat, $userID);
  1134. if(dao::isError())
  1135. {
  1136. $this->im->chatAddAction($chatID, $visible ? 'bepublic' : 'beprivate', $userID, 'fail');
  1137. return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Set chat visibility fail.'), 'messageResponsePack');
  1138. }
  1139. $this->im->chatAddAction($chatID, $visible ? 'bepublic' : 'beprivate', $userID, 'success');
  1140. $users = $this->im->userGetList($status = 'online', $chat->members);
  1141. $output = new stdclass();
  1142. $output->result = 'success';
  1143. $output->users = array_keys($users);
  1144. $output->data = $chat;
  1145. return $this->im->sendOutput($output, 'chatsetvisibilityResponse');
  1146. }
  1147. /**
  1148. * Star or cancel star a chat.
  1149. *
  1150. * @param bool $star true: star a chat | false: cancel star a chat.
  1151. * @param string $gid
  1152. * @param int $userID
  1153. * @access public
  1154. * @return void
  1155. */
  1156. public function chatStar($star = true, $gid = '', $userID = 0)
  1157. {
  1158. $this->im->chatStar($star, $gid, $userID);
  1159. if(dao::isError()) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Operate fail.'), 'messageResponsePack');
  1160. $output = new stdclass();
  1161. $output->result = 'success';
  1162. $output->users = $userID;
  1163. $output->data = new stdclass();
  1164. $output->data->gid = $gid;
  1165. $output->data->star = $star;
  1166. return $this->im->sendOutput($output, 'chatstarResponse');
  1167. }
  1168. /**
  1169. * Archive a chat or vice versa.
  1170. *
  1171. * @param bool $archive
  1172. * @param string $gid
  1173. * @param int $userID
  1174. * @access public
  1175. * @return void
  1176. */
  1177. public function chatArchive($archive = true, $gid = '', $userID = 0)
  1178. {
  1179. $chat = $this->im->chat->getByGid($gid, false, false);
  1180. if(!$chat) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notExist), 'messageResponsePack');
  1181. if($chat->type != 'group') return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notGroupChat), 'messageResponsePack');
  1182. $account = $this->dao->select('account')->from(TABLE_USER)->where('id')->eq($userID)->fetch('account');
  1183. $account = $this->dao->select('account')->from(TABLE_USER)->where('id')->eq($userID)->fetch('account');
  1184. $sysAdmins = $this->dao->select('admins')->from(TABLE_COMPANY)->where('id')->eq($this->app->company->id)->fetch('admins');
  1185. $sysAdminArray = explode(',', $sysAdmins);
  1186. $super = in_array($account, $sysAdminArray) ? 'super' : '';
  1187. if(!empty($chat->ownedBy) && $chat->ownedBy != $account && $super != 'super') return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notGroupCreator), 'messageResponsePack');
  1188. if($archive)
  1189. {
  1190. $chat->archiveDate = helper::now();
  1191. }
  1192. else
  1193. {
  1194. $chat->archiveDate = null;
  1195. }
  1196. $chatID = $chat->id;
  1197. $chat = $this->im->chatUpdate($chat, $userID);
  1198. $actionName = $archive ? 'archive' : 'unarchive';
  1199. if(dao::isError())
  1200. {
  1201. $this->im->chatAddAction($chatID, $actionName, $userID, 'fail');
  1202. return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Archive chat fail.'), 'messageResponsePack');
  1203. }
  1204. $this->im->chatAddAction($chatID, $actionName, $userID, 'success');
  1205. $users = $this->im->userGetList($status = 'online', $chat->members);
  1206. $output = new stdclass();
  1207. $output->result = 'success';
  1208. $output->method = $this->app->getMethodName();
  1209. $output->users = array_keys($users);
  1210. $output->data = $chat;
  1211. $broadcast = $this->im->messageCreateBroadcast($archive ? 'archiveChat' : 'unarchiveChat', $chat, array_keys($users), $userID);
  1212. if($broadcast)
  1213. {
  1214. $output = array($output, $broadcast);
  1215. return $this->im->sendOutputGroup($output);
  1216. }
  1217. return $this->im->sendOutput($output);
  1218. }
  1219. /**
  1220. * Hide or display a chat.
  1221. *
  1222. * @param bool $hide true: hide a chat | false: display a chat.
  1223. * @param string $gid
  1224. * @param int $userID
  1225. * @access public
  1226. * @return void
  1227. */
  1228. public function chatHide($hide = true, $gid = '', $userID = 0)
  1229. {
  1230. // discard chatHide from v6.6. For old xxc versions use chatMute and chatFreeze instead.
  1231. $this->im->chatMute($hide, $gid, $userID);
  1232. $this->im->chatFreeze($hide, $gid, $userID);
  1233. if(dao::isError()) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Toggle chat fail.'), 'messageResponsePack');
  1234. $outputs = array();
  1235. $chatHideResponse = new stdclass();
  1236. $chatHideResponse->result = 'success';
  1237. $chatHideResponse->users = $userID;
  1238. $chatHideResponse->method = 'chathide';
  1239. $chatHideResponse->data = new stdclass();
  1240. $chatHideResponse->data->gid = $gid;
  1241. $chatHideResponse->data->hide = false;
  1242. $outputs[] = $chatHideResponse;
  1243. $chatMuteResponse = new stdclass();
  1244. $chatMuteResponse->result = 'success';
  1245. $chatMuteResponse->users = $userID;
  1246. $chatMuteResponse->method = 'chatmute';
  1247. $chatMuteResponse->data = new stdclass();
  1248. $chatMuteResponse->data->gid = $gid;
  1249. $chatMuteResponse->data->mute = $hide;
  1250. $outputs[] = $chatMuteResponse;
  1251. $chatFreezeResponse = new stdclass();
  1252. $chatFreezeResponse->result = 'success';
  1253. $chatFreezeResponse->users = $userID;
  1254. $chatFreezeResponse->method = 'chatfreeze';
  1255. $chatFreezeResponse->data = new stdclass();
  1256. $chatFreezeResponse->data->gid = $gid;
  1257. $chatFreezeResponse->data->freeze = $hide;
  1258. $outputs[] = $chatFreezeResponse;
  1259. return $this->im->sendoutputGroup($outputs);
  1260. }
  1261. /**
  1262. * Mute a chat.
  1263. *
  1264. * @param string $gid
  1265. * @param bool $mute true: mute a chat | false: cacel mute a chat.
  1266. * @param int $userID
  1267. * @access public
  1268. * @return void
  1269. */
  1270. public function chatMute($mute = true, $gid = '', $userID = 0)
  1271. {
  1272. $this->im->chatMute($mute, $gid, $userID);
  1273. if(dao::isError()) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Mute chat fail.'), 'messageResponsePack');
  1274. $output = new stdclass();
  1275. $output->result = 'success';
  1276. $output->users = $userID;
  1277. $output->data = new stdclass();
  1278. $output->data->gid = $gid;
  1279. $output->data->mute = $mute;
  1280. return $this->im->sendOutput($output, 'chatmuteResponse');
  1281. }
  1282. /**
  1283. * Freeze a chat.
  1284. *
  1285. * @param string $gid
  1286. * @param bool $freeze true: freeze a chat | false: unfreeze a chat.
  1287. * @param int $userID
  1288. * @access public
  1289. * @return void
  1290. */
  1291. public function chatFreeze($freeze = true, $gid = '', $userID = 0)
  1292. {
  1293. $this->im->chatFreeze($freeze, $gid, $userID);
  1294. if(dao::isError()) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Set chat freeze fail.'), 'messageResponsePack');
  1295. $output = new stdclass();
  1296. $output->result = 'success';
  1297. $output->users = $userID;
  1298. $output->data = new stdclass();
  1299. $output->data->gid = $gid;
  1300. $output->data->freeze = $freeze;
  1301. return $this->im->sendOutput($output, 'chatfreezeResponse');
  1302. }
  1303. /**
  1304. * Set category for a chat
  1305. *
  1306. * @param array $gids
  1307. * @param string $category
  1308. * @param int $userID
  1309. * @access public
  1310. * @return void
  1311. */
  1312. public function chatSetCategory($gids = array(), $category = '', $userID = 0)
  1313. {
  1314. $this->im->chat->setCategory($gids, $category, $userID);
  1315. if(dao::isError()) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Set chat category fail.'), 'messageResponsePack');
  1316. $output = new stdclass();
  1317. $output->result = 'success';
  1318. $output->users = $userID;
  1319. $output->data = new stdclass();
  1320. $output->data->gids = $gids;
  1321. $output->data->category = $category;
  1322. return $this->im->sendOutput($output, 'chatsetcategoryResponse');
  1323. }
  1324. /**
  1325. * Invite members to a chat.
  1326. *
  1327. * @param string $gid
  1328. * @param array $members
  1329. * @param int $userID
  1330. * @access public
  1331. * @return void
  1332. */
  1333. public function chatInvite($gid = '', $members = array(), $userID = 0)
  1334. {
  1335. $chat = $this->im->chat->getByGid($gid, true);
  1336. $user = $this->im->userGetById($userID);
  1337. if(!$chat) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notExist), 'messageResponsePack');
  1338. if(!$this->im->chatIsAdmin($chat, $userID) && $chat->adminInvite == '1' && $chat->public == '0' && $user->admin !='super') return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->adminCanInvite), 'messageResponsePack');
  1339. if($user->admin != 'super' && !in_array($userID, $chat->members)) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->userNotInGroup), 'messageResponsePack');
  1340. if($chat->type != 'group') return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notGroupChat), 'messageResponsePack');
  1341. $joinedMembers = array();
  1342. foreach($members as $member)
  1343. {
  1344. $result = $this->im->chatJoin($gid, $member);
  1345. if(is_int($result)) $joinedMembers[] = $result;
  1346. }
  1347. $chat = $this->im->chat->getByGid($gid, true, true, true);
  1348. $users = $this->im->userGetList($status = 'online', $chat->members);
  1349. $comment = json_encode(array('members' => $members));
  1350. if(dao::isError())
  1351. {
  1352. $this->im->chatAddAction($chat->id, 'invite', $userID, 'fail', $comment);
  1353. return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Invite chat member fail.'), 'messageResponsePack');
  1354. }
  1355. $this->im->chatAddAction($chat->id, 'invite', $userID, 'success', $comment);
  1356. $output = new stdclass();
  1357. $output->result = 'success';
  1358. $output->method = $this->app->getMethodName();
  1359. $output->users = array_keys($users);
  1360. $output->data = $chat;
  1361. if($user->admin == 'super')
  1362. {
  1363. $output->users[] = (int)$userID;
  1364. $output->users = array_unique($output->users);
  1365. }
  1366. $members = array_diff($members, $joinedMembers);
  1367. if(!empty($members))
  1368. {
  1369. $broadcast = $this->im->messageCreateBroadcast('inviteUser', $chat, $output->users, $userID, $members);
  1370. if($broadcast)
  1371. {
  1372. $output = array($output, $broadcast);
  1373. return $this->im->sendOutputGroup($output);
  1374. }
  1375. }
  1376. return $this->im->sendOutput($output, 'chatinviteResponse');
  1377. }
  1378. /**
  1379. * Kick members from a chat.
  1380. *
  1381. * @param string $gid
  1382. * @param array $users
  1383. * @param int $userID
  1384. * @access public
  1385. * @return void
  1386. */
  1387. public function chatKick($gid = '', $users = array(), $userID = 0)
  1388. {
  1389. $chat = $this->im->chat->getByGid($gid);
  1390. if(!$chat) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notExist), 'messageResponsePack');
  1391. if(!$this->im->chatIsAdmin($gid, $userID))
  1392. {
  1393. $user = $this->im->userGetByID($userID);
  1394. if(empty($user->admin) || $user->admin != 'super') return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notGroupCreator), 'messageResponsePack');
  1395. }
  1396. if($chat->type != 'group') return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notGroupChat), 'messageResponsePack');
  1397. $groupOwner = $this->dao->select('tu.id')->from(TABLE_IM_CHAT)->alias('tc')->leftJoin(TABLE_USER)->alias('tu')->on('tc.ownedBy=tu.account')->where('tc.gid')->eq($gid)->fetch('id');
  1398. if(!empty($groupOwner) && in_array($groupOwner, $users))
  1399. {
  1400. $users = array_diff($users, array($groupOwner));
  1401. }
  1402. if(empty($users))
  1403. {
  1404. return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->canNotDelOwner), 'messageResponsePack');
  1405. }
  1406. foreach($users as $user) $this->im->chatLeave($gid, $user);
  1407. $chat = $this->im->chat->getByGid($gid, true);
  1408. $members = $this->im->userGetList($status = 'online', $chat->members);
  1409. $members = array_keys($members);
  1410. $members = array_merge($members, $users);
  1411. $comment = json_encode(array('members' => $users));
  1412. if(dao::isError())
  1413. {
  1414. $this->im->chatAddAction($chat->id, 'kick', $userID, 'fail', $comment);
  1415. return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Kick chat member fail.'), 'messageResponsePack');
  1416. }
  1417. $this->im->chatAddAction($chat->id, 'kick', $userID, 'success', $comment);
  1418. $users = $members;
  1419. $users[] = $userID;
  1420. $users = array_unique($users);
  1421. $output = new stdclass();
  1422. $output->result = 'success';
  1423. $output->users = $users;
  1424. $output->data = $chat;
  1425. return $this->im->sendOutput($output, 'chatkickResponse');
  1426. }
  1427. /**
  1428. * Get history messages of a chat.
  1429. *
  1430. * @param string $gid
  1431. * @param int $recPerPage
  1432. * @param int $pageID
  1433. * @param int $recTotal
  1434. * @param bool $continued
  1435. * @param int $startDate
  1436. * @param int $userID
  1437. * @access public
  1438. * @return void
  1439. * @deprecated The method is unnecessary in new versions.
  1440. */
  1441. public function chatGetHistory($gid = '', $recPerPage = 20, $pageID = 1, $recTotal = 0, $continued = false, $startDate = 0, $userID = 0)
  1442. {
  1443. if($startDate) $startDate = date('Y-m-d H:i:s', $startDate);
  1444. $this->app->loadClass('pager', $static = true);
  1445. $pager = new pager($recTotal, $recPerPage, $pageID);
  1446. if($gid)
  1447. {
  1448. $messageList = $this->im->message->getListByCgid($gid, $pager, $startDate);
  1449. }
  1450. else
  1451. {
  1452. $messageList = $this->im->message->getList('', $idList = array(), $pager, $startDate);
  1453. }
  1454. if(dao::isError()) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Get history fail'), 'messageResponsePack');
  1455. $output = new stdclass();
  1456. $output->result = 'success';
  1457. $output->users = array($userID);
  1458. $output->data = $messageList;
  1459. $output->pager = new stdclass();
  1460. $output->pager->recPerPage = $pager->recPerPage;
  1461. $output->pager->pageID = $pager->pageID;
  1462. $output->pager->recTotal = $pager->recTotal;
  1463. $output->pager->gid = $gid;
  1464. $output->pager->continued = $continued;
  1465. return $this->im->sendOutput($output, 'chatgethistoryResponse');
  1466. }
  1467. /**
  1468. * Set last read message for a chat
  1469. *
  1470. * @param string $gid
  1471. * @param int $lastReadMessageID
  1472. * @param int $userID
  1473. * @access public
  1474. * @return void
  1475. */
  1476. public function chatSetLastReadMessage($gid, $lastReadMessageID = 0, $userID = 0)
  1477. {
  1478. $this->im->chatSetLastReadMessage($gid, $lastReadMessageID, $userID);
  1479. if(dao::isError()) return $this->im->sendOutput(array('result' => 'fail', 'message' => "Set last read message fail for chat $gid."), 'messageResponsePack');
  1480. $output = new stdclass();
  1481. $output->result = 'success';
  1482. $output->users = $userID;
  1483. $output->data = new stdclass();
  1484. $output->data->gid = $gid;
  1485. $output->data->id = $lastReadMessageID;
  1486. return $this->im->sendOutput($output, 'chatsetlastreadmessageResponse');
  1487. }
  1488. /**
  1489. * Merge chat by gid.
  1490. *
  1491. * @param string $gid
  1492. * @param string $targetGid
  1493. * @param int $userID
  1494. * @access public
  1495. * @return void
  1496. */
  1497. public function chatMerge($gid, $targetGid, $userID)
  1498. {
  1499. $chat = $this->im->chatGetByGid($gid, true);
  1500. $targetChat = $this->im->chatGetByGid($targetGid, true);
  1501. if(empty($chat) || empty($targetChat)) return $this->im->sendOutput(array('result' => 'fail', 'message' => "Get chats fail, check if chats exist."), 'messageResponsePack');
  1502. if($chat->archiveDate) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->operationNotSupportedOnArchivedChat), 'messageResponsePack');
  1503. if($targetChat->archiveDate) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->operationNotSupportedOnArchivedChat), 'messageResponsePack');
  1504. $newMembers = array_diff($chat->members, $targetChat->members);
  1505. $targetChat = $this->im->chatMerge($chat, $targetChat, $userID);
  1506. if(empty($targetChat))
  1507. {
  1508. $this->im->chat->addAction($chat->id, 'merge', $userID, 'fail', json_encode(array('targetChat' => $targetChat->id)));
  1509. return $this->im->sendOutput(array('result' => 'fail', 'message' => "Unable to merge chat $gid into chat $targetGid."), 'messageResponsePack');
  1510. }
  1511. $this->im->chat->addAction($chat->id, 'merge', $userID, 'success', json_encode(array('targetChat' => $targetChat->id)));
  1512. $mergeNoticeChat = $chat;
  1513. $mergeNoticeChat->intoName = $targetChat->name;
  1514. $mergeNotice = $this->im->messageCreateBroadcast('chatMerged', $mergeNoticeChat, $mergeNoticeChat->members, $userID);
  1515. $chat->members = array();
  1516. $targetChatName = $targetChat->name;
  1517. $broadcastChat = $targetChat;
  1518. $broadcastChat->name = $chat->name; // Use merged chat name in broadcast.
  1519. $mergeBroadcast = $this->im->messageCreateBroadcast(empty($newMembers) ? 'mergeChat' : 'mergeChatWithMembers', $broadcastChat, $targetChat->members, $userID, $newMembers);
  1520. $targetChat->name = $targetChatName; // Restore target chat name.
  1521. $leaveOutput = new stdclass();
  1522. $leaveOutput->result = 'success';
  1523. $leaveOutput->method = 'chatLeave';
  1524. $leaveOutput->users = $targetChat->members;
  1525. $leaveOutput->data = $chat;
  1526. $joinOutput = new stdclass();
  1527. $joinOutput->result = 'success';
  1528. $joinOutput->method = 'chatJoin';
  1529. $joinOutput->users = $targetChat->members;
  1530. $joinOutput->data = $targetChat;
  1531. $outputGroup = array($leaveOutput, $joinOutput, $mergeBroadcast, $mergeNotice);
  1532. $user = $this->im->userGetById($userID);
  1533. if($user->admin == 'super')
  1534. {
  1535. $targetChat->members[] = (int)$userID;
  1536. $leaveOutput->users = array_unique($leaveOutput->users);
  1537. $mergeOutput = new stdclass();
  1538. $mergeOutput->result = 'success';
  1539. $mergeOutput->users = $userID;
  1540. $mergeOutput->method = 'chatMerge';
  1541. $mergeOutput->data = new stdclass();
  1542. $mergeOutput->data->targetGid = $targetGid;
  1543. $outputGroup[] = $mergeOutput;
  1544. }
  1545. return $this->im->sendOutputGroup($outputGroup);
  1546. }
  1547. /**
  1548. * Set last read message for a chat
  1549. *
  1550. * @param string $gid
  1551. * @param int $lastReadMessageIndex
  1552. * @param int $userID
  1553. * @access public
  1554. * @return void
  1555. */
  1556. public function chatSetLastReadMessageByIndex($gid, $lastReadMessageIndex = 0, $userID = 0)
  1557. {
  1558. $this->im->chat->setLastReadMessageByIndex($gid, $lastReadMessageIndex, $userID);
  1559. if(dao::isError()) return $this->im->sendOutput(array('result' => 'fail', 'message' => "Set last read message fail for chat $gid."), 'messageResponsePack');
  1560. $output = new stdclass();
  1561. $output->result = 'success';
  1562. $output->users = $userID;
  1563. $readStatus = zget($this->config->xuanxuan, 'readStatus', 'off');
  1564. if($readStatus == 'on')
  1565. {
  1566. $chat = $this->im->chat->getByGid($gid, true);
  1567. $output->users = $chat->members;
  1568. }
  1569. $output->data = new stdclass();
  1570. $output->data->gid = $gid;
  1571. $output->data->id = $lastReadMessageIndex;
  1572. return $this->im->sendOutput($output, 'chatsetlastreadmessageResponse');
  1573. }
  1574. /**
  1575. * Get chat by gid.
  1576. *
  1577. * @param string $gid
  1578. * @access public
  1579. * @return void
  1580. */
  1581. public function chatGetByGid($gid, $userID)
  1582. {
  1583. $output = new stdclass();
  1584. $output->module = 'im';
  1585. $output->method = 'chatgetbygid';
  1586. $output->result = 'success';
  1587. $output->users = array($userID);
  1588. $output->data = new stdclass();
  1589. $output->data = $this->im->chatGetByGid($gid, true);
  1590. return $this->im->sendOutput($output, 'chatgetbygidResponse');
  1591. }
  1592. /**
  1593. * Change ownership of group.
  1594. *
  1595. * @param string $gid
  1596. * @param int $ownerUserID new owner id
  1597. * @param int $userID
  1598. * @access public
  1599. * @return void
  1600. */
  1601. public function chatChangeOwnership($gid, $ownerUserID, $userID = 0)
  1602. {
  1603. $chat = $this->im->chatGetByGid($gid, true);
  1604. /* Check if new owner is a member of chat. */
  1605. if(!in_array($ownerUserID, $chat->members)) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Cannot change ownership of chat, new owner must be in the chat.'), 'messageResponsePack');
  1606. $account = $this->dao->select('account')->from(TABLE_USER)->where('id')->eq($userID)->fetch('account');
  1607. $sysAdmins = $this->dao->select('admins')->from(TABLE_COMPANY)->where('id')->eq($this->app->company->id)->fetch('admins');
  1608. $sysAdminArray = explode(',', $sysAdmins);
  1609. $super = in_array($account, $sysAdminArray) ? 'super' : '';
  1610. if($chat->archiveDate && $super != 'super') return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->operationNotSupportedOnArchivedChat), 'messageResponsePack');
  1611. /* Check if current user is a member of chat or super admin. */
  1612. $user = $this->im->userGetByID($userID);
  1613. $byAdmin = !empty($user->admin) && $user->admin == 'super';
  1614. if(!$byAdmin && !in_array($userID, $chat->members)) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Cannot change ownership of chat, current user must be in the chat.'));
  1615. $result = $this->im->chatChangeOwnership($chat, $ownerUserID, $userID, $byAdmin);
  1616. if(empty($result)) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Change ownership failed.'), 'messageResponsePack');
  1617. $output = new stdclass();
  1618. $output->method = 'chatchangeownership';
  1619. $output->result = 'success';
  1620. $output->users = $chat->members;
  1621. $output->data = $result;
  1622. if($byAdmin)
  1623. {
  1624. $output->users[] = $userID;
  1625. $output->users = array_unique($output->users);
  1626. }
  1627. $users = $this->im->userGetList($status = 'online', $chat->members);
  1628. $this->im->chatAddAction($chat->id, 'changeOwnership', $userID, 'success');
  1629. $broadcast = $this->im->messageCreateBroadcast('changeChatOwnership' . ($byAdmin ? 'ByAdmin' : ''), $chat, array_keys($users), $ownerUserID, $chat->members);
  1630. if($broadcast) $output = array($output, $broadcast);
  1631. return $this->im->sendOutputGroup($output);
  1632. }
  1633. /**
  1634. * Retract a message.
  1635. *
  1636. * @param array $messages
  1637. * @param int $userID
  1638. * @access public
  1639. * @return void
  1640. */
  1641. public function messageRetract($messages = array(), $userID = 0)
  1642. {
  1643. $chats = array();
  1644. foreach($messages as $key => $message)
  1645. {
  1646. $message = (object) $message;
  1647. $chats[$message->cgid] = $message->cgid;
  1648. if(isset($message->type) && $message->type == 'broadcast') unset($messages[$key]);
  1649. }
  1650. $message = (object) current($messages);
  1651. $chat = $this->im->chat->getByGid($message->cgid, $getMembers = true);
  1652. $onlineUsers = $this->im->userGetList($status = 'online', $chat->members);
  1653. $messages = $this->im->messageRetract($message->gid, $this->im->chatIsAdmin($chat, $userID), $userID);
  1654. if(dao::isError() && count($messages) == 0) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Retract message fail.'), 'messageResponsePack');
  1655. $output = new stdclass();
  1656. $output->result = 'success';
  1657. $output->users = array_keys($onlineUsers);
  1658. $output->data = $messages;
  1659. return $this->im->sendOutput($output, 'messageretractResponse');
  1660. }
  1661. /**
  1662. * Send message to a chat.
  1663. *
  1664. * @param array $messages
  1665. * @param int $userID
  1666. * @access public
  1667. * @return void
  1668. */
  1669. public function messageSend($messages = array(), $userID = 0, $version = '', $device = 'desktop')
  1670. {
  1671. /* Check if the messages belong to the same chat. */
  1672. $chats = array();
  1673. foreach($messages as $key => $message)
  1674. {
  1675. $message = (object) $message;
  1676. $chats[$message->cgid] = $message->cgid;
  1677. }
  1678. $message = (object) current($messages);
  1679. $members = explode('&', $message->cgid);
  1680. $isOne2OneChat = (count($members) == 2);
  1681. if($message->user != $userID) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notSameUser), 'messageResponsePack');
  1682. $chat = $this->im->chat->getByGid($message->cgid, $getMembers = true);
  1683. /* Call bots if is chat with bot. */
  1684. $responsesFromBot = array();
  1685. if($isOne2OneChat && in_array('xuanbot', $members)) // TODO: check for chat type later.
  1686. {
  1687. $members = array_filter($members, static function ($member) {
  1688. return is_numeric($member);
  1689. });
  1690. $repliesFromBot = $this->im->botProcessMessage($message, $userID);
  1691. $messagesFromBot = $repliesFromBot->messages;
  1692. if(version_compare($version, '7.0', 'lt') && $device != 'mobile')
  1693. {
  1694. foreach($messagesFromBot as $message)
  1695. {
  1696. $message->user = -1;
  1697. }
  1698. }
  1699. $responsesFromBot = $repliesFromBot->responses;
  1700. $messages = array_merge($messages, $messagesFromBot);
  1701. }
  1702. $newChat = false;
  1703. if(!$chat && $isOne2OneChat)
  1704. {
  1705. $newChat = true;
  1706. $chat = $this->im->chatcreate($message->cgid, '', 'one2one', $members, 0, false, $userID);
  1707. if(dao::isError())
  1708. {
  1709. return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => 'Create chat fail.'), 'messageResponsePack');
  1710. }
  1711. }
  1712. if($chat->archiveDate) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->operationNotSupportedOnArchivedChat), 'messageResponsePack');
  1713. /* Check whether the logon user can send message in chat. */
  1714. $isCommitter = $this->im->chatIsCommitter($message, $userID, $chat);
  1715. if($isCommitter !== true) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->cantChat), 'messageResponsePack');
  1716. /* If message is a bulletin, check if user is an admin. */
  1717. if($message->type == 'bulletin')
  1718. {
  1719. $isAdmin = $this->im->chatIsAdmin($chat, $userID);
  1720. if(!$isAdmin) return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => 'Only admins can send bulletin messages.'), 'messageResponsePack');
  1721. }
  1722. $onlineUsers = array($userID);
  1723. $offlineUsers = array();
  1724. $users = $this->im->userGetList($status = '', $chat->members);
  1725. foreach($users as $id => $user)
  1726. {
  1727. if($id == $userID) continue;
  1728. if($user->clientStatus == 'offline') $offlineUsers[] = $id;
  1729. if($user->clientStatus != 'offline') $onlineUsers[] = $id;
  1730. }
  1731. /* Create messages. */
  1732. $messages = $this->im->messageCreate($messages, $userID);
  1733. if(empty($messages)) return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => 'No message created.'), 'messageResponsePack');
  1734. $this->im->message->saveOfflineList($messages, $offlineUsers);
  1735. /* Push message to offline users */
  1736. if(dao::isError()) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Send message fail'), 'messageResponsePack');
  1737. $output = new stdclass();
  1738. $output->result = 'success';
  1739. $output->method = 'messagesend';
  1740. $output->users = $onlineUsers;
  1741. $output->data = $messages;
  1742. $outputs = array_merge(array($output), $responsesFromBot);
  1743. if($newChat)
  1744. {
  1745. $chatOutput = new stdclass();
  1746. $chatOutput->module = 'im';
  1747. $chatOutput->method = 'chatcreate';
  1748. $chatOutput->result = 'success';
  1749. $chatOutput->users = $onlineUsers;
  1750. $chatOutput->data = $chat;
  1751. array_unshift($outputs, $chatOutput);
  1752. return $this->im->sendOutputGroup($outputs);
  1753. }
  1754. return $this->im->sendOutputGroup($outputs);
  1755. }
  1756. /**
  1757. * Get read statuses of messages.
  1758. *
  1759. * @param array $messageIds
  1760. * @param bool $detailed return detailed read status or not
  1761. * @param int $userID
  1762. * @access public
  1763. * @return void
  1764. */
  1765. public function messageGetReadStatus($messageIds, $detailed = false, $userID = 0)
  1766. {
  1767. $statuses = $this->im->message->getReadStatus($messageIds, $detailed, $userID);
  1768. $output = new stdclass();
  1769. $output->result = 'success';
  1770. $output->users = array($userID);
  1771. $output->data = $statuses;
  1772. return $this->im->sendOutput($output, 'messagegetreadstatusResponse');
  1773. }
  1774. /**
  1775. * Get messages from chat by ID.
  1776. *
  1777. * @param string $cgid
  1778. * @param array $idList
  1779. * @param int $userID
  1780. * @param int $fromMerged
  1781. * @access public
  1782. * @return void
  1783. */
  1784. public function messageGetList($cgid, $idList, $fromMerged = 0, $userID = 0)
  1785. {
  1786. $chat = $this->im->chatGetByGid($cgid, true);
  1787. if(is_array($chat->members) && !in_array($userID, $chat->members) && ($chat->mergedDate == null || empty($chat->mergedDate)))
  1788. {
  1789. if($fromMerged == 0) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'No such chat, or you are not in the chat.'), 'messageResponsePack');
  1790. $messages = $this->im->message->getList('', array($fromMerged));
  1791. if(empty($messages)) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'No such chat, or you are not in the chat.'), 'messageResponsePack');
  1792. $mergedMessage = current($messages);
  1793. if(empty($mergedMessage) || empty($mergedMessage->data)) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'No such chat, or you are not in the chat.'), 'messageResponsePack');
  1794. $data = json_decode($mergedMessage->data);
  1795. $merge = json_decode($data->merge);
  1796. if(empty($merge) || !is_array($merge) || $data->chat !== $cgid || !empty(array_diff($idList, $merge))) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'No such chat, or you are not in the chat.'), 'messageResponsePack');
  1797. }
  1798. $messages = $this->im->messageGetList($cgid, $idList);
  1799. $output = new stdclass();
  1800. $output->result = 'success';
  1801. $output->method = 'messagegetlist';
  1802. $output->users = array($userID);
  1803. $output->data = $messages;
  1804. return $this->im->sendOutput($output, 'messagegetlistResponse');
  1805. }
  1806. /**
  1807. * Get messages from chat by indexes.
  1808. *
  1809. * @param string $cgid
  1810. * @param array $indexList
  1811. * @param int $userID
  1812. * @access public
  1813. * @return void
  1814. */
  1815. public function messageGetListByIndexes($cgid, $indexList, $userID = 0)
  1816. {
  1817. $members = $this->im->chatGetMembers($cgid, true);
  1818. if(is_array($members) && !in_array($userID, $members)) $this->im->sendOutput(array('result' => 'fail', 'message' => 'No such chat, or you are not in the chat.'), 'messageResponsePack');
  1819. $messages = $this->im->messageGetListByIndexes($cgid, $indexList);
  1820. $output = new stdclass();
  1821. $output->result = 'success';
  1822. $output->method = 'messagegetlistbyindexes';
  1823. $output->users = array($userID);
  1824. $output->data = $messages;
  1825. return $this->im->sendOutput($output, 'messagegetlistbyindexesResponse');
  1826. }
  1827. /**
  1828. * Sync message from $fromID.
  1829. *
  1830. * @param string $cgid
  1831. * @param int $fromID
  1832. * @param bool $reverse
  1833. * @param int $limit
  1834. * @param bool $returnID
  1835. * @param int $userID
  1836. * @access public
  1837. * @return void
  1838. */
  1839. public function messageSync($cgid, $fromID, $reverse = false, $limit = 50, $returnID = false, $userID = 0)
  1840. {
  1841. $chat = $this->im->chatGetByGid($cgid, true);
  1842. if(is_array($chat->members) && !in_array($userID, $chat->members) && (empty($chat->mergedDate) || $chat->mergedDate == null)) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'No such chat, or you are not in the chat.'), 'messageResponsePack');
  1843. $messages = $this->im->messageGetListAroundIDForUser($cgid, $fromID, $reverse, $limit, $userID, $returnID);
  1844. $output = new stdclass();
  1845. $output->result = 'success';
  1846. $output->method = 'messagesync';
  1847. $output->users = array($userID);
  1848. $output->data = $messages;
  1849. return $this->im->sendOutput($output, $returnID ? 'messagesyncidResponse' :'messagesyncResponse');
  1850. }
  1851. /**
  1852. * Sync message by indexIds.
  1853. *
  1854. * @param string $cgid
  1855. * @param array $indexList
  1856. * @param bool $reverse
  1857. * @param bool $returnID
  1858. * @param int $userID
  1859. * @access public
  1860. * @return void
  1861. */
  1862. public function messageSyncByIndexes($cgid, $indexList, $reverse = false, $returnID = false, $userID = 0)
  1863. {
  1864. $members = $this->im->chatGetMembers($cgid, true);
  1865. if(is_array($members) && !in_array($userID, $members)) $this->im->sendOutput(array('result' => 'fail', 'message' => 'No such chat, or you are not in the chat.'), 'messageResponsePack');
  1866. $messages = $this->im->messageGetListAroundIDByIndexes($cgid, $indexList, $reverse, $returnID);
  1867. $output = new stdclass();
  1868. $output->result = 'success';
  1869. $output->method = 'messagesyncbyindexes';
  1870. $output->users = array($userID);
  1871. $output->data = $messages;
  1872. return $this->im->sendOutput($output, $returnID ? 'messagesyncidResponse' :'messagesyncResponse');
  1873. }
  1874. /**
  1875. * Sync messages since last logout.
  1876. *
  1877. * @param bool $full whether to lookup partitions or not.
  1878. * @param int $userID
  1879. * @access public
  1880. * @return void
  1881. */
  1882. public function messageSyncSinceOffline($full = false, $userID = 0)
  1883. {
  1884. $messages = $this->im->message->getOfflineList($full, $userID);
  1885. $output = new stdclass();
  1886. $output->result = 'success';
  1887. $output->method = 'messagesyncsinceoffline';
  1888. $output->users = array($userID);
  1889. $output->data = $messages;
  1890. return $this->im->sendOutput($output, 'messagesyncsinceofflineResponse');
  1891. }
  1892. /**
  1893. * Sync missed messages. (Messages that are read but not synced to client.)
  1894. *
  1895. * @param int $lastKnownMessage
  1896. * @param int $userID
  1897. * @access public
  1898. * @return void
  1899. */
  1900. public function messageSyncMissed($lastKnownMessage, $userID = 0)
  1901. {
  1902. $messages = $this->im->message->getMissedByLastKnown($lastKnownMessage, $userID);
  1903. $output = new stdclass();
  1904. $output->result = 'success';
  1905. $output->method = 'messagesyncmissed';
  1906. $output->users = array($userID);
  1907. $output->data = $messages;
  1908. return $this->im->sendOutput($output, 'messagesyncmissedResponse');
  1909. }
  1910. /**
  1911. * Get a conference by number.
  1912. *
  1913. * @param string $number
  1914. * @param int $userID
  1915. * @access public
  1916. * @return void
  1917. */
  1918. public function conferenceGetByNumber($number, $userID = 0)
  1919. {
  1920. $conference = $this->im->conference->getByNumber($number);
  1921. $output = new stdclass();
  1922. $output->method = 'conferencegetbynumber';
  1923. $output->result = 'success';
  1924. $output->users = array($userID);
  1925. $output->data = empty($conference)
  1926. ? $conference
  1927. : $this->im->conference->format($conference);
  1928. return $this->im->sendOutput($output, 'conferencegetbynumberResponse');
  1929. }
  1930. /**
  1931. * Get a conference by id.
  1932. * @param string $type
  1933. * @param array $options
  1934. * @param object $pager
  1935. * @param int $userID
  1936. * @return mixed
  1937. */
  1938. public function conferenceGetByCondition($type = 'immediate', $options = array(), $pager = null, $userID = 0, $version = '', $device = 'desktop')
  1939. {
  1940. if(empty($pager)) $pager = new stdclass();
  1941. if(!isset($pager->pageID)) $pager->pageID = 1;
  1942. if(!isset($pager->recPerPage)) $pager->recPerPage = 9;
  1943. if(!isset($pager->recTotal)) $pager->recTotal = 0;
  1944. if(version_compare(helper::formatVersion($version), '9.0.0', '<'))
  1945. {
  1946. $output = new stdclass();
  1947. $output->result = 'success';
  1948. $output->data = array();
  1949. $output->users = array($userID);
  1950. $output->pager = new stdclass();
  1951. $output->pager->recPerPage = $pager->recPerPage;
  1952. $output->pager->pageID = $pager->pageID;
  1953. $output->pager->recTotal = $pager->recTotal;
  1954. return $this->im->sendOutput($output, 'conferenceGetByConditionResponse');
  1955. }
  1956. $this->app->loadClass('pager', $static = true);
  1957. $pager = new pager($pager->recTotal, $pager->recPerPage, $pager->pageID);
  1958. $conferences = $this->im->conference->getByCondition($type, $options, $pager, $userID);
  1959. $output = new stdclass();
  1960. $output->result = 'success';
  1961. $output->users = array($userID);
  1962. $output->data = array
  1963. (
  1964. 'conferences' => $conferences,
  1965. 'pager' => array
  1966. (
  1967. 'pageID' => $pager->pageID,
  1968. 'recPerPage' => $pager->recPerPage,
  1969. 'recTotal' => $pager->recTotal,
  1970. ),
  1971. );
  1972. return $this->im->sendOutput($output, 'conferenceGetByConditionResponse');
  1973. }
  1974. /**
  1975. * Get a conference of chat, returns a conference object if the conference is open.
  1976. *
  1977. * @deprecated
  1978. * @param string $chatID
  1979. * @param int $userID
  1980. * @param string $version
  1981. * @param string $device
  1982. * @access public
  1983. * @return void
  1984. */
  1985. public function conferenceGetByChat($chatID, $userID = 0, $version = '', $device = 'desktop')
  1986. {
  1987. $chat = $this->im->chatGetByGidForUser($chatID, $userID);
  1988. if(empty($chat)) return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => 'No such chat, or you are not in the chat.'), 'messageResponsePack');
  1989. $output = new stdclass();
  1990. $output->result = 'success';
  1991. $output->method = 'conferencegetbychat';
  1992. $output->users = array($userID);
  1993. $output->data = array();
  1994. $conference = $this->im->conferenceGetByChatID($chatID);
  1995. if(empty($conference)) return $this->im->sendOutput($output, 'conferencegetbychatResponse');
  1996. $conference = $this->im->conference->format($conference);
  1997. $output->data = array($conference);
  1998. return $this->im->sendOutput($output, 'conferencegetbychatResponse');
  1999. }
  2000. /**
  2001. * Create a detached conference.
  2002. * @param string $chatID
  2003. * @param array $invitee
  2004. * @param string $type
  2005. * @param string $topic
  2006. * @param string $password
  2007. * @param string $startTime
  2008. * @param string $endTime
  2009. * @param int $reminderTime (unit minute)
  2010. * @param string $note
  2011. * @param bool $isPrivate
  2012. * @param bool $isInner
  2013. * @param int $userID
  2014. * @param string $version
  2015. * @param string $device
  2016. * @return void
  2017. */
  2018. public function conferenceCreateDetached($chatID = '', $invitee = array(), $type = 'default', $topic = '', $password = '', $startTime = null, $endTime = null, $reminderTime = 0, $note = '', $isPrivate = false, $isInner = true, $userID = 0, $version = '', $device = 'desktop')
  2019. {
  2020. $this->loadModel('conference');
  2021. if(!$this->conference->isEnabled()) return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => $this->lang->im->owtIsDisabled), 'messageResponsePack');
  2022. $inviteeData = empty($invitee) ? '' : implode(',', $invitee);
  2023. $conference = $this->im->conference->createDetached($chatID, $inviteeData, $type, $topic, $password, $startTime, $endTime, $reminderTime, $note, $isPrivate, $isInner, $userID);
  2024. if(empty($conference)) return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => 'Create conference fail.'), 'messageResponsePack');
  2025. if($type === 'scheduled') {
  2026. return $this->conferenceAppointment($conference);
  2027. }
  2028. $privateChatMembers = explode('&', $chatID);
  2029. $isOne2OneChat = count($privateChatMembers) == 2;
  2030. $outputs = array();
  2031. $chat = null;
  2032. if($chatID) $chat = $this->im->chatGetByGidForUser($chatID, $userID);
  2033. if(empty($chat) && $isOne2OneChat)
  2034. {
  2035. $chat = $this->im->chatcreate($chatID, '', 'one2one', $privateChatMembers, 0, false, $userID);
  2036. $chatCreateOutput = new stdclass();
  2037. $chatCreateOutput->result = 'success';
  2038. $chatCreateOutput->method = 'chatcreate';
  2039. $chatCreateOutput->users = $privateChatMembers;
  2040. $chatCreateOutput->data = $chat;
  2041. }
  2042. $this->im->conference->addInvitee($conference->number, $invitee);
  2043. $conference = $this->im->conferenceGetByNumber($conference->number);
  2044. $conference = $this->im->conferenceFormat($conference);
  2045. $conferenceCreateOutput = new stdClass();
  2046. $conferenceCreateOutput->method = 'conferencecreatedetached';
  2047. $conferenceCreateOutput->users = array($userID);
  2048. $conferenceCreateOutput->result = 'success';
  2049. $conferenceCreateOutput->data = $conference;
  2050. $outputs[] = $conferenceCreateOutput;
  2051. if(!empty($invitee))
  2052. {
  2053. $inviteOutput = new stdClass();
  2054. $inviteOutput->method = 'conferenceinvite';
  2055. $inviteOutput->result = 'success';
  2056. $inviteOutput->users = $invitee;
  2057. $inviteOutput->data = $conference;
  2058. $outputs[] = $inviteOutput;
  2059. }
  2060. $inviteMessageContent = new stdClass();
  2061. $inviteMessageContent->type = 'conferenceInvite';
  2062. $inviteMessageContent->conferenceNumber = $conference->number;
  2063. $inviteMessageContent->topic = $conference->topic;
  2064. $inviteMessageContent->conferenceStatus = 'open';
  2065. $user = $this->im->user->getByID($userID);
  2066. $upgradeMessage = new stdclass();
  2067. $upgradeMessage->contentType = 'plain';
  2068. $upgradeMessage->content = sprintf($this->lang->im->jitsiConferenceInviteFailMessage->upgrade, $user->realname);
  2069. $upgradeMessageWithLink = new stdclass();
  2070. $upgradeMessageWithLink->contentType = 'plain';
  2071. $upgradeMessageWithLink->content = $this->lang->im->jitsiConferenceInviteFailMessage->upgradeWithLink . "\n";
  2072. $inviteLink = sprintf($this->lang->im->jitsiConferenceInviteLink->title, $user->realname, $conference->topic) . "\n";
  2073. $domain = $this->loadModel('setting')->getItem("owner=system&module=jitsi&section=common&key=domain");
  2074. $inviteLink = $inviteLink . "{$this->lang->im->jitsiConferenceInviteLink->link}: https://$domain/{$conference->number}";
  2075. // $inviteLink = $inviteLink . "{$this->lang->im->jitsiConferenceInviteLink->password}: $conference->password";
  2076. $upgradeMessageWithLink->content = $upgradeMessageWithLink->content . $inviteLink;
  2077. if(!empty($chat))
  2078. {
  2079. if(!$isPrivate || $isOne2OneChat) $broadcast = $this->im->messageCreateBroadcast('createConference', $chat, $chat->members, $userID, $invitee, true);
  2080. $inviteeInsideChat = $this->im->chatFilterUsers($chat->gid, $invitee);
  2081. $inviteeOutsideChat = array_diff($invitee, $inviteeInsideChat);
  2082. foreach ($inviteeInsideChat as $uid) {
  2083. $uid = (int)$uid;
  2084. if (!$this->im->user->isDeviceVersionGe($uid, '9.0') && !$this->im->user->isDeviceVersionGe($uid, '6.1.0', 'mobile'))
  2085. {
  2086. if ($conference->isInner === '0')
  2087. {
  2088. $outputs [] = $this->im->message->createXuanBotMessage($uid, $upgradeMessageWithLink->content, $upgradeMessageWithLink->contentType);
  2089. }
  2090. else
  2091. {
  2092. $outputs [] = $this->im->message->createXuanBotMessage($uid, $upgradeMessage->content, $upgradeMessage->contentType);
  2093. }
  2094. }
  2095. }
  2096. foreach ($inviteeOutsideChat as $uid) {
  2097. $uid = (int)$uid;
  2098. if ($this->im->user->isDeviceVersionGe($uid, '9.0') || $this->im->user->isDeviceVersionGe($uid, '6.1.0', 'mobile'))
  2099. {
  2100. $outputs [] = $this->im->message->createConferenceMessage($inviteMessageContent, $uid);
  2101. }
  2102. else
  2103. {
  2104. if ($conference->isInner === '0')
  2105. {
  2106. $outputs [] = $this->im->message->createXuanBotMessage($uid, $upgradeMessageWithLink->content, $upgradeMessageWithLink->contentType);
  2107. }
  2108. else
  2109. {
  2110. $outputs [] = $this->im->message->createXuanBotMessage($uid, $upgradeMessage->content, $upgradeMessage->contentType);
  2111. }
  2112. }
  2113. }
  2114. $output = new stdClass();
  2115. $output->method = 'chatConferenceStatusChange';
  2116. $output->users = $chat->members;
  2117. $output->result = 'success';
  2118. $output->data = array('number' => $conference->number, 'cgid' => $conference->cgid);
  2119. $outputs[] = $output;
  2120. }
  2121. else
  2122. {
  2123. foreach ($invitee as $uid) {
  2124. $uid = (int)$uid;
  2125. if ($this->im->user->isDeviceVersionGe($uid, '9.0') || $this->im->user->isDeviceVersionGe($uid, '6.1.0', 'mobile'))
  2126. {
  2127. $outputs [] = $this->im->message->createConferenceMessage($inviteMessageContent, $uid);
  2128. }
  2129. else
  2130. {
  2131. if ($conference->isInner === '0')
  2132. {
  2133. $outputs [] = $this->im->message->createXuanBotMessage($uid, $upgradeMessageWithLink->content, $upgradeMessageWithLink->contentType);
  2134. }
  2135. else
  2136. {
  2137. $outputs [] = $this->im->message->createXuanBotMessage($uid, $upgradeMessage->content, $upgradeMessage->contentType);
  2138. }
  2139. }
  2140. }
  2141. }
  2142. if(!empty($broadcast))
  2143. {
  2144. $outputs[] = $broadcast;
  2145. }
  2146. if(isset($chatCreateOutput)) array_unshift($outputs, $chatCreateOutput);
  2147. return $this->im->sendOutputGroup($outputs);
  2148. }
  2149. /**
  2150. * process conference appointment.
  2151. * @param $conference
  2152. * @return void
  2153. */
  2154. public function conferenceAppointment($conference)
  2155. {
  2156. $receivers = explode(',', $conference->invitee);
  2157. $receivers = array_filter($receivers);
  2158. $outputs = array();
  2159. $title = $this->lang->im->conferenceAppointment->firstNotifyTitle;
  2160. $inviteMessageContent = new stdClass();
  2161. $inviteMessageContent->type = 'conferenceInvite';
  2162. $inviteMessageContent->conferenceNumber = $conference->number;
  2163. $inviteMessageContent->title = $title;
  2164. $inviteMessageContent->topic = $conference->topic;
  2165. foreach($receivers as $uid)
  2166. {
  2167. $outputs[] = $this->im->message->createConferenceMessage($inviteMessageContent, (int)$uid);
  2168. }
  2169. // 如果没有提醒则默认为发送过了提醒。预约会议进入 2 阶段。
  2170. $this->im->conferenceUpdateSentNotifyTimes($conference, $conference->reminderTime ? 1 : 2);
  2171. $conference = $this->im->conferenceGetByNumber($conference->number);
  2172. $conference = $this->im->conferenceFormat($conference);
  2173. $output = new stdClass();
  2174. $output->method = 'conferencecreatedetached';
  2175. $output->users = array((int)$conference->openedBy);
  2176. $output->result = 'success';
  2177. $output->data = $conference;
  2178. $outputs[] = $output;
  2179. return $this->im->sendOutputGroup($outputs);
  2180. }
  2181. /**
  2182. * send notify to scheduled conference invitee.
  2183. * @param $conference
  2184. * @return array
  2185. */
  2186. public function conferenceSendScheduledNotify($conference)
  2187. {
  2188. $outputs = array();
  2189. if (!$conference->reminderTime) return $outputs;
  2190. if (strtotime($conference->startTime) - strtotime(helper::now()) > $conference->reminderTime * 60) return $outputs;
  2191. if (empty($conference->invitee)) return $outputs;
  2192. $receivers = explode(',', $conference->invitee);
  2193. $receivers = array_filter($receivers);
  2194. $title = $this->lang->im->conferenceAppointment->reminderNotifyTitle;
  2195. $inviteMessageContent = new stdClass();
  2196. $inviteMessageContent->type = 'conferenceInvite';
  2197. $inviteMessageContent->conferenceNumber = $conference->number;
  2198. $inviteMessageContent->title = $title;
  2199. $inviteMessageContent->topic = $conference->topic;
  2200. foreach($receivers as $uid)
  2201. {
  2202. $outputs[] = $this->im->message->createConferenceMessage($inviteMessageContent, (int)$uid);
  2203. }
  2204. $this->im->conferenceUpdateSentNotifyTimes($conference, 2);
  2205. return $outputs;
  2206. }
  2207. /**
  2208. * start a schedule conference.
  2209. * @param $conference
  2210. * @return array
  2211. */
  2212. public function conferenceStartScheduled($conference)
  2213. {
  2214. // TODO: 为了防止掉入下一个轮询,这里提前 20 秒发送开始通知。修改轮询机制后,这里可以去掉。
  2215. if (strtotime($conference->startTime) - strtotime(helper::now()) > 20) return array();
  2216. $conference = $this->im->conferenceStartSchedule($conference);
  2217. $receivers = explode(',', $conference->invitee);
  2218. if(!$receivers) $receivers = array($conference->openedBy);
  2219. $receivers = array_filter($receivers, 'is_numeric');
  2220. $receivers = array_map('intval', $receivers);
  2221. $outputs = array();
  2222. $title = $this->lang->im->conferenceAppointment->startNotifyTitle;
  2223. $inviteMessageContent = new stdClass();
  2224. $inviteMessageContent->type = 'conferenceInvite';
  2225. $inviteMessageContent->conferenceNumber = $conference->number;
  2226. $inviteMessageContent->title = $title;
  2227. $inviteMessageContent->topic = $conference->topic;
  2228. $inviteMessageContent->conferenceStatus = 'open';
  2229. foreach($receivers as $uid)
  2230. {
  2231. $outputs[] = $this->im->message->createConferenceMessage($inviteMessageContent, (int)$uid);
  2232. }
  2233. $this->im->conferenceUpdateSentNotifyTimes($conference, 3);
  2234. $this->im->conference->addInvitee($conference->number, $receivers);
  2235. $conference = $this->im->conferenceGetByNumber($conference->number);
  2236. $conference = $this->im->conferenceFormat($conference);
  2237. $inviteOutput = new stdClass();
  2238. $inviteOutput->method = 'conferenceinvite';
  2239. $inviteOutput->result = 'success';
  2240. $inviteOutput->users = $receivers;
  2241. $inviteOutput->data = $conference;
  2242. $outputs[] = $inviteOutput;
  2243. return $outputs;
  2244. }
  2245. /**
  2246. * Invite members to join a conference.
  2247. *
  2248. * @param string $conferenceNumber
  2249. * @param int $userID
  2250. * @access public
  2251. * @return void
  2252. */
  2253. public function conferenceInvite($conferenceNumber, $newInvitee = array(), $userID = 0, $version = '', $device = 'desktop') {
  2254. $this->loadModel('conference');
  2255. if(!$this->conference->isEnabled()) return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => $this->lang->im->owtIsDisabled), 'messageResponsePack');
  2256. $conference = $this->im->conference->getByNumber($conferenceNumber);
  2257. if(empty($conference)) return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => 'No such conference.'), 'messageResponsePack');
  2258. if(!empty($conference->cgid)) $chat = $this->im->chatGetByGidForUser($conference->cgid, $userID);
  2259. $invitee = $this->im->conference->addInvitee($conferenceNumber, $newInvitee);
  2260. if(empty($invitee)) return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => 'Invitation failed.', 'data' => array('conferenceNumber' => $conferenceNumber)), 'messageResponsePack');
  2261. $conference->invitee = $invitee;
  2262. $conference = $this->im->conferenceFormat($conference);
  2263. $outputs = array();
  2264. $output = new stdClass();
  2265. $output->method = 'conferenceinvite';
  2266. $output->result = 'success';
  2267. $output->users = $newInvitee;
  2268. $output->data = $conference;
  2269. $outputs[] = $output;
  2270. $inviteMessageContent = new stdClass();
  2271. $inviteMessageContent->type = 'conferenceInvite';
  2272. $inviteMessageContent->conferenceNumber = $conference->number;
  2273. $inviteMessageContent->topic = $conference->topic;
  2274. $user = $this->im->user->getByID($userID);
  2275. $upgradeMessage = new stdClass();
  2276. $upgradeMessage->contentType = 'plain';
  2277. $upgradeMessage->content = sprintf($this->lang->im->jitsiConferenceInviteFailMessage->upgrade, $user->realname);
  2278. $upgradeMessageWithLink = new stdClass();
  2279. $upgradeMessageWithLink->contentType = 'plain';
  2280. $upgradeMessageWithLink->content = $this->lang->im->jitsiConferenceInviteFailMessage->upgradeWithLink . "\n";
  2281. $inviteLink = sprintf($this->lang->im->jitsiConferenceInviteLink->title, $user->realname, $conference->topic) . "\n";
  2282. $domain = $this->loadModel('setting')->getItem("owner=system&module=jitsi&section=common&key=domain");
  2283. $inviteLink = $inviteLink . "{$this->lang->im->jitsiConferenceInviteLink->link}: https://$domain/{$conference->number}";
  2284. // $inviteLink = $inviteLink . "{$this->lang->im->jitsiConferenceInviteLink->password}: $conference->password";
  2285. $upgradeMessageWithLink->content = $upgradeMessageWithLink->content . $inviteLink;
  2286. $broadcasts = array();
  2287. if(!empty($chat))
  2288. {
  2289. $privateChatMembers = explode('&', $chat->gid);
  2290. $isOne2OneChat = count($privateChatMembers) == 2;
  2291. if($conference->isPrivate === '0' && !$isOne2OneChat) $broadcasts[] = $this->im->messageCreateBroadcast('createConferenceInvitation', $chat, $chat->members, $userID, $newInvitee, true);
  2292. $inviteeInsideChat = $this->im->chatFilterUsers($chat->gid, $newInvitee);
  2293. $inviteeOutsideChat = array_diff($newInvitee, $inviteeInsideChat);
  2294. foreach ($inviteeInsideChat as $uid) {
  2295. $uid = (int)$uid;
  2296. if (!$this->im->user->isDeviceVersionGe($uid, '9.0') && !$this->im->user->isDeviceVersionGe($uid, '6.1.0', 'mobile'))
  2297. {
  2298. if ($conference->isInner === '0')
  2299. {
  2300. $outputs [] = $this->im->message->createXuanBotMessage($uid, $upgradeMessageWithLink->content, $upgradeMessageWithLink->contentType);
  2301. }
  2302. else
  2303. {
  2304. $outputs [] = $this->im->message->createXuanBotMessage($uid, $upgradeMessage->content, $upgradeMessage->contentType);
  2305. }
  2306. }
  2307. }
  2308. foreach ($inviteeOutsideChat as $uid) {
  2309. $uid = (int)$uid;
  2310. if ($this->im->user->isDeviceVersionGe($uid, '9.0') || $this->im->user->isDeviceVersionGe($uid, '6.1.0', 'mobile'))
  2311. {
  2312. $outputs [] = $this->im->message->createConferenceMessage($inviteMessageContent, $uid);
  2313. }
  2314. else
  2315. {
  2316. if ($conference->isInner === '0')
  2317. {
  2318. $outputs [] = $this->im->message->createXuanBotMessage($uid, $upgradeMessageWithLink->content, $upgradeMessageWithLink->contentType);
  2319. }
  2320. else
  2321. {
  2322. $outputs [] = $this->im->message->createXuanBotMessage($uid, $upgradeMessage->content, $upgradeMessage->contentType);
  2323. }
  2324. }
  2325. }
  2326. }
  2327. else
  2328. {
  2329. foreach ($newInvitee as $uid) {
  2330. $uid = (int)$uid;
  2331. if ($this->im->user->isDeviceVersionGe($uid, '9.0') || $this->im->user->isDeviceVersionGe($uid, '6.1.0', 'mobile'))
  2332. {
  2333. $outputs [] = $this->im->message->createConferenceMessage($inviteMessageContent, $uid);
  2334. }
  2335. else
  2336. {
  2337. if ($conference->isInner === '0')
  2338. {
  2339. $outputs [] = $this->im->message->createXuanBotMessage($uid, $upgradeMessageWithLink->content, $upgradeMessageWithLink->contentType);
  2340. }
  2341. else
  2342. {
  2343. $outputs [] = $this->im->message->createXuanBotMessage($uid, $upgradeMessage->content, $upgradeMessage->contentType);
  2344. }
  2345. }
  2346. }
  2347. }
  2348. $outputs = array_merge($outputs, $broadcasts);
  2349. return $this->im->sendOutputGroup($outputs);
  2350. }
  2351. /**
  2352. * Reject a conference invitation.
  2353. *
  2354. * @param string $conferenceNumber
  2355. * @access public
  2356. * @return void
  2357. */
  2358. public function conferenceReject($conferenceNumber, $userID = 0, $version = '', $device = 'desktop')
  2359. {
  2360. $conference = $this->im->conference->getByNumber($conferenceNumber);
  2361. if(empty($conference)) return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => 'No such conference.'), 'messageResponsePack');
  2362. $this->im->conference->rejectInvite($conference->id, $userID);
  2363. $isOneInvitee = count(array_filter(explode(',', $conference->invitee))) === 1;
  2364. $users = $isOneInvitee
  2365. ? array($userID, (int)$conference->openedBy)
  2366. : array($userID);
  2367. $output = new stdClass();
  2368. $output->method = 'conferencereject';
  2369. $output->result ='success';
  2370. $output->users = $users;
  2371. $output->data = array('cgid' => $conference->cgid, 'number' => $conference->number, 'user' => $userID, 'timestamp' => round(microtime(true)));
  2372. return $this->im->sendOutput($output, 'conferencerejectResponse');
  2373. }
  2374. /**
  2375. * Join a conference in a chat.
  2376. *
  2377. * @param string $conferenceNumber
  2378. * @param int $userID
  2379. * @access public
  2380. * @return void
  2381. */
  2382. public function conferenceJoin($conferenceNumber, $userID, $version = '', $device = 'desktop')
  2383. {
  2384. $this->loadModel('conference');
  2385. if(!$this->conference->isEnabled()) return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => $this->lang->im->owtIsDisabled), 'messageResponsePack');
  2386. $conference = $this->im->conference->getByNumber($conferenceNumber);
  2387. if(empty($conference)) return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => 'No such conference.'), 'messageResponsePack');
  2388. $this->im->conference->addSubscriber($conferenceNumber, $userID);
  2389. $this->im->conference->addParticipant($conferenceNumber, $userID);
  2390. $this->im->conference->acceptInvite($conference->id, $userID);
  2391. $conference = $this->im->conferenceFormat($conference);
  2392. return $this->im->sendOutput(array('result' => 'success', 'users' => array($userID), 'data' => $conference), 'conferencejoinResponse');
  2393. }
  2394. /**
  2395. * Leave a conference in a chat.
  2396. *
  2397. * @param string $conferenceNumber
  2398. * @param int $userID
  2399. * @access public
  2400. * @return void
  2401. */
  2402. public function conferenceLeave($conferenceNumber, $userID, $version = '', $device = 'desktop')
  2403. {
  2404. $conference = $this->im->conference->getByNumber($conferenceNumber);
  2405. if(empty($conference)) return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => 'No such conference.'), 'messageResponsePack');
  2406. $participants = $this->im->conference->removeParticipant($conferenceNumber, $userID);
  2407. if(empty($participants) && $conference->status === 'open')
  2408. {
  2409. $this->conferenceClose($conferenceNumber, $userID, $version, $device);
  2410. return;
  2411. }
  2412. $statusChangeOutput = new stdClass();
  2413. $statusChangeOutput->method = 'conferenceLeave';
  2414. $statusChangeOutput->users = array($userID);
  2415. $statusChangeOutput->result = 'success';
  2416. $statusChangeOutput->data = array('number' => $conferenceNumber, 'cgid' => $conference->cgid);
  2417. $this->im->sendOutput($statusChangeOutput, 'conferenceleaveResponse');
  2418. }
  2419. /**
  2420. * Close a conference in a chat.
  2421. *
  2422. * @param string $conferenceNumber
  2423. * @param int $userID
  2424. * @access public
  2425. * @return void
  2426. */
  2427. public function conferenceClose($conferenceNumber, $userID, $version = '', $device = 'desktop')
  2428. {
  2429. $conference = $this->im->conference->getByNumber($conferenceNumber);
  2430. $result = $this->im->conference->close($conference->id);
  2431. if(!$result) return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID,'message' => 'Close conference failed.'),'messageResponsePack');
  2432. $outputs = array();
  2433. if(!empty($conference->cgid))
  2434. {
  2435. $chat = $this->im->chatGetByGidForUser($conference->cgid, $userID);
  2436. $chatMembers = $this->im->chat->getMembers($conference->cgid);
  2437. // conference status change event for xxc chat header button.
  2438. $statusChangeOutput = new stdClass();
  2439. $statusChangeOutput->method = 'chatConferenceStatusChange';
  2440. $statusChangeOutput->users = $chatMembers;
  2441. $statusChangeOutput->result = 'success';
  2442. $statusChangeOutput->data = array('number' => $conferenceNumber, 'cgid' => $conference->cgid);
  2443. $outputs[] = $statusChangeOutput;
  2444. $subscribers = explode(',', $conference->subscribers);
  2445. $subscribers = array_filter($subscribers);
  2446. if ($conference->isPrivate === '0') $outputs[] = $this->im->message->createBroadcast('closeConference', $chat, $chat->members, $userID, $subscribers, true);
  2447. }
  2448. $users = explode(',', $conference->participants . $conference->subscribers . $conference->invitee);
  2449. $users = array_filter($users);
  2450. $users = array_values($users);
  2451. $users = array_map(function($v){
  2452. return (int)$v;
  2453. }, $users);
  2454. // send close event for disabling the invitation.
  2455. $conferenceCloseOutput = new stdClass();
  2456. $conferenceCloseOutput->method = 'conferenceclose';
  2457. $conferenceCloseOutput->users = $users;
  2458. $conferenceCloseOutput->result ='success';
  2459. $conferenceCloseOutput->data = array('number' => $conferenceNumber, 'cgid' => $conference->cgid, 'user' => $userID);
  2460. $outputs[] = $conferenceCloseOutput;
  2461. $this->im->sendOutputGroup($outputs);
  2462. }
  2463. /**
  2464. * Hide a conference for a user.
  2465. *
  2466. * @param string $conferenceNumber
  2467. * @access public
  2468. * @return void
  2469. */
  2470. public function conferenceHide($conferenceNumber, $userID)
  2471. {
  2472. $conference = $this->im->conference->getByNumber($conferenceNumber);
  2473. if(empty($conference)) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'No such conference.'));
  2474. $this->im->conferenceHide($conferenceNumber, $userID);
  2475. $output = new stdClass();
  2476. $output->method = 'conferencehide';
  2477. $output->users = array($userID);
  2478. $output->result = 'success';
  2479. $output->data = array('number' => $conferenceNumber, 'cgid' => $conference->cgid);
  2480. $this->im->sendOutput($output, 'conferencehideResponse');
  2481. }
  2482. /**
  2483. * Cancel a scheduled conference.
  2484. *
  2485. * @param string $conferenceNumber
  2486. * @param string $userID
  2487. * @param string $version
  2488. * @param string $device
  2489. * @access public
  2490. * @return void
  2491. */
  2492. public function conferenceCancelScheduled($conferenceNumber, $userID, $version = '', $device = 'desktop')
  2493. {
  2494. $conference = $this->im->conference->getByNumber($conferenceNumber);
  2495. if ($conference->type != 'scheduled' || $conference->status != 'notStarted' || $conference->openedBy != $userID) return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => 'Could not cancel the conference.', 'data' => array('number' => $conferenceNumber)));
  2496. $invitee = explode(',', $conference->invitee);
  2497. $invitee = array_filter($invitee);
  2498. $participants = explode(',', $conference->participants);
  2499. $participants = array_filter($participants);
  2500. $receiver = array_unique(array_merge($invitee, $participants));
  2501. $this->im->conference->cancel($conference->id);
  2502. $sender = $this->im->botCreateDefaultBotSender($this->lang->im->conference->botName);
  2503. if(empty($conference->endTime) || $conference->endTime == null)
  2504. {
  2505. $this->im->messageCreateNotify($receiver, $this->lang->im->conferenceCancel->title, '', sprintf($this->lang->im->conferenceCancel->noEndTimeBody, strftime('%Y-%m-%d %H:%M', strtotime($conference->startTime)), $conference->topic), 'text', '', array(), $sender);
  2506. }
  2507. else
  2508. {
  2509. $dateTimeDuration = strftime('%Y-%m-%d %H:%M', strtotime($conference->startTime)) . ' - ' . strftime('%H:%M', strtotime($conference->endTime));
  2510. $this->im->messageCreateNotify($receiver, $this->lang->im->conferenceCancel->title, '', sprintf($this->lang->im->conferenceCancel->hasEndTimeBody, $dateTimeDuration, $conference->topic), 'text', '', array(), $sender);
  2511. }
  2512. $conference = $this->im->conference->format($conference);
  2513. $output = new stdClass();
  2514. $output->method = 'conferencecancel';
  2515. $output->users = $receiver;
  2516. $output->result = 'success';
  2517. $output->data = $conference;
  2518. $this->im->sendOutput($output, 'conferencecancelResponse');
  2519. }
  2520. /**
  2521. * Edit a detached conference.
  2522. *
  2523. * @param string $number
  2524. * @param string $chatID
  2525. * @param array $invitee
  2526. * @param string $type
  2527. * @param string $topic
  2528. * @param string $password
  2529. * @param string $startTime
  2530. * @param string $endTime
  2531. * @param int $reminderTime (unit minute)
  2532. * @param string $note
  2533. * @param bool $isInner
  2534. * @param int $userID
  2535. * @param string $version
  2536. * @param string $device
  2537. * @return void
  2538. */
  2539. public function conferenceEdit($number, $chatID = '', $invitee = array(), $type = 'default', $topic = '', $password = '', $startTime = null, $endTime = null, $reminderTime = 0, $note = '', $isInner = true, $userID = 0, $version = '', $device = 'desktop')
  2540. {
  2541. $conference = $this->im->conference->getByNumber($number);
  2542. if(empty($conference)) return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => 'No such conference.'), 'messageResponsePack');
  2543. if($conference->status != 'notStarted') return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => $this->lang->im->conferenceEditFail), 'messageResponsePack');
  2544. $originInvitee = explode(',', $conference->invitee);
  2545. $originInvitee = array_filter($originInvitee);
  2546. $needNotify = false;
  2547. if($chatID !== $conference->cgid
  2548. || $type !== $conference->type
  2549. || $topic !== $conference->topic
  2550. || $startTime !== $conference->startTime
  2551. || $endTime !== $conference->endTime
  2552. || $note !== $conference->note
  2553. || $isInner !== ($conference->isInner === '1')
  2554. ) {
  2555. $needNotify = true;
  2556. }
  2557. $needResetNotify = false;
  2558. if ($reminderTime != $conference->reminderTime) {
  2559. $needResetNotify = true;
  2560. }
  2561. $conference->cgid = $chatID;
  2562. $conference->invitee = empty($invitee) ? '' : ',' . implode(',', $invitee) . ',';
  2563. $conference->type = $type;
  2564. $conference->topic = $topic;
  2565. $conference->startTime = $startTime;
  2566. $conference->endTime = $endTime;
  2567. $conference->reminderTime = $reminderTime;
  2568. $conference->note = $note;
  2569. $conference->isInner = $isInner === true ? '1' : '0';;
  2570. $result = $this->im->conferenceUpdate($conference);
  2571. if($needResetNotify)
  2572. {
  2573. $this->im->conferenceUpdateSentNotifyTimes($conference, $conference->reminderTime ? 1 : 2);
  2574. }
  2575. if (!$result) return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => $this->lang->im->conferenceEditFail), 'messageResponsePack');
  2576. $oldInvitee = array_intersect($originInvitee, $invitee);
  2577. $newInvitee = array_diff($invitee, $oldInvitee);
  2578. $removedInvitee = array_diff($originInvitee, $oldInvitee);
  2579. $outputs = array();
  2580. if($needNotify)
  2581. {
  2582. $inviteMessageContent = new stdClass();
  2583. $inviteMessageContent->type = 'conferenceInvite';
  2584. $inviteMessageContent->conferenceNumber = $conference->number;
  2585. $inviteMessageContent->title = $this->lang->im->conferenceEdit->title;
  2586. $inviteMessageContent->topic = $conference->topic;
  2587. foreach ($oldInvitee as $uid) {
  2588. $outputs [] = $this->im->message->createConferenceMessage($inviteMessageContent, (int)$uid);
  2589. }
  2590. }
  2591. if(!empty($newInvitee))
  2592. {
  2593. $inviteMessageContent = new stdClass();
  2594. $inviteMessageContent->type = 'conferenceInvite';
  2595. $inviteMessageContent->conferenceNumber = $conference->number;
  2596. $inviteMessageContent->topic = $conference->topic;
  2597. foreach ($newInvitee as $uid) {
  2598. $outputs [] = $this->im->message->createConferenceMessage($inviteMessageContent, (int)$uid);
  2599. }
  2600. }
  2601. if(!empty($removedInvitee))
  2602. {
  2603. $sender = $this->im->botCreateDefaultBotSender($this->lang->im->conference->botName);
  2604. $this->im->messageCreateNotify($removedInvitee, $this->lang->im->conferenceEdit->title, '', sprintf($this->lang->im->conferenceEdit->memberChange, strftime('%Y-%m-%d %H:%M', strtotime($conference->startTime)), $conference->topic), 'text', '', array(), $sender);
  2605. }
  2606. $conference = $this->im->conference->format($conference);
  2607. $output = new stdclass();
  2608. $output->result = 'success';
  2609. $output->data = array($conference);
  2610. $output->method = 'syncconferences';
  2611. $output->users = $invitee;
  2612. $outputs []= $output;
  2613. $output = new stdclass();
  2614. $output->result = 'success';
  2615. $output->data = array();
  2616. $output->method = 'conferenceedit';
  2617. $output->users = array($userID);
  2618. $outputs []= $output;
  2619. $this->im->sendOutputGroup($outputs);
  2620. }
  2621. /**
  2622. * get the latest open conference by chat.
  2623. *
  2624. * @param string $cgid
  2625. * @param int $userID
  2626. * @return null
  2627. */
  2628. public function conferenceGetLastOpenByChat($cgid, $userID)
  2629. {
  2630. $conference = $this->im->conference->getLatestByChatID($cgid);
  2631. if(empty($conference)) {
  2632. $conference = null;
  2633. } else {
  2634. $conference = $this->im->conference->format($conference);
  2635. }
  2636. $output = new stdclass();
  2637. $output->result = 'success';
  2638. $output->method = 'conferenceGetLastOpenByChat';
  2639. $output->users = array($userID);
  2640. $output->data = $conference;
  2641. return $this->im->sendOutput($output, 'conferenceGetLastOpenByChatResponse');
  2642. }
  2643. /**
  2644. * get a jwt token for jitsi authentication.
  2645. *
  2646. * @param $userID
  2647. * @return null
  2648. */
  2649. public function getConferenceJwt($userID)
  2650. {
  2651. require_once $this->app->getBasePath() . 'lib/jwt/JWT.php';
  2652. $user = $this->im->user->getByid($userID);
  2653. if(!$user) return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => 'No such user.'), 'messageResponsePack');
  2654. $key = $this->im->conference->getJwtSecret();
  2655. if(!$key) return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => 'No jwt secret.'), 'messageResponsePack');
  2656. $payload = [
  2657. "context" => [
  2658. "user" => [
  2659. "avatar" => $user->avatar,
  2660. "name" => $user->realname,
  2661. "email" => $user->id
  2662. ],
  2663. ],
  2664. "aud" => "xxb",
  2665. "iss" => "xbb",
  2666. "sub" => "meet.jitsi",
  2667. "room" => "*",
  2668. "iat" => time(),
  2669. // 默认签发 1 天
  2670. "exp" => time() + 86400
  2671. ];
  2672. $jwt = JWT::encode($payload, $key, 'HS256');
  2673. $output = new stdclass();
  2674. $output->result = 'success';
  2675. $output->data = $jwt;
  2676. $output->users = array($userID);
  2677. return $this->im->sendOutput($output, 'getConferenceJwtResponse');
  2678. }
  2679. /**
  2680. * Get extensions.
  2681. *
  2682. * @param int $userID
  2683. * @access public
  2684. * @return void
  2685. */
  2686. public function extensionGetList($userID = 0)
  2687. {
  2688. $output = new stdclass();
  2689. $output->result = 'success';
  2690. $output->data = $this->im->getExtensionList($userID);
  2691. $output->users = array($userID);
  2692. return $this->im->sendOutput($output, 'extensiongetlistResponse');
  2693. }
  2694. /**
  2695. * general polling method.
  2696. * @return void
  2697. */
  2698. public function generalPoll() {
  2699. $outputs = array();
  2700. $conferences = $this->im->conferenceGetNotStartedSchedule();
  2701. foreach($conferences as $conference)
  2702. {
  2703. $outputs = array_merge($outputs, $this->conferenceSendScheduledNotify($conference));
  2704. }
  2705. $conferences = $this->im->conferenceGetWillStartSchedule();
  2706. foreach($conferences as $conference)
  2707. {
  2708. $outputs = array_merge($outputs, $this->conferenceStartScheduled($conference));
  2709. }
  2710. $outputs = array_filter($outputs);
  2711. return $this->im->sendOutputGroup($outputs);
  2712. }
  2713. /**
  2714. * Grant moderator.
  2715. * @param string $conferenceNumber
  2716. * @param int $moderatorId
  2717. * @param int $userID
  2718. * @param string $version
  2719. * @param int $device
  2720. * @access public
  2721. * @return void
  2722. */
  2723. public function conferenceGrantModerator($conferenceNumber, $moderatorId, $userID, $version = '', $device = 'desktop')
  2724. {
  2725. $result = $this->im->conferenceAddModerator($conferenceNumber, $moderatorId);
  2726. if(!$result) return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => 'Grant moderator fail.'), 'messageResponsePack');
  2727. $conference = $this->im->conference->getByNumber($conferenceNumber);
  2728. $conference = $this->im->conference->format($conference);
  2729. $output = new stdclass();
  2730. $output->result = 'success';
  2731. $output->method = 'conferencegrantmoderator';
  2732. $output->users = array_filter(explode(',', $conference->participants));
  2733. $output->data = $conference;
  2734. return $this->im->sendOutput($output, 'conferenceGrantModeratorResponse');
  2735. }
  2736. /**
  2737. * Get latest notification and offline user.
  2738. * @param array $offline
  2739. * @param array $sendfail
  2740. * @access public
  2741. * @return void
  2742. */
  2743. public function syncNotifications($offline = array(), $sendfail = array())
  2744. {
  2745. if(!empty($offline)) $this->im->userSetOffline($offline);
  2746. if(!empty($sendfail)) $this->im->messageSendFailures($sendfail);
  2747. /* Push notifications to mobile clients. */
  2748. $output = new stdClass();
  2749. if(dao::isError())
  2750. {
  2751. $output->result = 'fail';
  2752. $output->message = 'Get notify fail.';
  2753. }
  2754. else
  2755. {
  2756. ini_set('memory_limit', '1024M'); // Set memory limit to avoid OOMs.
  2757. $output->result = 'success';
  2758. $output->data = $this->im->messageGetNotifyList();
  2759. }
  2760. return $this->app->output($this->app->encrypt($output));
  2761. }
  2762. /**
  2763. * get notifications initiative by client.
  2764. * @param $userID
  2765. * @param $version
  2766. * @param $device
  2767. * @return void
  2768. */
  2769. public function getNotification($userID, $version = '', $device = 'desktop')
  2770. {
  2771. $notifications = $this->im->message->getNotifyByUserID($userID);
  2772. $output = new stdclass();
  2773. $output->result = 'success';
  2774. $output->data = $notifications;
  2775. $output->method = 'syncnotifications';
  2776. $output->users = array($userID);
  2777. $this->im->sendOutput($output, 'syncnotificationsResponse');
  2778. }
  2779. /**
  2780. * Check user change, and update their pinyin of realname.
  2781. *
  2782. * @access public
  2783. * @return void
  2784. */
  2785. public function syncUsers()
  2786. {
  2787. $this->im->updateLastPoll();
  2788. $changedUsers = $this->im->userHasChanges();
  2789. if(!empty($changedUsers))
  2790. {
  2791. $this->im->userReindexPinyin($changedUsers);
  2792. $changedUsers = $this->im->userGetList('', $changedUsers, false);
  2793. }
  2794. $output = new stdClass();
  2795. $output->result = 'success';
  2796. $output->data = empty($changedUsers) ? array() : $changedUsers;
  2797. return $this->app->output($this->app->encrypt($output));
  2798. }
  2799. /**
  2800. * Check for dept changes, and provide sysgetdepts output if needed.
  2801. *
  2802. * @access public
  2803. * @return void
  2804. */
  2805. public function syncDepts()
  2806. {
  2807. $deptChanges = $this->im->userHasChanges('dept');
  2808. if(empty($deptChanges)) return $this->app->output($this->app->encrypt(array('result' => 'success', 'data' => '')));
  2809. $getDeptsOutput = $this->fetch('im', 'sysGetDepts', array(0));
  2810. $getDeptsOutput = explode("\n", $getDeptsOutput);
  2811. $getDeptsOutput = $getDeptsOutput[count($getDeptsOutput) - 1];
  2812. $getDeptsOutput = addslashes($getDeptsOutput); // Otherwise Go might not be able to parse such JSON.
  2813. return $this->app->output($this->app->encrypt(array('result' => 'success', 'data' => $getDeptsOutput)));
  2814. }
  2815. /**
  2816. * Get config settings for XXD.
  2817. *
  2818. * @access public
  2819. * @return void
  2820. */
  2821. public function syncConfig()
  2822. {
  2823. $output = new stdclass();
  2824. $output->module = 'im';
  2825. $output->method = 'syncConfig';
  2826. $output->result = 'success';
  2827. $output->data = new stdclass();
  2828. $output->data->ip = $this->config->xuanxuan->ip;
  2829. $output->data->chatPort = $this->config->xuanxuan->chatPort;
  2830. $output->data->commonPort = $this->config->xuanxuan->commonPort;
  2831. $output->data->https = $this->config->xuanxuan->https;
  2832. $output->data->pollingInterval = $this->config->xuanxuan->pollingInterval;
  2833. $output->data->uploadFileSize = $this->config->xuanxuan->uploadFileSize;
  2834. if(isset($this->config->xuanxuan->fileEncryptionKey)) $output->data->fileKey = $this->config->xuanxuan->fileEncryptionKey;
  2835. return $this->app->output($this->app->encrypt($output));
  2836. }
  2837. /**
  2838. * Upload file.
  2839. *
  2840. * @param string $fileName
  2841. * @param string $path
  2842. * @param int $size
  2843. * @param int $time
  2844. * @param string $gid
  2845. * @param int $userID
  2846. * @access public
  2847. * @return void
  2848. */
  2849. public function fileUpload($fileName = '', $path = '', $size = 0, $time = 0, $gid = '', $userID = 0)
  2850. {
  2851. $chat = $this->im->chat->getByGid($gid, true);
  2852. if(!$chat)
  2853. {
  2854. $one2oneMembers = explode('&', $gid);
  2855. if(count($one2oneMembers) !== 2) return $this->app->output($this->app->encrypt(array('result' => 'fail', 'message' => $this->lang->im->notExist)));
  2856. $chat = (object)array('id' => 0, 'members' => array($userID));
  2857. }
  2858. $users = $this->im->userGetList($status = 'online', $chat->members);
  2859. $fileID = $this->im->uploadFile($fileName, $path, $size, $time, $userID, $users, $chat);
  2860. if(dao::isError()) return $this->app->output($this->app->encrypt(array('result' => 'fail', 'message' => 'Upload file fail.')));
  2861. $output = new stdclass();
  2862. $output->result = 'success';
  2863. $output->users = array_keys($users);
  2864. $output->data = "$fileID";
  2865. return $this->app->output($this->app->encrypt($output));
  2866. }
  2867. /**
  2868. * Create, edit or delte todo
  2869. * @param object $todo
  2870. * @param int $userID
  2871. * @access public
  2872. * @return void
  2873. */
  2874. public function todoUpsert($todo, $userID = 0)
  2875. {
  2876. $user = $this->im->userGetByID($userID);
  2877. $this->app->user = $user;
  2878. if(is_object($todo))
  2879. {
  2880. if(isset($todo->id))
  2881. {
  2882. if($todo->delete)
  2883. {
  2884. $todo = $this->loadModel('todo')->getById($todo->id);
  2885. if($todo->account != $user->account)
  2886. {
  2887. return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => 'Cannot delete todo item witch not yours.', 'data' => $todo), 'messageResponsePack');
  2888. }
  2889. else
  2890. {
  2891. $this->dao->delete()->from(TABLE_TODO)->where('id')->eq($todo->id)->exec();
  2892. if(dao::isError())
  2893. {
  2894. return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => dao::getError()), 'messageResponsePack');
  2895. }
  2896. else
  2897. {
  2898. $this->loadModel('action')->create('todo', $todo->id, 'deleted', 'success', '', '', $user->account);
  2899. $output = new stdClass();
  2900. $output->result = 'success';
  2901. $output->users = array($userID);
  2902. $output->data = $todo;
  2903. return $this->im->sendOutput($output, 'todoupsertResponse');
  2904. }
  2905. }
  2906. }
  2907. else
  2908. {
  2909. $_POST = (array)$todo;
  2910. $changes = $this->loadModel('todo')->update($todo->id);
  2911. if(dao::isError())
  2912. {
  2913. return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => dao::getError()), 'messageResponsePack');
  2914. }
  2915. else
  2916. {
  2917. $actionID = $this->loadModel('action')->create('todo', $todo->id, 'edit', 'success', '', '', $user->account);
  2918. $this->action->logHistory($actionID, $changes);
  2919. $output = new stdClass();
  2920. $output->result = 'success';
  2921. $output->users = array($userID);
  2922. $output->data = $todo;
  2923. return $this->im->sendOutput($output, 'todoupsertResponse');
  2924. }
  2925. }
  2926. }
  2927. else
  2928. {
  2929. $_POST = (array)$todo;
  2930. $todoID = $this->loadModel('todo')->create();
  2931. if(dao::isError())
  2932. {
  2933. return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => dao::getError()), 'messageResponsePack');
  2934. }
  2935. else
  2936. {
  2937. $this->loadModel('action')->create('todo', $todoID, 'created', 'success', '', '', $user->account);
  2938. $todo->id = $todoID;
  2939. $output = new stdClass();
  2940. $output->result = 'success';
  2941. $output->users = array($userID);
  2942. $output->data = $todo;
  2943. return $this->im->sendOutput($output, 'todoupsertResponse');
  2944. }
  2945. }
  2946. }
  2947. else
  2948. {
  2949. return $this->im->sendOutput(array('result' => 'fail', 'users' => $userID, 'message' => 'The todo param is not an object.'), 'messageResponsePack');
  2950. }
  2951. }
  2952. /**
  2953. * Get todo list.
  2954. *
  2955. * @param string $mode
  2956. * @param string $orderBy
  2957. * @param string $status
  2958. * @param int $recTotal
  2959. * @param int $recPerPage
  2960. * @param int $pageID
  2961. * @param int $userID
  2962. * @access public
  2963. * @return void
  2964. */
  2965. public function todoGetList($mode = 'all', $status = 'unclosed', $orderBy = 'date_asc', $recTotal = 0, $recPerPage = 20, $pageID = 1, $userID = 0)
  2966. {
  2967. $user = $this->im->userGetByID($userID);
  2968. $this->app->loadClass('pager', $static = true);
  2969. $pager = new pager($recTotal, $recPerPage, $pageID);
  2970. if($mode == 'future')
  2971. {
  2972. $todos = $this->loadModel('todo')->getList('self', $user->account, 'future', empty($status) ? 'unclosed' : $status, $orderBy, $pager);
  2973. }
  2974. else if($mode == 'all')
  2975. {
  2976. $todos = $this->loadModel('todo')->getList('self', $user->account, 'all', empty($status) ? 'all' : $status, $orderBy, $pager);
  2977. }
  2978. else if($mode == 'undone')
  2979. {
  2980. $todos = $this->loadModel('todo')->getList('self', $user->account, 'before', empty($status) ? 'undone' : $status, $orderBy, $pager);
  2981. }
  2982. else
  2983. {
  2984. $todos = $this->loadModel('todo')->getList($mode, $user->account, 'all', empty($status) ? 'unclosed' : $status, $orderBy, $pager);
  2985. }
  2986. $output = new stdclass();
  2987. $output->data = $todos;
  2988. $output->result = 'success';
  2989. $output->users = array($userID);
  2990. return $this->app->output($this->app->encrypt($output));
  2991. }
  2992. /**
  2993. * Get chat group pairs.
  2994. *
  2995. * @access public
  2996. * @return void
  2997. */
  2998. public function getGroupChats()
  2999. {
  3000. $response = array();
  3001. $response['result'] = 'success';
  3002. $groupPairs = $this->im->chatGetGroupPairs();
  3003. if(dao::isError())
  3004. {
  3005. $response['result'] = 'fail';
  3006. $response['message'] = dao::getError();
  3007. }
  3008. else
  3009. {
  3010. $response['data'] = $groupPairs;
  3011. }
  3012. die(json_encode($response));
  3013. }
  3014. /**
  3015. * Get all user pairs or users of one chat group.
  3016. *
  3017. * @param string $gid
  3018. * @access public
  3019. * @return void
  3020. */
  3021. public function getChatUsers($gid = '')
  3022. {
  3023. $response = array();
  3024. $response['result'] = 'success';
  3025. $userPairs = $this->im->chatGetUserPairs($gid);
  3026. if(dao::isError())
  3027. {
  3028. $response['result'] = 'fail';
  3029. $response['message'] = dao::getError();
  3030. }
  3031. else
  3032. {
  3033. $response['data'] = $userPairs;
  3034. }
  3035. die(json_encode($response));
  3036. }
  3037. /**
  3038. * Send notification to users' notification center.
  3039. *
  3040. * @access public
  3041. * @return void
  3042. */
  3043. public function sendNotification()
  3044. {
  3045. /* Parse input data. */
  3046. $input = file_get_contents("php://input");
  3047. $data = json_decode($input);
  3048. $response = array('result' => 'success', 'message' => '');
  3049. if(empty($data->users))
  3050. {
  3051. $response['result'] = 'fail';
  3052. $response['message'] = $this->lang->im->notify->setUserList;
  3053. die(json_encode($response));
  3054. }
  3055. if(empty($data->sender))
  3056. {
  3057. $response['result'] = 'fail';
  3058. $response['message'] = $this->lang->im->notify->setSender;
  3059. die(json_encode($response));
  3060. }
  3061. if(empty($data->title))
  3062. {
  3063. $response['result'] = 'fail';
  3064. $response['message'] = $this->lang->im->notify->setTitle;
  3065. die(json_encode($response));
  3066. }
  3067. $users = $data->users;
  3068. $sender = $data->sender;
  3069. $title = $data->title;
  3070. $subtitle = $data->subtitle ?: '';
  3071. $content = $data->content ?: '';
  3072. $contentType = $data->contentType ?: 'text';
  3073. $url = $data->url ?: '';
  3074. $actions = $data->actions ?: array();
  3075. $result = $this->im->messageCreateNotify($users, $title, $subtitle, $content, $contentType, $url, $actions, $sender);
  3076. if(!$result)
  3077. {
  3078. $response['result'] = 'fail';
  3079. $response['message'] = dao::getError();
  3080. }
  3081. die(json_encode($response));
  3082. }
  3083. /**
  3084. * Send notification into chat.
  3085. *
  3086. * @access public
  3087. * @return void
  3088. */
  3089. public function sendChatMessage()
  3090. {
  3091. /* Parse input data. */
  3092. $input = file_get_contents("php://input");
  3093. $data = json_decode($input);
  3094. $response = array('result' => 'success', 'message' => '');
  3095. if(empty($data->gid))
  3096. {
  3097. $response['result'] = 'fail';
  3098. $response['message'] = $this->lang->im->notify->setGroup;
  3099. die(json_encode($response));
  3100. }
  3101. if(empty($data->sender))
  3102. {
  3103. $response['result'] = 'fail';
  3104. $response['message'] = $this->lang->im->notify->setSender;
  3105. die(json_encode($response));
  3106. }
  3107. if(empty($data->title))
  3108. {
  3109. $response['result'] = 'fail';
  3110. $response['message'] = $this->lang->im->notify->setTitle;
  3111. die(json_encode($response));
  3112. }
  3113. $gid = $data->gid;
  3114. $sender = $data->sender;
  3115. $title = $data->title;
  3116. $subtitle = $data->subtitle ?: '';
  3117. $content = $data->content ?: '';
  3118. $contentType = $data->contentType ?: 'text';
  3119. $url = $data->url ?: '';
  3120. $actions = $data->actions ?: array();
  3121. $result = $this->im->messageCreateNotify($gid, $title, $subtitle, $content, $contentType, $url, $actions, $sender);
  3122. if(!$result)
  3123. {
  3124. $response['result'] = 'fail';
  3125. $response['message'] = dao::getError();
  3126. }
  3127. die(json_encode($response));
  3128. }
  3129. /**
  3130. * Sync foreign user data into xuan database.
  3131. *
  3132. * @access public
  3133. * @return void
  3134. */
  3135. public function syncUsersData()
  3136. {
  3137. /* Parse input data, array of users. */
  3138. $input = file_get_contents("php://input");
  3139. $data = json_decode($input);
  3140. if(!is_array($data))
  3141. {
  3142. $response = array('result' => 'fail', 'message' => $this->lang->im->api->notArray);
  3143. die(json_encode($response));
  3144. }
  3145. $this->loadModel('user');
  3146. /* Get existing user list. */
  3147. $existingAccounts = array_map(function($u) {return $u->account;}, $this->user->getList($dept = null, $mode = 'all'));
  3148. $response = array('result' => 'success', 'message' => '', 'fails' => array());
  3149. /* Get departments mapping configuration. */
  3150. $deptsMapping = isset($this->config->im->depts) ? json_decode($this->config->im->depts->mapping) : new stdClass();
  3151. foreach($data as $user)
  3152. {
  3153. /* Try to find dept id in mapping configuration and replace. */
  3154. if(isset($user->dept) && isset($deptsMapping->{$user->dept})) $user->dept = $deptsMapping->{$user->dept};
  3155. if(in_array($user->account, $existingAccounts))
  3156. {
  3157. /* Update user with new data. */
  3158. $result = $this->user->apiUpdate($user);
  3159. }
  3160. else
  3161. {
  3162. /* Create user with the data. */
  3163. $result = $this->user->apiCreate($user);
  3164. }
  3165. /* Push account to fails on failure. */
  3166. if(!$result) $response['fails'][] = $user->account;
  3167. }
  3168. if(!empty($response['fails']))
  3169. {
  3170. $response['result'] = 'fail';
  3171. $response['message'] = dao::getError();
  3172. }
  3173. else
  3174. {
  3175. unset($response['fails']);
  3176. unset($response['message']);
  3177. }
  3178. die(json_encode($response));
  3179. }
  3180. /**
  3181. * Sync foreign department data into xuan database.
  3182. *
  3183. * @access public
  3184. * @return void
  3185. */
  3186. public function syncDeptsData()
  3187. {
  3188. /* Parse post data, array of depts. */
  3189. $input = file_get_contents("php://input");
  3190. $data = json_decode($input);
  3191. if(!is_array($data))
  3192. {
  3193. $response = array('result' => 'fail', 'message' => $this->lang->im->api->notArray);
  3194. die(json_encode($response));
  3195. }
  3196. $response = array('result' => 'success', 'message' => '', 'fails' => array());
  3197. /* Fetch depts mapping table. */
  3198. $mapping = isset($this->config->im->depts) ? json_decode($this->config->im->depts->mapping) : new stdClass();
  3199. $this->loadModel('dept');
  3200. foreach($data as $dept)
  3201. {
  3202. /* Set type as dept. */
  3203. $dept->type = 'dept';
  3204. /* If parent is set, use parent's mapping id. */
  3205. if($dept->parent != 0) $dept->parent = $mapping->{$dept->parent};
  3206. /* Create or update a dept and get its record id. */
  3207. $deptRecordID = $this->dept->apiUpsertDept($dept, isset($mapping->{$dept->id}) ? $mapping->{$dept->id} : null);
  3208. /* Break on error. */
  3209. if(!$deptRecordID)
  3210. {
  3211. $response['fails'][] = $dept->id;
  3212. continue;
  3213. }
  3214. /* Store acutal record id in $mapping. */
  3215. $mapping->{$dept->id} = $deptRecordID;
  3216. }
  3217. /* Save mapping configuration. */
  3218. $this->loadModel('setting')->setItem('system.im.depts.mapping', json_encode($mapping));
  3219. if(!empty($response['fails']))
  3220. {
  3221. $response['result'] = 'fail';
  3222. $response['message'] = dao::getError();
  3223. }
  3224. else
  3225. {
  3226. unset($response['fails']);
  3227. unset($response['message']);
  3228. }
  3229. die(json_encode($response));
  3230. }
  3231. /**
  3232. * Get user data by account or id, XXD OIDC functionality utilizes this.
  3233. *
  3234. * @param string $identity
  3235. * @access public
  3236. * @return void
  3237. */
  3238. public function getUser($identity)
  3239. {
  3240. if(empty($identity)) return $this->app->output($this->app->encrypt(array('result' => 'fail', 'message' => 'No identity provided.')));
  3241. $user = current($this->im->userGetList('', array($identity)));
  3242. if(empty($user)) return $this->app->output($this->app->encrypt(array('result' => 'fail', 'message' => 'No such user.')));
  3243. $output = new stdClass();
  3244. $output->result = 'success';
  3245. $output->data = $user;
  3246. return $this->app->output($this->app->encrypt($output));
  3247. }
  3248. /**
  3249. * Debug xuanxuan.
  3250. *
  3251. * @param string $source
  3252. * @access public
  3253. * @return void
  3254. */
  3255. public function debug($source = 'x_php')
  3256. {
  3257. if(RUN_MODE != 'front') return $this->app->output('Access Denied');
  3258. $this->view->title = $this->lang->im->debug;
  3259. $this->view->source = $source;
  3260. $this->view->xxdStatus = $this->im->getXxdStatus();
  3261. $this->view->checkXXBConfig = $this->im->checkXXBConfig();
  3262. $this->display();
  3263. }
  3264. /**
  3265. * Read content of log file and display.
  3266. *
  3267. * @access public
  3268. * @return void
  3269. */
  3270. public function showLog()
  3271. {
  3272. $logFile = $this->app->getLogRoot() . 'xuanxuan.' . date('Ymd') . '.log.php';
  3273. if(!file_exists($logFile)) $this->send(array('result' => 'fail', 'message' => $this->lang->im->noLogFile));
  3274. if(!function_exists('fopen')) $this->send(array('result' => 'fail', 'message' => $this->lang->im->noFopen));
  3275. $line = $this->config->im->logLine;
  3276. $pos = -2;
  3277. $eof = '';
  3278. $log = '';
  3279. $fp = fopen($logFile, 'r');
  3280. while($line > 0)
  3281. {
  3282. while($eof != "\n")
  3283. {
  3284. if(!fseek($fp, $pos, SEEK_END))
  3285. {
  3286. $eof = fgetc($fp);
  3287. $pos--;
  3288. }
  3289. else
  3290. {
  3291. break;
  3292. }
  3293. }
  3294. $log .= fgets($fp) . '<br>';
  3295. $eof = '';
  3296. $line--;
  3297. }
  3298. $this->send(array('result' => 'success', 'logs' => $log));
  3299. }
  3300. /**
  3301. * Update last polling time record.
  3302. *
  3303. * @access public
  3304. * @return void
  3305. */
  3306. public function updateLastPoll()
  3307. {
  3308. $this->im->updateLastPoll();
  3309. return $this->im->sendOutput(array('result' => 'success'));
  3310. }
  3311. /**
  3312. * Check for users that changed their password but did not re-login.
  3313. * TODO: Remove this function on a later release.
  3314. *
  3315. * @access public
  3316. * @deprecated 5.4
  3317. * @return void
  3318. */
  3319. public function checkPasswordChanges()
  3320. {
  3321. return $this->getKickList();
  3322. }
  3323. /**
  3324. * Run nightly maintenance jobs.
  3325. *
  3326. * @access public
  3327. * @return void
  3328. */
  3329. public function maintenance()
  3330. {
  3331. $output = new stdClass();
  3332. $output->module = 'im';
  3333. $output->method = 'maintenance';
  3334. $output->result = 'success';
  3335. set_time_limit(0);
  3336. ini_set('memory_limit', -1);
  3337. /* Reindex users' pinyin of realname. */
  3338. $this->im->userReindexPinyin();
  3339. /* Run message table partition job. */
  3340. $partitionMark = $this->im->messageMarkOngoingPartition(true);
  3341. if($partitionMark)
  3342. {
  3343. if($this->im->messageNeedPartition()) $this->im->messagePartitionTable();
  3344. $this->im->messageMarkOngoingPartition(false);
  3345. }
  3346. /* TODO: revive this in 6.3. */
  3347. // $shouldPruneChats = $this->loadModel('setting')->getItem("owner=system&module=common&section=xuanxuan&key=enableCleanDismissGroup");
  3348. // if(isset($shouldPruneChats) && $shouldPruneChats == 'on') $this->im->chatPruneExpired();
  3349. return $this->app->output($this->app->encrypt($output));
  3350. }
  3351. /**
  3352. * Donwload XXD package.
  3353. *
  3354. * @param string xxd package name.
  3355. * @access public
  3356. * @return void
  3357. */
  3358. public function downloadXxdPackage($xxdFileName)
  3359. {
  3360. set_time_limit(0);
  3361. $version = $this->config->xuanxuan->version;
  3362. $xxdDirectory = $this->app->tmpRoot . 'xxd' . DS . $version;
  3363. $xxdFile = fopen($xxdDirectory . DS . $xxdFileName, 'rb');
  3364. Header("Content-type: application/octet-stream");
  3365. Header("Accept-Ranges: bytes");
  3366. Header("Accept-Length: " . filesize ($xxdDirectory . DS . $xxdFileName));
  3367. Header("Content-Disposition: attachment; filename=" . $xxdFileName);
  3368. echo fread($xxdFile, filesize($xxdDirectory . DS . $xxdFileName));
  3369. fclose($xxdFile);
  3370. }
  3371. /**
  3372. * Authorize and redirect user to url.
  3373. *
  3374. * @param string $account
  3375. * @param string $token
  3376. * @param string $device
  3377. * @param string $url
  3378. * @access public
  3379. * @return void
  3380. */
  3381. public function authorize($account = '', $token = '', $device = '', $url = '')
  3382. {
  3383. if(!empty($url)) $url = str_replace('_', $this->config->requestFix, $url);
  3384. if(empty($account) || empty($token)) die('Invalid params. Please provide account, token and url.');
  3385. $user = $this->im->userIdentifyWithToken($account, $token, $device);
  3386. if(!$user || is_string($user)) die('Invalid token.');
  3387. if(empty($url)) die('Authorized, but no url to redirect to.');
  3388. $user = $this->loadModel('user')->getByAccount($account);
  3389. $user = $this->user->login($account, $user->password);
  3390. header("Location: $url", true, 307);
  3391. }
  3392. /**
  3393. * Get user list to kick, currently kicks users with password changes, deletions, and forbiddance.
  3394. *
  3395. * @access public
  3396. * @return void
  3397. */
  3398. public function getKickList()
  3399. {
  3400. $output = new stdclass();
  3401. $output->module = 'im';
  3402. $output->method = 'getkicklist';
  3403. $output->result = 'success';
  3404. $output->data = new stdclass();
  3405. $output->data->kickedChangePwd = array();
  3406. $output->data->kickedDeleted = $this->im->userGetOnlineDeleted();
  3407. $output->data->kickedForbided = $this->im->userGetOnlineForbidden();
  3408. return $this->app->output($this->app->encrypt($output));
  3409. }
  3410. /**
  3411. * Change a chat.
  3412. *
  3413. * @param string $gid
  3414. * @param objcet $config {"public":true,"adminInvite":true,"commiters":""}
  3415. * @param int $userID
  3416. * @access public
  3417. * @return void
  3418. */
  3419. public function chatSetConfig($gid = '', $config = array(), $userID = 0)
  3420. {
  3421. $chat = $this->im->chat->getByGid($gid);
  3422. if(!$chat) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notExist), 'messageResponsePack');
  3423. if($chat->type != 'group' && $chat->type != 'system') return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notGroupChat), 'messageResponsePack');
  3424. if($chat->archiveDate)
  3425. {
  3426. $chat = $this->im->chat->getByGid($gid, true);
  3427. $output = new stdclass();
  3428. $output->result = 'success';
  3429. $output->users = array($userID);
  3430. $output->data = $chat;
  3431. return $this->im->sendOutput($output, 'chatsetconfigResponse');
  3432. }
  3433. $chatID = $chat->id;
  3434. if(isset($config->public))
  3435. {
  3436. $chat->public = $config->public ? '1' : '0';
  3437. }
  3438. if(isset($config->committers))
  3439. {
  3440. if($chat->type != 'group' && $chat->type != 'system') return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notGroupChat), 'messageResponsePack');
  3441. $chat->committers = $config->committers;
  3442. }
  3443. if(isset($config->adminInvite))
  3444. {
  3445. $chat->adminInvite = $config->adminInvite ? '1' : '0';
  3446. }
  3447. if(isset($config->avatar))
  3448. {
  3449. $chat->avatar = $config->avatar;
  3450. }
  3451. $chat = $this->im->chatUpdate($chat, $userID);
  3452. if(dao::isError())
  3453. {
  3454. $this->im->chatAddAction($chatID, 'chatSetConfig', $userID, 'fail');
  3455. return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Set chat config fail.'), 'messageResponsePack');
  3456. }
  3457. $this->im->chatAddAction($chatID, 'chatSetConfig', $userID, 'success');
  3458. $users = $this->im->userGetList($status = 'online', $chat->members);
  3459. $output = new stdclass();
  3460. $output->result = 'success';
  3461. $output->users = array_keys($users);
  3462. $output->data = $chat;
  3463. return $this->im->sendOutput($output, 'chatsetconfigResponse');
  3464. }
  3465. /**
  3466. * search chats with super admin.
  3467. *
  3468. * @param string $searchField
  3469. * @param object $pager
  3470. * @param string $orderBy
  3471. * @param boolean $onlyGetChats
  3472. * @param int $userID
  3473. * @access public
  3474. * @return array
  3475. */
  3476. public function chatSearch($searchField='', $pager = null, $orderBy = '', $onlyGetChats = false, $userID = 0)
  3477. {
  3478. $account = $this->dao->select('account')->from(TABLE_USER)->where('id')->eq($userID)->fetch('account');
  3479. $sysAdmins = $this->dao->select('admins')->from(TABLE_COMPANY)->where('id')->eq($this->app->company->id)->fetch('admins');
  3480. $sysAdminArray = explode(',', $sysAdmins);
  3481. $super = in_array($account, $sysAdminArray) ? 'super' : '';
  3482. if($super != 'super')
  3483. {
  3484. return $this->im->sendOutput(array('result' => 'success', 'data' => array()));
  3485. }
  3486. $output = new stdclass();
  3487. $output->result = 'success';
  3488. $output->users = array($userID);
  3489. if($onlyGetChats)
  3490. {
  3491. $chatList = $this->im->chatAdminGetChatGroups();
  3492. $output->data = $this->im->chatFormat($chatList);
  3493. return $this->im->sendOutput($output, 'chatgetpubliclistResponse');
  3494. }
  3495. else
  3496. {
  3497. if(empty($pager)) $pager = new stdclass();
  3498. if(empty($orderBy)) $orderBy = 'createdDate_desc';
  3499. if(!isset($pager->pageID)) $pager->pageID = 1;
  3500. if(!isset($pager->recPerPage)) $pager->recPerPage = 10;
  3501. if(!isset($pager->recTotal)) $pager->recTotal = 0;
  3502. $this->app->loadClass('pager', $static = true);
  3503. $pager = new pager($pager->recTotal, $pager->recPerPage, $pager->pageID);
  3504. $chatList = $this->im->chatSearch($searchField, $pager, $orderBy);
  3505. $output->data = $chatList;
  3506. $output->pager = new stdclass();
  3507. $output->pager->recPerPage = $pager->recPerPage;
  3508. $output->pager->pageID = $pager->pageID;
  3509. $output->pager->recTotal = $pager->recTotal;
  3510. }
  3511. return $this->im->sendOutput($output, 'chatsearchResponse');
  3512. }
  3513. /**
  3514. * Set chat avatar.
  3515. *
  3516. * @param string $gid
  3517. * @param object $avatar
  3518. * @param int $userID
  3519. * @access public
  3520. * @return void
  3521. */
  3522. public function chatSetAvatar($gid, $avatar = null, $userID = 0)
  3523. {
  3524. $chat = $this->im->chat->getByGid($gid);
  3525. if(!$chat) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notExist), 'messageResponsePack');
  3526. if($chat->archiveDate)
  3527. {
  3528. $output = new stdclass();
  3529. $output->result = 'success';
  3530. $output->users = array($userID);
  3531. $output->data = $chat;
  3532. return $this->im->sendOutput($output, 'chatsetavatarResponse');
  3533. }
  3534. if(!$this->im->chatIsAdmin($chat, $userID)) return $this->im->sendOutput(array('result' => 'fail', 'message' => $this->lang->im->notAdmin), 'messageResponsePack');
  3535. if($avatar->type == 'image')
  3536. {
  3537. $file = $this->loadModel('file')->getById($avatar->data->imgId);
  3538. $avatar->data->imgUrl = $file->webPath;
  3539. unset($avatar->data->imgId);
  3540. }
  3541. /* Sanitize input. */
  3542. if($avatar->type == 'text') $avatar->data->customText = strip_tags($avatar->data->customText);
  3543. $avatarEncoded = json_encode($avatar);
  3544. $chat = $this->im->chatUpdateAvatar($gid, $avatarEncoded);
  3545. if(dao::isError())
  3546. {
  3547. $this->im->chatAddAction($gid, 'chatSetAvatar', $userID, 'fail');
  3548. return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Set chat avatar fail.'), 'messageResponsePack');
  3549. }
  3550. $this->im->chatAddAction($gid, 'chatSetAvatar', $userID, 'success');
  3551. if($avatar->type == 'image') $avatar->data->imgUrl = $this->loadModel('im')->getServer() . $avatar->data->imgUrl;
  3552. $chat->avatar = $avatar;
  3553. $users = $this->im->userGetList($status = 'online', $chat->members);
  3554. $output = new stdclass();
  3555. $output->result = 'success';
  3556. $output->users = array_keys($users);
  3557. $output->data = $chat;
  3558. return $this->im->sendOutput($output, 'chatsetavatarResponse');
  3559. }
  3560. /**
  3561. * Delete bulletin message by setting type to 'normal'.
  3562. *
  3563. * @param int $messageID
  3564. * @param string $cgid
  3565. * @param int $userID
  3566. * @access public
  3567. * @return void
  3568. */
  3569. public function bulletinDelete($messageID, $cgid, $userID = 0)
  3570. {
  3571. if(empty($messageID)) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Message ID is required.'), 'messageResponsePack');
  3572. if(empty($cgid)) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Cgid is required.'), 'messageResponsePack');
  3573. // Get the chat to check permissions
  3574. $chat = $this->im->chat->getByGid($cgid);
  3575. if(!$chat) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Chat not found.'), 'messageResponsePack');
  3576. // Check if user is admin of the chat
  3577. if(!$this->im->chat->isAdmin($chat, $userID)) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Only admins can delete bulletin messages.'), 'messageResponsePack');
  3578. // Update message type from 'bulletin' to 'normal'
  3579. $this->dao->update(TABLE_IM_MESSAGE)
  3580. ->set('type')->eq('normal')
  3581. ->set('data')->eq('')
  3582. ->where('id')->eq($messageID)
  3583. ->andWhere('type')->eq('bulletin')
  3584. ->exec();
  3585. if(dao::isError()) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Failed to delete bulletin message.'), 'messageResponsePack');
  3586. // Get online users in the chat
  3587. $onlineUsers = $this->im->user->getList('online', $chat->members);
  3588. $offlineUsers = $this->im->user->getList('offline', $chat->members);
  3589. $messages = $this->im->message->getList($cgid, array($messageID));
  3590. $this->im->message->saveOfflineList($messages, array_keys($offlineUsers));
  3591. $output = new stdclass();
  3592. $output->result = 'success';
  3593. $output->method = 'bulletindelete';
  3594. $output->users = array_keys($onlineUsers);
  3595. $output->data = current($messages);
  3596. return $this->im->sendOutput($output, 'responsePack');
  3597. }
  3598. /**
  3599. * Edit bulletin message content.
  3600. *
  3601. * @param int $messageID
  3602. * @param string $content
  3603. * @param string $cgid
  3604. * @param int $userID
  3605. * @access public
  3606. * @return void
  3607. */
  3608. public function bulletinEdit($messageID, $content, $cgid, $userID = 0)
  3609. {
  3610. if(empty($messageID)) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Message ID is required.'), 'messageResponsePack');
  3611. if(empty($content)) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Content is required.'), 'messageResponsePack');
  3612. if(empty($cgid)) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Cgid is required.'), 'messageResponsePack');
  3613. // Get the chat to check permissions
  3614. $chat = $this->im->chat->getByGid($cgid);
  3615. if(!$chat) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Chat not found.'), 'messageResponsePack');
  3616. // Check if user is admin of the chat
  3617. if(!$this->im->chat->isAdmin($chat, $userID)) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Only admins can edit bulletin messages.'), 'messageResponsePack');
  3618. // Update message content
  3619. $this->dao->update(TABLE_IM_MESSAGE)
  3620. ->set('content')->eq($content)
  3621. ->where('id')->eq($messageID)
  3622. ->andWhere('type')->eq('bulletin')
  3623. ->exec();
  3624. if(dao::isError()) return $this->im->sendOutput(array('result' => 'fail', 'message' => 'Failed to edit bulletin message.'), 'messageResponsePack');
  3625. // Get online users in the chat
  3626. $onlineUsers = $this->im->user->getList('online', $chat->members);
  3627. $offlineUsers = $this->im->user->getlist('offline', $chat->members);
  3628. $messages = $this->im->message->getList($cgid, array($messageID));
  3629. $this->im->message->saveOfflineList($messages, array_keys($offlineUsers));
  3630. $output = new stdclass();
  3631. $output->result = 'success';
  3632. $output->method = 'bulletinedit';
  3633. $output->users = array_keys($onlineUsers);
  3634. $output->data = current($messages);
  3635. return $this->im->sendOutput($output, 'responsePack');
  3636. }
  3637. /**
  3638. * Read voice message.
  3639. * @param int $messageID
  3640. * @param int $userID
  3641. * @access public
  3642. */
  3643. public function voiceRead($messageID, $userID = 0)
  3644. {
  3645. $message = $this->im->message->getById($messageID);
  3646. $output = new stdclass();
  3647. $output->method = 'voiceread';
  3648. $output->users = array_unique(array($userID, $message->user));
  3649. if ($message->read !== null && in_array($userID, json_decode($message->read, true)))
  3650. {
  3651. $output->result = 'success';
  3652. $output->data = $message;
  3653. return $this->im->sendOutput($output, 'responsePack');
  3654. }
  3655. $result = boolval($this->im->message->readVoice($messageID, $userID));
  3656. if ($result)
  3657. {
  3658. $output->result = 'success';
  3659. $output->data = $this->im->message->getById($messageID);
  3660. }
  3661. else
  3662. {
  3663. $output->result = 'fail';
  3664. $output->data = $message;
  3665. }
  3666. return $this->im->sendOutput($output, 'responsePack');
  3667. }
  3668. }