public function run($args) { exit('Disabled'); $Organisations = Organisation::model()->findAll(array('index' => 'id')); $command = Yii::app()->db->createCommand("\n\t\t\n\t\tSELECT i.id, i.status, i.date,i.contact_warehouse_id,organisation_id,store2contact_id,query_id, count(*) as 'dupe_count' \n\n\t\tFROM invite i\n\t\t\n\t\tGROUP BY i.contact_warehouse_id, i.organisation_id\n\t\t\n\t\tHAVING dupe_count > 1\n\t\t\n\t\tORDER BY dupe_count DESC\n\t\t\n\t\t"); $results = $command->queryAll(); $rows = ''; $mismatchedOrg = []; // 4006 //$results['contact_warehouse_id'] = 1234; //$results['organisation_id'] = 1; foreach ($results as $result) { // All the s2c rows, with store $Store2Contact = Store2Contact::model()->with('store')->find(array('condition' => 'contact_warehouse_id = :cwi AND store.origin_organisation_id = :org_id AND store.date_expired IS NULL', 'params' => array(':cwi' => $result['contact_warehouse_id'], ':org_id' => $result['organisation_id']))); if ($result['status'] == 3) { $acceeded = 'Y'; } else { $acceeded = 'N'; } // If Sent from Seven Stories, but no if ($result['organisation_id'] == 6 && $Store2Contact->store->origin_unique_id == 0) { $organisationName = 'Northern Stage (Sent from Seven Stories)'; } else { $organisationName = $Organisations[$result['organisation_id']]->title; } $rows .= $Store2Contact->store->origin_unique_id . ',' . $result['store2contact_id'] . ',' . $Store2Contact->id . ',' . $organisationName . ',' . $Store2Contact->store->email . ',' . $Store2Contact->store->first_name . ',' . $Store2Contact->store->last_name . ',' . $result['date'] . ',' . $acceeded . "\n"; } $myFile = Yii::app()->basePath . "/../../protected-file-uploads/misc/dupes.csv"; $fh = fopen($myFile, 'w') or die("can't open file"); fwrite($fh, $rows); fclose($fh); }
public function run($args) { exit('Disabled'); ini_set('memory_limit', '512M'); $Organisations = Organisation::model()->findAll(array('index' => 'id')); /* $command = Yii::app()->db->createCommand(" SELECT s2c.id, s.email, o.title, CONCAT(i.contact_warehouse_id,organisation_id) AS conc FROM suppression_list sl INNER JOIN store2contact s2c ON s2c.store_id = sl.store_id LEFT JOIN store s ON s.id = s2c.store_id LEFT JOIN invite i ON s2c.id = i.store2contact_id LEFT JOIN organisation o ON o.id = i.organisation_id WHERE sl.`date` >= '2014-12-05' AND s.email IS NOT NULL AND type = 1 GROUP BY conc "); */ $command = Yii::app()->db->createCommand("\n\t\tSELECT i.organisation_id, s2c.contact_warehouse_id, sl.*, s2c.id AS store2contact_id FROM suppression_list sl\n\t\t\n\t\tLEFT JOIN store2contact s2c ON s2c.store_id = sl.store_id\n\t\t\n\t\tLEFT JOIN invite i ON s2c.id = i.store2contact_id\n\t\t\n\t\tWHERE sl.`date` >= '2014-12-05' AND type = 1\n\t\t\n\t\tGROUP BY sl.store_id\n\t\t"); $results = $command->queryAll(); //print count($results) . ' unsubscribes' . "\n\n"; $rows = ''; $StoreModel = new Store(); foreach ($results as $result) { $Store2Contact = Store2Contact::model()->with('store')->find(array('condition' => 'contact_warehouse_id = :cwi AND store.origin_organisation_id = :org_id AND store.date_expired IS NULL', 'params' => array(':cwi' => $result['contact_warehouse_id'], ':org_id' => $result['organisation_id']))); if (!is_null($Store2Contact)) { // If Sent from Seven Stories, but no if ($result['organisation_id'] == 6 && $Store2Contact->store->origin_unique_id == 0) { $organisationName = 'Northern Stage (Sent from Seven Stories)'; } else { $organisationName = $Organisations[$result['organisation_id']]->title; } $rows .= $Store2Contact->store->origin_unique_id . ',' . $result['store2contact_id'] . ',' . $Store2Contact->id . ',' . $organisationName . ',' . $Store2Contact->store->email . ',' . $Store2Contact->store->first_name . ',' . $Store2Contact->store->last_name . "\n"; } else { print_r($result); } } $myFile = Yii::app()->basePath . "/../../protected-file-uploads/misc/unsubs.csv"; $fh = fopen($myFile, 'w') or die("can't open file"); fwrite($fh, $rows); fclose($fh); }
public function actionDownload($id) { // no limit for this. See #472 ini_set('memory_limit', '-1'); // ensure no timeout occurs during the creation of csv ini_set('max_execution_time', '180'); // do not include log info in generated file foreach (Yii::app()->log->routes as $route) { if ($route instanceof CProfileLogRoute) { $route->enabled = false; } } $Store = new Store(); $Campaign = Campaign::model()->findByPk($id, array('select' => array('name'), 'with' => array('contacts' => array('select' => array('id', 'opened', 'bounced', 'warehouse_id'), 'index' => 'warehouse_id', 'with' => array('contact2outcomes' => array('with' => 'campaign_outcome', 'select' => array('outcome')), 'group')), 'outcomes' => array('select' => array('id', 'name'))))); $implodedContactKeys = implode(', ', array_keys($Campaign->contacts)); if (!sizeof($implodedContactKeys)) { throw new CHttpException('404', 'That campaign has no data to return'); } $Accessions = Accession::model()->findAll(array('condition' => 'warehouse_id IN (' . $implodedContactKeys . ')', 'index' => 'warehouse_id')); $Store2Contacts = Store2Contact::model()->findAll(array('condition' => 'contact_warehouse_id IN (' . $implodedContactKeys . ')', 'index' => 'contact_warehouse_id', 'with' => array('store'))); unset($implodedContactKeys); // build the csv $rows = array(); $outcomeColumns = array(); $headings = array('campaign_contact_id' => 'campaign_contact_id', 'salutation' => 'Prefix', 'first_name' => 'Forename', 'last_name' => 'Surname', 'email' => 'Email', 'culture_segment' => 'Culture Segment'); $csvHeader = array_values($headings); // add each outcome as a column heading foreach ($Campaign->outcomes as $Outcome) { $csvHeader[] = 'outcome_' . $Outcome->id . ' - ' . $Outcome->name; } // add an empty one for $csvHeader[] = "Group"; $csvHeader[] = "Opened"; $csvHeader[] = "Bounced"; 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=Contacts - " . $Campaign->name . ".csv"); header("Content-Transfer-Encoding: binary"); flush(); $csv = fopen('php://output', 'w'); fputcsv($csv, $csvHeader); // build each row $loop = 0; foreach ($Campaign->contacts as $warehouse_id => $CampaignContact) { $row = array(); // use headings to get data for basic details foreach ($headings as $key => $value) { switch ($key) { case 'campaign_contact_id': $row['campaign_contact_id'] = $Campaign->contacts[$warehouse_id]->id; break; case 'email': // already decrypted on find $row[$value] = $Store2Contacts[$warehouse_id]->store->{$key}; break; case 'last_name': // already decrypted on find $row[$value] = $Store2Contacts[$warehouse_id]->store->{$key}; break; case 'culture_segment': $row[$value] = $Accessions[$warehouse_id]->culture_segment; break; default: $row[$value] = $Store2Contacts[$warehouse_id]->store->{$key}; } } // do outcome row values foreach ($CampaignContact->contact2outcomes as $Outcome) { $row[$Outcome->campaign_outcome->name] = $Outcome->outcome; } $row['Group'] = $CampaignContact->group->name; // open and bounce. Once will likely be null / blank. $row['Opened'] = $CampaignContact->opened; $row['Bounced'] = $CampaignContact->bounced; //$rows[] = $row; fputcsv($csv, $row, ',', '"'); if (!($loop++ % 100)) { ob_flush(); flush(); // Attempt to flush output to the browser every 100 lines. // You may want to tweak this number based upon the size of your CSV rows. } unset($row); unset($CampaignContact); } fclose($csv); }
<div class="alert alert-warning"> <p>You are on the server <em><?php print $_SERVER['HTTP_HOST']; ?> </em>, which is the <?php print ENVIRONMENT; ?> environment.</p> </div> <p>Your current data is as follows:</p> <?php $Store = Store::model()->count(); $Store2Contact = Store2Contact::model()->count(); $Accession = Accession::model()->count(); $CleanWarehouse = Yii::app()->db->createCommand("SELECT COUNT(*) as tot FROM clean_warehouse")->queryRow(); ?> <table class="table table-bordered"> <tr> <th>Table</th> <th>Rows</th> </tr> <tr> <td>store</td> <td><?php print $Store; ?> </td>
public function actionInviteUnsubscribe() { // campaign_id -> used to send the invite // campaign_hash -> used to check the id isn't manipulated // invite_id -> use to store the invite row // invite_hash_partial -> used to store the first 8 characters of the much longer 40 char invite hash // match the invite to a contact? $Invite = Invite::model()->find(array('condition' => 'id = :invite_id AND SUBSTR(hash,1,8) = :invite_hash_partial', 'params' => array(':invite_id' => $_GET['invite_id'], ':invite_hash_partial' => $_GET['invite_hash_partial']))); // matches an invite if (is_null($Invite) || ($Invite->campaign->id !== $_GET['campaign_id'] || $Invite->campaign->hash !== $_GET['campaign_hash'])) { $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(); } $Store2Contact = Store2Contact::model()->with(array('store' => array('with' => array('organisation'))))->findByPk($Invite->store2contact_id); if (is_null($Store2Contact)) { $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(); } // check for existing suppression row. Should only be one row per campaign $SuppressionList = SuppressionList::model()->findByAttributes(array('store2contact_id' => $Store2Contact->id, 'campaign_id' => $Invite->campaign_id)); // add a suppression row if (is_null($SuppressionList)) { $NewSuppressionList = new SuppressionList(); // Warehouse ID is null because we only want to supress from this single org... $NewSuppressionList->warehouse_id = null; // ... which represented by a single Store row $NewSuppressionList->store_id = $Store2Contact->store_id; $NewSuppressionList->store2contact_id = $Store2Contact->id; $NewSuppressionList->campaign_id = $Invite->campaign_id; $NewSuppressionList->type = SuppressionList::TYPE_UNSUBSCRIBE; if (!$NewSuppressionList->save()) { var_dump($NewSuppressionList->errors); exit; } } // show the success message page $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 from ' . $Store2Contact->store->organisation->title . '.')); Yii::app()->end(); }
private function import() { $db = new PDO(Yii::app()->params['db']['connectionString'], Yii::app()->params['db']['username'], Yii::app()->params['db']['password'], array(PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING)); $resultRows = $db->query('SELECT * FROM raw_import WHERE id > ' . $this->lastRowProcessed . ' LIMIT ' . $this->rowsToProcess); $suppressionCount = 0; echo "\n\n" . 'Pointer is at ' . $this->lastRowProcessed . "\n\n"; while ($data = $resultRows->fetch(PDO::FETCH_ASSOC)) { $StoreView = null; $DupeMatch = null; $CodeMatch = null; $Store2Contact = null; //20532 // 1 yes 0 no 2 unknown $contact_email = 2; //unkown $contact_post = 2; $contact_sms = 2; $organisation_id = null; // create base Store instance. $StoreView = new Store(); $data['CCR_Client_URN'] = $this->emptyToNull($data['CCR_Client_URN']); if (is_null($data['CCR_Client_URN'])) { // no URN no insert continue; } $StoreView['origin_unique_id'] = trim($data['CCR_Client_URN']); $StoreView['csv_file_uuid'] = $data['Cleaning_UUID']; $StoreView['date_imported'] = date('Y-m-d H:i:s'); //Get organisation id switch ($data['CCR_Organisation']) { case 'Example 1': $organisation_id = 1; switch ($data['CCR_Email_Allow']) { case 'Allow': $contact_email = 1; break; case 'Do Not Allow': $contact_email = 0; break; } break; default: break; } $StoreView['contact_email'] = $contact_email; $StoreView['contact_sms'] = $contact_sms; $StoreView['contact_post'] = $contact_post; $StoreView['origin_organisation_id'] = $organisation_id; $StoreView['salutation'] = $this->emptyToNull($data['CCR_Title']); $StoreView['first_name'] = $this->emptyToNull($data['CCR_Forename']); $StoreView['last_name'] = $this->emptyToNull($data['CCR_Surname']); if (!is_null($StoreView['last_name'])) { $StoreView['last_name'] = rtrim(mcrypt_decrypt($this->cipher, $this->key3, base64_decode($StoreView['last_name']), $this->mode, $this->iv)); } $StoreView['address_line_1'] = $this->emptyToNull($data['CCR_Address1']); if (!is_null($StoreView['address_line_1'])) { $StoreView['address_line_1'] = rtrim(mcrypt_decrypt($this->cipher, $this->key2, base64_decode($StoreView['address_line_1']), $this->mode, $this->iv)); } $StoreView['address_line_2'] = $this->emptyToNull($data['CCR_Address2']); $StoreView['address_line_3'] = $this->emptyToNull($data['CCR_Address3']); $StoreView['address_line_4'] = $this->emptyToNull($data['CCR_Address4']); $StoreView['address_town'] = $this->emptyToNull($data['CCR_Town']); $data['CCR_Postcode'] = trim($data['CCR_Postcode']); if ($this->isPostcode($data['CCR_Postcode'])) { $StoreView['address_postcode'] = $data['CCR_Postcode']; } else { $StoreView['address_postcode'] = null; } $StoreView['address_county'] = $this->emptyToNull($data['CCR_County']); // phone and mobile //regex to to see if provided phone number is mobile $phone1 = intval(rtrim(mcrypt_decrypt($this->cipher, $this->key4, base64_decode($data['CCR_Phone1']), $this->mode, $this->iv))); $phone2 = intval(rtrim(mcrypt_decrypt($this->cipher, $this->key5, base64_decode($data['CCR_Phone2']), $this->mode, $this->iv))); if ($phone1 && $phone2) { if ($this->isMobile($phone1)) { $StoreView['mobile'] = $phone1; $StoreView['phone'] = $phone2; } if ($this->isMobile($phone2)) { $StoreView['mobile'] = $phone2; $StoreView['phone'] = $phone1; } } else { if ($phone1) { if ($this->isMobile($phone1)) { $StoreView['mobile'] = $phone1; } else { $StoreView['phone'] = $phone1; } } else { if ($phone2) { if ($this->isMobile($phone2)) { $StoreView['mobile'] = $phone2; } else { $StoreView['phone'] = $phone2; } } } } // end phone and mobile // email $StoreView->email = $data['CCR_Email']; if (!is_null($StoreView->email)) { $StoreView->email = rtrim(mcrypt_decrypt($this->cipher, $this->key1, base64_decode($StoreView['email']), $this->mode, $this->iv)); } if (!is_null($StoreView['email']) && !filter_var($StoreView->email, FILTER_VALIDATE_EMAIL)) { $StoreView->email = null; } // end email // Save the contact in the store if (!$StoreView->validate()) { print '$StoreView->errors:' . "\n"; print_r($StoreView->errors); } else { $this->totalImported++; //in dupe set $data['CCR_Ind_Set'] = (int) trim($data['CCR_Ind_Set']); /* if(this row has (int)CCR_Ind_Set > 0){ select existing 1+ duplicates if(this row (int)CCR_Ind_Set matches a ccr_duplicate_id with the same organisation_id){ // mega dupe if( existing record has 'Yes' for CCR_Ind_Dupe1 ){ insert and expire this row } else { expire existing insert this row } } else { // no other rows in same org insert this row } } else { // not a duplicate } */ // is this the ccr dupe favoured row? $StoreView['ccr_ind_dupe1'] = trim($data['CCR_Ind_Dupe1']) === 'Yes' ? 1 : 0; // If CCR has detected a duplicate... if ($data['CCR_Ind_Set'] > 0) { $this->totalDupes++; $StoreView->ccr_duplicate_id = $data['CCR_Ind_Set']; //print "CCR_Ind_Set > 0\n"; //first of all, let see if the dupe has the same origin id as a previous in the database $DupeMatches = Store::model()->with(array('store2contact'))->findAllByAttributes(array('ccr_duplicate_id' => $data['CCR_Ind_Set'], 'date_expired' => null), array('index' => 'origin_organisation_id')); // print ('starting new loop with dupes'); if (sizeof($DupeMatches)) { // print "size DupeMatches > 0\n"; $Store2Contact = null; // print_r(array_keys($DupeMatches)); // print "\nDupeMatch orgs: " . $organisation_id . "\n"; if (array_key_exists((int) $organisation_id, $DupeMatches)) { // we have a match from the same organisation // print "org exists in dupes data\n"; //not do in the correct order, needs to be done with CCR_Ind_Set //we need to expire the match and update the warehouse record //we the new one //echo 'DupeMatch'; if ($DupeMatches[$organisation_id]->ccr_ind_dupe1) { // print "Alread have trusted row, expire row\n"; // already have a trusted row. Expire and insert this one. $StoreView->date_expired = date('Y-m-d H:i:s'); $StoreView->ccr_ind_dupe1 = 0; // just in case. } else { // print "Update store row\n"; // update store row $DupeMatches[$organisation_id]->date_expired = date('Y-m-d H:i:s'); $DupeMatches[$organisation_id]->save(); // update any suppression list rows to not have warehouse or store_id. They're old and expired. SuppressionList::model()->deleteAll('store2contact_id = ' . (int) $DupeMatches[$organisation_id]->store2contact->id); // clone the contact_warehouse_id and ind set. Gets saved below. $Store2Contact = $DupeMatches[$organisation_id]->store2contact; // print 'Store2Contact='; // print_r ($Store2Contact->attributes); $Store2Contact->contact_warehouse_id = $DupeMatches[$organisation_id]->store2contact->contact_warehouse_id; } } else { // print "org does not exist in dupes data\n"; //is it not a dupe match but someone else has the same dupe id? //if so, lets find their Warehouse ID and then add as a new row $LastDuplicate = end($DupeMatches); $Store2Contact = new Store2Contact(); $Store2Contact->contact_warehouse_id = $LastDuplicate->store2contact->contact_warehouse_id; } // the save for dupes is here if (!$StoreView->save()) { print_r($StoreView->errors); } // if we have a store2contact save it here if (!is_null($Store2Contact)) { //update store_id to new one $Store2Contact->store_id = $StoreView->id; $Store2Contact->origin_unique_id = $data['CCR_Client_URN']; $Store2Contact->origin_id = $organisation_id; // print 'saving a (dupe style) store2contact ' . $Store2Contact->id . "\n"; if (!$Store2Contact->save()) { print_r($Store2Contact->errors); } } // currently required below. //unset($Store2Contact); } } // when not a duplicate or there is no other dupe stored yet if ($data['CCR_Ind_Set'] == 0 || !sizeof($DupeMatches)) { // save for when no duplicates if (!$StoreView->save()) { print_r($StoreView->errors); } $Warehouse = new Warehouse(); if (!$Warehouse->save()) { print_r($Warehouse->errors); } // Create a new Store2Contact row $Store2Contact = new Store2Contact(); $Store2Contact->store_id = $StoreView->id; $Store2Contact->contact_warehouse_id = $Warehouse->id; $Store2Contact->origin_unique_id = $data['CCR_Client_URN']; $Store2Contact->origin_id = $organisation_id; if (!$Store2Contact->save()) { print_r($Store2Contact->errors); } } // Check for non-contactable by email, and add to the supression list if ($StoreView->contact_email == 0) { if (!is_null($Store2Contact) && (int) $Store2Contact->id) { $Suppression = new SuppressionList(); $Suppression->type = SuppressionList::TYPE_UNSUBSCRIBE; // always save the store id against this row $Suppression->store_id = $StoreView->id; // we have a store2contact row for this person. Add to suppression data. $Suppression->store2contact_id = $Store2Contact->id; //We don't need the warehouse id //$Suppression->warehouse_id = $Store2Contact->contact_warehouse_id; $Suppression->date = date('Y-m-d H:i:s'); if ($Suppression->save()) { $suppressionCount++; } } } } unset($data); unset($StoreView); unset($Store2Contact); unset($DupeMatch); unset($CodeMatch); $this->lastRowProcessed++; if (!($this->lastRowProcessed % 100)) { $this->completedToNow = $this->lastRowProcessed; $timeTotal = microtime(true) - $this->time_start; $timeForThis100 = $timeTotal - $this->timeTakenSoFar; $this->timeTakenSoFar = $timeTotal; $speed = round(1 / $timeForThis100 * 100, 3); $currentExecutionTime = round($timeTotal / 60, 2); echo $this->lastRowProcessed / 1000 . 'k done in ' . $currentExecutionTime . ' mins. ' . $speed . ' rows/s ' . "\r"; } } print "\n\n" . $suppressionCount . ' contacts were added to suppression list - not contactable by email' . "\n\n"; }
public function send($Campaign) { //exit(); $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) { $params[$config['key']] = $config['value']; } // Load contacts for this invite from the invite table // They'll be marked with this campaign ID, and status=0 - unsent $Invite = Invite::model(); $transaction = $Invite->dbConnection->beginTransaction(); try { $InviteRows = $Invite->with("store")->findAll(array("condition" => "campaign_id = :campaign_id AND processing = 0 AND status = :status", "params" => array(":campaign_id" => $Campaign->id, ":status" => Invite::STATUS_UNSENT))); $inviteIDs = []; foreach ($InviteRows as $Invite) { $inviteIDs[] = $Invite->id; } $command = Yii::app()->db->createCommand(); $command->update('invite', array("processing" => 1), array('in', 'id', $inviteIDs)); $transaction->commit(); } catch (Exception $e) { $transaction->rollback(); throw $e; } set_time_limit(0); // Load all organisations, we'll need their info $Organisations = Organisation::model()->findAll(array('condition' => 'id IN (1,2,3,4,5,6,7,8,9)', 'index' => 'id')); // Group by organisation $orgContacts = array(); foreach ($InviteRows as $Invite) { $orgContacts[$Invite->organisation_id][] = $Invite; } // Chunk these into arrays of up to 1000 contacts per organisation - this is the Mailgun limit $chunkedOrgContacts = array(); foreach ($orgContacts as $orgID => $contactArray) { $chunkedOrgContacts[$orgID] = array_chunk($orgContacts[$orgID], 1000); } // Parse the email content, replace tags with the Mailgun recipient params $parsedContent = $this->parseEmailContent($Campaign->invite_email_subject, $Campaign->invite_email_body, array('first_name' => '%recipient.first_name%', 'last_name' => '%recipient.last_name%', 'invite_url' => '%recipient.invite_url%', 'unsubscribe_url' => '%recipient.unsubscribe_url%')); // Debug / counter vars $sentCount = 0; $campaignSuccess = false; $toEmails = []; Yii::import('application.extensions.*'); foreach ($chunkedOrgContacts as $orgID => $orgChunks) { // Only set real email info if we're on production server // Let's not send emails to everyone in Newcastle before we're live... if (ENVIRONMENT === 'PRODUCTION' || ENVIRONMENT === 'PHOENIX') { // Get the correct email domain for the organisation in question $fromEmailDomain = $Organisations[$orgID]->email_domain; $fromEmailAddress = $Organisations[$orgID]->email_address; $fromEmailName = $Organisations[$orgID]->title; } else { $fromEmailDomain = Yii::app()->params['insiderEmailDomain']; $fromEmailAddress = 'email@' . $fromEmailDomain; $fromEmailName = $Organisations[$orgID]->title; } $mailgunApi = new MailgunApi($fromEmailDomain, Yii::app()->params['mailgun']['key']); $message = $mailgunApi->newMessage(); $message->setFrom($fromEmailAddress, $fromEmailName); $message->setSubject($parsedContent['subject']); $message->addTag('Invite'); // Tag with invite so it can be filtered in Mailgun admin if (ENVIRONMENT !== 'PRODUCTION') { $message->addTag('Test'); } /* TEST MODE */ //$message->enableTestMode(); // Now loop the contacts, which are in chunks (arrays) of up to 1000 foreach ($orgChunks as $upTo1000Invites) { //start transaction? try { $transaction = $Invite->dbConnection->beginTransaction(); $invite1000IDs = []; //reset the to fields $message->resetTo(); // Add all the contacts in this chunk, there could be up to 1000 of 'em foreach ($upTo1000Invites as $Invite) { $invite1000IDs[] = $Invite->id; if (strlen($Invite->store->email)) { $Store2Contact = Store2Contact::model()->findByPk($Invite->store2contact_id); if (!is_null($Store2Contact)) { // Check values match if ($Store2Contact->contact_warehouse_id === $Invite->contact_warehouse_id && $Store2Contact->store_id === $Invite->store_id) { // Also save the date they were invited to Store2Contact so we can query it easily $Store2Contact->most_recent_invite_date = date('Y-m-d H:i:s'); $Store2Contact->save(true, array('most_recent_invite_date')); unset($Store2Contact); // Now create the invitation link to pass into the email template $inviteURL = ($params['https'] === 1 ? 'https://' : 'http://') . $params['host'] . '/accession/invite/' . $Invite->hash; // Only set real email info if we're on production server // Let's not send emails to everyone in Newcastle before we're live... if (ENVIRONMENT === 'PRODUCTION') { $toEmail = $Invite->store->email; } else { $toEmail = '*****@*****.**'; } $unsubscribeUrl = $Invite->unsubscribeUrl; // Check first name $firstName = $Invite->store->first_name; if (!strlen(trim($firstName))) { $firstName = 'friend'; } // Add the recipient to the message object, including the params unique for them $message->addTo($toEmail, $Invite->store->first_name . ' ' . $Invite->store->last_name, array('first_name' => $firstName, 'last_name' => $Invite->store->last_name, 'invite_url' => $inviteURL, 'unsubscribe_url' => $unsubscribeUrl)); //$toEmails[] = 'Email: ' . $toEmail . " - " . $contact['first_name'] . ' ' . $lastName . '('.$fromEmailName.')' . "\n\n"; // Increment the counter $sentCount++; } else { $contactInfo = print_r($contact, true); mail('*****@*****.**', 'Invite attempted but store2contact row did not match contact found in query', $contactInfo); } } else { $contactInfo = print_r($contact, true); mail('*****@*****.**', 'Invite attempted but store2contact could not be found', $contactInfo); } } else { $contactInfo = print_r($contact, true); mail('*****@*****.**', 'Invite attempted with no email address', $contactInfo); } } // foreach upTo1000Invites } catch (Exception $e) { $transaction->rollback(); $campaignSuccess = false; } // Now we have the data for our 1000 contacts set up, render the template for the organisation $Controller = new Controller('foo'); $renderedView = $Controller->renderInternal(Yii::app()->basePath . '/views/mail/organisation-templates/' . $Organisations[$orgID]->email_template . ".php", array('body' => $parsedContent['body']), true); $message->setHtml($renderedView); // SEND THE MESSAGE if (sizeof($message->getTo())) { try { $response = $message->send(); $command = Yii::app()->db->createCommand(); $command->update('invite', array("status" => Invite::STATUS_SENT, "processing" => 0), array('in', 'id', $invite1000IDs)); $transaction->commit(); $campaignSuccess = true; } 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($invite1000IDs); $command = Yii::app()->db->createCommand(); $command->update('invite', array("status" => Invite::STATUS_MAILGUN_ERROR, "processing" => 0), array('in', 'id', $invite1000IDs)); $transaction->commit(); $msg = print_r($e, true); $msg .= print_r($message, true); mail('*****@*****.**', 'Mailgun error', $msg); } } } // end of org 1000 chunk } // foreach organisations if ($campaignSuccess) { $Campaign->status = Campaign::STATUS_HAS_BEEN_RUN; } else { $Campaign->status = Campaign::STATUS_ERROR_SEND; } $Campaign->save(true, array("status")); }
public function actionStepOne() { $this->inAccession = true; // Have we arrived here with an accession hash, allowing us to track this contact through accession? if (isset($_GET['accessionhash'])) { $Accession = $this->getAccessionRecord(); $this->checkStep($Accession, 1); } else { $Accession = new Accession(); $Accession->step = 1; } $this->pageTitle = 'Welcome to ' . Yii::app()->name . ' | Step One | Accession'; if (isset($_POST['Accession'])) { if ($_POST['Accession']['terms_agreed'] === '1') { // Accession hash will be null if they've signed up from the public link if (is_null($Accession->accession_hash)) { $Accession->accession_hash = sha1(rand(1, 99999) . microtime(true)); } // TERMS ARE AGREED! We're good to go. Set up all the models $Accession->terms_agreed = date('Y-m-d H:i:s'); if (!$Accession->save()) { print_r($Accession->errors); exit; } // Now they've agreed terms, update the invite (if they had one) if ($Accession->invite_id) { $Invite = Invite::model()->findByPk($Accession->invite_id); if (!is_null($Invite)) { $Invite->status = Invite::STATUS_ACCEPTED; $Invite->save(true, array('status')); } } $new = false; // If it's a new contact coming to the list, we just have a blank row // If they've come via an invite then we copy their Store row if (is_null($Accession->original_store2contact_id)) { // This contact is new $Store = new Store(); // Create a new warehouse row $Warehouse = new Warehouse(); $Warehouse->save(); // Set the warehouse id to the accession model $Accession->warehouse_id = $Warehouse->id; $Accession->save(true, array('warehouse_id')); $new = true; } else { // This contact came from an invite // Grab their previous data $Store2Contact = Store2Contact::model()->findByPk($Accession->original_store2contact_id); // Get the contact's warehouse_id - this identifies them uniquely, even if they have multiple instances in Store $Warehouse = Warehouse::model()->findByPk($Store2Contact->contact_warehouse_id); $ExistingStore = Store::model()->findByPk($Store2Contact->store_id); // Now make a new store to duplicate their info to $Store = new Store(); $Store->attributes = $ExistingStore->attributes; $Store->id = null; } // Set the org ID to THE LIST $Store->origin_organisation_id = 10; // Try to save the Store if (!$Store->save()) { print 'Store errors:<br>'; print_r($Store->errors); exit; } // Also create a new Store2Contact row $Store2Contact = new Store2Contact(); $Store2Contact->store_id = $Store->id; $Store2Contact->contact_warehouse_id = $Warehouse->id; $Store2Contact->origin_id = 10; if (!$Store2Contact->save()) { print 'Store2Contact errors:<br>'; print_r($Store2Contact->errors); exit; } // Now also save the new Store2Contact ID to Accession $Accession->store2contact_id = $Store2Contact->id; if ($new) { $Accession->original_store2contact_id = $Store2Contact->id; } } if ($Accession->save(true, array('terms_agreed', 'store2contact_id', 'original_store2contact_id'))) { $this->updateStep($Accession, 1); $this->redirect(array('accession/stepTwo', 'accessionhash' => $Accession->accession_hash)); } } $this->render('step1', array('Accession' => $Accession, 'progress' => 1)); }