Example #1
0
 /**
  * Add/remove leads from campaigns based on lead list changes
  *
  * @param ListChangeEvent $event
  */
 public function onLeadListChange(ListChangeEvent $event)
 {
     $lead = $event->getLead();
     $list = $event->getList();
     $action = $event->wasAdded() ? 'added' : 'removed';
     $repo = $this->campaignModel->getRepository();
     //get campaigns for the list
     $listCampaigns = $repo->getPublishedCampaignsByLeadLists($list->getId());
     $leadLists = $this->leadModel->getLists($lead, true);
     $leadListIds = array_keys($leadLists);
     // If the lead was removed then don't count it
     if ($action == 'removed') {
         $key = array_search($list->getId(), $leadListIds);
         unset($leadListIds[$key]);
     }
     if (!empty($listCampaigns)) {
         foreach ($listCampaigns as $c) {
             $campaign = $this->em->getReference('MauticCampaignBundle:Campaign', $c['id']);
             if (!isset($campaignLists[$c['id']])) {
                 $campaignLists[$c['id']] = array_keys($c['lists']);
             }
             if ($action == 'added') {
                 $this->campaignModel->addLead($campaign, $lead);
             } else {
                 if (array_intersect($leadListIds, $campaignLists[$c['id']])) {
                     continue;
                 }
                 $this->campaignModel->removeLead($campaign, $lead);
             }
             unset($campaign);
         }
     }
 }
Example #2
0
 /**
  * @param CampaignExecutionEvent $event
  */
 public function onCampaignTriggerActionChangeStage(CampaignExecutionEvent $event)
 {
     $stageChange = false;
     $lead = $event->getLead();
     $leadStage = null;
     if ($lead instanceof Lead) {
         $leadStage = $lead->getStage();
     }
     $stageId = (int) $event->getConfig()['stage'];
     $stageToChangeTo = $this->stageModel->getEntity($stageId);
     if ($stageToChangeTo != null && $stageToChangeTo->isPublished()) {
         if ($leadStage && $leadStage->getWeight() <= $stageToChangeTo->getWeight()) {
             $stageChange = true;
         } elseif (!$leadStage) {
             $stageChange = true;
         }
     }
     if ($stageChange) {
         $parsed = explode('.', $stageToChangeTo->getName());
         $lead->stageChangeLogEntry($parsed[0], $stageToChangeTo->getId() . ": " . $stageToChangeTo->getName(), $event->getName());
         $lead->setStage($stageToChangeTo);
         $this->leadModel->saveEntity($lead);
     }
     return $event->setResult($stageChange);
 }
Example #3
0
 /**
  * @param Event|int                                $event
  * @param Campaign                                 $campaign
  * @param \Mautic\LeadBundle\Entity\Lead|null      $lead
  * @param \Mautic\CoreBundle\Entity\IpAddress|null $ipAddress
  * @param bool                                     $systemTriggered
  *
  * @return LeadEventLog
  *
  * @throws \Doctrine\ORM\ORMException
  */
 public function getLogEntity($event, $campaign, $lead = null, $ipAddress = null, $systemTriggered = false)
 {
     $log = new LeadEventLog();
     if ($ipAddress == null) {
         // Lead triggered from system IP
         $ipAddress = $this->ipLookupHelper->getIpAddress();
     }
     $log->setIpAddress($ipAddress);
     if (!$event instanceof Event) {
         $event = $this->em->getReference('MauticCampaignBundle:Event', $event);
     }
     $log->setEvent($event);
     if (!$campaign instanceof Campaign) {
         $campaign = $this->em->getReference('MauticCampaignBundle:Campaign', $campaign);
     }
     $log->setCampaign($campaign);
     if ($lead == null) {
         $lead = $this->leadModel->getCurrentLead();
     }
     $log->setLead($lead);
     $log->setDateTriggered(new \DateTime());
     $log->setSystemTriggered($systemTriggered);
     // Save some RAM for batch processing
     unset($event, $campaign, $lead);
     return $log;
 }
Example #4
0
 /**
  * @param CampaignExecutionEvent $event
  */
 public function onCampaignTriggerCondition(CampaignExecutionEvent $event)
 {
     $lead = $event->getLead();
     if (!$lead || !$lead->getId()) {
         return $event->setResult(false);
     }
     $operators = $this->leadModel->getFilterExpressionFunctions();
     $result = $this->leadFieldModel->getRepository()->compareValue($lead->getId(), $event->getConfig()['field'], $event->getConfig()['value'], $operators[$event->getConfig()['operator']]['expr']);
     return $event->setResult($result);
 }
Example #5
0
 /**
  * Triggers a specific stage change (this function is not being used any more but leaving it in case we do want to move stages through different actions)
  *
  * @param $type
  * @param mixed $eventDetails passthrough from function triggering action to the callback function
  * @param mixed $typeId Something unique to the triggering event to prevent  unnecessary duplicate calls
  * @param Lead  $lead
  *
  * @return void
  */
 public function triggerAction($type, $eventDetails = null, $typeId = null, Lead $lead = null)
 {
     //only trigger actions for anonymous users
     if (!$this->security->isAnonymous()) {
         return;
     }
     if ($typeId !== null && MAUTIC_ENV === 'prod') {
         $triggeredEvents = $this->session->get('mautic.triggered.stage.actions', array());
         if (in_array($typeId, $triggeredEvents)) {
             return;
         }
         $triggeredEvents[] = $typeId;
         $this->session->set('mautic.triggered.stage.actions', $triggeredEvents);
     }
     //find all the actions for published stages
     /** @var \Mautic\StageBundle\Entity\StageRepository $repo */
     $repo = $this->getRepository();
     $availableStages = $repo->getPublishedByType($type);
     if (null === $lead) {
         $lead = $this->leadModel->getCurrentLead();
         if (null === $lead || !$lead->getId()) {
             return;
         }
     }
     //get available actions
     $availableActions = $this->getStageActions();
     //get a list of actions that has already been performed on this lead
     $completedActions = $repo->getCompletedLeadActions($type, $lead->getId());
     $persist = array();
     foreach ($availableStages as $action) {
         //if it's already been done, then skip it
         if (isset($completedActions[$action->getId()])) {
             continue;
         }
         //make sure the action still exists
         if (!isset($availableActions['actions'][$action->getName()])) {
             continue;
         }
         $parsed = explode('.', $action->getName());
         $lead->stageChangeLogEntry($parsed[0], $action->getId() . ": " . $action->getName(), 'Moved by an action');
         $lead->setStage($action);
         $log = new LeadStageLog();
         $log->setStage($action);
         $log->setLead($lead);
         $log->setDateFired(new \DateTime());
         $persist[] = $log;
     }
     if (!empty($persist)) {
         $this->leadModel->saveEntity($lead);
         $this->getRepository()->saveEntities($persist);
         // Detach logs to reserve memory
         $this->em->clear('Mautic\\StageBundle\\Entity\\LeadStageLog');
     }
 }
Example #6
0
 /**
  * @param PageDisplayEvent $event
  */
 public function onPageDisplay(PageDisplayEvent $event)
 {
     $page = $event->getPage();
     $leadId = $this->security->isAnonymous() ? $this->leadModel->getCurrentLead()->getId() : null;
     $tokens = $this->generateTokensFromContent($event, $leadId, ['page', $page->getId()]);
     $content = $event->getContent();
     if (!empty($tokens)) {
         $content = str_ireplace(array_keys($tokens), $tokens, $content);
     }
     $event->setContent($content);
 }
