/** * Invitation was accepted by visitor * * Triggers {@link \Mibew\EventDispatcher\Events::INVITATION_ACCEPT} event. * * @param int $visitor_id ID of the visitor who accept invitation * @return Thread|boolean Thread object or boolean false on failure */ function invitation_accept($visitor_id) { // Check if visitor was invited $invitation_state = invitation_state($visitor_id); if (!$invitation_state['invited']) { // Visitor was not invited return false; } // Get thread related with the visitor $db = Database::getInstance(); $result = $db->query("SELECT threadid FROM {sitevisitor} WHERE visitorid = :visitor_id", array(':visitor_id' => $visitor_id), array('return_rows' => Database::RETURN_ONE_ROW)); if (empty($result['threadid'])) { // Something went wrong. There is no thread related with the visitor. return false; } $thread = Thread::load($result['threadid']); if (!$thread) { // Something went wrong. Cannot load thread. return false; } // Update thread info $thread->state = Thread::STATE_CHATTING; $thread->invitationState = Thread::INVITATION_ACCEPTED; $thread->chatStarted = time(); $thread->save(); // Update visitor info $db->query("UPDATE {sitevisitor} SET chats = chats + 1 " . "WHERE visitorid = :visitor_id", array(':visitor_id' => $visitor_id)); $args = array('invitation' => $thread); EventDispatcher::getInstance()->triggerEvent(Events::INVITATION_ACCEPT, $args); return $thread; }
/** * Process chat in an invitation block. * * @param Request $request Incoming request. * @return string|\Symfony\Component\HttpFoundation\RedirectResponse Rendered * page content or a redirect response. */ public function invitationAction(Request $request) { // Check if an user tries to use invitation functionality when it's // disabled. if (!Settings::get('enabletracking')) { return $this->redirect($this->generateUrl('chat_user_start')); } // Check if we should force the user to use SSL. $ssl_redirect = $this->sslRedirect($request); if ($ssl_redirect !== false) { return $ssl_redirect; } // Check if user invited to chat. $invitation_state = invitation_state($_SESSION[SESSION_PREFIX . 'visitorid']); if (!$invitation_state['invited'] || !$invitation_state['threadid']) { return $this->redirect($this->generateUrl('chat_user_start')); } $thread = Thread::load($invitation_state['threadid']); // Store own thread ids to restrict access for other people if (!isset($_SESSION[SESSION_PREFIX . 'own_threads'])) { $_SESSION[SESSION_PREFIX . 'own_threads'] = array(); } $_SESSION[SESSION_PREFIX . 'own_threads'][] = $thread->id; // Prepare page $page = setup_invitation_view($thread); // Build js application options $page['invitationOptions'] = $page['invitation']; // Initialize client side application $this->getAssetManager()->attachJs('js/compiled/chat_app.js'); $this->getAssetManager()->attachJs( $this->startJsApplication($request, $page), AssetManagerInterface::INLINE, 1000 ); // Expand page return $this->render('chat', $page); }
function track_visit_page($visitor_id, $page) { $db = Database::getInstance(); if (empty($page)) { return; } $last_page = $db->query("SELECT address " . "FROM {visitedpage} " . "WHERE visitorid = ? " . "ORDER BY visittime DESC " . "LIMIT 1", array($visitor_id), array('return_rows' => Database::RETURN_ONE_ROW)); if ($last_page['address'] != $page) { $db->query("INSERT INTO {visitedpage} (" . "visitorid, address, visittime " . ") VALUES ( " . ":visitorid, :page, :now " . ")", array(':visitorid' => $visitor_id, ':page' => $page, ':now' => time())); // If the visitor was invited and he goes to another page the invitation // should be automatically rejected. $invitation_state = invitation_state($visitor_id); if ($invitation_state['invited']) { invitation_reject($visitor_id); } } }
/** * Start chat thread for user * * @param int $group_id Id of group related to thread * @param array $requested_operator Array of requested operator info * @param string $visitor_id Id of the visitor * @param string $visitor_name Name of the visitor * @param string $referrer Page user came from * @param string $info User info * * @return Thread thread object */ function chat_start_for_user($group_id, $requested_operator, $visitor_id, $visitor_name, $referrer, $info) { // Get user info $remote_host = get_remote_host(); $user_browser = $_SERVER['HTTP_USER_AGENT']; // Check connection limit if (Thread::connectionLimitReached($remote_host)) { die("number of connections from your IP is exceeded, try again later"); } // Check if visitor was invited to chat $is_invited = false; if (Settings::get('enabletracking')) { $invitation_state = invitation_state($_SESSION[SESSION_PREFIX . 'visitorid']); if ($invitation_state['invited']) { $is_invited = true; } } // Get info about requested operator $requested_operator_online = false; if ($requested_operator) { $requested_operator_online = is_operator_online($requested_operator['operatorid']); } // Get thread object if ($is_invited) { // Get thread from invitation $thread = invitation_accept($_SESSION[SESSION_PREFIX . 'visitorid']); if (!$thread) { die("Cannot start thread"); } } else { // Create thread $thread = new Thread(); $thread->state = Thread::STATE_LOADING; $thread->agentId = 0; if ($requested_operator && $requested_operator_online) { $thread->nextAgent = $requested_operator['operatorid']; } } // Update thread fields $thread->groupId = $group_id; $thread->userName = $visitor_name; $thread->remote = $remote_host; $thread->referer = $referrer; $thread->locale = get_current_locale(); $thread->userId = $visitor_id; $thread->userAgent = $user_browser; $thread->save(); $_SESSION[SESSION_PREFIX . 'threadid'] = $thread->id; // Store own thread ids to restrict access for other people if (!isset($_SESSION[SESSION_PREFIX . 'own_threads'])) { $_SESSION[SESSION_PREFIX . 'own_threads'] = array(); } $_SESSION[SESSION_PREFIX . 'own_threads'][] = $thread->id; // Bind thread to the visitor if (Settings::get('enabletracking')) { track_visitor_bind_thread($visitor_id, $thread); } // Send several messages if ($is_invited) { $operator = operator_by_id($thread->agentId); $operator_name = get_operator_name($operator); $thread->postMessage(Thread::KIND_FOR_AGENT, getlocal('Visitor accepted invitation from operator {0}', array($operator_name), get_current_locale(), true)); } else { if ($referrer) { $thread->postMessage(Thread::KIND_FOR_AGENT, getlocal('Vistor came from page {0}', array($referrer), get_current_locale(), true)); } if ($requested_operator && !$requested_operator_online) { $thread->postMessage(Thread::KIND_INFO, getlocal('Thank you for contacting us. We are sorry, but requested operator <strong>{0}</strong> is offline. Another operator will be with you shortly.', array(get_operator_name($requested_operator)), get_current_locale(), true)); } else { $thread->postMessage(Thread::KIND_INFO, getlocal('Thank you for contacting us. An operator will be with you shortly.', null, get_current_locale(), true)); } } // TODO: May be move sending this message somewhere else? if ($info) { $thread->postMessage(Thread::KIND_FOR_AGENT, getlocal('Info: {0}', array($info), get_current_locale(), true)); } // Let plugins know that user is ready to chat. $dispatcher = EventDispatcher::getInstance(); $event_args = array('thread' => $thread); $dispatcher->triggerEvent(Events::THREAD_USER_IS_READY, $event_args); return $thread; }
/** * Provides a gateway for widget requests. * * Triggers {@link \Mibew\EventDispatcher\Events::VISITOR_TRACK} event. * * @param Request $request * @return string Rendered page content */ public function indexAction(Request $request) { $operator = array(); $response_data = array('load' => array(), 'handlers' => array(), 'dependencies' => array(), 'data' => array()); $tracking_allowed = Settings::get('enabletracking') == '1' && (Settings::get('trackoperators') == '1' || !$this->getOperator()); if ($tracking_allowed) { $entry = $request->query->get('entry', ''); $referer = $request->server->get('HTTP_REFERER', ''); $user_id = $request->query->get('user_id', false); // Check if session was started if (isset($_SESSION[SESSION_PREFIX . 'visitorid']) && preg_match('/^[0-9]+$/', $_SESSION[SESSION_PREFIX . 'visitorid'])) { // Session was started. Just track the visitor. $visitor_id = track_visitor($_SESSION[SESSION_PREFIX . 'visitorid'], $entry, $referer); $visitor = track_get_visitor_by_id($visitor_id); } else { $visitor = track_get_visitor_by_user_id($user_id); if ($visitor !== false) { // Session is not started but the visitor exists in // database. Probably third-party cookies are disabled by // the browser. Use tracking by local cookie at target site. $visitor_id = track_visitor($visitor['visitorid'], $entry, $referer); } else { // Start tracking session $visitor_id = track_visitor_start($entry, $referer); $visitor = track_get_visitor_by_id($visitor_id); } } if ($visitor_id) { $_SESSION[SESSION_PREFIX . 'visitorid'] = $visitor_id; } if ($user_id === false) { // Update local cookie value at target site $response_data['handlers'][] = 'updateUserId'; $response_data['dependencies']['updateUserId'] = array(); $response_data['data']['user']['id'] = $visitor['userid']; } // Provide an ability for others to make something on visitor // tracking $event_arguments = array('visitor' => $visitor); EventDispatcher::getInstance()->triggerEvent(Events::VISITOR_TRACK, $event_arguments); // Get invitation state $invitation_state = invitation_state($visitor_id); // Check if invitation is closed if (!$invitation_state['invited'] && !empty($_SESSION[SESSION_PREFIX . 'invitation_threadid'])) { $response_data['handlers'][] = 'invitationClose'; $response_data['dependencies']['invitationClose'] = array(); unset($_SESSION[SESSION_PREFIX . 'invitation_threadid']); } // Check if the visitor is just invited to chat $is_invited = $invitation_state['invited'] && (empty($_SESSION[SESSION_PREFIX . 'invitation_threadid']) ? true : $_SESSION[SESSION_PREFIX . 'invitation_threadid'] != $invitation_state['threadid']); if ($is_invited) { // Load invitation thread $thread = Thread::load($invitation_state['threadid']); // Get operator info $operator = operator_by_id($thread->agentId); $locale = $request->query->get('locale', ''); $operator_name = $locale == get_home_locale() ? $operator['vclocalename'] : $operator['vccommonname']; $avatar_url = $operator['vcavatar'] ? $this->asset($operator['vcavatar'], AssetUrlGeneratorInterface::ABSOLUTE_URL) : false; // Show invitation dialog at widget side $response_data['handlers'][] = 'invitationCreate'; $response_data['dependencies']['invitationCreate'] = array(); $response_data['data']['invitation'] = array('operatorName' => htmlspecialchars($operator_name), 'avatarUrl' => htmlspecialchars($avatar_url), 'threadUrl' => $this->generateUrl('chat_user_invitation', array(), UrlGeneratorInterface::ABSOLUTE_URL), 'acceptCaption' => getlocal('Answer')); $_SESSION[SESSION_PREFIX . 'invitation_threadid'] = $thread->id; } // Check if the visitor rejects invitation if ($invitation_state['invited'] && $request->query->get('invitation_rejected')) { invitation_reject($visitor_id); } $event_arguments = array('visitor' => $visitor, 'request' => $request, 'response' => $response_data, 'route_url_generator' => $this->getRouter(), 'asset_url_generator' => $this->getAssetManager()->getUrlGenerator()); EventDispatcher::getInstance()->triggerEvent(Events::WIDGET_RESPONSE_ALTER, $event_arguments); $response_data = $event_arguments['response']; } // Builds JSONP response $response = new JsonResponse($response_data); $response->setCallback("Mibew.Objects.widget.onResponse"); // Add headers to overcome third-party cookies problem. $response->headers->set('P3P', 'CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"'); return $response; }