private function addEvent($type, $id, $email, $datetime)
 {
     echo 'Adding ' . strtoupper($type) . ' to campaign ' . $id . ' with date of ' . $datetime . ' and email of ' . $email . "\r\n";
     $StoreModel = new Store();
     $encryptedEmail = $StoreModel->encryptEmail($email);
     // Look for this email address in store table
     $StoreRows = Store::model()->with('store2contact')->findAll(array('condition' => 'email = :email', 'params' => array(':email' => $encryptedEmail)));
     // collect our warehouse_ids up to match in campaign_contact table.
     $warehouseIDs = [];
     if (sizeof($StoreRows)) {
         // Save 1 suppression row for every instance of the email address in the store table - use store_id
         foreach ($StoreRows as $Store) {
             if ($Store->store2contact != null) {
                 $warehouseIDs[] = $Store->store2contact->contact_warehouse_id;
             }
         }
         $Contacts = null;
         // check for contact
         if (sizeof($warehouseIDs) && is_numeric($id)) {
             //Bounces
             if ($type === 'bounce') {
                 $Contacts = CampaignContact::model()->updateAll(array('bounced' => $datetime), "campaign_id = :campaign_id AND warehouse_id IN (" . implode(',', $warehouseIDs) . ") AND bounced IS NULL", array(':campaign_id' => $id));
             } else {
                 $Contacts = CampaignContact::model()->updateAll(array('opened' => $datetime), "campaign_id = :campaign_id AND warehouse_id IN (" . implode(',', $warehouseIDs) . ") AND opened IS NULL", array(':campaign_id' => $id));
             }
         }
         echo 'Updated ' . sizeof($Contacts) . ' contact';
     } else {
         echo 'Campaign contact not found' . "\r\n";
     }
     echo "\r\n";
 }
示例#2
0
 public function actionExport($id)
 {
     $Campaign = Campaign::model()->findByPk($_GET['campaign_id']);
     if (!$Campaign->hasBeenRun) {
         throw new CHttpException('404', 'Not found');
     }
     // check campaign has been run
     if (!$Campaign->hasBeenRun) {
         throw new CHttpException('403', 'Forbidden');
         // not possible. Forbidden.
     }
     $CampaignGroup = CampaignGroup::model()->findByAttributes(array('id' => $id, 'campaign_id' => $Campaign->id));
     if (is_null($CampaignGroup)) {
         throw new CHttpException('404', 'Not found');
     }
     $Criteria = new CDbCriteria();
     $Criteria->compare('`t`.`campaign_id`', $Campaign->id);
     $Criteria->compare('`t`.`group_id`', $id);
     $Criteria->with = array('contact');
     $Criteria->order = '`t`.`group_id` ASC';
     $CampaignContacts = CampaignContact::model()->findAll($Criteria);
     // build the csv
     $rows = array();
     $outcomeColumns = array();
     foreach ($CampaignGroup->outcomes as $Outcome) {
         // will be a url or NULL so fine
         $outcomeColumns[$Outcome->name] = $Outcome->url;
     }
     $headings = array('contact_warehouse_id' => 'insider_id', 'salutation' => 'Prefix', 'first_name' => 'Forename', 'last_name' => 'Surname', 'email' => 'Email', 'phone' => 'Telephone', 'mobile' => 'Mobile', 'dob' => 'Date of Birth', 'address_line_1' => 'Address Line 1', 'address_line_2' => 'Address Line 2', 'address_line_3' => 'Address Line 3', 'address_line_4' => 'Address Line 4', 'address_town' => 'Town', 'address_postcode' => 'Postcode', 'address_county' => 'County', 'culture_segment' => 'Culture Segment', 'level_of_engagement' => 'Level of Engagement');
     // build each row
     foreach ($CampaignContacts as $CampaignContact) {
         $row = array();
         // use headings to get data
         foreach ($headings as $key => $value) {
             $row[$value] = $CampaignContact->contact->{$key};
         }
         $rows[] = array_merge($row, array_values($outcomeColumns));
     }
     // stick headers on the start after adding outcome names to it
     array_unshift($rows, array_values(array_merge($headings, array_keys($outcomeColumns))));
     $cleanGroupName = preg_replace(array("@[^a-z0-9\\-\\s]@i", "@\\s+@", "@\\-{2,}@"), array("", "-", "-"), $CampaignGroup->name) . '-' . date("Y-m-d");
     $csv = fopen('php://output', 'w');
     header("Expires: Tue, 03 Jul 2001 06:00:00 GMT");
     header("Cache-Control: max-age=0, no-cache, must-revalidate, proxy-revalidate");
     header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
     header('Content-Encoding: UTF-8');
     header('Content-type: text/csv; charset=UTF-8');
     // disposition / encoding on response body
     header("Content-Disposition: attachment;filename=" . $cleanGroupName . ".csv");
     header("Content-Transfer-Encoding: binary");
     foreach ($rows as $column) {
         fputcsv($csv, $column);
     }
     fclose($csv);
     //echo $csv;
     exit;
 }