Example #7
0
 /**
  * @param CampaignExecutionEvent $event
  */
 public function onCampaignTriggerAction(CampaignExecutionEvent $event)
 {
     $lead = $event->getLead();
     if ($this->leadModel->isContactable($lead, 'sms') !== DoNotContact::IS_CONTACTABLE) {
         return $event->setFailed('mautic.sms.campaign.failed.not_contactable');
     }
     $leadPhoneNumber = $lead->getFieldValue('mobile');
     if (empty($leadPhoneNumber)) {
         $leadPhoneNumber = $lead->getFieldValue('phone');
     }
     if (empty($leadPhoneNumber)) {
         return $event->setFailed('mautic.sms.campaign.failed.missing_number');
     }
     $smsId = (int) $event->getConfig()['sms'];
     $sms = $this->smsModel->getEntity($smsId);
     if ($sms->getId() !== $smsId) {
         return $event->setFailed('mautic.sms.campaign.failed.missing_entity');
     }
     $smsEvent = new SmsSendEvent($sms->getMessage(), $lead);
     $smsEvent->setSmsId($smsId);
     $this->dispatcher->dispatch(SmsEvents::SMS_ON_SEND, $smsEvent);
     $tokenEvent = $this->dispatcher->dispatch(SmsEvents::TOKEN_REPLACEMENT, new TokenReplacementEvent($smsEvent->getContent(), $lead, ['channel' => ['sms', $sms->getId()]]));
     $metadata = $this->smsApi->sendSms($leadPhoneNumber, $tokenEvent->getContent());
     $defaultFrequencyNumber = $this->factory->getParameter('sms_frequency_number');
     $defaultFrequencyTime = $this->factory->getParameter('sms_frequency_time');
     /** @var \Mautic\LeadBundle\Entity\FrequencyRuleRepository $frequencyRulesRepo */
     $frequencyRulesRepo = $this->leadModel->getFrequencyRuleRepository();
     $leadIds = $lead->getId();
     $dontSendTo = $frequencyRulesRepo->getAppliedFrequencyRules('sms', $leadIds, null, $defaultFrequencyNumber, $defaultFrequencyTime);
     if (!empty($dontSendTo) and $dontSendTo[0]['lead_id'] != $lead->getId()) {
         $metadata = $this->smsApi->sendSms($leadPhoneNumber, $smsEvent->getContent());
     }
     // If there was a problem sending at this point, it's an API problem and should be requeued
     if ($metadata === false) {
         return $event->setResult(false);
     }
     $this->smsModel->createStatEntry($sms, $lead);
     $this->smsModel->getRepository()->upCount($smsId);
     $event->setChannel('sms', $sms->getId());
     $event->setResult(['type' => 'mautic.sms.sms', 'status' => 'mautic.sms.timeline.status.delivered', 'id' => $sms->getId(), 'name' => $sms->getName(), 'content' => $tokenEvent->getContent()]);
 }
Example #8
0
 public function unsubscribe($number)
 {
     $number = $this->phoneNumberHelper->format($number, PhoneNumberFormat::E164);
     /** @var \Mautic\LeadBundle\Entity\LeadRepository $repo */
     $repo = $this->em->getRepository('MauticLeadBundle:Lead');
     $args = ['filter' => ['force' => [['column' => 'mobile', 'expr' => 'eq', 'value' => $number]]]];
     $leads = $repo->getEntities($args);
     if (!empty($leads)) {
         $lead = array_shift($leads);
     } else {
         // Try to find the lead based on the given phone number
         $args['filter']['force'][0]['column'] = 'phone';
         $leads = $repo->getEntities($args);
         if (!empty($leads)) {
             $lead = array_shift($leads);
         } else {
             return false;
         }
     }
     return $this->leadModel->addDncForLead($lead, 'sms', null, DoNotContact::UNSUBSCRIBED);
 }
Example #9
0
 /**
  * @param CampaignExecutionEvent $event
  */
 public function onCampaignTriggerAction(CampaignExecutionEvent $event)
 {
     $lead = $event->getLead();
     if ($this->leadModel->isContactable($lead, 'notification') !== DoNotContact::IS_CONTACTABLE) {
         return $event->setFailed('mautic.notification.campaign.failed.not_contactable');
     }
     // If lead has subscribed on multiple devices, get all of them.
     /** @var \Mautic\NotificationBundle\Entity\PushID[] $pushIDs */
     $pushIDs = $lead->getPushIDs();
     $playerID = [];
     foreach ($pushIDs as $pushID) {
         $playerID[] = $pushID->getPushID();
     }
     if (empty($playerID)) {
         return $event->setFailed('mautic.notification.campaign.failed.not_subscribed');
     }
     $notificationId = (int) $event->getConfig()['notification'];
     /** @var \Mautic\NotificationBundle\Entity\Notification $notification */
     $notification = $this->notificationModel->getEntity($notificationId);
     if ($notification->getId() !== $notificationId) {
         return $event->setFailed('mautic.notification.campaign.failed.missing_entity');
     }
     if ($url = $notification->getUrl()) {
         $url = $this->notificationApi->convertToTrackedUrl($url, ['notification' => $notification->getId(), 'lead' => $lead->getId()]);
     }
     $tokenEvent = $this->dispatcher->dispatch(NotificationEvents::TOKEN_REPLACEMENT, new TokenReplacementEvent($notification->getMessage(), $lead, ['channel' => ['notification', $notification->getId()]]));
     $sendEvent = $this->dispatcher->dispatch(NotificationEvents::NOTIFICATION_ON_SEND, new NotificationSendEvent($tokenEvent->getContent(), $notification->getHeading(), $lead));
     $response = $this->notificationApi->sendNotification($playerID, $sendEvent->getMessage(), $sendEvent->getHeading(), $url);
     $event->setChannel('notification', $notification->getId());
     // If for some reason the call failed, tell mautic to try again by return false
     if ($response->code !== 200) {
         return $event->setResult(false);
     }
     $this->notificationModel->createStatEntry($notification, $lead);
     $this->notificationModel->getRepository()->upCount($notificationId);
     $result = ['status' => 'mautic.notification.timeline.status.delivered', 'type' => 'mautic.notification.notification', 'id' => $notification->getId(), 'name' => $notification->getName(), 'heading' => $event->getHeading(), 'content' => $event->getMessage()];
     $event->setResult($result);
 }
Example #10
0
 /**
  * Gets the campaigns a specific lead is part of
  *
  * @param Lead $lead
  * @param bool $forList
  *
  * @return mixed
  */
 public function getLeadCampaigns(Lead $lead = null, $forList = false)
 {
     static $campaigns = array();
     if ($lead === null) {
         $lead = $this->leadModel->getCurrentLead();
     }
     if (!isset($campaigns[$lead->getId()])) {
         $repo = $this->getRepository();
         $leadId = $lead->getId();
         //get the campaigns the lead is currently part of
         $campaigns[$leadId] = $repo->getPublishedCampaigns(null, $lead->getId(), $forList);
     }
     return $campaigns[$lead->getId()];
 }
Example #11
0
 /**
  * @param        $email
  * @param int    $reason
  * @param string $comments
  * @param bool   $flush
  * @param null   $leadId
  *
  * @return array
  */
 public function setEmailDoNotContact($email, $reason = DoNotContact::BOUNCED, $comments = '', $flush = true, $leadId = null)
 {
     /** @var \Mautic\LeadBundle\Entity\LeadRepository $leadRepo */
     $leadRepo = $this->em->getRepository('MauticLeadBundle:Lead');
     if (null === $leadId) {
         $leadId = (array) $leadRepo->getLeadByEmail($email, true);
     } elseif (!is_array($leadId)) {
         $leadId = [$leadId];
     }
     $dnc = [];
     foreach ($leadId as $lead) {
         $dnc[] = $this->leadModel->addDncForLead($this->em->getReference('MauticLeadBundle:Lead', $lead), 'email', $comments, $reason, $flush);
     }
     return $dnc;
 }
Example #12
0
 /**
  * Triggers a specific event
  *
  * @param array   $event
  * @param Lead    $lead
  * @param bool    $force
  *
  * @return bool Was event triggered
  */
 public function triggerEvent($event, Lead $lead = null, $force = false)
 {
     //only trigger events for anonymous users
     if (!$force && !$this->security->isAnonymous()) {
         return false;
     }
     if ($lead == null) {
         $lead = $this->leadModel->getCurrentLead();
     }
     if (!$force) {
         //get a list of events that has already been performed on this lead
         $appliedEvents = $this->getEventRepository()->getLeadTriggeredEvents($lead->getId());
         //if it's already been done, then skip it
         if (isset($appliedEvents[$event['id']])) {
             return false;
         }
     }
     $availableEvents = $this->getEvents();
     $eventType = $event['type'];
     //make sure the event still exists
     if (!isset($availableEvents[$eventType])) {
         return false;
     }
     $settings = $availableEvents[$eventType];
     $args = array('event' => $event, 'lead' => $lead, 'factory' => $this->factory, 'config' => $event['properties']);
     if (is_callable($settings['callback'])) {
         if (is_array($settings['callback'])) {
             $reflection = new \ReflectionMethod($settings['callback'][0], $settings['callback'][1]);
         } elseif (strpos($settings['callback'], '::') !== false) {
             $parts = explode('::', $settings['callback']);
             $reflection = new \ReflectionMethod($parts[0], $parts[1]);
         } else {
             $reflection = new \ReflectionMethod(null, $settings['callback']);
         }
         $pass = array();
         foreach ($reflection->getParameters() as $param) {
             if (isset($args[$param->getName()])) {
                 $pass[] = $args[$param->getName()];
             } else {
                 $pass[] = null;
             }
         }
         return $reflection->invokeArgs($this, $pass);
     }
     return false;
 }
