From: Steve Sutton Date: Tue, 14 Feb 2017 22:07:54 +0000 (-0500) Subject: WIP for streamsend X-Git-Url: http://cvs2.gaslightmedia.com/gitweb/index.cgi?a=commitdiff_plain;h=385d57a62de2b806112c5dcfcdd2027d532f6cf4;p=WP-Plugins%2Fglm-member-db-communicator.git WIP for streamsend Have setting all working and saving. Commenting out the others. just using streamsend right now. Working on adding member type into streamsend. Adds type but not the Categories. --- diff --git a/classes/data/dataManagement.php b/classes/data/dataManagement.php index c9fc599..d2510a8 100644 --- a/classes/data/dataManagement.php +++ b/classes/data/dataManagement.php @@ -122,6 +122,97 @@ class GlmDataCommunicatorManagement extends GlmDataAbstract 'use' => 'a' ), + 'enable_streamsend' => array( + 'field' => 'enable_streamsend', + 'type' => 'checkbox', + 'default' => false, + 'use' => 'a', + ), + + 'streamsend_login' => array( + 'field' => 'streamsend_login', + 'type' => 'text', + 'required' => false, + 'use' => 'a', + ), + + 'streamsend_key' => array( + 'field' => 'streamsend_key', + 'type' => 'text', + 'required' => false, + 'use' => 'a', + ), + + 'streamsend_audience' => array( + 'field' => 'streamsend_audience', + 'type' => 'text', + 'required' => false, + 'use' => 'a', + ), + + 'enable_constant_contact' => array( + 'field' => 'enable_constant_contact', + 'type' => 'checkbox', + 'default' => false, + 'use' => 'a', + ), + + 'constant_contact_password' => array( + 'field' => 'constant_contact_password', + 'type' => 'text', + 'required' => false, + 'use' => 'a', + ), + + 'constant_contact_api_key' => array( + 'field' => 'constant_contact_api_key', + 'type' => 'text', + 'required' => false, + 'use' => 'a', + ), + + 'constant_contact_login' => array( + 'field' => 'constant_contact_login', + 'type' => 'text', + 'required' => false, + 'use' => 'a', + ), + + 'constant_contact_api_path' => array( + 'field' => 'constant_contact_api_path', + 'type' => 'text', + 'required' => false, + 'use' => 'a', + ), + + 'constant_contact_list' => array( + 'field' => 'constant_contact_list', + 'type' => 'text', + 'required' => false, + 'use' => 'a', + ), + + 'enable_mailchimp' => array( + 'field' => 'enable_mailchimp', + 'type' => 'checkbox', + 'default' => false, + 'use' => 'a', + ), + + 'mailchimp_apikey' => array( + 'field' => 'mailchimp_apikey', + 'type' => 'text', + 'required' => false, + 'use' => 'a', + ), + + 'mailchimp_list_id' => array( + 'field' => 'mailchimp_list_id', + 'type' => 'text', + 'required' => false, + 'use' => 'a', + ), + ); } diff --git a/index.php b/index.php index 0d1def7..41c9786 100644 --- a/index.php +++ b/index.php @@ -144,9 +144,9 @@ if (is_file(GLM_MEMBERS_COMMUNICATOR_PLUGIN_DB_SCRIPTS.'/dbVersions.php')) { // Load Add-On Management Settings data /* None - Need to figure out a smooth way to do this. -$glmMembersCommunicatorManagementSettings = $wpdb->get_row( "SELECT * FROM ".GLM_MEMBERS_COMMUNICATOR_PLUGIN_DB_PREFIX."management WHERE id = 1", ARRAY_A ); -unset($glmMembersCommunicatorManagementSettings['id']); */ +$communicatorManagementSettings = $wpdb->get_row("SELECT * FROM ".GLM_MEMBERS_COMMUNICATOR_PLUGIN_DB_PREFIX."management WHERE id = 1", ARRAY_A); +unset($communicatorManagementSettings['id']); function glmMembersCommunicatorRegisterAddOn($addOns) { @@ -158,6 +158,7 @@ function glmMembersCommunicatorRegisterAddOn($addOns) { 'slug' => GLM_MEMBERS_COMMUNICATOR_PLUGIN_SLUG, 'actions' => $GLOBALS['glmMembersCommunicatorAddOnValidActions'], 'config' => array( + 'settings' => $GLOBALS['communicatorManagementSettings'], ), 'shortcodes' => $GLOBALS['glmMembersCommunicatorShortcodes'], 'shortcodesDescription' => $GLOBALS['glmMembersCommunicatorShortcodesDescription'] diff --git a/lib/StreamSend/class_streamsend_api.inc b/lib/StreamSend/class_streamsend_api.inc new file mode 100644 index 0000000..43513ed --- /dev/null +++ b/lib/StreamSend/class_streamsend_api.inc @@ -0,0 +1,2162 @@ + + * @copyright 2008 Gaslight Media - All rights Reserved + * @license Trade Secret and Proprietary Materials - No License + * @version CVS: $Id: class_streamsend_api.inc,v 1.2 2010/03/23 14:28:23 matrix Exp $ + * @link (none) + * @see + * @since File available since Release 1.0 + * @deprecated + */ + +/** +* Require DocBlock +* +* No includes required. +* +* PHP libcurl support required. +*/ + +/** + * ---------------------------------------------------------- + * Definitions + */ +define ("STREAMSEND_MAX_PAGE_SIZE", 10000); // This must be set to the maximum page size for the StreamSend system + +/** + * API Interface Error Codes + * + * Also add an error message for each error code + */ + /** Errors related to responses from StreamSend */ +define ("STREAMSEND_API_ERROR_NONE", 0); +define ("STREAMSEND_API_ERROR_NO_RESPONSE", 1); +define ("STREAMSEND_API_ERROR_HTTP_RESPONSE", 2); +define ("STREAMSEND_API_ERROR_BAD_XML", 3); + + /** Errors related to use of the GLM StreamSend methods and functions */ +define ("STREAMSEND_API_ERROR_POSTDATA_NOT_SUPPLIED", 100); + +// Base url for streamsend +define('STREAMSEND_BASE_URL', "https://app.streamsend.com"); +/** + * API Interface Error Messages + * + * Requires an error code for each error message + */ +$streamsendErrorMessage = array ( + + /** Errors related to responses from StreamSend */ + STREAMSEND_API_ERROR_NONE => 'No error reported.', + STREAMSEND_API_ERROR_NO_RESPONSE => 'No response received from server.', + STREAMSEND_API_ERROR_HTTP_RESPONSE => 'Server replied with an unexpected HTTP response code.', + STREAMSEND_API_ERROR_BAD_XML => 'The XML response was malformed.', + + /** Errors related to use of the GLM StreamSend methods and functions */ + STREAMSEND_API_ERROR_POSTDATA_NOT_SUPPLIED => 'No POST data was supplied to send to StreamSend.', +); + +/** + * Field Types + */ +define("STREAMSEND_API_FIELD_TYPE_TEXT", 1); +define("STREAMSEND_API_FIELD_TYPE_TEXTAREA", 2); +define("STREAMSEND_API_FIELD_TYPE_DATETIME", 3); +define("STREAMSEND_API_FIELD_TYPE_DATE", 4); +define("STREAMSEND_API_FIELD_TYPE_TIME", 5); +define("STREAMSEND_API_FIELD_TYPE_SELECT", 6); +define("STREAMSEND_API_FIELD_TYPE_RADIO", 7); +define("STREAMSEND_API_FIELD_TYPE_CHECKBOX", 8); + +$streamsendFieldTypes = array ( + STREAMSEND_API_FIELD_TYPE_TEXT => array( 'Name' => 'Text Field', 'Options' => false ), + STREAMSEND_API_FIELD_TYPE_TEXTAREA => array( 'Name' => 'Text Area', 'Options' => false ), + STREAMSEND_API_FIELD_TYPE_DATETIME => array( 'Name' => 'Date/Time', 'Options' => false ), + STREAMSEND_API_FIELD_TYPE_DATE => array( 'Name' => 'Date', 'Options' => false ), + STREAMSEND_API_FIELD_TYPE_TIME => array( 'Name' => 'Time', 'Options' => false ), + STREAMSEND_API_FIELD_TYPE_SELECT => array( 'Name' => 'Select', 'Options' => true ), + STREAMSEND_API_FIELD_TYPE_RADIO => array( 'Name' => 'Radio', 'Options' => true ), + STREAMSEND_API_FIELD_TYPE_CHECKBOX => array( 'Name' => 'Checkbox', 'Options' => true ) +); + +/** + * Other General Setup Data + */ + +$HTTPResponseCodeText = array( + 100 => 'Continue', + 101 => 'Switching Protocols', + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + 300 => 'Multiple Choices', + 301 => 'Permanently Moved', + 302 => 'Found', + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 306 => 'Tempoorary Redirect', + 400 => 'Your browser sent a request that this server could not understand. XML included with a request may be malformed', + 401 => 'Authorization Required or StreamSend authentication error', + 402 => 'Payment Required, plan upgrade required, number of recipients for blast may exceed available quota for account', + 403 => 'Forbidden or permission not granted by StreamSend - Contact support staff', + 404 => 'Not Found - Possible reasons: The resource never existed, The resource was destroyed, The requested URI is invalid.', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Time-out', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Large', + 415 => 'Unsupported Media Type', + 416 => 'Requested Range Not Satisfiable', + 417 => 'Expectation Failed', + 422 => 'Unprocessable Entity', + 423 => 'Locked', + 424 => 'Failed Dependency', + 425 => 'No code', + 426 => 'Upgrade Required', + 500 => 'Internal Server Error', + 501 => 'Method Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Temporarily Unavailable', + 504 => 'Gateway Time-out', + 505 => 'HTTP Version Not Supported', + 506 => 'Variant Also Negotiates', + 507 => 'Insufficient Storage', + 510 => 'Not Extended' +); + + +/** + * End of Definitions + * ---------------------------------------------------------- + */ + + + +/** + * StreamSend Class + */ + +class StreamSend { + + /** + * Field types in StreamSend + * + * This var is assigned the field type array in the constructor + * and is available for reference. + */ + var $streamsendFieldTypes; + + /** + * Clase Debug Status + * + * Set to true to enable debug output + */ + var $debug = false; + + /** + * Base URL at which the StreamSend API is located + */ + var $baseURL; + + /** + * Complete URL at which the specific StreamSend API method is located + */ + var $completeURL; + + /** + * Setting for CURLOPT_SSL_VERIFYPEER + * + * Defines whether we should verify the peer's certificate + * + * Normally should be set to "true". + */ + var $verifyPeer; + + /** + * Setting for CURLOPT_RETURNTRANSFER + * + * Defines if PHP curl_exec() should return a string or + * display the response directly to the user's browser. + * + * In all cases this should be "true" to return rather + * than display the response. + */ + var $returnTransfer; + + /** + * User name to use for authentication into StreamSend API + * + * The user name and password for the StreamSend API is generated + * via the StreamSend partner Web site. + */ + var $userName; + + /** + * User password to use for authentication into StreamSend API + */ + var $userPassword; + + /** + * XML Request + * + * This is detail of the request sent to the StreamSend API. + */ + var $xmlRequest = ''; + + /** + * Default Setting for CURLOPT_HTTPHEADER + * + * An array of HTTP header fields that is included in all requests. + * This is set in the GET, POST, MULTIPART case options in sendRequest(). + */ + var $httpHeader = false; + + /** + * Setting for CURLOPT_CUSTOMREQUEST + * + * The HTTP method to use for a request. + * For StreamSend API may be: "GET", "POST", "PUT", or "DELETE" + */ + var $requestMethod; + + /** + * Curl POST data + * + * Text to supply to StreamSend in a POST operation + * Set to false by default to detect when data is not supplied. + */ + var $postData = false; + + /** + * Currently select StreamSend Account + * + * A StreamSend Account equates to a Gaslight Media customer. + * All customer lists and blasts are contained within their account. + */ + var $currentAccount = NULL; + + /** + * Int - Last Curl Return Code + */ + var $curlError = NULL; + + /** + * String - Last Curl Return String + */ + var $curlErrorString = NULL; + + /** + * Boolean - Was last API request successful + */ + var $responseStatus = NULL; + + /** + * Numeric Error Code we assign to API failures + */ + var $responseError = NULL; + + /** + * Text error message describing $responseError + */ + var $responseErrorText = NULL; + + /** + * API Server HTTP Response Code + * + * The response HTTP response code from the last request to the StreamSend server. + * (i.e. 200, 404, ...) + */ + var $responseHTTPStatus = NULL; + + /** + * Text describing HTTP Response code + */ + var $responseHTTPStatusText = NULL; + + /** + * API XML Response + * + * The raw XML response from the last API request to the StreamSend server. + * $noXMLExpected tells the sendRequest() method to no bother trying to + * parse the response from StreamSend as XML. + */ + var $response = NULL; + var $noXMLExpected = false; + + /** + * Return headers in response from curl. + * + * If this is true, curl will include the response headers in the response. + */ + var $returnHeaders = false; + + /** + * Destination for parsed header data returned in a response when $returnHeaders is true + */ + var $parsedHeaders = false; + + /** + * Parsed API Response Data + * + * This is an array containing the parsed data from the XML response. + */ + var $responseData = NULL; + + /** + * Display a debug message if debug is enabled + */ + var $debugBuffer = ''; + + function debug($message) + { + if ($this->debug) + $this->debugBuffer .= '

