/** * DO_CheckValidStatisticType * Data Object Method: Check whether or not statistic record exists * Method should only be called by DataObject class * * @param Int $statisticID Statistic ID * @param String $statisticType Statistic type * * @uses Stats_API * @uses Stats_API::FetchStats() * * @return Boolean Returns TRUE if exists, FALSE otherwise */ function DO_CheckStatisticAvailable($statisticID, $statisticType) { if (is_null($this->_cachedStatisticAPI)) { require_once(SENDSTUDIO_API_DIRECTORY . '/stats.php'); $this->_cachedStatisticAPI = new Stats_API(); } $status = $this->_cachedStatisticAPI->FetchStats($statisticID, $statisticType); // It should only return boolean AND NOTHING ELSE if ($status == false) { return false; } return true; }
/** * Show_Send_Step_5 * Step 5 handles the final step of doing a send. * It marks the stats as finished, * it cleans up anything left over in the send queue * Then it calls PrintSendFailureReport to show a report of how many emails were sent and how long it took. * * @uses Stats_API::MarkNewsletterFinished * @uses PrintSendFailureReport * @uses GetApi * @uses Splittest_Send_API::FinishJob * @uses Jobs_API::ClearQueue */ public function Show_Send_Step_5() { $send_details = IEM::sessionGet('SplitTestSendDetails'); $this->template_system->Assign('AdminUrl', $this->admin_url, false); $jobid = $send_details['Job']; require_once SENDSTUDIO_API_DIRECTORY . '/stats.php'; $statsapi = new Stats_API(); /** * Pass all of the stats through to the stats api. * * Since the stats contains an array of: * newsletterid => statid * * we just need to pass through the statid's. */ $statsapi->MarkNewsletterFinished(array_values($send_details['Stats']), $send_details['SendSize']); $timetaken = $send_details['SendEndTime'] - $send_details['SendStartTime']; $timedifference = $this->TimeDifference($timetaken); $this->template_system->Assign('SendReport_Intro', sprintf(GetLang('Addon_splittest_Send_Step5_Intro'), $timedifference)); $sendreport = ''; if ($send_details['EmailResults']['success'] > 0) { if ($send_details['EmailResults']['success'] == 1) { FlashMessage(GetLang('Addon_splittest_Send_Step5_SendReport_Success_One'), SS_FLASH_MSG_SUCCESS); } else { FlashMessage(sprintf(GetLang('Addon_splittest_Send_Step5_SendReport_Success_Many'), $this->PrintNumber($send_details['EmailResults']['success'])), SS_FLASH_MSG_SUCCESS); } $sendreport = GetFlashMessages(); } $this->PrintSendFailureReport($jobid, $sendreport); require_once SENDSTUDIO_API_DIRECTORY . '/jobs.php'; $jobs_api = new Jobs_API(); $send_api = $this->GetApi('Splittest_Send'); $send_api->FinishJob($jobid, $send_details['splitid']); $jobs_api->ClearQueue($send_details['SendQueue'], 'splittest'); }
/** * Delete * Delete an autoresponder from the database. Also deletes the queue associated with it. * * @param Int $autoresponderid Autoresponderid of the autoresponder to delete. If not passed in, it will delete 'this' autoresponder. We delete the autoresponder, then reset all class vars. * @param Int $userid The user doing the deleting of the autoresponder. This is so the stats api can "hide" autoresponder stats. * * @see Stats_API::HideStats * @see ClearQueue * * @return Boolean True if it deleted the autoresponder, false otherwise. * */ function Delete($autoresponderid=0, $userid=0) { if ($autoresponderid == 0) { $autoresponderid = $this->autoresponderid; } $this->Load($autoresponderid); $query = "DELETE FROM " . SENDSTUDIO_TABLEPREFIX . "autoresponders WHERE autoresponderid='" . $autoresponderid. "'"; $result = $this->Db->Query($query); if (!$result) { list($error, $level) = $this->Db->GetError(); trigger_error($error, $level); return false; } $this->ClearQueue($this->queueid, 'autoresponder'); $autoresponder_dir = TEMP_DIRECTORY . '/autoresponders/' . $autoresponderid; remove_directory($autoresponder_dir); $this->autoresponderid = 0; $this->name = ''; $this->format = 'h'; $this->hoursaftersubscription = 0; $this->queueid = 0; $this->archive = 0; $this->SetBody('text', ''); $this->SetBody('html', ''); $this->ownerid = 0; $this->autorespondersize = 0; $stats = array(); $query = "SELECT statid FROM " . SENDSTUDIO_TABLEPREFIX . "stats_autoresponders WHERE autoresponderid='" . $autoresponderid . "'"; $result = $this->Db->Query($query); while ($row = $this->Db->Fetch($result)) { $stats[] = $row['statid']; } // clean up stats if (!class_exists('stats_api', false)) { require_once(dirname(__FILE__) . '/stats.php'); } $stats_api = new Stats_API(); $stats_api->HideStats($stats, 'autoresponder', $userid); return true; }
/** * getCampaignStats * For a given Campaign ID get the send statistics for a particular job * this jobid is associated with a particular Splittest send. * * @param Int $campaignId the Newsletter ID. * @param Int $jobid the jobid for the Splittest statstics. * * @return Mixed Array of values from the appropriate record in the stats_newsletters table. */ private function getCampaignStats($campaignId, $jobid) { $query = 'SELECT ' . implode(',', $this->statsNewsletterFields) . ', SUM(bouncecount_soft + bouncecount_hard + bouncecount_unknown) AS bouncecount_total, SUM(htmlrecipients + textrecipients + multipartrecipients) AS recipients FROM [|PREFIX|]stats_newsletters WHERE newsletterid = ' . intval($campaignId) . ' AND jobid = ' . intval($jobid) . ' GROUP BY ' . implode(',', $this->statsNewsletterFields); $rs = $this->Db->Query($query); require_once dirname(dirname(dirname(dirname(__FILE__)))) . '/functions/api/stats.php'; $stats_api = new Stats_API(); $row = array(); while ($row = $this->Db->Fetch($rs)) { $row['linkclicks_unique'] = $stats_api->GetUniqueClickers($row['statid']); $row['recipients'] > 0 ? $recipients = $row['recipients'] : ($recipients = 0); $row['percent_emailopens_unique'] = $this->_doPercentage($row['emailopens_unique'], $recipients); $row['percent_linkclicks_unique'] = $this->_doPercentage($row['linkclicks_unique'], $recipients); $row['percent_bouncecount_total'] = $this->_doPercentage($row['bouncecount_total'], $recipients); $row['percent_unsubscribecount'] = $this->_doPercentage($row['unsubscribecount'], $recipients); $row['campaign_name'] = $this->getNewsletterNameFromStatid($row['statid']); $this->finishTime = $row['finishtime']; break; } $this->Db->FreeResult($rs); return $row; }
/** * Delete * Delete a list from the database. First we delete the list (and check the result for that), then we delete the subscribers for the list, the 'custom field data' for the list, the user permissions for the list, and finally reset all class vars. * * @param Int $listid Listid of the list to delete. If not passed in, it will delete 'this' list. * @param Int $userid The userid that is deleting the list. This is used so the stats api can "hide" stats. * * @see Stats_API::HideStats * @see DeleteAllSubscribers * * @return Boolean True if it deleted the list, false otherwise. * */ function Delete($listid=0, $userid=0) { $listid = (int)$listid; if ($listid == 0) { $listid = $this->listid; } $this->Db->StartTransaction(); $query = "DELETE FROM " . SENDSTUDIO_TABLEPREFIX . "lists WHERE listid=" . $listid; $result = $this->Db->Query($query); if (!$result) { list($error, $level) = $this->Db->GetError(); $this->Db->RollbackTransaction(); trigger_error($error, $level); return false; } $this->DeleteAllSubscribers($listid, true); $query = "DELETE FROM " . SENDSTUDIO_TABLEPREFIX . "customfield_lists WHERE listid=" . $listid; $result = $this->Db->Query($query); $query = "DELETE FROM " . SENDSTUDIO_TABLEPREFIX . "form_lists WHERE listid=" . $listid; $result = $this->Db->Query($query); $query = "DELETE FROM " . SENDSTUDIO_TABLEPREFIX . "usergroups_access WHERE resourcetype='lists' AND resourceid=" . $listid; $result = $this->Db->Query($query); if (!class_exists('stats_api', false)) { require_once(dirname(__FILE__) . '/stats.php'); } $stats_api = new Stats_API(); // clean up stats $stats = array('0'); $query = "SELECT statid FROM " . SENDSTUDIO_TABLEPREFIX . "stats_newsletter_lists WHERE listid=" . $listid; $result = $this->Db->Query($query); while ($row = $this->Db->Fetch($result)) { $stats[] = $row['statid']; } $stats_api->HideStats($stats, 'newsletter', $userid); $stats = array('0'); $query = "SELECT statid FROM " . SENDSTUDIO_TABLEPREFIX . "stats_autoresponders sa, " . SENDSTUDIO_TABLEPREFIX . "autoresponders a WHERE a.autoresponderid=sa.autoresponderid AND a.listid=" . $listid; $result = $this->Db->Query($query); while ($row = $this->Db->Fetch($result)) { $stats[] = $row['statid']; } $stats_api->HideStats($stats, 'autoresponder', $userid); // autoresponder queues are cleaned up in DeleteAllSubscribers. // we just need to clean up the autoresponders. $query = "DELETE FROM " . SENDSTUDIO_TABLEPREFIX . "autoresponders WHERE listid=" . $listid; $result = $this->Db->Query($query); // clean up banned emails. $query = "DELETE FROM " . SENDSTUDIO_TABLEPREFIX . "banned_emails WHERE list='" . $listid . "'"; $result = $this->Db->Query($query); if ($listid == $this->listid) { $this->listid = 0; $this->name = ''; $this->ownername = ''; $this->owneremail = ''; $this->bounceemail = ''; $this->replytoemail = ''; $this->bounceserver = ''; $this->bounceusername = ''; $this->bouncepassword = ''; $this->extramailsettings = ''; $this->subscribecount = 0; $this->unsubscribecount = 0; } /** * Clear out list cache */ if (array_key_exists('Lists_API::GetListByUserID[listCache]', $GLOBALS)) { unset($GLOBALS['Lists_API::GetListByUserID[listCache]']); } $this->Db->CommitTransaction(); return true; }
/** * OpenTracked * Logs an event when a user opens a campaign or autoresponder * * @uses Subscriber_API::AddEvent * @uses Stats_API::GetNewsletterSummary * @uses Stats_API::GetAutoresponderSummary * * @return Void Returns nothing */ public static function OpenTracked($eventdata) { if (!self::LoadSelf()) { return; } $subscribersapi = new Subscribers_API(); $statsapi = new Stats_API(); if (!isset($eventdata->open_details['subscriberid']) || !isset($eventdata->open_details['listid'])) { return; } switch ($eventdata->statstype[0]) { case 'n': $newsletter = $statsapi->GetNewsletterSummary($eventdata->open_details['statid'], true); if (empty($newsletter) || !isset($newsletter['newsletterid'])) { return false; } $event = array('type' => GetLang('Addon_emaileventlog_open'), 'eventdate' => $subscribersapi->GetServerTime(), 'subject' => sprintf(GetLang('Addon_emaileventlog_open_subject'), htmlspecialchars($newsletter['newslettername'], ENT_QUOTES, SENDSTUDIO_CHARSET)), 'notes' => GetLang('Addon_emaileventlog_opened_campaign')); break; case 'a': $stats = $statsapi->FetchStats($eventdata->open_details['statid'], 'a'); $autoresponder = $statsapi->GetAutoresponderSummary($stats['autoresponderid'], true); if (empty($autoresponder) || !isset($autoresponder['autoresponderid'])) { return false; } $event = array('type' => GetLang('Addon_emaileventlog_open_autoresponder'), 'eventdate' => $subscribersapi->GetServerTime(), 'subject' => sprintf(GetLang('Addon_emaileventlog_open_autoresponder_subject'), htmlspecialchars($autoresponder['autorespondername'], ENT_QUOTES, SENDSTUDIO_CHARSET)), 'notes' => GetLang('Addon_emaileventlog_opened_autoresponder')); break; default: } $subscribersapi->AddEvent($eventdata->open_details['subscriberid'], $eventdata->open_details['listid'], $event); }
/** * GetRecordByAssociatedLinkIDStatID * Get trigger email records that are being triggered by link clicked on a particular statistic. * * This method will return an array of the following: * - listid: All of the list id associated with the statistics * - triggeremails: All of triggeremails that is listening to this particular newsletter open * * @param Integer $linkid ID of the link to be searched for * @param Integer $statid ID of the statistic of which the link was clicked from * @return Mixed Returns FALSE if it couldn't retrieve trigger emails information. Otherwise returns an array response (see description). * * @uses SENDSTUDIO_TABLEPREFIX * @uses Db::Query() * @uses Db::GetError() * @uses Db::Fetch() * @uses Db::FreeResult() */ protected function GetRecordByAssociatedLinkIDStatID($linkid, $statid) { $return = array( 'lists' => array(), 'triggeremails' => array() ); $linkid = intval($linkid); $statid = intval($statid); $newsletter = null; if ($linkid == 0 || $statid == 0) { trigger_error('Invalid link ID/Stat ID specified', E_USER_NOTICE); return false; } // ----- Get Newsletter ID from statistic require_once(dirname(__FILE__) . '/stats.php'); $statapi = new Stats_API(); $newsletter = $statapi->GetNewsletterSummary($statid, true); if (empty($newsletter) || !isset($newsletter['newsletterid'])) { // Fail silently, because if the newsletter record has been removed we don't want to fill up the logs. return false; } unset($statapi); // ----- if (isset($newsletter['lists']) && is_array($newsletter['lists'])) { $return['lists'] = $newsletter['lists']; } $query = " SELECT t.* FROM [|PREFIX|]triggeremails AS t JOIN [|PREFIX|]triggeremails_data AS tdl ON ( tdl.triggeremailsid = t.triggeremailsid AND tdl.datakey = 'linkid' AND tdl.datavalueinteger = {$linkid}) JOIN [|PREFIX|]triggeremails_data AS tdn ON ( tdn.triggeremailsid = t.triggeremailsid AND tdn.datakey = 'linkid_newsletterid' AND tdn.datavalueinteger = {$newsletter['newsletterid']}) WHERE t.active = '1' AND t.triggertype = 'l' "; $result = $this->Db->Query($query); if (!$result) { list($error, $level) = $this->Db->GetError(); trigger_error($error, $level); return false; } while (($row = $this->Db->Fetch($result))) { $return['triggeremails'][$row['triggeremailsid']] = $row; } $this->Db->FreeResult($result); // ----- Get data and actions associated with the triggers if (!empty($return['triggeremails'])) { $triggerids = array_keys($return['triggeremails']); $tempData = $this->GetData($triggerids); if (!$tempData) { trigger_error('Cannot fetch triggeremails data', E_USER_NOTICE); return false; } foreach ($tempData as $id => $each) { $return['triggeremails'][$id]['data'] = $each; } $tempActions = $this->GetActions($triggerids); if (!$tempActions) { trigger_error('Cannot fetch triggeremails actions', E_USER_NOTICE); return false; } foreach ($tempActions as $id => $each) { $return['triggeremails'][$id]['triggeractions'] = $each; } } // ----- return $return; }
/** * ResendJob_Setup * This sets up the scheduled send 'job' ready for a resend. * This includes fixing up user statistics, moving the unsent recipients from the unsent queue to the live queue and making the job ready to go. * * If an invalid jobid is passed in (not an in or it's less than 0) this will return false. * There needs to be a user object set up so statistics can be re-allocated properly. If this is not set up, the function returns false. * * @param Int $jobid The job we are re-setting up. * * @uses Jobs_API::GetJobQueue * @uses Jobs_API::GetJobQueueSize * @uses Jobs_API::RestoreUnsentQueue * @uses Stats_API::ChangeUserStats * * @return Boolean Returns false if there is an invalid jobid provided or if the user object is not set up properly. Otherwise, it does all of it's work and returns true. */ function ResendJob_Setup($jobid=0) { $jobid = (int)$jobid; if ($jobid <= 0) { return false; } if ($this->jobowner <= 0) { return false; } require_once(dirname(__FILE__) . '/jobs.php'); require_once(dirname(__FILE__) . '/stats.php'); $jobapi = new Jobs_API(); $stats_api = new Stats_API(); $sendqueue = $jobapi->GetJobQueue($jobid); // if we're resending a newsletter, restore the 'unsent' queue back to the original. $jobsize_info_before = $jobapi->GetJobQueueSize($jobid); $jobapi->RestoreUnsentQueue($jobid, $sendqueue, $this->jobowner, 'send'); // then make sure we mark the emails as allocated in statistics. $restore_size = $jobapi->QueueSize($sendqueue, 'send'); $new_size = $jobsize_info_before['totalsent'] + $restore_size; $stats_api->ChangeUserStats($this->jobowner, $jobid, $new_size); unset($jobapi); unset($stats_api); return true; }
/** * _FinishJob * This does a few cleanup jobs. * - Marks the job as complete in stats * - Clears out any unsent recipients from the "queue". * - Calls the parent FinishJob method to do it's work. * * @uses _stats_api * @uses Stats_API::MarkNewsletterFinished * @uses ClearQueue * @uses FinishJob * * @return Void Doesn't return anything. */ function _FinishJob() { /** * Pass all of the stats through to the stats api. * * Since the stats contains an array of: * newsletterid => statid * * we just need to pass through the statid's. */ $this->_stats_api->MarkNewsletterFinished(array_values($this->jobdetails['Stats']), $this->jobdetails['SendSize']); $this->ClearQueue($this->jobdetails['SendQueue'], 'splittest'); $this->FinishJob($this->_jobid, $this->jobdetails['splitid']); }
/** * DeleteSchedules * If scheduled items are going to be deleted, this processes the jobs it needs to. * * The data passed in contains lots of data: * jobids - the job id's that need to be processed * message - the current success/failure message * success - the current success counter (how many jobs have successfully been deleted previous to getting here) * failure - the current failure counter (how many jobs have not successfully been deleted previous to getting here) * * Any non-"splittest" job types are skipped * Any "in progress" splittest jobs are skipped and the failure counter is incremented * Any jobs that can be deleted are - as well as figuring out whether a job needs to give back any email credits. * * Any appropriate messages are added to the "message" item in the passed in array. * * @param EventData_IEM_SCHEDULE_DELETEJOBS $data The data array containing the jobs to process, the current message, success and failure counts. * * @uses Jobs_API::LoadJob() * @uses Stats_API::DeleteUserStats() * @uses Stats_API::MarkNewsletterFinished() * @uses Splittest_Send_API::DeleteJob() * @uses User_API::ReduceEmails() * @uses EventData_IEM_SCHEDULE_DELETEJOBS */ public static function DeleteSchedules(EventData_IEM_SCHEDULE_DELETEJOBS $data) { $jobids =& $data->jobids; $message =& $data->Message; $success =& $data->success; $failure =& $data->failure; $user = GetUser(); require_once SENDSTUDIO_API_DIRECTORY . '/jobs.php'; require_once SENDSTUDIO_API_DIRECTORY . '/stats.php'; require_once dirname(__FILE__) . '/api/splittest_send.php'; $jobapi = new Jobs_API(); $stats_api = new Stats_API(); $send_api = new Splittest_Send_API(); foreach ($jobids as $p => $jobid) { $jobinfo = $jobapi->LoadJob($jobid); if (empty($jobinfo)) { continue; } if ($jobinfo['jobtype'] !== 'splittest') { continue; } if ($jobinfo['jobstatus'] == 'i') { $failure++; unset($jobids[$p]); continue; } $statids = array(); if (isset($jobinfo['jobdetails']['Stats'])) { $statids = array_values($jobinfo['jobdetails']['Stats']); } /** * If there are no stats, then the send hasn't started yet. * So just credit the user back with the number of emails they were trying to send. * Use 'ReduceEmails' to re-add the credits by using a double negative :) */ if (empty($statids) && $jobinfo['jobstatus'] == 'w') { $stats_api->DeleteUserStats($jobinfo['ownerid'], $jobid); $user->ReduceEmails(-(int) $jobinfo['jobdetails']['SendSize']); } /** * If a send is started (ie it has stats), * but is not completed, * We need to mark it as complete. * * This also credits a user back if they have any limits in place. * * This needs to happen before we delete the 'job' from the database * as deleting the job cleans up the queues/unsent items. */ if (!empty($statids) && $jobinfo['jobstatus'] != 'c') { $stats_api->MarkNewsletterFinished($statids, $jobinfo['jobdetails']['SendSize']); // Credits needs to be returned too whenever the job is canceled AFTER it has been scheduled, but before it was sent } elseif ($jobinfo['jobstatus'] != 'c') { $stats_api->RefundFixedCredit($jobid); } $result = $send_api->DeleteJob($jobid); if ($result) { $success++; } else { $failure++; } unset($jobids[$p]); } /** * Only failure messages get added to the message stack. * Successful deletes are handled in the calling code * in case: * - a non-addon deletes an item * - other addons delete their own items */ if ($failure > 0) { if ($failure == 1) { FlashMessage(GetLang('Addon_splittest_Schedule_JobDeleteFail'), SS_FLASH_MSG_ERROR); } else { FlashMessage(sprintf(GetLang('Addon_splittest_Schedule_JobsDeleteFail'), self::PrintNumber($failure)), SS_FLASH_MSG_SUCCESS); } } $message .= GetFlashMessages(); }
/** * Delete * Delete a newsletter from the database * * @param Int $newsletterid Newsletterid of the newsletter to delete. If not passed in, it will delete 'this' newsletter. We delete the newsletter, then reset all class vars. * @param Int $userid The user doing the deleting of the newsletter. This is passed through to the stats api to "hide" statistics rather than deleting them. * * @see Stats_API::HideStats * * @return Boolean True if it deleted the newsletter, false otherwise. * * @uses module_TrackerFactory * @uses module_Tracker * @uses module_Tracker::DeleteRecordsForAllTrackerByID() */ function Delete($newsletterid=0, $userid=0) { if ($newsletterid == 0) { $newsletterid = $this->newsletterid; } $newsletterid = intval($newsletterid); /** * Status being 'true' means * it's ok to delete the newsletter. * If it's not true, then the delete method returns false. */ $trigger_details = array ( 'status' => true, 'newsletterid' => $newsletterid ); /** * Trigger event */ $tempEventData = new EventData_IEM_NEWSLETTERSAPI_DELETE(); $tempEventData->status = &$trigger_details['status']; $tempEventData->newsletterid = &$trigger_details['newsletterid']; $tempEventData->trigger(); unset($tempEventData); /** * ----- */ if ($trigger_details['status'] !== true) { return false; } $this->Db->StartTransaction(); /** * Cleanup trackers * * When newsletter are deleted, delete associated tracker record too * * This was added here, because it's not calling the stats API to clear it's statistic */ $tempContinue = false; if (!class_exists('module_TrackerFactory', false)) { $tempFile = dirname(__FILE__) . '/module_trackerfactory.php'; if (is_file($tempFile)) { require_once($tempFile); $tempContinue = true; } } else { $tempContinue = true; } if ($tempContinue) { module_Tracker::DeleteRecordForAllTrackerByNewsletterID($newsletterid); } /** * ----- */ $query = "DELETE FROM " . SENDSTUDIO_TABLEPREFIX . "newsletters WHERE newsletterid=" . $newsletterid; $result = $this->Db->Query($query); if (!$result) { $this->Db->RollbackTransaction(); list($error, $level) = $this->Db->GetError(); trigger_error($error, $level); return false; } $newsletter_dir = TEMP_DIRECTORY . '/newsletters/' . $newsletterid; remove_directory($newsletter_dir); $this->newsletterid = 0; $this->name = ''; $this->format = 'h'; $this->active = 0; $this->archive = 0; $this->SetBody('text', ''); $this->SetBody('html', ''); $this->ownerid = 0; $stats = array(); $query = "SELECT statid FROM " . SENDSTUDIO_TABLEPREFIX . "stats_newsletters WHERE newsletterid=" . $newsletterid; $result = $this->Db->Query($query); if (!$result) { $this->Db->RollbackTransaction(); list($error, $level) = $this->Db->GetError(); trigger_error($error, $level); return false; } while ($row = $this->Db->Fetch($result)) { $stats[] = $row['statid']; } // clean up stats if (!class_exists('stats_api', false)) { require_once(dirname(__FILE__) . '/stats.php'); } $stats_api = new Stats_API(); $stats_api->HideStats($stats, 'newsletter', $userid); $this->Db->CommitTransaction(); return true; }