Example #13
0
 /**
  * @param Form $form
  * @param      $formHtml
  */
 public function populateValuesWithLead(Form $form, &$formHtml)
 {
     $formName = $form->generateFormName();
     $lead = $this->leadModel->getCurrentLead();
     $fields = $form->getFields();
     /** @var \Mautic\FormBundle\Entity\Field $f */
     foreach ($fields as $f) {
         $leadField = $f->getLeadField();
         $isAutoFill = $f->getIsAutoFill();
         if (isset($leadField) && $isAutoFill) {
             $value = $lead->getFieldValue($leadField);
             if (!empty($value)) {
                 $this->fieldHelper->populateField($f, $value, $formName, $formHtml);
             }
         }
     }
 }
Example #14
0
 /**
  * Generate the form's html
  *
  * @param Form $entity
  * @param bool $persist
  *
  * @return string
  */
 public function generateHtml(Form $entity, $persist = true)
 {
     //generate cached HTML
     $theme = $entity->getTemplate();
     $submissions = null;
     $lead = $this->leadModel->getCurrentLead();
     if (!empty($theme)) {
         $theme .= '|';
     }
     if ($entity->usesProgressiveProfiling()) {
         $submissions = $this->getRepository()->getFormResults($entity, ['leadId' => $lead->getId(), 'limit' => 200]);
     }
     $html = $this->templatingHelper->getTemplating()->render($theme . 'MauticFormBundle:Builder:form.html.php', ['form' => $entity, 'theme' => $theme, 'submissions' => $submissions, 'lead' => $lead]);
     if (!$entity->usesProgressiveProfiling()) {
         $entity->setCachedHtml($html);
         if ($persist) {
             //bypass model function as events aren't needed for this
             $this->getRepository()->saveEntity($entity);
         }
     }
     return $html;
 }
Example #15
0
 /**
  * @param Request $request
  * @param string  $code
  *
  * @throws \Doctrine\ORM\ORMException
  * @throws \Exception
  */
 public function hitVideo($request, $code = '200')
 {
     //don't skew results with in-house hits
     if (!$this->security->isAnonymous()) {
         //return;
     }
     $lead = $this->leadModel->getCurrentLead();
     $guid = $request->get('guid');
     $hit = $this->getHitForLeadByGuid($lead, $guid);
     $hit->setGuid($guid);
     $hit->setDateHit(new \Datetime());
     $hit->setDuration($request->get('duration'));
     $hit->setUrl($request->get('url'));
     $hit->setTimeWatched($request->get('total_watched'));
     //check for existing IP
     $ipAddress = $this->ipLookupHelper->getIpAddress();
     $hit->setIpAddress($ipAddress);
     // Store query array
     $query = $request->query->all();
     unset($query['d']);
     $hit->setQuery($query);
     $hit->setLead($lead);
     //glean info from the IP address
     if ($details = $ipAddress->getIpDetails()) {
         $hit->setCountry($details['country']);
         $hit->setRegion($details['region']);
         $hit->setCity($details['city']);
         $hit->setIsp($details['isp']);
         $hit->setOrganization($details['organization']);
     }
     $hit->setCode($code);
     if (!$hit->getReferer()) {
         $hit->setReferer($request->server->get('HTTP_REFERER'));
     }
     $hit->setUserAgent($request->server->get('HTTP_USER_AGENT'));
     $hit->setRemoteHost($request->server->get('REMOTE_HOST'));
     //get a list of the languages the user prefers
     $browserLanguages = $request->server->get('HTTP_ACCEPT_LANGUAGE');
     if (!empty($browserLanguages)) {
         $languages = explode(',', $browserLanguages);
         foreach ($languages as $k => $l) {
             if ($pos = strpos(';q=', $l) !== false) {
                 //remove weights
                 $languages[$k] = substr($l, 0, $pos);
             }
         }
         $hit->setBrowserLanguages($languages);
     }
     // Wrap in a try/catch to prevent deadlock errors on busy servers
     try {
         $this->em->persist($hit);
         $this->em->flush($hit);
     } catch (\Exception $exception) {
         if (MAUTIC_ENV === 'dev') {
             throw $exception;
         } else {
             $this->logger->addError($exception->getMessage(), ['exception' => $exception]);
         }
     }
     if ($this->dispatcher->hasListeners(PageEvents::VIDEO_ON_HIT)) {
         $event = new VideoHitEvent($hit, $request, $code);
         $this->dispatcher->dispatch(PageEvents::VIDEO_ON_HIT, $event);
     }
 }
Example #16
0
 /**
  * Initialize the QueryBuilder object to generate reports from.
  *
  * @param ReportGraphEvent $event
  */
 public function onReportGraphGenerate(ReportGraphEvent $event)
 {
     // Context check, we only want to fire for Lead reports
     if (!$event->checkContext(['leads', 'lead.pointlog', 'contact.attribution.multi'])) {
         return;
     }
     $graphs = $event->getRequestedGraphs();
     $qb = $event->getQueryBuilder();
     $pointLogRepo = $this->leadModel->getPointLogRepository();
     foreach ($graphs as $g) {
         $queryBuilder = clone $qb;
         $options = $event->getOptions($g);
         /** @var ChartQuery $chartQuery */
         $chartQuery = clone $options['chartQuery'];
         $attributionQb = clone $queryBuilder;
         $chartQuery->applyDateFilters($queryBuilder, 'date_added', 'l');
         switch ($g) {
             case 'mautic.lead.graph.pie.attribution_stages':
             case 'mautic.lead.graph.pie.attribution_campaigns':
             case 'mautic.lead.graph.pie.attribution_actions':
             case 'mautic.lead.graph.pie.attribution_channels':
                 $attributionQb->resetQueryParts(['select', 'orderBy']);
                 $outerQb = clone $attributionQb;
                 $outerQb->resetQueryParts()->select('slice, sum(contact_attribution) as total_attribution')->groupBy('slice');
                 $groupBy = str_replace('mautic.lead.graph.pie.attribution_', '', $g);
                 switch ($groupBy) {
                     case 'stages':
                         $attributionQb->select('CONCAT_WS(\':\', s.id, s.name) as slice, l.attribution as contact_attribution')->groupBy('l.id, s.id');
                         break;
                     case 'campaigns':
                         $attributionQb->select('CONCAT_WS(\':\', c.id, c.name) as slice, l.attribution as contact_attribution')->groupBy('l.id, c.id');
                         break;
                     case 'actions':
                         $attributionQb->select('SUBSTRING_INDEX(e.type, \'.\', -1) as slice, l.attribution as contact_attribution')->groupBy('l.id, SUBSTRING_INDEX(e.type, \'.\', -1)');
                         break;
                     case 'channels':
                         $attributionQb->select('SUBSTRING_INDEX(e.type, \'.\', 1) as slice, l.attribution as contact_attribution')->groupBy('l.id, SUBSTRING_INDEX(e.type, \'.\', 1)');
                         break;
                 }
                 $outerQb->from(sprintf('(%s) subq', $attributionQb->getSQL()));
                 $outerQb->setParameters($attributionQb->getParameters());
                 $chart = new PieChart();
                 $data = $outerQb->execute()->fetchAll();
                 foreach ($data as $row) {
                     switch ($groupBy) {
                         case 'actions':
                             $label = $this->channelActions[$row['slice']];
                             break;
                         case 'channels':
                             $label = $this->channels[$row['slice']];
                             break;
                         default:
                             $label = empty($row['slice']) ? $this->translator->trans('mautic.core.none') : $row['slice'];
                     }
                     $chart->setDataset($label, $row['total_attribution']);
                 }
                 $event->setGraph($g, ['data' => $chart->render(), 'name' => $g, 'iconClass' => 'fa-dollar']);
                 break;
             case 'mautic.lead.graph.line.leads':
                 $chart = new LineChart(null, $options['dateFrom'], $options['dateTo']);
                 $chartQuery->modifyTimeDataQuery($queryBuilder, 'date_added', 'l');
                 $leads = $chartQuery->loadAndBuildTimeData($queryBuilder);
                 $chart->setDataset($options['translator']->trans('mautic.lead.all.leads'), $leads);
                 $queryBuilder->andwhere($qb->expr()->isNotNull('l.date_identified'));
                 $identified = $chartQuery->loadAndBuildTimeData($queryBuilder);
                 $chart->setDataset($options['translator']->trans('mautic.lead.identified'), $identified);
                 $data = $chart->render();
                 $data['name'] = $g;
                 $event->setGraph($g, $data);
                 break;
             case 'mautic.lead.graph.line.points':
                 $chart = new LineChart(null, $options['dateFrom'], $options['dateTo']);
                 $chartQuery->modifyTimeDataQuery($queryBuilder, 'date_added', 'lp');
                 $leads = $chartQuery->loadAndBuildTimeData($queryBuilder);
                 $chart->setDataset($options['translator']->trans('mautic.lead.graph.line.points'), $leads);
                 $data = $chart->render();
                 $data['name'] = $g;
                 $event->setGraph($g, $data);
                 break;
             case 'mautic.lead.table.most.points':
                 $queryBuilder->select('l.id, l.email as title, sum(lp.delta) as points')->groupBy('l.id, l.email')->orderBy('points', 'DESC');
                 $limit = 10;
                 $offset = 0;
                 $items = $pointLogRepo->getMostPoints($queryBuilder, $limit, $offset);
                 $graphData = [];
                 $graphData['data'] = $items;
                 $graphData['name'] = $g;
                 $graphData['iconClass'] = 'fa-asterisk';
                 $graphData['link'] = 'mautic_contact_action';
                 $event->setGraph($g, $graphData);
                 break;
             case 'mautic.lead.table.top.countries':
                 $queryBuilder->select('l.country as title, count(l.country) as quantity')->groupBy('l.country')->orderBy('quantity', 'DESC');
                 $limit = 10;
                 $offset = 0;
                 $items = $pointLogRepo->getMostLeads($queryBuilder, $limit, $offset);
                 $graphData = [];
                 $graphData['data'] = $items;
                 $graphData['name'] = $g;
                 $graphData['iconClass'] = 'fa-globe';
                 $event->setGraph($g, $graphData);
                 break;
             case 'mautic.lead.table.top.cities':
                 $queryBuilder->select('l.city as title, count(l.city) as quantity')->groupBy('l.city')->orderBy('quantity', 'DESC');
                 $limit = 10;
                 $offset = 0;
                 $items = $pointLogRepo->getMostLeads($queryBuilder, $limit, $offset);
                 $graphData = [];
                 $graphData['data'] = $items;
                 $graphData['name'] = $g;
                 $graphData['iconClass'] = 'fa-university';
                 $event->setGraph($g, $graphData);
                 break;
             case 'mautic.lead.table.top.events':
                 $queryBuilder->select('lp.event_name as title, count(lp.event_name) as events')->groupBy('lp.event_name')->orderBy('events', 'DESC');
                 $limit = 10;
                 $offset = 0;
                 $items = $pointLogRepo->getMostPoints($queryBuilder, $limit, $offset);
                 $graphData = [];
                 $graphData['data'] = $items;
                 $graphData['name'] = $g;
                 $graphData['iconClass'] = 'fa-calendar';
                 $event->setGraph($g, $graphData);
                 break;
             case 'mautic.lead.table.top.actions':
                 $queryBuilder->select('lp.action_name as title, count(lp.action_name) as actions')->groupBy('lp.action_name')->orderBy('actions', 'DESC');
                 $limit = 10;
                 $offset = 0;
                 $items = $pointLogRepo->getMostPoints($queryBuilder, $limit, $offset);
                 $graphData = [];
                 $graphData['data'] = $items;
                 $graphData['name'] = $g;
                 $graphData['iconClass'] = 'fa-bolt';
                 $event->setGraph($g, $graphData);
                 break;
         }
         unset($queryBuilder);
     }
 }