示例#3
0
 public function run($args)
 {
     $campaignSuccess = false;
     $configs = Yii::app()->db->createCommand("SELECT * FROM `config` WHERE `key` IN ('host', 'https')")->queryAll();
     if (sizeof($configs) < 2) {
         throw new CException("\n\n\n===\nDomain or HTTPS config not yet set. View any admin area page in a browser to remedy this.\n===\n\n");
     }
     foreach ($configs as $config) {
         $configParams[$config['key']] = $config['value'];
     }
     date_default_timezone_set("Europe/London");
     print "Getting campaigns to process \n";
     $CampaignCollection = Campaign::model()->findAll(array('with' => array('query', 'groups' => array('with' => array('email_template'))), "condition" => "processing = 0 AND status = :status AND invite = 0", "params" => array(":status" => Campaign::STATUS_QUEUED)));
     print count($CampaignCollection) . ' campaigns to process' . "\n";
     $campaignIDs = [];
     foreach ($CampaignCollection as $Campaign) {
         $campaignIDs[] = $Campaign->id;
         print "Will process Campaign ID: " . $Campaign->id . " \n";
     }
     $command = Yii::app()->db->createCommand();
     $command->update('campaign', array("processing" => 1), array('in', 'id', $campaignIDs));
     foreach ($CampaignCollection as $Campaign) {
         /* sending logic */
         /* create mailgun campaign id */
         $mailgunApi = new MailgunCampaign(Yii::app()->params['insiderEmailDomain'], Yii::app()->params['mailgun']['key']);
         // Check if the campaign ID exists
         try {
             $checkCampaignResponse = $mailgunApi->getCampaign(Yii::app()->params['insiderEmailDomain'], $Campaign->id);
         } catch (Exception $e) {
             $checkCampaignResponse = false;
         }
         if (!$checkCampaignResponse) {
             $mailgunCampaignResponse = $mailgunApi->createCampaign(Yii::app()->params['insiderEmailDomain'], array("name" => $Campaign->name, "id" => $Campaign->id));
         } else {
             $mailgunCampaignResponse['campaign'] = $checkCampaignResponse;
         }
         /* Example Response
         			Array
         			(
         				[message] => Campaign created
         				[campaign] => Array
         					(
         						[clicked_count] => 0
         						[opened_count] => 0
         						[submitted_count] => 0
         						[unsubscribed_count] => 0
         						[bounced_count] => 0
         						[id] => 691
         						[name] => Hicks 2
         						[created_at] => Tue, 24 Feb 2015 13:34:25 GMT
         						[delivered_count] => 0
         						[complained_count] => 0
         						[dropped_count] => 0
         					)
         
         			)
         			*/
         $Store = new Store();
         /* loop groups */
         /* load & render template (campaign_group) */
         foreach ($Campaign->groups as $CampaignGroup) {
             $mailgunApi = new MailgunApi(Yii::app()->params['insiderEmailDomain'], Yii::app()->params['mailgun']['key']);
             $mailgunApi->enableTracking();
             $mailgunApi->enableOpensTracking();
             $mailgunApi->enableClicksTracking();
             $message = $mailgunApi->newMessage();
             $message->setFrom(Yii::app()->params['fromEmail'], Yii::app()->name);
             $message->setSubject($CampaignGroup->subject);
             $message->setCampaignId($mailgunCampaignResponse['campaign']['id']);
             $message->setHtml($CampaignGroup->email_template->parsedHtml($configParams));
             // send variables to mailgun so that bounces and opens are easier to deal with.
             $message->addVar('campaign_id', $Campaign->id);
             $message->addVar('group_id', $CampaignGroup->id);
             //get contacts
             $CampaignContactCollection = CampaignContact::model()->findAll(array('with' => array('contact2outcomes' => array('index' => 'campaign_outcome_id')), "condition" => "\n\t\t\t\t\t\tgroup_id = :groupid\n\t\t\t\t\t\tAND `t`.`status` = 0\n\t\t\t\t\t", "params" => array(":groupid" => $CampaignGroup->id), 'index' => 'warehouse_id'));
             echo sizeof($CampaignContactCollection);
             // get the contact rows for the above campaigncontact rows
             $Criteria = new CDbCriteria();
             $Criteria->index = 'contact_warehouse_id';
             $Contacts = CleanWarehouse::model()->findAllByPk(array_keys($CampaignContactCollection), $Criteria);
             $chunkedCampaignContacts = array_chunk($CampaignContactCollection, 1000, true);
             foreach ($chunkedCampaignContacts as $campaign1000) {
                 //echo 'C';
                 $transaction = $Campaign->dbConnection->beginTransaction();
                 $campaign1000IDs = array();
                 $sentCount = 0;
                 $message->resetTo();
                 foreach ($campaign1000 as $warehouse_id => $CampaignContact) {
                     //echo '.';
                     $campaign1000IDs[] = $CampaignContact->id;
                     $thisContact = $Contacts[$warehouse_id];
                     $standardTags = array('first_name' => $thisContact->first_name, 'last_name' => $Store->decryptLastName($thisContact->last_name), 'email' => $Store->decryptEmail($thisContact->email), 'insider_unsubscribe' => 'http' . ($configParams['https'] ? 's' : '') . '://' . $configParams['host'] . Yii::app()->urlManager->createUrl('data/campaignUnsubscribe', array('campaign_id' => $Campaign->id, 'campaign_hash' => $Campaign->hash, 'campaign_contact_id' => $CampaignContact->id, 'campaign_contact_hash' => $CampaignContact->hash)), 'warehouse_id' => $warehouse_id);
                     $campaignTags = $CampaignGroup->email_template->returnOutcomeTagsToUrls($configParams, $Campaign, $CampaignContact->contact2outcomes);
                     $parsedTagsArray = array_merge($standardTags, $campaignTags);
                     if (ENVIRONMENT === 'PRODUCTION') {
                         $message->addTo($Store->decryptEmail($thisContact->email), $thisContact->first_name . ' ' . $Store->decryptLastName($thisContact->last_name), $parsedTagsArray);
                     } else {
                         $message->addTo("*****@*****.**", $thisContact->first_name . ' ' . $Store->decryptLastName($thisContact->last_name), $parsedTagsArray);
                     }
                     $sentCount++;
                 }
                 /* send email to mailgun */
                 try {
                     $response = $message->send();
                     $command = Yii::app()->db->createCommand();
                     $command->update('campaign_contact', array("status" => CampaignContact::STATUS_SENT, "processing" => 0), array('in', 'id', $campaign1000IDs));
                     $transaction->commit();
                     $campaignSuccess = true;
                     echo 'Success';
                 } catch (Exception $e) {
                     //print $e->getMessage();
                     // mailgun returned an error - we rollback the transaction and remove the number of failed ids from the sent count
                     // consider mainatining a fail count??
                     $sentCount -= count($campaign1000);
                     $command = Yii::app()->db->createCommand();
                     $command->update('campaign_contact', array("status" => CampaignContact::STATUS_MAILGUN_ERROR, "processing" => 0), array('in', 'id', $campaign1000IDs));
                     $transaction->commit();
                     $msg = print_r($e, true);
                     $msg .= print_r($message, true);
                     mail('*****@*****.**', 'Mailgun error', $msg);
                 }
             }
         }
         if ($campaignSuccess) {
             $Campaign->status = Campaign::STATUS_HAS_BEEN_RUN;
         } else {
             $Campaign->status = Campaign::STATUS_ERROR_SEND;
         }
         $Campaign->processing = 0;
         $Campaign->save(true, array("processing", "status"));
         print "Completed processing " . $Campaign->id . " \n";
         $Campaign->refresh();
         print "Status of campaign was " . $Campaign->getStatusText() . "\n\n";
     }
 }