StreamSend API Debug: '.$message.'
'; + } + + /** + * Parse headers into a key/value array + * + */ + function parseHeaders( $header ) + { + $retVal = array(); + + $fields = explode("\r\n", preg_replace('/\x0D\x0A[\x09\x20]+/', ' ', $header)); + + foreach( $fields as $field ) { + + if( preg_match('/([^:]+): (.+)/m', $field, $match) ) { + + $match[1] = preg_replace('/(?<=^|[\x09\x20\x2D])./e', 'strtoupper("\0")', strtolower(trim($match[1]))); + + if( isset($retVal[$match[1]]) ) { + $retVal[$match[1]] = array($retVal[$match[1]], $match[2]); + } else { + $retVal[$match[1]] = trim($match[2]); + } + } + } + return $retVal; + } + + /** StreamSend + * Class construtor. Set up the default variables for the class. + * + * May be called with optional $debug parameter to set debug right away. + */ + function StreamSend($base_url, $user_name, $user_password, $debug = false ) + { + global $streamsendFieldTypes; + + $this->baseURL = $base_url; + $this->verifyPeer = true; + $this->returnTransfer = true; + $this->userName = $user_name; + $this->userPassword = $user_password; + $this->debug = $debug; + $this->streamsendFieldTypes = $streamsendFieldTypes; + + $this->debug("StreamSend() Constructor called with:
+ URL: $base_url
+ User Name: $user_name
+ User Password: $user_password
"); + } + + /** + * Sets and API error code along with the corresponding error description. + * + * If the error code is anything but 0 (successful), it must be a failure + */ + function setAPIError($error) + { + global $streamsendErrorMessage; + + $this->responseError = $error; + $this->responseErrorText = $streamsendErrorMessage[$error]; + $this->responseStatus = ( $error > 0 ); + } + + function sendRequest($method, $uri ) + { + global $HTTPResponseCodeText; + + $this->debug("sendRequest() called with:
$uri"); + + /** Build complete URL to specific StreamSend API method */ + $this->completeURL = $this->baseURL.'/'.$uri; + + /** Create curl object */ + $c = curl_init( ); + + /** Setup Curl Parameters */ + curl_setopt($c, CURLOPT_URL, $this->completeURL); + curl_setopt($c, CURLOPT_SSL_VERIFYPEER, $this->verifyPeer); + curl_setopt($c, CURLOPT_RETURNTRANSFER, $this->returnTransfer); + curl_setopt($c, CURLOPT_USERPWD, $this->userName.':'.$this->userPassword); + curl_setopt($c, CURLOPT_POST, false); + curl_setopt($c, CURLOPT_POSTFIELDS, NULL); + + /** set request method */ + switch ($method) { + case 'PUT' : + $this->httpHeader = array ( + 'Accept: application/xml', # any data returned should be XML + 'Content-Type: application/xml' # any data we send will be XML + ); + curl_setopt($c, CURLOPT_HTTPHEADER, $this->httpHeader); + curl_setopt($c, CURLOPT_CUSTOMREQUEST, 'PUT'); + curl_setopt($c, CURLOPT_POST, true); + + /** Check for post data */ + if( !$this->postData ) { + $this->setAPIError(STREAMSEND_API_ERROR_POSTDATA_NOT_SUPPLIED); + return(false); + } + + /** Provide the post data */ + curl_setopt($c, CURLOPT_POSTFIELDS, $this->postData); + break; + case 'GET': + $this->httpHeader = array ( + 'Accept: application/xml', # any data returned should be XML + 'Content-Type: application/xml' # any data we send will be XML + ); + curl_setopt($c, CURLOPT_HTTPHEADER, $this->httpHeader); + curl_setopt($c, CURLOPT_HTTPGET, true); + + break; + + case 'DELETE': + $this->httpHeader = array ( + 'Accept: application/xml' # any data returned should be XML + ); + curl_setopt($c, CURLOPT_HTTPHEADER, $this->httpHeader); + curl_setopt($c, CURLOPT_CUSTOMREQUEST, 'DELETE'); + + break; + + case 'POST': + + $this->httpHeader = array ( + 'Accept: application/xml', # any data returned should be XML + 'Content-Type: application/xml' # any data we send will be XML + ); + curl_setopt($c, CURLOPT_HTTPHEADER, $this->httpHeader); + curl_setopt($c, CURLOPT_POST, true); + + /** Check for post data */ + if( !$this->postData ) { + $this->setAPIError(STREAMSEND_API_ERROR_POSTDATA_NOT_SUPPLIED); + return(false); + } + + /** Provide the post data */ + curl_setopt($c, CURLOPT_POSTFIELDS, $this->postData); + break; + + case 'MULTIPART': + /** This method sends multipart/form-data for uploading files */ + + $this->httpHeader = array ( + 'Accept: application/xml', # any data returned should be XML + ); + curl_setopt($c, CURLOPT_HTTPHEADER, $this->httpHeader); + curl_setopt($c, CURLOPT_POST, true); + + /** Check for post data */ + if( !$this->postData ) { + $this->setAPIError(STREAMSEND_API_ERROR_POSTDATA_NOT_SUPPLIED); + return(false); + } + + /** Provide the post data */ + curl_setopt($c, CURLOPT_POSTFIELDS, $this->postData); + break; + + default: + curl_setopt($c, CURLOPT_CUSTOMREQUEST, $method); + break; + } + + /** Clear all response data */ + $this->setAPIError(STREAMSEND_API_ERROR_NONE); + $this->responseHTTPStatus = NULL; + $this->response = NULL; + $this->responseData = NULL; + + /** If requested, include the returned headers in the respone output */ + if( $this->returnHeaders ) + curl_setopt($c, CURLOPT_HEADER, true); + + /** + * Send the request to the StreamSend server. + * + * If there's a complete failure to talk with it, return false. + */ + if (!($this->response = curl_exec($c))) { + $this->setAPIError(STREAMSEND_API_ERROR_NO_RESPONSE); + $this->curlError = curl_errno($c); + $this->curlErrorString = curl_error($c); + $this->responseErrorText = curl_error($c); + $this->debug('sendRequest() CURL Error:
'.$this->responseErrorText); + return(clone $this); + } + + $this->debug('sendRequest() Call to curl_exec() completed
Full Response
'
+                    ."\n".htmlentities($this->response)."\n"
+                    .'
'); + + + /** + * We received some kind of response from the StreamSend server. + * + * Save the returned HTTP result status (i.e. 200, 404, etc) + */ + $this->responseHTTPStatus = curl_getinfo($c, CURLINFO_HTTP_CODE); + $this->debug('sendRequest() HTTP response code returned: '.$this->responseHTTPStatus); + + /** + * Check for if the HTTP result status indicates a problem + */ + $this->responseHTTPStatusText = $HTTPResponseCodeText[$this->responseHTTPStatus]; + if ($this->responseHTTPStatus > 299) { + $this->debug('sendRequest() Received unexpected HTTP response status ('.$this->responseHTTPStatus.').
'.$this->responseHTTPStatusText); + $this->setAPIError(STREAMSEND_API_ERROR_HTTP_RESPONSE); + } + + /** + * If we have a failed HTTP reponse then return now + */ + if ($this->responseError > 0) { + return( $this->responseError ); + } + + /** + * If there's no data returned, assume that's what was expected + * and return. + */ + $response = trim($this->response); + if (empty($response)) { + $this->debug('sendRequest() No response provided. Assuming it was not expected. Returning.'); + $this->setAPIError(STREAMSEND_API_ERROR_NONE); + return( $this->responseError ); + } + + /** + * If return headers were requested, parse them out into an array + */ + if( $this->returnHeaders ) + $this->parsedHeaders = $this->parseHeaders($response); + + /** If no XML is expected, return now */ + if( $this->noXMLExpected ) + return $this->responseError; + + /** + * Parse the XML response to a data array. + */ + $this->debug('sendRequest() Have text of a response. Trying to parse XML.'); + try { + $this->responseData = new SimpleXMLElement($response); + } catch (Exception $e) { + $this->setAPIError(STREAMSEND_API_ERROR_BAD_XML); + return( $this->responseError ); + } + $this->setAPIError(STREAMSEND_API_ERROR_NONE); + $this->debug('sendRequest() Result of parsed XML
'.htmlentities(print_r($this->responseData,true)).'