Example #17
0
 /**
  * @param MauticEvents\CommandListEvent $event
  */
 public function onBuildCommandList(MauticEvents\CommandListEvent $event)
 {
     if ($this->security->isGranted(['lead:leads:viewown', 'lead:leads:viewother'], 'MATCH_ONE')) {
         $event->addCommands('mautic.lead.leads', $this->leadModel->getCommandList());
     }
 }
Example #18
0
 /**
  * @param $queue
  *
  * @return int
  */
 public function processMessageQueue($queue)
 {
     if (!is_array($queue)) {
         if (!$queue instanceof MessageQueue) {
             throw new \InvalidArgumentException('$queue must be an instance of ' . MessageQueue::class);
         }
         $queue = [$queue->getId() => $queue];
     }
     $counter = 0;
     $contacts = [];
     $byChannel = [];
     // Lead entities will not have profile fields populated due to the custom field use - therefore to optimize resources,
     // get a list of leads to fetch details all at once along with company details for dynamic email content, etc
     /** @var MessageQueue $message */
     foreach ($queue as $message) {
         $contacts[$message->getId()] = $message->getLead()->getId();
     }
     $contactData = $this->leadModel->getRepository()->getContacts($contacts);
     $companyData = $this->companyModel->getRepository()->getCompaniesForContacts($contacts);
     foreach ($contacts as $messageId => $contactId) {
         $contactData[$contactId]['companies'] = $companyData[$contactId];
         $queue[$messageId]->getLead()->setFields($contactData[$contactId]);
     }
     // Group queue by channel and channel ID - this make it possible for processing listeners to batch process such as
     // sending emails in batches to 3rd party transactional services via HTTP APIs
     foreach ($queue as $key => $message) {
         if (MessageQueue::STATUS_SENT == $message->getStatus()) {
             unset($queue[$key]);
             continue;
         }
         $messageChannel = $message->getChannel();
         $messageChannelId = $message->getChannelId();
         if (!$messageChannelId) {
             $messageChannelId = 0;
         }
         if (!isset($byChannel[$messageChannel])) {
             $byChannel[$messageChannel] = [];
         }
         if (!isset($byChannel[$messageChannel][$messageChannelId])) {
             $byChannel[$messageChannel][$messageChannelId] = [];
         }
         $byChannel[$messageChannel][$messageChannelId][] = $message;
     }
     // First try to batch process each channel
     foreach ($byChannel as $messageChannel => $channelMessages) {
         foreach ($channelMessages as $messageChannelId => $messages) {
             $event = new MessageQueueBatchProcessEvent($messages, $messageChannel, $messageChannelId);
             $ignore = null;
             $this->dispatchEvent('process_batch_message_queue', $ignore, false, $event);
         }
     }
     unset($byChannel);
     // Now check to see if the message was processed by the listener and if not
     // send it through a single process event listener
     foreach ($queue as $message) {
         if (!$message->isProcessed()) {
             $event = new MessageQueueProcessEvent($message);
             $this->dispatchEvent('process_message_queue', $message, false, $event);
         }
         if ($message->isSuccess()) {
             ++$counter;
             $message->setSuccess();
             $message->setLastAttempt(new \DateTime());
             $message->setDateSent(new \DateTime());
             $message->setStatus(MessageQueue::STATUS_SENT);
         } elseif ($message->isFailed()) {
             // Failure such as email delivery issue or something so retry in a short time
             $this->rescheduleMessage($message, '15M');
         }
         // otherwise assume the listener did something such as rescheduling the message
     }
     //add listener
     $this->saveEntities($queue);
     return $counter;
 }