示例#4
0
 public function actionUploadOutcome($id)
 {
     // ensure csv line endings are correctly recognised.
     ini_set('auto_detect_line_endings', true);
     $Campaign = Campaign::model()->with(array('outcomes' => array('index' => 'id')))->findByPk($id);
     if (!sizeof($Campaign->outcomes)) {
         Yii::app()->user->setFlash('Warning', 'This campaign has no outcomes and as such cannot be updated via file upload.');
     }
     // check for upload file
     if (sizeof($Campaign->outcomes) && sizeof($_FILES['file']) && strlen($_FILES['file']['tmp_name'])) {
         // confirm the organisation.
         if (Yii::app()->user->role < User::ROLE_MANAGER) {
             $organisation_id = Yii::app()->user->organisation_id;
         } else {
             // should have one in post.
             if (!is_numeric($_POST['organisation_id'])) {
                 throw new CHttpException('400', 'Bad Request - missing organisation_id');
             }
             $organisation_id = (int) $_POST['organisation_id'];
         }
         $Organisation = Organisation::model()->findByPk($organisation_id);
         // check outcome belongs to campaign
         if (!array_key_exists($_POST['outcome_id'], $Campaign->outcomes)) {
             // not a valid outcome
             throw new CHttpException('400', 'Bad Request - invalid outcome.');
         }
         //get the csv file
         $fh = fopen($_FILES['file']['tmp_name'], "r");
         // store number of successes so we can tell rows and individual columns;
         $successes = [];
         //loop through the csv file and gather unique ids
         for ($lines = 0; $data = fgetcsv($fh); $lines++) {
             if (strlen($data[0])) {
                 $uniqueIDs[] = $data[0];
             }
         }
         if (!sizeof($uniqueIDs)) {
             exit('no uniques');
         }
         $CDbCriteria = new CDbCriteria();
         $CDbCriteria->join = 'INNER JOIN store2contact ON `t`.warehouse_id = `store2contact`.`contact_warehouse_id`';
         $CDbCriteria->addCondition('`t`.`campaign_id` = :campaign_id');
         $CDbCriteria->addCondition('`store2contact`.origin_id = :origin_organisation_id');
         $CDbCriteria->params = array(':campaign_id' => $Campaign->id, ':origin_organisation_id' => (int) $_POST['organisation_id']);
         $CDbCriteria->compare('`store2contact`.`origin_unique_id`', $uniqueIDs);
         $CDbCriteria->index = 'id';
         $CampaignContacts = CampaignContact::model()->findAll($CDbCriteria);
         // update all who match against a campaign contact 2 outcome
         if (sizeof($CampaignContacts)) {
             // do update on those rows
             CampaignContact2Outcome::model()->updateAll(array('outcome' => date("Y-m-d H:i:s")), "campaign_contact_id IN (" . implode(", ", array_keys($CampaignContacts)) . ")\n\t\t\t\t\t\tAND campaign_outcome_id = :campaign_outcome_id\n\t\t\t\t", array(':campaign_outcome_id' => $_POST['outcome_id']));
         }
         // at least something got updated.
         Yii::app()->user->setFlash('success', sizeof($CampaignContacts) . ' (of ' . $lines . ') rows provided a matching contact to allow outcome update.');
         $this->refresh();
     }
     $this->pageTitle = 'Upload Campaign Outcome Users | ' . Yii::app()->name;
     $this->breadcrumbs = array('Campaigns' => array('index'), $Campaign->name => array('campaign/createUpdate', 'id' => $Campaign->id), 'Upload Campaign Outcome Users');
     // show form
     $this->render('uploadOutcome', array('Campaign' => $Campaign));
 }