'); + + return( $this->responseError ); + } + + /***************************************************************************************************** + * + * STREAMSEND RESOURCE CATEGORIES + * + * The StreamSend API is divided into general categories of functionality. Below are groupings of + * methods intended to address GLM needs to interact with the StreamSend API under each category. + * + * System Configuration + * Audiences Top level grouping - There is an Audience ID for each account that doesn't change + * Fields Attributes that describe each contact who receives E-Mail from a blast + * Fields Options Available options for contact picklist fields + * Accounts Customer level functionality + * Users Users who have access to specific accounts + * + * Contacts and Contact Groupings + * People Individual contacts + * Lists Groups of contacts + * Memberships Links contacts to lists (subscriptions) + * Filters Means of grouping lists and filtering contacts for use in a blast + * + * E-Mail Blasts + * Emails E-Mails (newsletters) that may be sent + * Blasts An individual instance of E-Mail distribution + * Bounces Bounce reporting for a specific Blast + * Unsubscribes Unsubscribe requests resulting from a specific blast + * Clicks Instances of contacts clicking on a link in an E-Mail + * Views Instances of a contact viewing an E-Mail + * + *****************************************************************************************************/ + + + /** ---------------------------------- System Configuration Methods -------------------------------- */ + + + /** + * Audience Methods + * + * Audiences form the highest level grouping of people. Within each audience, people may be grouped + * into any number of lists, but audiences themselves are self-contained and mutually exclusive. + * Each StreamSend account has one audience, as StreamSend does not currently provide support for + * multiple audiences per account. This resource is provided for conceptual consistency and is + * limited to the index, show, and update actions. + * + * Each account had an Audience ID that doesn't change, but it's not the same for all accounts. This + * method can be used to determine the correct ID for an account. + * another request to the StreamSend API. + */ + + function audienceList() + { + $this->debug('audienceList() called'); + + /** This operation requires the "GET" Method */ + if ($this->sendRequest('GET', 'audiences') === false) { + $this->debug('audienceList() Call to sendRequest() failed.'); + return( false ); + } + + /** + * Check if the response request was successful + */ + if ($this->responseError > 0) { + $this->debug('audienceList() Call to sendRequest() returned an error code.'); + } else { + $this->debug('audienceList() Received good response from sendRequest().'); + } + + return(clone $this); + } + + /** + * Fields Methods + * + * Fields are the various attributes that describe each person, e.g. first name, last name. + * Each account may have a unique set of fields. Be sure to maintain a standard set of + * fields to ensure compatibility with Gaslight Media applications. + */ + + function fieldCreate( $name, $type, $options = false, $include_blank = false, $allow_other = false ) + { + global $streamsendFieldTypes; + + $this->debug('fieldCreate() called to create field type: '.$streamsendFieldTypes[$type]['Name']); + + /** Make sure a valid name is supplied */ + if( ($name = trim($name)) == '') { + $this->debug('fieldCreate() Name not provided or invalid.'); + return false; + } + + /** Force type to be numerit and make sure the specified field type is valid. */ + $type = ($type + 0); + if( $type == 0 || !isset($streamsendFieldTypes[$type]) ) { + $this->debug('fieldCreate() Field type not provided or not a valid type number.'); + return false; + } + + /** If the field type requires options then make sure at least one was provided */ + if( $streamsendFieldTypes[$type]['Options'] && ( !is_array($options) || count($options) == 0 ) ) { + $this->debug('fieldCreate() Options not provided for field type that requires options.'); + return false; + } + + /** + * Build XML POST data string for supplied field + */ + $post_data = "\n"; + $post_data .= " $name\n" + ." ".$streamsendFieldTypes[$type]['Name']."\n" + ." ".($include_blank?'true':'false')."\n" + ." ".($allow_other?'true':'false')."\n"; + if( $streamsendFieldTypes[$type]['Options'] ) { + $post_data .= " \n"; + foreach( $options as $opt ) + $post_data .= " \n"; + $post_data .= " \n"; + } + $post_data .= "\n"; + + $this->postData = $post_data; + $this->debug('fieldCreate() XML POST request data
'
+                    ."\n".htmlentities($this->postData)."\n"
+                    .'
'); + + /** Tell sendRequest() to not bother parsing response as XML and to return response headers for parsing */ + $this->noXMLExpected = true; + $this->returnHeaders = true; + + /** This operation requires the "POST" Method */ + if ($this->sendRequest('POST', 'audiences/'.STREAMSEND_AUDIENCE.'/fields') === false) { + $this->debug('fieldCreate() Call to sendRequest() failed.'); + return false; + } + + /** Be sure to reset these parameters or other functions may have trouble */ + $this->noXMLExpected = false; + $this->returnHeaders = false; + + /** + * Check if the response request was successful + */ + if ($this->responseError > 0) { + $this->debug('fieldCreate() Call to sendRequest() returned an error code.'); + } else { + $this->debug('fieldCreate() Received good response from sendRequest().'); + } + + /** Did we get a 422 response? If so, it could be that the field already exists */ + if ($this->responseHTTPStatus != '201' ) { + $this->debug('fieldCreate() StreamSend returned a "422 Unprocessable Entry" response. Does the field already exist?'); + return false; + } + + /** We should have received a 201 response */ + if ($this->responseHTTPStatus != '201' ) { + $this->debug('fieldCreate() StreamSend did not return a "201 Created" response.'); + return false; + } + + /** Check for the field ID in the "Location:" header line */ + if( !isset($this->parsedHeaders['Location']) ) { + $this->debug('fieldCreate() StreamSend did not return a "Location:" header with the field ID.'); + return false; + } + + /** Get field ID from "Location" header and force it to a number, then check it's not 0 */ + if( ($field_id = substr( strrchr( $this->parsedHeaders['Location'], '/' ), 1 ) + 0) == 0 ) { + $this->debug('fieldCreate() StreamSend did not return a valid field ID. ('.$id.')'); + return false; + } + + $this->debug('fieldCreate() Have a valid field ID. ('.$field_id.')'); + + $this->responseData->fieldID = $field_id; + + return clone $this; + + } + + + function fieldsList() + { + $this->debug('fieldsList() called'); + + /** This operation requires the "GET" Method */ + if ($this->sendRequest('GET', 'audiences/'.STREAMSEND_AUDIENCE.'/fields') === false) { + $this->debug('fieldsList() Call to sendRequest() failed.'); + return false; + } + + /** + * Check if the response request was successful + */ + if ($this->responseError > 0) { + $this->debug('fieldsList() Call to sendRequest() returned an error code.'); + } else { + $this->debug('fieldsList() Received good response from sendRequest().'); + } + + return(clone $this); + } + + /** + * Field Get + * + * Fields are the various attributes that describe each person, e.g. first name, last name. + * Each account may have a unique set of fields. Be sure to maintain a standard set of + * fields to ensure compatibility with Gaslight Media applications. + */ + + function fieldGet( $id ) + { + $this->debug('fieldGet() called'); + + /** This operation requires the "GET" Method */ + if ($this->sendRequest('GET', 'audiences/'.STREAMSEND_AUDIENCE.'/fields/'.$id) === false) { + $this->debug('fieldGet() Call to sendRequest() failed.'); + return false; + } + + /** + * Check if the response request was successful + */ + if ($this->responseError > 0) { + $this->debug('fieldGet() Call to sendRequest() returned an error code.'); + } else { + $this->debug('fieldGet() Received good response from sendRequest().'); + } + + return(clone $this); + } + + function fieldOptionCreate($fieldId, $name) + { + global $streamsendFieldTypes; + + $this->debug('fieldOptionCreate() called to create field type: '.$streamsendFieldTypes[$type]['Name']); + + /** Make sure a valid name is supplied */ + if( ($name = trim($name)) == '') { + $this->debug('fieldOptionCreate() Name not provided or invalid.'); + return false; + } + + /** Force fieldId to be numeric and make sure the specified field type is valid. */ + $fieldId = ($fieldId + 0); + if( $fieldId == 0 || !is_numeric($fieldId) ) { + $this->debug('fieldOptionCreate() FieldId not provided or not a number.'); + return false; + } + + /** + * Build XML POST data string for supplied field + */ + $post_data = "\n"; + + $this->postData = $post_data; + $this->debug('fieldOptionCreate() XML POST request data
'
+                    ."\n".htmlentities($this->postData)."\n"
+                    .'
'); + + /** Tell sendRequest() to not bother parsing response as XML and to return response headers for parsing */ + $this->noXMLExpected = true; + $this->returnHeaders = true; + + /** This operation requires the "POST" Method */ + $postUrl = "audiences/".STREAMSEND_AUDIENCE."/fields/{$fieldId}/options"; + if ($this->sendRequest('POST', $postUrl) === false) { + $this->debug('fieldOptionCreate() Call to sendRequest() failed.'); + return false; + } + + /** Be sure to reset these parameters or other functions may have trouble */ + $this->noXMLExpected = false; + $this->returnHeaders = false; + + /** + * Check if the response request was successful + */ + if ($this->responseError > 0) { + $this->debug('fieldOptionCreate() Call to sendRequest() returned an error code.'); + } else { + $this->debug('fieldOptionCreate() Received good response from sendRequest().'); + } + + /** Did we get a 404 response? */ + if ($this->responseHTTPStatus == '404' ) { + $this->debug('fieldOptionCreate() StreamSend returned a "404 Page Not Found" response.'); + return false; + } + + /** Did we get a 422 response? If so, it could be that the field already exists */ + if ($this->responseHTTPStatus == '422' ) { + $this->debug('fieldOptionCreate() StreamSend returned a "422 Unprocessable Entry" response. Does the field already exist?'); + return false; + } + + /** We should have received a 201 response */ + if ($this->responseHTTPStatus != '201' ) { + $this->debug('fieldOptionCreate() StreamSend did not return a "201 Created" response.'); + return false; + } + + /** Check for the field ID in the "Location:" header line */ + if( !isset($this->parsedHeaders['Location']) ) { + $this->debug('fieldOptionCreate() StreamSend did not return a "Location:" header with the field ID.'); + return false; + } + + /** Get field ID from "Location" header and force it to a number, then check it's not 0 */ + if( ($optionId = substr( strrchr( $this->parsedHeaders['Location'], '/' ), 1 ) + 0) == 0 ) { + $this->debug('fieldOptionCreate() StreamSend did not return a valid option ID. ('.$id.')'); + return false; + } + + $this->debug('fieldOptionCreate() Have a valid field ID. ('.$optionId.')'); + + $this->responseData->optionID = $optionId; + + return clone $this; + } + + function fieldOptionDelete($fieldId, $optionId) + { + $this->debug('fieldOptionDelete() Called to delete Field Option '.$optionId ); + + /** Force fieldId to be numeric and make sure the specified field type is valid. */ + $fieldId = ($fieldId + 0); + if( $fieldId == 0 || !is_numeric($fieldId) ) { + $this->debug('fieldOptionDelete() FieldId not provided or not a number.'); + return false; + } + + /** Force optionId to be numeric and make sure the specified field type is valid. */ + $optionId = ($optionId + 0); + if( $optionId == 0 || !is_numeric($optionId) ) { + $this->debug('fieldOptionDelete() OptionId not provided or not a number.'); + return false; + } + + /** Expecting only an HTTP response code, so no XML parsing is required */ + $this->noXMLExpected = true; + + /** This operation requires the "DELETE" Method */ + $deleteUrl = "audiences/" + . STREAMSEND_AUDIENCE + . "/fields/{$fieldId}/options/{$optionId}/"; + if ($this->sendRequest('DELETE', $deleteUrl) === false) { + $this->debug('fieldOptionDelete() Call to sendRequest() failed.'); + return false; + } + + /** Be sure to reset these parameters or other functions may have trouble */ + $this->noXMLExpected = false; + + /** Process the two normally expected response codes related to deleting a contact */ + switch( $this->responseHTTPStatus ) { + + case '200': + $this->debug('fieldOptionDelete() Call to sendRequest() returned a 200 OK. Contact should be deleted.'); + return clone $this; + break; + + case '423': + $this->debug('fieldOptionDelete() Call to sendRequest() returned a 423 LOCKED. Contact cannot be deleted at this time.'); + return clone $this; + break; + + } + + /** We get here because an unexpected HTTP response code was recieved */ + $this->debug('fieldOptionDelete() Call to sendRequest() returned an unexpected code. Contact may not be deleted.'); + return false; + } + + /** + * Fields Options Methods + * + * Those fields that utilize enumerated values, e.g. Select, Radio, Checkbox, will present + * each person with a series of options from which they may choose. The available options + * for a given field constitute an ordered set onto which new options will be appended. + */ + + function fieldOptionsGet( $id ) + { + $this->debug('fieldOptionsGet() called'); + + /** This operation requires the "GET" Method */ + if ($this->sendRequest('GET', 'audiences/'.STREAMSEND_AUDIENCE.'/fields/'.$id.'/options') === false) { + $this->debug('fieldOptionsGet() Call to sendRequest() failed.'); + return false; + } + + /** + * Check if the response request was successful + */ + if ($this->responseError > 0) { + $this->debug('fieldOptionsGet() Call to sendRequest() returned an error code.'); + } else { + $this->debug('fieldOptionsGet() Received good response from sendRequest().'); + } + + return(clone $this); + } + + /** + * To update a given option for a field. + * + * @global type $streamsendFieldTypes (why we still using globals?) + * + * @param type $fieldId + * @param type $optionId + * @param type $name + * + * @return type + */ + function fieldOptionUpdate($fieldId, $optionId, $name) + { + global $streamsendFieldTypes; + + $this->debug('fieldOptionUpdate() called to create field type: '.$streamsendFieldTypes[$type]['Name']); + + /** Make sure a valid name is supplied */ + if( ($name = trim($name)) == '') { + $this->debug('fieldOptionUpdate() Name not provided or invalid.'); + return false; + } + + /** Force fieldId to be numeric and make sure the specified field type is valid. */ + $fieldId = ($fieldId + 0); + if( $fieldId == 0 || !is_numeric($fieldId) ) { + $this->debug('fieldOptionUpdate() FieldId not provided or not a number.'); + return false; + } + + /** Force optionId to be numeric and make sure the specified field type is valid. */ + $optionId = ($optionId + 0); + if( $optionId == 0 || !is_numeric($optionId) ) { + $this->debug('fieldOptionUpdate() OptionId not provided or not a number.'); + return false; + } + + /** + * Build XML POST data string for supplied field + */ + $post_data = "\n"; + + $this->postData = $post_data; + $this->debug('fieldOptionUpdate() XML POST request data
'
+                    ."\n".htmlentities($this->postData)."\n"
+                    .'
'); + + /** This operation requires the "POST" Method */ + $putUrl = "audiences/".STREAMSEND_AUDIENCE."/fields/{$fieldId}/options/{$optionId}/"; + if ($this->sendRequest('PUT', $putUrl) === false) { + $this->debug('fieldOptionUpdate() Call to sendRequest() failed.'); + return false; + } + + /** + * Check if the response request was successful + */ + if ($this->responseError > 0) { + $this->debug('fieldOptionUpdate() Call to sendRequest() returned an error code.'); + } else { + $this->debug('fieldOptionUpdate() Received good response from sendRequest().'); + } + + return clone $this; + } + + function fieldsGetAll() + { + $this->debug('fieldsGetAll() called'); + + if (!($fields = $this->fieldsList($field_id)) || $fields->responseStatus) { + $this->debug('fieldsGetAll() Call to fieldGet() failed.'); + return false; + } + + $this->fieldsData = array(); + + foreach ($fields->responseData->field as $field) { + + $f_id = (int) $field->id; + + /** Add the field data to the plain fieldsData array */ + $this->fieldsData[$f_id] = array( + 'name' => ( (string) $field->name ), + 'data-type' => ( (string) $field->{'data-type'} ), + 'include-blank' => ( (string) $field->{'include-blank'} ), + 'allow-other' => ( (string) $field->{'allow-other'} ), + 'slug' => ( (string) $field->slug ) + ); + + + switch( $field->{'data-type'} ) { + + /** These fields have no additional data */ + case 'Text Field': + case 'Text Area': + case 'Date/Time': + case 'Date': + case 'Time': + $this->fieldsData[$f_id]['options'] = false; + break; + + /** These fields have options associated with them */ + case 'Select': + case 'Radio': + case 'Checkbox': + + /** Get the options for this field - Don't fail completely here */ + if (!($options = $this->fieldOptionsGet($f_id)) || $options->responseStatus) { + $this->debug('fieldsGetAll() Call to fieldOptionsGet() failed.'); + $fields_data[$f_id]['Options'] = false; + break; + } + + + //$fields_data + foreach( $options->responseData->option as $option ) { + $this->fieldsData[$f_id]['options'][(int) $option->id] = (string) $option->name; + } + + break; + } + + } + + return(clone $this); + } + + /** + * Accounts Methods + * + * Resellers of StreamSend may create additional accounts underneath their parent account. + * The quota for child accounts constitutes a subset of the quota for the parent reseller account. + * + * Gaslight Media will have one account per customer or Web site. In some cases, customers may + * want to conduct E-Mail blasts for multiple related Web sites. + */ + function accountList() + { + $this->debug('accountList() called'); + + /** + * This operation requires the "GET" Method + * A false indicates that the server didn't respond at all. + */ + if ($this->sendRequest('GET', 'accounts') === false) { + $this->debug('accountList() Call to sendRequest() failed.'); + return false; + } + + /** + * Check if the response request was successful + */ + if ($this->responseError > 0) { + $this->debug('accountList() Call to sendRequest() returned an error code.'); + } else { + $this->debug('accountList() Received good response from sendRequest().'); + } + + return(clone $this); + } + + function accountGet( $id ) + { + $this->debug('acccountGet() called'); + + /** This operation requires the "GET" Method */ + if ($this->sendRequest('GET', 'accounts/'.$id) === false) { + $this->debug('accountGet() Call to sendRequest() failed.'); + return false; + } + + /** + * Check if the response request was successful + */ + if ($this->responseError > 0) { + $this->debug('accountGet() Call to sendRequest() returned an error code.'); + } else { + $this->debug('accoun tGet() Received good response from sendRequest().'); + } + + /** Stuff the results into a logical and consistent place to use by the calling program */ + $this->contact = $this->responseData; + + return clone $this; + } + + + + /** + * Destroy Account - USE WITH CAUTION!!! + * Seems to take the StreamSend servers some time to complete and may + * cause their systems to be unresponsive or require killing the cookie for + * the Web login to their account management interface and loging in again. + * + * This may have to be used to remove an account since it's not possible as far + * as I can tell to change the name on a sub-account and no way to delete it from + * the Web interface. This does totally remove it. + * + * @return unknown_type + */ + function accountDestroy( $id ) + { + $this->debug('accountDestroy() called'); + + /** + * This operation requires the "GET" Method + * A false indicates that the server didn't respond at all. + */ + if ($this->sendRequest('DELETE', 'accounts/'.$id) === false) { + $this->debug('accountDestroy() Call to sendRequest() failed.'); + return false; + } + + /** + * Check if the response request was successful + */ + if ($this->responseError > 0) { + $this->debug('accountDestroy() Call to sendRequest() returned an error code.'); + } else { + $this->debug('accountDestroy() Received good response from sendRequest().'); + } + + return(clone $this); + } + + + + + + /** + * User Methods + * + * One may manage the users that have access to one�s account or, if one is a + * reseller, the users that have access to one�s resold accounts. + * + * Gaslight Media will normally have at least one user per account to permit + * the customer access to the StreamSend interface. + */ + + function userList() + { + $this->debug('userList() called'); + + /** This operation requires the "GET" Method */ + if ($this->sendRequest('GET', 'users') === false) { + $this->debug('userList() Call to sendRequest() failed.'); + return false; + } + + /** + * Check if the response request was successful + */ + if ($this->responseError > 0) { + $this->debug('userList() Call to sendRequest() returned an error code.'); + } else { + $this->debug('userList() Received good response from sendRequest().'); + } + + return(clone $this); + } + + + /** ------------------------------ Contacts and Contact Grouping Methods --------------------------- */ + + /** + * People (contacts) Methods + * + * People are the recipients of mailings. + */ + + function contactList( $page = 1, $pagesize = 100 ) + { + $this->debug('contactList() called'); + + /** Check for and limit to the maximum page size **/ + if ($pagesize > STREAMSEND_MAX_PAGE_SIZE) { + $pagesize = STREAMSEND_MAX_PAGE_SIZE; + $this->debug('contactList() Maximum page size exceeded. Page size set to StreamSend maximum.'); + } + + /** This operation requires the "GET" Method */ + if ($this->sendRequest('GET', 'audiences/'.STREAMSEND_AUDIENCE.'/people?page='.$page.'&per_page='.$pagesize) === false) { + $this->debug('contactList() Call to sendRequest() failed.'); + return false; + } + + /** + * Check if the response request was successful + */ + if ($this->responseError > 0) { + $this->debug('contactList() Call to sendRequest() returned an error code.'); + } else { + $this->debug('contactList() Received good response from sendRequest().'); + } + + /** Place list of "persons" in results as "contacts" */ + $this->contacts = $contacts->responseData->person; + + return clone $this; + } + + function contactSearch( $email ) + { + $this->debug('contactSearch() called'); + + /** This operation requires the "GET" Method */ + if ($this->sendRequest('GET', 'audiences/'.STREAMSEND_AUDIENCE.'/people?email_address='.$email) === false) { + $this->debug('contactSearch() Call to sendRequest() failed.'); + return false; + } + + /** + * Check if the response request was successful + */ + if ($this->responseError > 0) { + $this->debug('contactSearch() Call to sendRequest() returned an error code.'); + } else { + $this->debug('contactSearch() Received good response from sendRequest().'); + } + + /** + * We now need to see if we actually got any contact data back + */ + $this->contact = false; + foreach ($this->responseData->person as $contact) { + + /** Check to see if there's more than one contact returned, which would be an error */ + if( $this->contact != false ) { + $this->debug('contactSearch() Received mulitple contact results. This should not happen.'); + return false; + } + + /** Stuff the results into a logical and consistent place to use by the calling program */ + $this->contact = $contact; + } + + return clone $this; + } + + function contactGet( $id ) + { + $this->debug('contactGet() called'); + + /** This operation requires the "GET" Method */ + if ($this->sendRequest('GET', 'audiences/'.STREAMSEND_AUDIENCE.'/people/'.$id) === false) { + $this->debug('contactGet() Call to sendRequest() failed.'); + return false; + } + + /** + * Check if the response request was successful + */ + if ($this->responseError > 0) { + $this->debug('contactGet() Call to sendRequest() returned an error code.'); + } else { + $this->debug('contactGet() Received good response from sendRequest().'); + } + + /** Stuff the results into a logical and consistent place to use by the calling program */ + $this->contact = $this->responseData; + + return(clone $this); + } + + /** + * Create a Contact + * + * $contact is field/value array. + * + * The index of contactData is the field name slug (i.e. field name = "First Name", slug = "first_name" ) + * Slugs may only contain lower-case alphanumeric characters and "_". + * + * Minimum required fields include: email_address + * + * See setup file for explanation on other default values. + */ + + function contactCreate( $contact, + $activate = STREAMSEND_DEFAULT_ACTIVATE, + $deliver = STREAMSEND_DEFAULT_DELIVER_ACTIVATION, + $welcome = STREAMSEND_DEFAULT_DELIVER_WELCOME ) + { + $this->debug('contactCreate() called'); + + /** + * Check for minimum contact data + */ + if( !isset($contact['email-address']) || preg_match( "/^[A-Z0-9._%-]+@[A-Z0-9._%-]+\.[A-Z]{2,4}$/i", $contact['email-address'] ) == 0 ) { + $this->debug('contactCreate() E-Mail address not provided or not a valid E-Mail address.'); + return false; + } + + /** + * Build XML POST data string for supplied contact + */ + $post_data = "\n"; + while( list($k, $v) = each($contact) ) { + $v = str_replace("&", "&", $v); + $v = str_replace("'", "'", $v); + if (strstr($v, "|")) { + $mSect = explode("|", $v); + foreach ($mSect as $multiples) { + $post_data .= ' <'.trim($k).'>'.trim($multiples).'\n"; + } + } else { + $post_data .= ' <'.trim($k).'>'.trim($v).'\n"; + } + } + $post_data .= " $activate\n" + ." $deliver\n" + ." $welcome\n"; + $post_data .= "\n"; + $this->postData = $post_data; + $this->debug('contactCreate() XML POST request data
'
+                    ."\n".htmlentities($this->postData)."\n"
+                    .'
'); + + /** This operation requires the "POST" Method */ + if ($this->sendRequest('POST', 'audiences/'.STREAMSEND_AUDIENCE.'/people') === false) { + $this->debug('contactCreate() Call to sendRequest() failed.'); + return false; + } + + /** + * Check if the response request was successful + */ + if ($this->responseError > 0) { + $this->debug('contactCreate() Call to sendRequest() returned an error code.'); + } else { + $this->debug('contactCreate() Received good response from sendRequest().'); + } + + return clone $this; + } + + function contactUpdate($id, $contact) + { + $this->debug('contactUpdate() called'); + + /** + * Check for minimum contact data + */ + if( !isset($contact['email-address']) || preg_match( "/^[A-Z0-9._%-]+@[A-Z0-9._%-]+\.[A-Z]{2,4}$/i", $contact['email-address'] ) == 0 ) { + $this->debug('contactUpdate() E-Mail address not provided or not a valid E-Mail address.'); + return false; + } + + /** + * Build XML POST data string for supplied contact + */ + $post_data = "\n"; + while( list($k, $v) = each($contact) ) { + $v = str_replace("&", "&", $v); + $v = str_replace("'", "'", $v); + if (strstr($v, "|")) { + $mSect = explode("|", $v); + foreach ($mSect as $multiples) { + $post_data .= ' <'.trim($k).'>'.trim($multiples).'\n"; + } + } else { + $post_data .= ' <'.trim($k).'>'.trim($v).'\n"; + } + } + $post_data .= "\n"; + $this->postData = $post_data; + $this->debug('contactUpdate() XML POST request data
'
+                    ."\n".htmlentities($this->postData)."\n"
+                    .'
'); + + /** This operation requires the "POST" Method */ + if ($this->sendRequest('PUT', 'audiences/'.STREAMSEND_AUDIENCE.'/people/'.$id) === false) { + $this->debug('contactUpdate() Call to sendRequest() failed.'); + return false; + } + + /** + * Check if the response request was successful + */ + if ($this->responseError > 0) { + var_dump($this->responseError); + $this->debug('contactUpdate() Call to sendRequest() returned an error code.'); + } else { + $this->debug('contactUpdate() Received good response from sendRequest().'); + } + + return clone $this; + } + + /** + * Delete a Contact + * + * Requires a valid contact E-Mail address + */ + function contactDelete( $email ) + { + $this->debug('contactDelete() Called to delete E-Mail address: '.$email ); + + /** + * First find the contact to get the contact ID + */ + if (!($c = $this->contactSearch( $email ))) { + $this->debug('contactDelete() Call to sendRequest() failed.'); + return false; + } elseif ($c->responseStatus){ + $this->debug('contactDelete() Call to sendRequest returned an error code.'); + return false; + } + + if( $c->contact == false ) { + $this->debug('contactDelete() Search for specified E-Mail address failed. Does Contact exist?'); + return false; + } + + $id = $c->contact->id; + $this->debug('contactDelete() Have an ID for this contact: '.$id); + + /** Expecting only an HTTP response code, so no XML parsing is required */ + $this->noXMLExpected = true; + + /** This operation requires the "DELETE" Method */ + if ($this->sendRequest('DELETE', 'audiences/'.STREAMSEND_AUDIENCE.'/people/'.$id) === false) { + $this->debug('contactDelete() Call to sendRequest() failed.'); + return false; + } + + /** Be sure to reset these parameters or other functions may have trouble */ + $this->noXMLExpected = false; + + /** Process the two normally expected response codes related to deleting a contact */ + switch( $this->responseHTTPStatus ) { + + case '200': + $this->debug('uploadContacts() Call to sendRequest() returned a 200 OK. Contact should be deleted.'); + return clone $this; + break; + + case '423': + $this->debug('uploadContacts() Call to sendRequest() returned a 423 LOCKED. Contact cannot be deleted at this time.'); + return clone $this; + break; + + } + + /** We get here because an unexpected HTTP response code was recieved */ + $this->debug('uploadContacts() Call to sendRequest() returned an unexpected code. Contact may not be deleted.'); + return false; + } + + + /** + * Lists Methods + * + * Lists are groups of contacts. People (contacts) may be subscribed to multiple lists. + */ + + function listList() + { + $this->debug('listList() called'); + + /** This operation requires the "GET" Method */ + if ($this->sendRequest('GET', 'audiences/'.STREAMSEND_AUDIENCE.'/lists') === false) { + $this->debug('listList() Call to sendRequest() failed.'); + return( false ); + } + + /** + * Check if the response request was successful + */ + if ($this->responseError > 0) { + $this->debug('listList() Call to sendRequest() returned an error code.'); + } else { + $this->debug('listsList() Received good response from sendRequest().'); + } + + return(clone $this); + } + + + + /** + * Memberships (subscription) Methods + * + * Membership records track to which lists each person belongs. For any given list to + * which a person is subscribed, a membership record exists. The creation of a membership + * record linking a person and a list represents the act of joining that list. The + * destruction of a membership record represents the act of leaving that list. + */ + + /** Not written yet */ + + + /** + * Filters Methods + * + * Filters, along with lists, are one of two ways that the people in your audience + * can be grouped and manipulated. While lists are fairly static and unchanging, + * filters are completely dynamic. That is, no person ever "belongs" to a filter, + * as they might a list. Instead they are said to "match" a filter, and only when + * the filter is used does a clear group of people emerge. + */ + + /** Not written yet */ + + + /** -------------------------------------- E-Mail Blast Methods ------------------------------------ */ + + + /** + * Emails Methods + * + * Emails in StreamSend are those that have been saved for later use. They consist + * of some combination of HTML and plain text content and may be modified at any + * time without affecting any blasts that have used or will be using them. + */ + + /** Not written yet */ + + + /** + * Blasts Methods + * + * A blast is the act of sending an email to one or more people in your audience. Blasts + * may be sent immediately or at some specified date in the future. + */ + + function blastList() + { + $this->debug('blastList() called'); + + /** This operation requires the "GET" Method */ + if ($this->sendRequest('GET', 'audiences/'.STREAMSEND_AUDIENCE.'/blasts') === false) { + $this->debug('blastList() Call to sendRequest() failed.'); + return( false ); + } + + /** + * Check if the response request was successful + */ + if ($this->responseError > 0) { + $this->debug('blastList() Call to sendRequest() returned an error code.'); + } else { + $this->debug('blastList() Received good response from sendRequest().'); + } + + return(clone $this); + } + + function blastGet( $id ) + { + $this->debug('blastGet() called'); + + /** This operation requires the "GET" Method */ + if ($this->sendRequest('GET', 'audiences/'.STREAMSEND_AUDIENCE.'/blasts/'.$id) === false) { + $this->debug('blastGet() Call to sendRequest() failed.'); + return false; + } + + /** + * Check if the response request was successful + */ + if ($this->responseError > 0) { + $this->debug('blastGet() Call to sendRequest() returned an error code.'); + } else { + $this->debug('blastGet() Received good response from sendRequest().'); + } + + /** Stuff the results into a logical and consistent place to use by the calling program */ + $this->contact = $this->responseData; + + return clone $this; + } + + function monthlyStats( $month, $year ) + { + global $StreamSendAccounts; + + $this->debug('monthlyStats() called'); + + $total_accounts = $total_blasts = $total_sent = $total_delivered = $total_undelivered = $total_bounced = + $total_views = $total_clicks = $total_unsubscribes = $total_complaints = 0; + + /** + * Get list of all accounts + */ + if ( !($accounts = $this->accountList()) || $accounts->responseStatus ) { + $this->debug('monthlyStats() Unable to get account list'); + return false; + } + + /** Array that will contact all resulting data */ + $account_data = array(); + + /** + * For each account + */ + foreach ($accounts->responseData->account as $account) { + + $a_id = (int) $account->id; + $account_data[$a_id] = array( + 'name' => (string) $account->name, + 'quota' => (int) $account->quota, + 'soft-bounce-tolerance' => (int) $account->{'soft-bounce-tolerance'}, + 'automated-email-address' => (string) $account->{'automated-email-address'}, + 'owner' => (string) $account->owner->{'last-name'}.', '.$account->owner->{'first-name'}, + 'email-address' => (string) $account->owner->{'email-address'}, + 'blasts' => 0, + 'sent' => 0, + 'delivered' => 0, + 'undelivered' => 0, + 'bounced' => 0, + 'views' => 0, + 'clicks' => 0, + 'unsubscribes' => 0, + 'complaints' => 0 + ); + + $this->debug('monthlyStats() Processing account: '.$a_id); + + $total_accounts++; + + /** + * Get all blasts for the specified month + */ + + $account_data[$a_id]['blast_detail'] = array(); + + /** Set the account id */ + $this->currentAccount = $a_id; + $this->userName = $StreamSendAccounts[$a_id]['id']; + $this->userPassword = $StreamSendAccounts[$a_id]['key']; + + if (!($blasts = $this->blastList()) || $blasts->responseStatus ) { + $this->debug('monthlyStats() Unable to get blast list for account: '.$a_id); + $account_data[$a_id][$b_id] = false; + } else { + + foreach ($blasts->responseData->blast as $blast) { + + /** Get the scheduled date for this blast and break it up into parts */ + $date = getdate(strtotime( $blast->{'scheduled-for'} )); + + /** Is this blast scheduled for the requested month */ + if( $date['mon'] == $month && $date['year'] == $year ) { + + $account_data[$a_id]['blasts']++; + + $b_id = (int) $blast->id; + + $account_data[$a_id]['blast_detail'][$b_id] = array( + 'subject' => (string) $blast->subject, + 'email-address' => (string) $blast->from->{'email-address'}, + 'scheduled-for' => (string) $blast->{'scheduled-for'}, + 'completed-at' => (string) $blast->{'completed-at'}, + 'status' => (string) $blast->status, + 'sent' => 0 + ); + + /** + * Get blast detail + */ + + if (!($b = $this->blastGet($b_id)) || $b->responseStatus ){ + $this->debug('monthlyStats() Unable to get blast list for account: '.$a_id); + } else { + + $b_delivery = $b->responseData->statistics->delivery; + $b_activity = $b->responseData->statistics->activity; + + $account_data[$a_id]['blast_detail'][$b_id]['delivered'] = (int) $b_delivery->delivered; + $account_data[$a_id]['blast_detail'][$b_id]['undelivered'] = (int) $b_delivery->undelivered; + $account_data[$a_id]['blast_detail'][$b_id]['bounced'] = (int) $b_delivery->bounced; + $account_data[$a_id]['blast_detail'][$b_id]['views'] = (int) $b_activity->views; + $account_data[$a_id]['blast_detail'][$b_id]['clicks'] = (int) $b_activity->clicks; + $account_data[$a_id]['blast_detail'][$b_id]['unsubscribes'] = (int) $b_activity->unsubscribes; + $account_data[$a_id]['blast_detail'][$b_id]['complaints'] = (int) $b_activity->complaints; + + /** Calculate total number of E-Mails sent for this blast */ + $sent = (int) $b_delivery->delivered + (int) $b_delivery->undelivered + (int) $b_delivery->bounced; + $account_data[$a_id]['blast_detail'][$b_id]['sent'] = $sent; + + /** Add into account stats */ + $account_data[$a_id]['blasts']++; + $account_data[$a_id]['sent'] += $sent; + $account_data[$a_id]['delivered'] += (int) $b_delivery->delivered; + $account_data[$a_id]['undelivered'] += (int) $b_delivery->undelivered; + $account_data[$a_id]['bounced'] += (int) $b_delivery->bounced; + $account_data[$a_id]['views'] += (int) $b_activity->views; + $account_data[$a_id]['clicks'] += (int) $b_activity->clicks; + $account_data[$a_id]['unsubscribes'] += (int) $b_activity->unsubscribes; + $account_data[$a_id]['complaints'] += (int) $b_activity->complaints; + + /** Add into overall stats */ + $total_blasts++; + $total_sent += $sent; + $total_delivered += (int) $b_delivery->delivered; + $total_undelivered += (int) $b_delivery->undelivered; + $total_bounced += (int) $b_delivery->bounced; + $total_views += (int) $b_activity->views; + $total_clicks += (int) $b_activity->clicks; + $total_unsubscribes += (int) $b_activity->unsubscribes; + $total_complaints += (int) $b_activity->complaints; + + } // Have good blast detail + + } // Check date + + } // for each blast + + } // Have good list of blasts for account + + } // For each account + + /** Stuff the results into a logical and consistent place to use by the calling program */ + $this->stats = array( + 'total_blasts' => $total_blasts, + 'total_sent' => $total_sent, + 'total_delivered' => $total_delivered, + 'total_undelivered' => $total_undelivered, + 'total_bounced' => $total_bounced, + 'total_views' => $total_views, + 'total_clicks' => $total_clicks, + 'total_unsubscribes' => $total_unsubscribes, + 'total_complaints' => $total_complaints, + 'account_detail' => $account_data + ); + + return clone $this; + } + + + + /** + * Bounces Methods + * + * Bounces are those instances wherein certain people do not receive a particular blast. + * There are many reasons for this including an invalid email address, a full inbox, a + * problem with the receiving email server, etc. + */ + + /** Not written yet */ + + + /** + * Unsubcribes Methods + * + * Unsubscribes track two instances of people unsubscribing from one�s audience: manual + * and complaint-based. + */ + + /** Not written yet */ + + + /** + * Clicks Methods + * + * Clicks are those instances in which a person clicks on an external link in a particular + * message. Because clicks are tracked by modifying hyperlink URLs in the body of the message, + * clicks can only be registered for those viewing the HTML portion of the message and only + * for those URLs that are linked via an HTML hyperlink tag. + */ + + /** Not written yet */ + + + /** + * Views Methods + * + * Views are those instances in which a person views a particular message. Because views are + * tracked by way of a tracking image embedded in the message, views can only be registered + * for those viewing the HTML portion of the message and for whom the viewing of images is + * currently enabled in his or her email client. + */ + + /** Not written yet */ + + /** -------------------------------------- Upload and Import Methods ------------------------------------ */ + + + /** + * Upload Method + * + * Uploads a list of contacts and import into the contact list. + * + * $contacts is an array of contacts to upload. The array should be formatted as... + * + * $contacts = array( + * 0 => array( + * 'email_address' => '{email}', + * '{field_name}' => '{field_value}', + * '{field_name}' => '{field_value}', + * ... + * ), + * 1 => array( + * 'email_address' => '{email}', + * '{field_name}' => '{field_value}', + * '{field_name}' => '{field_value}', + * ... + * ), + * ... + * ); + * + * The contact data must have at least 'email_address', but can have additional + * fields that are setup for the account on the StreamSend side. The {field_name} + * for the addional field names must a "slug" for the actual name. Slugs are the + * field name but converted to only contain lower-case alphanumeric characters and "_". + * + * Also, all contact sub arrays must have exactly the same field names or the upload + * will be rejected. + * + * $reactivate re-starts the double opt-in process for the uploaded contacts that + * already exist in StreamSend. This is an optional parameter that defaults to false. + * + * $lists is a simple array of List ID's for Lists to which uploaded contacts should + * be added. This is an optional parameter. + * + */ + + function uploadContacts( $contacts, $reactivate = false, $lists = '' ) + { + $this->debug('uploadContacts() called'); + + /** + * Compile the contacts array into a text file for upload and send it to StreamSend. + * + * This is the first step in the import process. It should result in a valid + * upload ID that will then be used to import the contacts. + */ + + /** + * Check for minimum required data + * + * Was there a list of contacts supplied? + */ + if( !isset($contacts) || !is_array($contacts) || count($contacts) == 0 ) { + $this->debug('uploadContacts() A valid list of contacts was not provided.'); + return false; + } + + $this->debug('uploadContacts() '.count($contacts).' contacts provided.'); + + /** + * Get the list of valid fields for this account and convert to array with key = slug and value = id + */ + if( !($fields_list = $this->fieldsList()) ) { + $this->debug('uploadContacts() Call to fieldsList() failed.'); + return false; + } + + /** Email_address is not returned in fieldsList() but is required. Curiously it doesn't have an ID like the other fields */ + $available_fields = array( 'email_address' => 'email_address' ); + foreach( $fields_list->responseData->field as $field ) { + $available_fields[(string) $field->slug] = (string) $field->id; + } + + /** + * Build the text file for submission to StreamSend, "|" delimited, one contact per line. + * Also get the list of fields from the first contact and verify that all the rest are the same. + */ + $field_names = array(); + $upload_data = $contact_fields = $contact_data_header = $contact_data_header_sep = ''; + $numb_contacts = $numb_fields = 0; + $have_email_field = false; + + foreach( $contacts as $fields ) { + + $field = 0; + $contact_data = ''; + + /** If this is not the first contact, make sure we have the same number of fields as the first. */ + if( $numb_contacts > 0 && count($fields) != $numb_fields ) { + $this->debug('uploadContacts() Contact # '.($numb_contacts+1).' does not have the same number of fields as the first.'); + return false; + } + + /** For each field in this contact */ + while( list($k, $v) = each($fields) ) { + + /** If this is the first contact in the supplied array, save the field name */ + if( $numb_contacts == 0 ) { + /** Check for proper field name Slug */ + if( !isset($available_fields[$k]) ) { + $this->debug('uploadContacts() Improper field name Slug provided: '.$k); + return false; + } + + /** Add this field to our array of field names */ + $field_names[$field] = $k; + + /** Add this field to a header that will be sent as the first line in the contact data file */ + $contact_data_header .= $contact_data_header_sep.$k; + + /** Check if this is the email_address field. If so, say that we have it */ + if( $k == 'email_address' ) + $have_email_field = true; + + /** Compile list of contact fields for debug output */ + $contact_fields .= $k."\n"; + + } + else + /** Otherwise check to see if this is the expected field name */ + if( $field_names[$field] != $k ) { + $this->debug('uploadContacts() Fields for contact # '.($numb_contacts+1).' did not match first contact.'); + return false; + } + + /** Add field to contact, use "|" separator if it's not the first field */ + $contact_data .= ($field>0?"\t":'').$v; + + $contact_data_header_sep = "\t"; + + $field++; + + } // for each field + + /** If this is the first contact, save the number of expected fields, and set the header line for the file */ + if( $numb_contacts == 0 ) { + $numb_fields = $field; + $upload_data = "$contact_data_header\n"; + } + + /** Add this contact to the upload data */ + $upload_data .= "$contact_data\n"; + + $numb_contacts++; + + } // For each Contact + + /** Was the required email_address field supplied? */ + if( !$have_email_field ) { + $this->debug('uploadContacts() Required "email_address" field not supplied.'); + return false; + } + $this->debug('uploadContacts() Have required "email_address" field.'); + + $this->debug('uploadContacts() Contacts fields supplied...
'
+                    ."\n".htmlentities($contact_fields)
+                    .'
'); + + $this->debug('uploadContacts() Contacts data supplied...
'
+                    ."\n".htmlentities($upload_data)
+                    .'
'); + + /** Write the upload data to a file for Curl to send using multipart/form-data */ + $tmpname = tempnam("/tmp", "ss_"); + $h = fopen($tmpname, "w"); + fwrite($h, $upload_data); + fclose($h); + + /** Add file name of upload data to Post array */ + $this->postData = array( 'data' => "@$tmpname" ); + + /** Tell sendRequest() to not bother parsing response as XML and to return response headers for parsing */ + $this->noXMLExpected = true; + $this->returnHeaders = true; + + /** This operation requires the "MULTIPART" Method */ + if ($this->sendRequest('MULTIPART', 'uploads') === false) { + $this->debug('uploadContacts() Contacts upload call to sendRequest() failed.'); + return false; + } + + /** Be sure to reset these parameters or other functions may have trouble */ + $this->noXMLExpected = false; + $this->returnHeaders = false; + + /** Delete the temporary file */ + unlink($tmpname); + + /** We should have received a 201 response */ + if ($this->responseHTTPStatus != '201' ) { + $this->debug('uploadContacts() StreamSend did not return a "201 Created" response.'); + return false; + } + + /** Check for the upload ID in the "Location:" header line */ + if( !isset($this->parsedHeaders['Location']) ) { + $this->debug('uploadContacts() StreamSend did not return a "Location:" header with the upload ID.'); + return false; + } + + /** Get upload ID from "Location" header and force it to a number, then check it's not 0 */ + if( ($upload_id = substr( strrchr( $this->parsedHeaders['Location'], '/' ), 1 ) + 0) == 0 ) { + $this->debug('uploadContacts() StreamSend did not return a valid upload ID. ('.$id.')'); + return false; + } + $this->debug('uploadContacts() Have a valid upload ID. ('.$upload_id.')'); + + $this->responseData->uploadID = $upload_id; + + /** + * Tell StreamSend to import the contacts supplied in the upload above. + * + * This is the second step of the process. + */ + + /** Build XML POST data string for import - Note that fields other than email_address use the field IDs here. */ + $post_data = "\n" + ." ".($reactivate?'true':'false')."\n" + ." $lists\n" + ." $upload_id\n" + ." Tab\n" + ." \n"; + reset( $field_names ); + foreach( $field_names as $f ) { + $post_data .= " ".$available_fields[$f]."\n"; + } + $post_data .= " \n" + .""; + + $this->postData = $post_data; + $this->debug('uploadContacts() XML POST request data
'
+                    ."\n".htmlentities($this->postData)."\n"
+                    .'
'); + + /** This operation requires the "POST" Method */ + if ($this->sendRequest('POST', 'audiences/'.STREAMSEND_AUDIENCE.'/imports') === false) { + $this->debug('uploadContacts() Contact import call to sendRequest() failed.'); + return false; + } + + /** We should have received a 201 response */ + if ($this->responseHTTPStatus != '201' ) { + $this->debug('uploadContacts() StreamSend did not return a "201 Created" response.'); + return false; + } + + /** Check for the upload ID in the "Location:" header line */ + if( !isset($this->parsedHeaders['Location']) ) { + $this->debug('uploadContacts() StreamSend did not return a "Location:" header with import ID.'); + return false; + } + + /** Get upload ID from "Location" header and force it to a number, then check it's not 0 */ + if( ($import_id = substr( strrchr( $this->parsedHeaders['Location'], '/' ), 1 ) + 0) == 0 ) { + $this->debug('uploadContacts() StreamSend did not return a valid upload ID. ('.$id.')'); + return false; + } + $this->debug('uploadContacts() Have a valid import ID. ('.$import_id.')'); + + $this->responseData->importID = $import_id; + + return clone $this; + } + + +} + +?> diff --git a/models/admin/communicator/index.php b/models/admin/communicator/index.php index 6602edf..4393156 100644 --- a/models/admin/communicator/index.php +++ b/models/admin/communicator/index.php @@ -12,6 +12,22 @@ * @release index.php,v 1.0 2014/10/31 19:31:47 cscott Exp $ * @link http://dev.gaslightmedia.com/ */ +/** + * Default parameters for contact create operations. + * Note that these are strings for use in XML data not true/false values. + * If false, the person will be created with a status of pending + */ +//define('STREAMSEND_DEFAULT_ACTIVATE', 'true'); +/** + * If activate is false, setting this to true will trigger the sending of the built-in + * activation notification; if activate is true, this setting has no effect + */ +//define('STREAMSEND_DEFAULT_DELIVER_ACTIVATION', 'false'); +/** + * If activate is true, setting this to true will trigger the sending of the built-in + * welcome notification; if activate is false, this setting has no effect + */ +//define('STREAMSEND_DEFAULT_DELIVER_WELCOME', 'false'); class GlmMembersAdmin_communicator_index // extends GlmDataCommunicator { @@ -77,16 +93,77 @@ class GlmMembersAdmin_communicator_index // extends GlmDataCommunicator public function modelAction($actionData = false) { + // Get the settings + $config = $this->config['settings']; + // Check to see if StreamSend is setup + if ( $config['enable_streamsend'] ) { + define( 'STREAMSEND_AUDIENCE', $config['streamsend_audience'] ); + $streamsend = new StreamSend( + STREAMSEND_BASE_URL, + $config['streamsend_login'], + $config['streamsend_key'] + ); + $streamsend->debug = true; + switch ( $actionData['type'] ) { + case 'memberInfo': + // set memberInfo + $memberInfo = $actionData['memberInfo']['fieldData']; + if ( isset( $memberInfo['email'] ) && $memberInfo['email'] ) { + //echo '

$memberInfo: ' . print_r( $memberInfo, true ) . '
'; + // check to see if the memberInfo email exists on streamsend + $ret = $streamsend->contactSearch( $memberInfo['email'] ); + $categories = ''; + if ( isset( $memberInfo['categories'] ) ) { + $cats = array(); + foreach ( $memberInfo['categories'] as $cat ) { + $cats[] = $cat['name']; + } + $categories = implode( '|', $cats ); + } + $contactData = array( + 'email-address' => $memberInfo['email'], + 'company' => $memberInfo['member_name'], + 'address1' => $memberInfo['addr1'], + 'address2' => $memberInfo['addr2'], + 'city' => $memberInfo['city']['name'], + 'stateprovince' => $memberInfo['state']['name'], + 'postal-code' => $memberInfo['zip'], + 'phone-number' => $memberInfo['phone'], + 'member-category' => $categories, + 'member-type' => 'Member', + ); + //echo '
$contactData: ' . print_r( $contactData, true ) . '
'; + if ( $ret->contact ) { + echo '
$ret->contact: ' . print_r( $ret->contact, true ) . '
'; + if ( $memberInfo['status']['value'] == 10 ) { + // Update Contact if member is active + } else { + // Delete Contact if member is inactive + } + } else { + // Add Contact if member is active + if ( $memberInfo['status']['value'] == 10 ) { + $contacts = $streamsend->contactCreate( + $contactData, + STREAMSEND_DEFAULT_ACTIVATE, + STREAMSEND_DEFAULT_DELIVER_ACTIVATION, + STREAMSEND_DEFAULT_DELIVER_WELCOME + ); + } + } + } + + break; + case 'memberContact': + break; + } + } + //echo '
$config: ' . print_r( $config, true ) . '
'; + - // Compile template data - $templateData = array( - ); - // Return status, any suggested view, and any data to controller return array( 'status' => true, 'modelRedirect' => false, - 'view' => 'admin/communicator/index.html', - 'data' => $templateData ); } diff --git a/models/admin/management/communicator.php b/models/admin/management/communicator.php index 50d17b5..486e904 100644 --- a/models/admin/management/communicator.php +++ b/models/admin/management/communicator.php @@ -14,7 +14,7 @@ */ // Load Management Communicator data abstract -//require_once GLM_MEMBERS_COMMUNICATOR_PLUGIN_CLASS_PATH.'/data/dataManagement.php'; +require_once GLM_MEMBERS_COMMUNICATOR_PLUGIN_CLASS_PATH.'/data/dataManagement.php'; /** * GlmMembersAdmin_management_communicator @@ -28,7 +28,7 @@ * @release SVN: $Id: packaging.php,v 1.0 2011/01/25 19:31:47 cscott * Exp $ */ -class GlmMembersAdmin_management_communicator //extends GlmDataCommunicatorManagement +class GlmMembersAdmin_management_communicator extends GlmDataCommunicatorManagement { /** @@ -96,7 +96,7 @@ class GlmMembersAdmin_management_communicator //extends GlmDataCommunicatorManag $this->config = $config; // Run constructor for members data class - //parent::__construct(false, false); + parent::__construct(false, false); } @@ -113,7 +113,7 @@ class GlmMembersAdmin_management_communicator //extends GlmDataCommunicatorManag $option = false; $settings_updated = false; $settings_update_error = false; - $communicator_settings = false; + $communicator_settings = false; $option2 = false; if (isset($_REQUEST['option'])) { @@ -154,7 +154,7 @@ class GlmMembersAdmin_management_communicator //extends GlmDataCommunicatorManag case 'submit': // Update the event management settings - //$communicator_settings = $this->updateEntry(1); + $communicator_settings = $this->updateEntry(1); if ($communicator_settings['status']) { $settings_updated = true; } else { @@ -167,7 +167,7 @@ class GlmMembersAdmin_management_communicator //extends GlmDataCommunicatorManag default: // Try to get the first (should be only) entry for general settings. - //$communicator_settings = $this->editEntry(1); + $communicator_settings = $this->editEntry(1); //echo '
$communicator_settings: ' . print_r( $communicator_settings, true ) . '
'; if ($communicator_settings === false) { diff --git a/setup/adminHooks.php b/setup/adminHooks.php index 6b33557..6ac8206 100644 --- a/setup/adminHooks.php +++ b/setup/adminHooks.php @@ -27,10 +27,12 @@ */ // Adding Action for when the memberInfo record is saved (new or update) add_action('glm-member-db-memberinfosave', function($member){ - // Code here for hook - echo '

MemberInfo action hook

'; - echo '
$member: ' . print_r( $member, true ) . '
'; -}, 10, 1); + $memberData = array( + 'type' => 'memberInfo', + 'memberInfo' => $member + ); + $this->controller( 'communicator', 'index', $memberData ); +}, 10, 2); // Adding Action for when the Member Contact record is saved (new or update) add_action('glm-member-db-membercontactsave', function($contact){ diff --git a/setup/databaseScripts/create_database_V0.0.1.sql b/setup/databaseScripts/create_database_V0.0.1.sql index 75e2ee4..76f87d9 100644 --- a/setup/databaseScripts/create_database_V0.0.1.sql +++ b/setup/databaseScripts/create_database_V0.0.1.sql @@ -22,7 +22,7 @@ CREATE TABLE {prefix}management ( enable_constant_contact BOOLEAN NULL, -- Constant Contact On Off Flag constant_contact_password TINYTEXT NULL, -- Constant Contact Password constant_contact_api_key TINYTEXT NULL, -- Constant Contact API Key - constant_contact_login TINTYTEXT NULL, -- Constant Contact Login + constant_contact_login TINYTEXT NULL, -- Constant Contact Login constant_contact_api_path TINYTEXT NULL, -- Constant Contact API Path constant_contact_list TINYTEXT NULL, -- Constant Contact List ID enable_mailchimp BOOLEAN NULL, -- MailChimp On Off diff --git a/setup/databaseScripts/dbVersions.php b/setup/databaseScripts/dbVersions.php new file mode 100644 index 0000000..03a3548 --- /dev/null +++ b/setup/databaseScripts/dbVersions.php @@ -0,0 +1,19 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release dbVersions.php,v 1.0 2014/10/31 19:31:47 cscott Exp $ + * @link http://dev.gaslightmedia.com/ + */ + +$glmMembersCommunicatorDbVersions = array( + '0.0.1' => array('version' => '0.0.1', 'tables' => 1), +); + diff --git a/setup/validActions.php b/setup/validActions.php index 40f4c0b..ff237ac 100644 --- a/setup/validActions.php +++ b/setup/validActions.php @@ -59,6 +59,9 @@ $glmMembersCommunicatorAddOnValidActions = array( 'adminActions' => array( + 'communicator' => array( + 'index' => GLM_MEMBERS_COMMUNICATOR_PLUGIN_SLUG, + ), 'management' => array( 'communicator' => GLM_MEMBERS_COMMUNICATOR_PLUGIN_SLUG, ), diff --git a/views/admin/management/communicator.html b/views/admin/management/communicator.html index aa721e9..95b932b 100644 --- a/views/admin/management/communicator.html +++ b/views/admin/management/communicator.html @@ -21,6 +21,101 @@ + + + + + + + + + + + + + + + + + + + +

StreamSend Settings

+ Enable StreamSend: + + +
StreamSend Login: + +
StreamSend Key: + +
StreamSend Audience: + +