Example #19
0
 /**
  * Create/update lead from form submit.
  *
  * @param       $form
  * @param array $leadFieldMatches
  *
  * @return Lead
  */
 protected function createLeadFromSubmit($form, array $leadFieldMatches, $leadFields)
 {
     //set the mapped data
     $inKioskMode = $form->isInKioskMode();
     if (!$inKioskMode) {
         // Default to currently tracked lead
         $lead = $this->leadModel->getCurrentLead();
         $leadId = $lead->getId();
         $currentFields = $this->leadModel->flattenFields($lead->getFields());
         $this->logger->debug('FORM: Not in kiosk mode so using current contact ID #' . $lead->getId());
     } else {
         // Default to a new lead in kiosk mode
         $lead = new Lead();
         $lead->setNewlyCreated(true);
         $currentFields = $leadFieldMatches;
         $leadId = null;
         $this->logger->debug('FORM: In kiosk mode so assuming a new contact');
     }
     $uniqueLeadFields = $this->leadFieldModel->getUniqueIdentiferFields();
     // Closure to get data and unique fields
     $getData = function ($currentFields, $uniqueOnly = false) use($leadFields, $uniqueLeadFields) {
         $uniqueFieldsWithData = $data = [];
         foreach ($leadFields as $alias => $properties) {
             $data[$alias] = '';
             if (isset($currentFields[$alias])) {
                 $value = $currentFields[$alias];
                 $data[$alias] = $value;
                 // make sure the value is actually there and the field is one of our uniques
                 if (!empty($value) && array_key_exists($alias, $uniqueLeadFields)) {
                     $uniqueFieldsWithData[$alias] = $value;
                 }
             }
         }
         return $uniqueOnly ? $uniqueFieldsWithData : [$data, $uniqueFieldsWithData];
     };
     // Closure to help search for a conflict
     $checkForIdentifierConflict = function ($fieldSet1, $fieldSet2) {
         // Find fields in both sets
         $potentialConflicts = array_keys(array_intersect_key($fieldSet1, $fieldSet2));
         $this->logger->debug('FORM: Potential conflicts ' . implode(', ', array_keys($potentialConflicts)) . ' = ' . implode(', ', $potentialConflicts));
         $conflicts = [];
         foreach ($potentialConflicts as $field) {
             if (!empty($fieldSet1[$field]) && !empty($fieldSet2[$field])) {
                 if (strtolower($fieldSet1[$field]) !== strtolower($fieldSet2[$field])) {
                     $conflicts[] = $field;
                 }
             }
         }
         return [count($conflicts), $conflicts];
     };
     // Get data for the form submission
     list($data, $uniqueFieldsWithData) = $getData($leadFieldMatches);
     $this->logger->debug('FORM: Unique fields submitted include ' . implode(', ', $uniqueFieldsWithData));
     // Check for duplicate lead
     /** @var \Mautic\LeadBundle\Entity\Lead[] $leads */
     $leads = !empty($uniqueFieldsWithData) ? $this->em->getRepository('MauticLeadBundle:Lead')->getLeadsByUniqueFields($uniqueFieldsWithData, $leadId) : [];
     $uniqueFieldsCurrent = $getData($currentFields, true);
     if (count($leads)) {
         $this->logger->debug(count($leads) . ' found based on unique identifiers');
         /** @var \Mautic\LeadBundle\Entity\Lead $foundLead */
         $foundLead = $leads[0];
         $this->logger->debug('FORM: Testing contact ID# ' . $foundLead->getId() . ' for conflicts');
         // Check for a conflict with the currently tracked lead
         $foundLeadFields = $this->leadModel->flattenFields($foundLead->getFields());
         // Get unique identifier fields for the found lead then compare with the lead currently tracked
         $uniqueFieldsFound = $getData($foundLeadFields, true);
         list($hasConflict, $conflicts) = $checkForIdentifierConflict($uniqueFieldsFound, $uniqueFieldsCurrent);
         if ($inKioskMode || $hasConflict) {
             // Use the found lead without merging because there is some sort of conflict with unique identifiers or in kiosk mode and thus should not merge
             $lead = $foundLead;
             if ($hasConflict) {
                 $this->logger->debug('FORM: Conflicts found in ' . implode(', ', $conflicts) . ' so not merging');
             } else {
                 $this->logger->debug('FORM: In kiosk mode so not merging');
             }
         } else {
             $this->logger->debug('FORM: Merging contacts ' . $lead->getId() . ' and ' . $foundLead->getId());
             // Merge the found lead with currently tracked lead
             $lead = $this->leadModel->mergeLeads($lead, $foundLead);
         }
         // Update unique fields data for comparison with submitted data
         $currentFields = $this->leadModel->flattenFields($lead->getFields());
         $uniqueFieldsCurrent = $getData($currentFields, true);
     }
     if (!$inKioskMode) {
         // Check for conflicts with the submitted data and the currently tracked lead
         list($hasConflict, $conflicts) = $checkForIdentifierConflict($uniqueFieldsWithData, $uniqueFieldsCurrent);
         $this->logger->debug('FORM: Current unique contact fields ' . implode(', ', array_keys($uniqueFieldsCurrent)) . ' = ' . implode(', ', $uniqueFieldsCurrent));
         $this->logger->debug('FORM: Submitted unique contact fields ' . implode(', ', array_keys($uniqueFieldsWithData)) . ' = ' . implode(', ', $uniqueFieldsWithData));
         if ($hasConflict) {
             // There's a conflict so create a new lead
             $lead = new Lead();
             $lead->setNewlyCreated(true);
             $this->logger->debug('FORM: Conflicts found in ' . implode(', ', $conflicts) . ' between current tracked contact and submitted data so assuming a new contact');
         }
     }
     //check for existing IP address
     $ipAddress = $this->ipLookupHelper->getIpAddress();
     //no lead was found by a mapped email field so create a new one
     if ($lead->isNewlyCreated()) {
         if (!$inKioskMode) {
             $lead->addIpAddress($ipAddress);
             $this->logger->debug('FORM: Associating ' . $ipAddress->getIpAddress() . ' to contact');
         }
     } elseif (!$inKioskMode) {
         $leadIpAddresses = $lead->getIpAddresses();
         if (!$leadIpAddresses->contains($ipAddress)) {
             $lead->addIpAddress($ipAddress);
             $this->logger->debug('FORM: Associating ' . $ipAddress->getIpAddress() . ' to contact');
         }
     }
     //set the mapped fields
     $this->leadModel->setFieldValues($lead, $data, false);
     if (!empty($event)) {
         $event->setIpAddress($ipAddress);
         $lead->addPointsChangeLog($event);
     }
     // last active time
     $lead->setLastActive(new \DateTime());
     //create a new lead
     $this->leadModel->saveEntity($lead, false);
     if (!$inKioskMode) {
         // Set the current lead which will generate tracking cookies
         $this->leadModel->setCurrentLead($lead);
     } else {
         // Set system current lead which will still allow execution of events without generating tracking cookies
         $this->leadModel->setSystemCurrentLead($lead);
     }
     return $lead;
 }
Example #20
0
 /**
  * Triggers a specific point change
  *
  * @param $type
  * @param mixed $eventDetails passthrough from function triggering action to the callback function
  * @param mixed $typeId Something unique to the triggering event to prevent  unnecessary duplicate calls
  * @param Lead  $lead
  *25
  * @return void
  */
 public function triggerAction($type, $eventDetails = null, $typeId = null, Lead $lead = null)
 {
     //only trigger actions for anonymous users
     if (!$this->security->isAnonymous()) {
         return;
     }
     if ($typeId !== null && MAUTIC_ENV === 'prod') {
         //let's prevent some unnecessary DB calls
         $triggeredEvents = $this->session->get('mautic.triggered.point.actions', array());
         if (in_array($typeId, $triggeredEvents)) {
             return;
         }
         $triggeredEvents[] = $typeId;
         $this->session->set('mautic.triggered.point.actions', $triggeredEvents);
     }
     //find all the actions for published points
     /** @var \Mautic\PointBundle\Entity\PointRepository $repo */
     $repo = $this->getRepository();
     $availablePoints = $repo->getPublishedByType($type);
     $ipAddress = $this->ipLookupHelper->getIpAddress();
     if (null === $lead) {
         $lead = $this->leadModel->getCurrentLead();
         if (null === $lead || !$lead->getId()) {
             return;
         }
     }
     //get available actions
     $availableActions = $this->getPointActions();
     //get a list of actions that has already been performed on this lead
     $completedActions = $repo->getCompletedLeadActions($type, $lead->getId());
     $persist = array();
     foreach ($availablePoints as $action) {
         //if it's already been done, then skip it
         if (isset($completedActions[$action->getId()])) {
             continue;
         }
         //make sure the action still exists
         if (!isset($availableActions['actions'][$action->getType()])) {
             continue;
         }
         $settings = $availableActions['actions'][$action->getType()];
         $args = array('action' => array('id' => $action->getId(), 'type' => $action->getType(), 'name' => $action->getName(), 'properties' => $action->getProperties(), 'points' => $action->getDelta()), 'lead' => $lead, 'factory' => $this->factory, 'eventDetails' => $eventDetails);
         $callback = isset($settings['callback']) ? $settings['callback'] : array('\\Mautic\\PointBundle\\Helper\\EventHelper', 'engagePointAction');
         if (is_callable($callback)) {
             if (is_array($callback)) {
                 $reflection = new \ReflectionMethod($callback[0], $callback[1]);
             } elseif (strpos($callback, '::') !== false) {
                 $parts = explode('::', $callback);
                 $reflection = new \ReflectionMethod($parts[0], $parts[1]);
             } else {
                 $reflection = new \ReflectionMethod(null, $callback);
             }
             $pass = array();
             foreach ($reflection->getParameters() as $param) {
                 if (isset($args[$param->getName()])) {
                     $pass[] = $args[$param->getName()];
                 } else {
                     $pass[] = null;
                 }
             }
             $pointsChange = $reflection->invokeArgs($this, $pass);
             if ($pointsChange) {
                 $delta = $action->getDelta();
                 $lead->adjustPoints($delta);
                 $parsed = explode('.', $action->getType());
                 $lead->addPointsChangeLogEntry($parsed[0], $action->getId() . ": " . $action->getName(), $parsed[1], $delta, $ipAddress);
                 $event = new PointActionEvent($action, $lead);
                 $this->dispatcher->dispatch(PointEvents::POINT_ON_ACTION, $event);
                 $log = new LeadPointLog();
                 $log->setIpAddress($ipAddress);
                 $log->setPoint($action);
                 $log->setLead($lead);
                 $log->setDateFired(new \DateTime());
                 $persist[] = $log;
             }
         }
     }
     if (!empty($persist)) {
         $this->leadModel->saveEntity($lead);
         $this->getRepository()->saveEntities($persist);
         // Detach logs to reserve memory
         $this->em->clear('Mautic\\PointBundle\\Entity\\LeadPointLog');
     }
 }