示例#5
0
 public function actionCampaignUnsubscribe()
 {
     // find them
     $CampaignContact = CampaignContact::model()->find(array('with' => array('campaign'), 'condition' => "\n\t\t\t\t`t`.`id` = :campaign_contact_id\n\t\t\t\tAND `t`.hash = :campaign_contact_hash\n\t\t\t\tAND `campaign`.id = :campaign_id\n\t\t\t\tAND `campaign`.hash = :campaign_hash\n\t\t\t", 'params' => array('campaign_contact_id' => $_GET['campaign_contact_id'], 'campaign_contact_hash' => $_GET['campaign_contact_hash'], ':campaign_id' => $_GET['campaign_id'], ':campaign_hash' => $_GET['campaign_hash'])));
     if (is_null($CampaignContact)) {
         $this->layout = 'vanilla';
         $this->pageTitle = '404 not found';
         $this->render('unsubscribed', array('title' => 'We couldn\'t find that.', 'message' => 'We weren\'t able to find the page you were looking for. Sorry about that.'));
         Yii::app()->end();
     }
     // they exist so unsubscribe them
     $ExistingSuppression = SuppressionList::model()->findByAttributes(array('warehouse_id' => $CampaignContact->warehouse_id));
     if (is_null($ExistingSuppression)) {
         $SuppressionList = new SuppressionList();
         $SuppressionList->setAttributes(array('warehouse_id' => $CampaignContact->warehouse_id, 'campaign_id' => $CampaignContact->campaign->id, 'date' => date('Y-m-d H:i:s'), 'type' => 1));
         $SuppressionList->save();
     }
     // show them a nice success message
     $this->layout = 'vanilla';
     $this->pageTitle = 'You have been unsubscribed';
     $this->render('unsubscribed', array('title' => 'You\'ve unsubscribed successfully.', 'message' => 'We\'re registered your unsubscribe request. You may still receive already queued email correspondance.'));
     Yii::app()->end();
 }
