/**
  * Clean target helpdesks
  */
 public function actionCleanOffline(array $ids)
 {
     $cache = Yii::$app->cache;
     foreach ($ids as $helpDeskId) {
         $helpDesk = HelpDesk::findByPk(new \MongoId($helpDeskId));
         $accountId = $helpDesk->accountId;
         $conversations = $cache->get('conversations' . $accountId);
         unset($conversations[$helpDeskId]);
         $cache->set('conversations' . $accountId, $conversations);
     }
 }
 /**
  * This method is used to push message.
  *  If mobile help-desk client is on backend, push message.
  */
 public function pushMessage($deskId, $eventType, $extra, $message = null)
 {
     $cache = \Yii::$app->cache;
     $deskStrId = $deskId . '';
     //Update the helpdesk unread message count
     $count = $cache->get(ConversationController::UNREAD_COUNT_PREFIX . $deskStrId);
     empty($count) && ($count = 0);
     $desk = HelpDesk::findByPk($deskId);
     if (empty($desk->deviceToken) || empty($desk->environment)) {
         LogUtil::info(['push' => 'missing device token', 'desk' => $deskId, 'eventType' => $eventType, 'extra' => $extra]);
     } else {
         if ($eventType == ConversationController::EVENT_CHAT_MESSAGE && $this->isPushMessage($deskId, $desk->accountId)) {
             $cache->set(ConversationController::UNREAD_COUNT_PREFIX . $deskStrId, ++$count);
         } else {
             //no code here, push state like 'sessionConnected', no need to add $count
         }
         $extra['type'] = $eventType;
         $target = [$desk->environment => [$desk->deviceToken]];
         \Yii::$app->tuisongbao->pushMessage($target, $count, $extra, $message);
     }
 }
 /**
  * Used for tuisongbao web hook, realtime engine will call the service when user subscribe or unsubscribe a channel
  * @return string json status
  */
 public function actionUserState()
 {
     $body = $this->getParams();
     $headers = Yii::$app->request->getHeaders();
     $signature = hash_hmac('sha256', json_encode($body), TUISONGBAO_SECRET);
     LogUtil::info(['body' => $body, 'signature' => $signature], 'webhook');
     // Check whether it is called by the tuisongbao web hook
     if ($signature === $headers['X-Engine-Signature']) {
         //TODO: First event may not be the correct one
         $time = $body['timestamp'];
         $event = $body['events'][0];
         $userId = $event['userId'];
         $eventName = $event['name'];
         //Tip: Only handle the user_removed event on global channel here
         if (strpos($event['channel'], ChatConversation::CHANNEL_GLOBAL) !== false && ChatConversation::MONGOID_LENGTH === strlen($userId)) {
             $helpdesk = HelpDesk::findByPk(new \MongoId($userId));
             if (!empty($helpdesk)) {
                 if ($eventName == ChatConversation::EVENT_USER_ADDED || $eventName == ChatConversation::EVENT_USER_REMOVED) {
                     $updateTimePrefix = 'wm-update-time';
                     $cache = Yii::$app->cache;
                     $lastTime = $cache->get($updateTimePrefix . $userId);
                     // failed events will be send again, but timestamp will not change
                     // if a event is failed and other event has success, skip that failed event
                     // Event_1. user_add failed; Event_2, user_remove successed; Event_1. user_add successed
                     // skip Event_1. user_add successed
                     if (empty($lastTime) || $lastTime < $time) {
                         $cache->set($updateTimePrefix . $userId, $time);
                         HelpDesk::cacheOnlineDesks($helpdesk->_id . '', $helpdesk->accountId . '', $eventName);
                     }
                 }
             }
         }
     }
 }
 /**
  * Reset password
  */
 public function actionResetPassword()
 {
     $code = $this->getParams('code');
     $newPassword = $this->getParams('password');
     $result = Validation::validateCode($code);
     if ($result == Validation::LINK_INVALID) {
         throw new BadRequestHttpException(Yii::t('common', 'link_invalid'));
     } else {
         if ($result == Validation::LINK_EXPIRED) {
             throw new BadRequestHttpException(Yii::t('common', 'link_expired'));
         }
     }
     $userId = $result;
     $user = HelpDesk::findByPk($userId);
     if (empty($user)) {
         throw new BadRequestHttpException(Yii::t('commmon', 'incorrect_userid'));
     }
     // update the user password
     $user->password = HelpDesk::encryptPassword($newPassword, $user->salt);
     if (!$user->save()) {
         throw new ServerErrorHttpException("Save user failed!");
     }
     return ['status' => 'ok'];
 }
 public function actionCheckAuth()
 {
     $secret = TUISONGBAO_SECRET;
     $socketId = $this->getParams('socketId');
     $channelName = $this->getParams('channelName');
     $authData = $this->getParams('authData');
     //helpdesk is saved as authData
     $parts = explode(':', $authData);
     //If it is the helpdesk
     $clientId = $parts[1];
     $userData = ['userId' => $clientId, 'userInfo' => []];
     if ('h' === $parts[0]) {
         $client = HelpDesk::findByPk(new \MongoId($clientId));
         $userData['userInfo'] = ['badge' => $client->badge, 'email' => $client->email];
     }
     $userDataJsonStr = json_encode($userData);
     $strToSign = $socketId . ':' . $channelName . ':' . $userDataJsonStr;
     LogUtil::info(['strToSign' => $strToSign, 'secret' => $secret], 'signature');
     $signature = hash_hmac('sha256', $strToSign, $secret);
     LogUtil::info(['signature' => $signature, 'channelData' => $userDataJsonStr], 'signature');
     $result = ['signature' => $signature, 'channelData' => $userDataJsonStr];
     header("Content-Type:application/json");
     echo json_encode($result);
 }