Example #21
0
 /**
  * Record page hit.
  *
  * @param           $page
  * @param Request   $request
  * @param string    $code
  * @param Lead|null $lead
  * @param array     $query
  *
  * @return Hit $hit
  *
  * @throws \Exception
  */
 public function hitPage($page, Request $request, $code = '200', Lead $lead = null, $query = [])
 {
     // Don't skew results with user hits
     if (!$this->security->isAnonymous()) {
         return;
     }
     // Process the query
     if (empty($query)) {
         $query = $this->getHitQuery($request, $page);
     }
     $hit = new Hit();
     $hit->setDateHit(new \Datetime());
     // Check for existing IP
     $ipAddress = $this->ipLookupHelper->getIpAddress();
     $hit->setIpAddress($ipAddress);
     // Check for any clickthrough info
     $clickthrough = [];
     if (!empty($query['ct'])) {
         $clickthrough = $query['ct'];
         if (!is_array($clickthrough)) {
             $clickthrough = $this->decodeArrayFromUrl($clickthrough);
         }
         if (!empty($clickthrough['channel'])) {
             if (count($clickthrough['channel']) === 1) {
                 $channelId = reset($clickthrough['channel']);
                 $channel = key($clickthrough['channel']);
             } else {
                 $channel = $clickthrough['channel'][0];
                 $channelId = (int) $clickthrough['channel'][1];
             }
             $hit->setSource($channel);
             $hit->setSourceId($channelId);
         } elseif (!empty($clickthrough['source'])) {
             $hit->setSource($clickthrough['source'][0]);
             $hit->setSourceId($clickthrough['source'][1]);
         }
         if (!empty($clickthrough['email'])) {
             $emailRepo = $this->em->getRepository('MauticEmailBundle:Email');
             if ($emailEntity = $emailRepo->getEntity($clickthrough['email'])) {
                 $hit->setEmail($emailEntity);
             }
         }
     }
     // Get lead if required
     if (null == $lead) {
         $lead = $this->leadModel->getContactFromRequest($query);
     }
     $this->leadModel->saveEntity($lead);
     // Set info from request
     $hit->setQuery($query);
     $hit->setUrl(isset($query['page_url']) ? $query['page_url'] : $request->getRequestUri());
     if (isset($query['page_referrer'])) {
         $hit->setReferer($query['page_referrer']);
     }
     if (isset($query['page_language'])) {
         $hit->setPageLanguage($query['page_language']);
     }
     if (isset($query['page_title'])) {
         $hit->setUrlTitle($query['page_title']);
     }
     // Store tracking ID
     list($trackingId, $trackingNewlyGenerated) = $this->leadModel->getTrackingCookie();
     $hit->setTrackingId($trackingId);
     $hit->setLead($lead);
     $isUnique = $trackingNewlyGenerated;
     if (!$trackingNewlyGenerated) {
         $lastHit = $request->cookies->get('mautic_referer_id');
         if (!empty($lastHit)) {
             //this is not a new session so update the last hit if applicable with the date/time the user left
             $this->getHitRepository()->updateHitDateLeft($lastHit);
         }
         // Check if this is a unique page hit
         $isUnique = $this->getHitRepository()->isUniquePageHit($page, $trackingId);
     }
     if (!empty($page)) {
         if ($page instanceof Page) {
             $hit->setPage($page);
             $hit->setPageLanguage($page->getLanguage());
             $isVariant = $isUnique ? $page->getVariantStartDate() : false;
             try {
                 $this->getRepository()->upHitCount($page->getId(), 1, $isUnique, !empty($isVariant));
             } catch (\Exception $exception) {
                 $this->logger->addError($exception->getMessage(), ['exception' => $exception]);
             }
         } elseif ($page instanceof Redirect) {
             $hit->setRedirect($page);
             try {
                 $this->pageRedirectModel->getRepository()->upHitCount($page->getId(), 1, $isUnique);
                 // If this is a trackable, up the trackable counts as well
                 if (!empty($clickthrough['channel'])) {
                     $channelId = reset($clickthrough['channel']);
                     $channel = key($clickthrough['channel']);
                     $this->pageTrackableModel->getRepository()->upHitCount($page->getId(), $channel, $channelId, 1, $isUnique);
                 }
             } catch (\Exception $exception) {
                 if (MAUTIC_ENV === 'dev') {
                     throw $exception;
                 } else {
                     $this->logger->addError($exception->getMessage(), ['exception' => $exception]);
                 }
             }
         }
     }
     //glean info from the IP address
     if ($details = $ipAddress->getIpDetails()) {
         $hit->setCountry($details['country']);
         $hit->setRegion($details['region']);
         $hit->setCity($details['city']);
         $hit->setIsp($details['isp']);
         $hit->setOrganization($details['organization']);
     }
     $hit->setCode($code);
     if (!$hit->getReferer()) {
         $hit->setReferer($request->server->get('HTTP_REFERER'));
     }
     $hit->setUserAgent($request->server->get('HTTP_USER_AGENT'));
     $hit->setRemoteHost($request->server->get('REMOTE_HOST'));
     if ($isUnique) {
         // Add UTM tags entry if a UTM tag exist
         $queryHasUtmTags = false;
         if (!is_array($query)) {
             parse_str($query, $query);
         }
         foreach ($query as $key => $value) {
             if (strpos($key, 'utm_') !== false) {
                 $queryHasUtmTags = true;
                 break;
             }
         }
         if ($queryHasUtmTags) {
             $utmTags = new UtmTag();
             $utmTags->setDateAdded($hit->getDateHit());
             $utmTags->setUrl($hit->getUrl());
             $utmTags->setReferer($hit->getReferer());
             $utmTags->setQuery($hit->getQuery());
             $utmTags->setUserAgent($hit->getUserAgent());
             $utmTags->setRemoteHost($hit->getRemoteHost());
             $utmTags->setLead($lead);
             if (key_exists('utm_campaign', $query)) {
                 $utmTags->setUtmCampaign($query['utm_campaign']);
             }
             if (key_exists('utm_term', $query)) {
                 $utmTags->setUtmTerm($query['utm_term']);
             }
             if (key_exists('utm_content', $query)) {
                 $utmTags->setUtmConent($query['utm_content']);
             }
             if (key_exists('utm_medium', $query)) {
                 $utmTags->setUtmMedium($query['utm_medium']);
             }
             if (key_exists('utm_source', $query)) {
                 $utmTags->setUtmSource($query['utm_source']);
             }
             $repo = $this->em->getRepository('MauticLeadBundle:UtmTag');
             $repo->saveEntity($utmTags);
             $this->leadModel->setUtmTags($lead, $utmTags);
         }
     }
     //get a list of the languages the user prefers
     $browserLanguages = $request->server->get('HTTP_ACCEPT_LANGUAGE');
     if (!empty($browserLanguages)) {
         $languages = explode(',', $browserLanguages);
         foreach ($languages as $k => $l) {
             if ($pos = strpos(';q=', $l) !== false) {
                 //remove weights
                 $languages[$k] = substr($l, 0, $pos);
             }
         }
         $hit->setBrowserLanguages($languages);
     }
     //device granularity
     $dd = new DeviceDetector($request->server->get('HTTP_USER_AGENT'));
     $dd->parse();
     $deviceRepo = $this->leadModel->getDeviceRepository();
     $device = $deviceRepo->getDevice(null, $lead, $dd->getDeviceName(), $dd->getBrand(), $dd->getModel());
     if (empty($device)) {
         $device = new LeadDevice();
         $device->setClientInfo($dd->getClient());
         $device->setDevice($dd->getDeviceName());
         $device->setDeviceBrand($dd->getBrand());
         $device->setDeviceModel($dd->getModel());
         $device->setDeviceOs($dd->getOs());
         $device->setDateOpen($hit->getDateHit());
         $device->setLead($lead);
         $this->em->persist($device);
     } else {
         $device = $deviceRepo->getEntity($device['id']);
     }
     $hit->setDeviceStat($device);
     // Wrap in a try/catch to prevent deadlock errors on busy servers
     try {
         $this->em->persist($hit);
         $this->em->flush($hit);
     } catch (\Exception $exception) {
         if (MAUTIC_ENV === 'dev') {
             throw $exception;
         } else {
             $this->logger->addError($exception->getMessage(), ['exception' => $exception]);
         }
     }
     if ($this->dispatcher->hasListeners(PageEvents::PAGE_ON_HIT)) {
         $event = new PageHitEvent($hit, $request, $code, $clickthrough, $isUnique);
         $this->dispatcher->dispatch(PageEvents::PAGE_ON_HIT, $event);
     }
     //save hit to the cookie to use to update the exit time
     $this->cookieHelper->setCookie('mautic_referer_id', $hit->getId());
     return $hit;
 }