示例#6
0
 public function actionOpen()
 {
     // See http://documentation.mailgun.com/user_manual.html#webhooks
     // Mail so we know we have received the opened webhook
     // Set up authorisation
     $authString = $_POST['timestamp'] . $_POST['token'];
     $authHash = hash_hmac('sha256', $authString, Yii::app()->params['mailgun']['key']);
     // Check Auth
     if ($authHash === $_POST['signature']) {
         // Huzzah! Authorized HTTP POST from Mailgun
         $uniques = array();
         $StoreModel = new Store();
         // Encrypt the email so we can find a match
         $openedEmailAddress = $StoreModel->encryptEmail($_POST['recipient']);
         // Look for this email address in store table
         $StoreRows = Store::model()->with('store2contact')->findAll(array('condition' => 'email = :email', 'params' => array(':email' => $openedEmailAddress)));
         // collect our warehouse_ids up to match in campaign_contact table.
         $warehouseIDs = [];
         if (sizeof($StoreRows)) {
             // Save 1 suppression row for every instance of the email address in the store table - use store_id
             foreach ($StoreRows as $Store) {
                 // expired? No store to contact. Skip
                 if (!is_null($Store->store2contact)) {
                     $warehouseIDs[] = $Store->store2contact->contact_warehouse_id;
                 }
             }
             // check for campaign_contacts.
             if (sizeof($warehouseIDs) && is_numeric($_POST['campaign_id']) && is_numeric($_POST['group_id'])) {
                 // it's a bounce of a campaign email. Mark against the row.
                 CampaignContact::model()->updateAll(array('opened' => date('Y-m-d H:i:s', $_POST['timestamp'])), "campaign_id = :campaign_id AND group_id = :group_id AND warehouse_id IN (" . implode(',', array_filter($warehouseIDs)) . ") AND opened IS NULL", array(':campaign_id' => $_POST['campaign_id'], ':group_id' => $_POST['group_id']));
             }
             header("HTTP/1.0 200 Ok");
             exit;
         } else {
             header("HTTP/1.0 404 Not Found");
             exit('Not Found');
         }
     } else {
         // Go away
         sleep(5);
         header("HTTP/1.0 401 Unauthorized");
         exit('Unauthorized');
     }
 }