Example #22
0
 /**
  * Set a widget detail when needed.
  *
  * @param WidgetDetailEvent $event
  */
 public function onWidgetDetailGenerate(WidgetDetailEvent $event)
 {
     $this->checkPermissions($event);
     $canViewOthers = $event->hasPermission('form:forms:viewother');
     if ($event->getType() == 'created.leads.in.time') {
         $widget = $event->getWidget();
         $params = $widget->getParams();
         if (isset($params['flag'])) {
             $params['filter']['flag'] = $params['flag'];
         }
         if (!$event->isCached()) {
             $event->setTemplateData(['chartType' => 'line', 'chartHeight' => $widget->getHeight() - 80, 'chartData' => $this->leadModel->getLeadsLineChartData($params['timeUnit'], $params['dateFrom'], $params['dateTo'], $params['dateFormat'], $params['filter'], $canViewOthers)]);
         }
         $event->setTemplate('MauticCoreBundle:Helper:chart.html.php');
         $event->stopPropagation();
         return;
     }
     if ($event->getType() == 'anonymous.vs.identified.leads') {
         if (!$event->isCached()) {
             $params = $event->getWidget()->getParams();
             $event->setTemplateData(['chartType' => 'pie', 'chartHeight' => $event->getWidget()->getHeight() - 80, 'chartData' => $this->leadModel->getAnonymousVsIdentifiedPieChartData($params['dateFrom'], $params['dateTo'], $canViewOthers)]);
         }
         $event->setTemplate('MauticCoreBundle:Helper:chart.html.php');
         $event->stopPropagation();
         return;
     }
     if ($event->getType() == 'map.of.leads') {
         if (!$event->isCached()) {
             $params = $event->getWidget()->getParams();
             $event->setTemplateData(['height' => $event->getWidget()->getHeight() - 80, 'data' => $this->leadModel->getLeadMapData($params['dateFrom'], $params['dateTo'], $canViewOthers)]);
         }
         $event->setTemplate('MauticCoreBundle:Helper:map.html.php');
         $event->stopPropagation();
         return;
     }
     if ($event->getType() == 'top.lists') {
         if (!$event->isCached()) {
             $params = $event->getWidget()->getParams();
             if (empty($params['limit'])) {
                 // Count the list limit from the widget height
                 $limit = round(($event->getWidget()->getHeight() - 80) / 35 - 1);
             } else {
                 $limit = $params['limit'];
             }
             $lists = $this->leadListModel->getTopLists($limit, $params['dateFrom'], $params['dateTo'], $canViewOthers);
             $items = [];
             // Build table rows with links
             if ($lists) {
                 foreach ($lists as &$list) {
                     $listUrl = $this->router->generate('mautic_segment_action', ['objectAction' => 'edit', 'objectId' => $list['id']]);
                     $row = [['value' => $list['name'], 'type' => 'link', 'link' => $listUrl], ['value' => $list['leads']]];
                     $items[] = $row;
                 }
             }
             $event->setTemplateData(['headItems' => [$event->getTranslator()->trans('mautic.dashboard.label.title'), $event->getTranslator()->trans('mautic.lead.leads')], 'bodyItems' => $items, 'raw' => $lists]);
         }
         $event->setTemplate('MauticCoreBundle:Helper:table.html.php');
         $event->stopPropagation();
         return;
     }
     if ($event->getType() == 'lead.lifetime') {
         $params = $event->getWidget()->getParams();
         if (empty($params['limit'])) {
             // Count the list limit from the widget height
             $limit = round(($event->getWidget()->getHeight() - 80) / 35 - 1);
         } else {
             $limit = $params['limit'];
         }
         $maxSegmentsToshow = 4;
         $params['filter']['flag'] = [];
         if (isset($params['flag'])) {
             $params['filter']['flag'] = $params['flag'];
             $maxSegmentsToshow = count($params['filter']['flag']);
         }
         $lists = $this->leadListModel->getLifeCycleSegments($maxSegmentsToshow, $params['dateFrom'], $params['dateTo'], $canViewOthers, $params['filter']['flag']);
         $items = [];
         if (empty($lists)) {
             $lists[] = ['leads' => 0, 'id' => 0, 'name' => $event->getTranslator()->trans('mautic.lead.all.leads'), 'alias' => ''];
         }
         // Build table rows with links
         if ($lists) {
             $stages = [];
             $deviceGranularity = [];
             foreach ($lists as &$list) {
                 if ($list['alias'] != '') {
                     $listUrl = $this->router->generate('mautic_contact_index', ['search' => 'segment:' . $list['alias']]);
                 } else {
                     $listUrl = $this->router->generate('mautic_contact_index', []);
                 }
                 if ($list['id']) {
                     $params['filter']['leadlist_id'] = ['value' => $list['id'], 'list_column_name' => 't.id'];
                 } else {
                     unset($params['filter']['leadlist_id']);
                 }
                 $column = $this->leadListModel->getLifeCycleSegmentChartData($params['timeUnit'], $params['dateFrom'], $params['dateTo'], $params['dateFormat'], $params['filter'], $canViewOthers, $list['name']);
                 $items['columnName'][] = $list['name'];
                 $items['value'][] = $list['leads'];
                 $items['link'][] = $listUrl;
                 $items['chartItems'][] = $column;
                 $stages[] = $this->leadListModel->getStagesBarChartData($params['timeUnit'], $params['dateFrom'], $params['dateTo'], $params['dateFormat'], $params['filter'], $canViewOthers);
                 $deviceGranularity[] = $this->leadListModel->getDeviceGranularityData($params['timeUnit'], $params['dateFrom'], $params['dateTo'], $params['dateFormat'], $params['filter'], $canViewOthers);
             }
             $width = 100 / count($lists);
             $event->setTemplateData(['columnName' => $items['columnName'], 'value' => $items['value'], 'width' => $width, 'link' => $items['link'], 'chartType' => 'pie', 'chartHeight' => $event->getWidget()->getHeight() - 180, 'chartItems' => $items['chartItems'], 'stages' => $stages, 'devices' => $deviceGranularity]);
             $event->setTemplate('MauticCoreBundle:Helper:lifecycle.html.php');
             $event->stopPropagation();
         }
         return;
     }
     if ($event->getType() == 'top.owners') {
         if (!$canViewOthers) {
             $event->setErrorMessage($this->translator->trans('mautic.dashboard.missing.permission', ['%section%' => $this->bundle]));
             $event->stopPropagation();
             return;
         }
         if (!$event->isCached()) {
             $params = $event->getWidget()->getParams();
             if (empty($params['limit'])) {
                 // Count the list limit from the widget height
                 $limit = round(($event->getWidget()->getHeight() - 80) / 35 - 1);
             } else {
                 $limit = $params['limit'];
             }
             $owners = $this->leadModel->getTopOwners($limit, $params['dateFrom'], $params['dateTo']);
             $items = [];
             // Build table rows with links
             if ($owners) {
                 foreach ($owners as &$owner) {
                     $ownerUrl = $this->router->generate('mautic_user_action', ['objectAction' => 'edit', 'objectId' => $owner['owner_id']]);
                     $row = [['value' => $owner['first_name'] . ' ' . $owner['last_name'], 'type' => 'link', 'link' => $ownerUrl], ['value' => $owner['leads']]];
                     $items[] = $row;
                 }
             }
             $event->setTemplateData(['headItems' => [$event->getTranslator()->trans('mautic.user.account.permissions.editname'), $event->getTranslator()->trans('mautic.lead.leads')], 'bodyItems' => $items, 'raw' => $owners]);
         }
         $event->setTemplate('MauticCoreBundle:Helper:table.html.php');
         $event->stopPropagation();
         return;
     }
     if ($event->getType() == 'top.creators') {
         if (!$canViewOthers) {
             $event->setErrorMessage($this->translator->trans('mautic.dashboard.missing.permission', ['%section%' => $this->bundle]));
             $event->stopPropagation();
             return;
         }
         if (!$event->isCached()) {
             $params = $event->getWidget()->getParams();
             if (empty($params['limit'])) {
                 // Count the list limit from the widget height
                 $limit = round(($event->getWidget()->getHeight() - 80) / 35 - 1);
             } else {
                 $limit = $params['limit'];
             }
             $creators = $this->leadModel->getTopCreators($limit, $params['dateFrom'], $params['dateTo']);
             $items = [];
             // Build table rows with links
             if ($creators) {
                 foreach ($creators as &$creator) {
                     $creatorUrl = $this->router->generate('mautic_user_action', ['objectAction' => 'edit', 'objectId' => $creator['created_by']]);
                     $row = [['value' => $creator['created_by_user'], 'type' => 'link', 'link' => $creatorUrl], ['value' => $creator['leads']]];
                     $items[] = $row;
                 }
             }
             $event->setTemplateData(['headItems' => [$event->getTranslator()->trans('mautic.user.account.permissions.editname'), $event->getTranslator()->trans('mautic.lead.leads')], 'bodyItems' => $items, 'raw' => $creators]);
         }
         $event->setTemplate('MauticCoreBundle:Helper:table.html.php');
         $event->stopPropagation();
         return;
     }
     if ($event->getType() == 'created.leads') {
         if (!$event->isCached()) {
             $params = $event->getWidget()->getParams();
             if (empty($params['limit'])) {
                 // Count the leads limit from the widget height
                 $limit = round(($event->getWidget()->getHeight() - 80) / 35 - 1);
             } else {
                 $limit = $params['limit'];
             }
             $leads = $this->leadModel->getLeadList($limit, $params['dateFrom'], $params['dateTo'], $canViewOthers, [], ['canViewOthers' => $canViewOthers]);
             $items = [];
             if (empty($leads)) {
                 $leads[] = ['name' => $this->translator->trans('mautic.report.report.noresults')];
             }
             // Build table rows with links
             if ($leads) {
                 foreach ($leads as &$lead) {
                     $leadUrl = isset($lead['id']) ? $this->router->generate('mautic_contact_action', ['objectAction' => 'view', 'objectId' => $lead['id']]) : '';
                     $type = isset($lead['id']) ? 'link' : 'text';
                     $row = [['value' => $lead['name'], 'type' => $type, 'link' => $leadUrl]];
                     $items[] = $row;
                 }
             }
             $event->setTemplateData(['headItems' => [$event->getTranslator()->trans('mautic.dashboard.label.title')], 'bodyItems' => $items, 'raw' => $leads]);
         }
         $event->setTemplate('MauticCoreBundle:Helper:table.html.php');
         $event->stopPropagation();
         return;
     }
 }
Example #23
0
 /**
  * @param $asset
  * @param null   $request
  * @param string $code
  * @param array  $systemEntry
  *
  * @throws \Doctrine\ORM\ORMException
  * @throws \Exception
  */
 public function trackDownload($asset, $request = null, $code = '200', $systemEntry = [])
 {
     // Don't skew results with in-house downloads
     if (empty($systemEntry) && !$this->security->isAnonymous()) {
         return;
     }
     if ($request == null) {
         $request = $this->request;
     }
     $download = new Download();
     $download->setDateDownload(new \Datetime());
     // Download triggered by lead
     if (empty($systemEntry)) {
         //check for any clickthrough info
         $clickthrough = $request->get('ct', false);
         if (!empty($clickthrough)) {
             $clickthrough = $this->decodeArrayFromUrl($clickthrough);
             if (!empty($clickthrough['lead'])) {
                 $lead = $this->leadModel->getEntity($clickthrough['lead']);
                 if ($lead !== null) {
                     $this->leadModel->setLeadCookie($clickthrough['lead']);
                     list($trackingId, $trackingNewlyGenerated) = $this->leadModel->getTrackingCookie();
                     $leadClickthrough = true;
                     $this->leadModel->setCurrentLead($lead);
                 }
             }
             if (!empty($clickthrough['channel'])) {
                 if (count($clickthrough['channel']) === 1) {
                     $channelId = reset($clickthrough['channel']);
                     $channel = key($clickthrough['channel']);
                 } else {
                     $channel = $clickthrough['channel'][0];
                     $channelId = (int) $clickthrough['channel'][1];
                 }
                 $download->setSource($channel);
                 $download->setSourceId($channelId);
             } elseif (!empty($clickthrough['source'])) {
                 $download->setSource($clickthrough['source'][0]);
                 $download->setSourceId($clickthrough['source'][1]);
             }
             if (!empty($clickthrough['email'])) {
                 $emailRepo = $this->em->getRepository('MauticEmailBundle:Email');
                 if ($emailEntity = $emailRepo->getEntity($clickthrough['email'])) {
                     $download->setEmail($emailEntity);
                 }
             }
         }
         if (empty($leadClickthrough)) {
             list($lead, $trackingId, $trackingNewlyGenerated) = $this->leadModel->getCurrentLead(true);
         }
         $download->setLead($lead);
     } else {
         $trackingId = '';
         if (isset($systemEntry['lead'])) {
             $lead = $systemEntry['lead'];
             if (!$lead instanceof Lead) {
                 $leadId = is_array($lead) ? $lead['id'] : $lead;
                 $lead = $this->em->getReference('MauticLeadBundle:Lead', $leadId);
             }
             $download->setLead($lead);
         }
         if (!empty($systemEntry['source'])) {
             $download->setSource($systemEntry['source'][0]);
             $download->setSourceId($systemEntry['source'][1]);
         }
         if (isset($systemEntry['email'])) {
             $email = $systemEntry['email'];
             if (!$email instanceof Email) {
                 $emailId = is_array($email) ? $email['id'] : $email;
                 $email = $this->em->getReference('MauticEmailBundle:Email', $emailId);
             }
             $download->setEmail($email);
         }
         if (isset($systemEntry['tracking_id'])) {
             $trackingId = $systemEntry['tracking_id'];
             $trackingNewlyGenerated = false;
         } elseif ($this->security->isAnonymous() && !defined('IN_MAUTIC_CONSOLE')) {
             // If the session is anonymous and not triggered via CLI, assume the lead did something to trigger the
             // system forced download such as an email
             list($trackingId, $trackingNewlyGenerated) = $this->leadModel->getTrackingCookie();
         }
     }
     $isUnique = true;
     if (!empty($trackingNewlyGenerated)) {
         // Cookie was just generated so this is definitely a unique download
         $isUnique = $trackingNewlyGenerated;
     } elseif (!empty($trackingId)) {
         // Determine if this is a unique download
         $isUnique = $this->getDownloadRepository()->isUniqueDownload($asset->getId(), $trackingId);
     }
     $download->setTrackingId($trackingId);
     if (!empty($asset) && empty($systemEntry)) {
         $download->setAsset($asset);
         $this->getRepository()->upDownloadCount($asset->getId(), 1, $isUnique);
     }
     //check for existing IP
     $ipAddress = $this->ipLookupHelper->getIpAddress();
     $download->setCode($code);
     $download->setIpAddress($ipAddress);
     if ($request !== null) {
         $download->setReferer($request->server->get('HTTP_REFERER'));
     }
     // Dispatch event
     if ($this->dispatcher->hasListeners(AssetEvents::ASSET_ON_LOAD)) {
         $event = new AssetLoadEvent($download, $isUnique);
         $this->dispatcher->dispatch(AssetEvents::ASSET_ON_LOAD, $event);
     }
     // Wrap in a try/catch to prevent deadlock errors on busy servers
     try {
         $this->em->persist($download);
         $this->em->flush($download);
     } catch (\Exception $e) {
         if (MAUTIC_ENV === 'dev') {
             throw $e;
         } else {
             error_log($e);
         }
     }
     $this->em->detach($download);
 }