Version Notes
We've introduced a new mechanic to this extension. It does not allow double-dipping -- if a shopper gets an instant discount, they should not be able to redeem a coupon code for the same cart.
You can sign up for an account immediately after you register. Do let us know if you have any feedback or comments either through our website http://getadvocado.com, or via our email: dax@getadvocado.com
Download this release
Release Info
Developer | SY Quek |
Extension | Advocado |
Version | 1.1.0 |
Comparing to | |
See all releases |
Code changes from version 1.0.3 to 1.1.0
- app/code/community/GozoLabs/Advocado/Block/Adminhtml/Login.php +0 -1
- app/code/community/GozoLabs/Advocado/Helper/Analytics.php +75 -0
- app/code/community/GozoLabs/Advocado/Helper/Backend.php +16 -0
- app/code/community/GozoLabs/Advocado/Helper/Data.php +87 -1
- app/code/community/GozoLabs/Advocado/Model/Observer.php +5 -2
- app/code/community/GozoLabs/Advocado/controllers/CampaignController.php +162 -0
- app/code/community/GozoLabs/Advocado/controllers/V1Controller.php +59 -0
- app/code/community/GozoLabs/Advocado/etc/config.xml +14 -8
- app/design/frontend/base/default/layout/gozolabs_advocado.xml +2 -2
- lib/Analytics/Analytics.php +82 -0
- lib/Analytics/Analytics/Client.php +126 -0
- lib/Analytics/Analytics/Consumer.php +86 -0
- lib/Analytics/Analytics/Consumer/File.php +117 -0
- lib/Analytics/Analytics/Consumer/ForkCurl.php +59 -0
- lib/Analytics/Analytics/Consumer/Socket.php +172 -0
- lib/Analytics/Analytics/QueueConsumer.php +144 -0
- package.xml +7 -5
app/code/community/GozoLabs/Advocado/Block/Adminhtml/Login.php
CHANGED
@@ -126,7 +126,6 @@ class GozoLabs_Advocado_Block_Adminhtml_Login extends
|
|
126 |
* - storeGroupName
|
127 |
*/
|
128 |
public function websiteStoreGroups() {
|
129 |
-
Mage::log('trying to find the errors');
|
130 |
$websites = Mage::getModel('core/website')
|
131 |
->getCollection();
|
132 |
|
126 |
* - storeGroupName
|
127 |
*/
|
128 |
public function websiteStoreGroups() {
|
|
|
129 |
$websites = Mage::getModel('core/website')
|
130 |
->getCollection();
|
131 |
|
app/code/community/GozoLabs/Advocado/Helper/Analytics.php
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// test commit
|
4 |
+
if ( isset( $_SERVER[ 'ADVOC_LOCAL_DEBUG' ] ) || isset( $_SERVER['ADVOC_STAGING'] ) ) {
|
5 |
+
define( 'SEGMENT_IO_PIN', '8sm4kvvp9hyzwn99ykdr' );
|
6 |
+
} else {
|
7 |
+
define( 'SEGMENT_IO_PIN', 'mdsygwjezbsovqi0j31y' );
|
8 |
+
}
|
9 |
+
|
10 |
+
//require_once(Mage::getBaseDir('lib') . '/Raven/Client.php');
|
11 |
+
require_once(Mage::getBaseDir('lib') . '/Analytics/Analytics.php');
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Logging tool for Advocado's use.
|
15 |
+
* There are specific cases for its use, however we need to take note that
|
16 |
+
* we are just an extension. So we should not be capturing all exceptions.
|
17 |
+
* Rather we should just catch exceptions that are relevant to this
|
18 |
+
* extension's smooth operation (for iteration).
|
19 |
+
*
|
20 |
+
*/
|
21 |
+
class GozoLabs_Advocado_Helper_Analytics extends Mage_Core_Helper_Abstract {
|
22 |
+
|
23 |
+
public $isInit;
|
24 |
+
public $siteUrl;
|
25 |
+
|
26 |
+
public function isInitialized() {
|
27 |
+
return isset($this->isInit) && $this->isInit;
|
28 |
+
}
|
29 |
+
|
30 |
+
private function getBaseIdTraits() {
|
31 |
+
if (!isset($this->siteUrl) || !$this->siteUrl) {
|
32 |
+
$dh = Mage::helper('gozolabs_advocado');
|
33 |
+
$this->siteUrl = $dh->getSiteUrl();
|
34 |
+
}
|
35 |
+
return array(
|
36 |
+
'Site URL'=> $this->siteUrl,
|
37 |
+
'Platform' => 'Magento'
|
38 |
+
);
|
39 |
+
}
|
40 |
+
|
41 |
+
public function initialize() {
|
42 |
+
Mage::log('[Analytics] Initialising with ' . SEGMENT_IO_PIN);
|
43 |
+
Analytics::init(SEGMENT_IO_PIN);
|
44 |
+
Mage::log('[Analytics] Initialised');
|
45 |
+
$this->isInit = true;
|
46 |
+
$baseTraits = $this->getBaseIdTraits();
|
47 |
+
Mage::log('[Analytics] got base traits');
|
48 |
+
$this->identify($baseTraits);
|
49 |
+
Mage::log('[Analytics] identified');
|
50 |
+
}
|
51 |
+
|
52 |
+
public function identify($traits) {
|
53 |
+
if (!$this->isInitialized()) {
|
54 |
+
$this->initialize();
|
55 |
+
}
|
56 |
+
Analytics::identify('019mr8mf4r', $traits);
|
57 |
+
}
|
58 |
+
|
59 |
+
public function track($eventName, $traits) {
|
60 |
+
if (!$this->isInitialized()) {
|
61 |
+
Mage::log('[Analytics] Starting initialisation');
|
62 |
+
$this->initialize();
|
63 |
+
Mage::log('[Analytics] Done initialisation');
|
64 |
+
}
|
65 |
+
Mage::log('[Analytics] Getting the base traits');
|
66 |
+
$baseIdTraits = $this->getBaseIdTraits();
|
67 |
+
Mage::log('[Analytics] base traits: ' . var_export($baseIdTraits, true));
|
68 |
+
$t = array_merge($traits, $this->getBaseIdTraits());
|
69 |
+
Mage::log('[Analytics] Tracking: '.$eventName.' , ' . var_export($traits, true));
|
70 |
+
Analytics::track('019mr8mf4r', $eventName, $t);
|
71 |
+
}
|
72 |
+
}
|
73 |
+
|
74 |
+
|
75 |
+
?>
|
app/code/community/GozoLabs/Advocado/Helper/Backend.php
CHANGED
@@ -91,10 +91,22 @@ class GozoLabs_Advocado_Helper_Backend extends Mage_Core_Helper_Abstract {
|
|
91 |
const TEMP_WEBSITE_ID = 1;
|
92 |
const TEMP_STORE_GROUP_ID = 1;
|
93 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
|
95 |
public function isStoreConnected() {
|
96 |
$sc = $this->storeCredentials();
|
97 |
if ($sc) {
|
|
|
|
|
|
|
|
|
98 |
return true;
|
99 |
}
|
100 |
return false;
|
@@ -731,6 +743,10 @@ class GozoLabs_Advocado_Helper_Backend extends Mage_Core_Helper_Abstract {
|
|
731 |
strval($rp->getStatus()) .
|
732 |
')' .
|
733 |
$rp->getMessage());
|
|
|
|
|
|
|
|
|
734 |
}
|
735 |
|
736 |
}
|
91 |
const TEMP_WEBSITE_ID = 1;
|
92 |
const TEMP_STORE_GROUP_ID = 1;
|
93 |
|
94 |
+
private $analyticsHelper;
|
95 |
+
|
96 |
+
private function getAnalytics() {
|
97 |
+
if (!isset($this->analyticsHelper) || !$this->analyticsHelper) {
|
98 |
+
$this->analyticsHelper = Mage::helper('gozolabs_advocado/analytics');
|
99 |
+
}
|
100 |
+
return $this->analyticsHelper;
|
101 |
+
}
|
102 |
|
103 |
public function isStoreConnected() {
|
104 |
$sc = $this->storeCredentials();
|
105 |
if ($sc) {
|
106 |
+
$this->getAnalytics()->track(
|
107 |
+
'Connected Store Viewing Dashboard',
|
108 |
+
array()
|
109 |
+
);
|
110 |
return true;
|
111 |
}
|
112 |
return false;
|
743 |
strval($rp->getStatus()) .
|
744 |
')' .
|
745 |
$rp->getMessage());
|
746 |
+
$log = Mage::helper('gozolabs_advocado/analytics');
|
747 |
+
$log->track('Backend Error', array(
|
748 |
+
'Status' => 'Cannot invalidate coupon (Backend Coupon ID=' . $couponId . ')',
|
749 |
+
));
|
750 |
}
|
751 |
|
752 |
}
|
app/code/community/GozoLabs/Advocado/Helper/Data.php
CHANGED
@@ -74,6 +74,10 @@ class AdvocPCoupon extends AdvocModelInstance {
|
|
74 |
) ) ? true : false;
|
75 |
}
|
76 |
|
|
|
|
|
|
|
|
|
77 |
public function getData( $field=null ) {
|
78 |
|
79 |
if ($field) {
|
@@ -1102,6 +1106,7 @@ class GozoLabs_Advocado_Helper_Data extends Mage_Core_Helper_Data {
|
|
1102 |
const SHARE_CODES_PARENT_SUB = 'parent_sub_id';
|
1103 |
const SHARE_CODES_ST_CODE = 'st_code';
|
1104 |
const SHARE_CODES_SHARES = 'shares';
|
|
|
1105 |
|
1106 |
function getWebsite($websiteId) {
|
1107 |
$sites = Mage::app()->getWebsites();
|
@@ -1147,6 +1152,56 @@ class GozoLabs_Advocado_Helper_Data extends Mage_Core_Helper_Data {
|
|
1147 |
return $product->isConfigurable();
|
1148 |
}
|
1149 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1150 |
/**
|
1151 |
* @param $product1 Mage_Catalog_Model_Product
|
1152 |
* @param $product2 Mage_Catalog_Model_Product
|
@@ -1308,6 +1363,38 @@ class GozoLabs_Advocado_Helper_Data extends Mage_Core_Helper_Data {
|
|
1308 |
return $websiteIds;
|
1309 |
}
|
1310 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1311 |
function createCartCoupon( $code, $amt, $toDate, $type='amt',
|
1312 |
$websiteIds=null ) {
|
1313 |
|
@@ -1345,7 +1432,6 @@ class GozoLabs_Advocado_Helper_Data extends Mage_Core_Helper_Data {
|
|
1345 |
->setIsActive(1)
|
1346 |
->setConditionsSerialized('')
|
1347 |
->setActionsSerialized('')
|
1348 |
-
->setConditionsSerialized('')
|
1349 |
->setCustomerGroupIds($this->_getAllCustomerGroups())
|
1350 |
->setStopRulesProcessing(0)
|
1351 |
->setIsAdvanced(1)
|
74 |
) ) ? true : false;
|
75 |
}
|
76 |
|
77 |
+
public function getRule() {
|
78 |
+
return $this->origObject;
|
79 |
+
}
|
80 |
+
|
81 |
public function getData( $field=null ) {
|
82 |
|
83 |
if ($field) {
|
1106 |
const SHARE_CODES_PARENT_SUB = 'parent_sub_id';
|
1107 |
const SHARE_CODES_ST_CODE = 'st_code';
|
1108 |
const SHARE_CODES_SHARES = 'shares';
|
1109 |
+
const ADVOCADO_CATEGORY_NAME = 'Advocado Products';
|
1110 |
|
1111 |
function getWebsite($websiteId) {
|
1112 |
$sites = Mage::app()->getWebsites();
|
1152 |
return $product->isConfigurable();
|
1153 |
}
|
1154 |
|
1155 |
+
/* ------------------------------------------------------------------------
|
1156 |
+
* For Advocado Magento v1.1.0
|
1157 |
+
* -----------------------------------------------------------------------*/
|
1158 |
+
|
1159 |
+
/* Advocado works with a special category so that application of coupons
|
1160 |
+
* only takes place on these items.
|
1161 |
+
*/
|
1162 |
+
function createAdvocadoCategory() {
|
1163 |
+
$cat = new Mage_Catalog_Model_Category();
|
1164 |
+
$cat->setName(self::ADVOCADO_CATEGORY_NAME);
|
1165 |
+
$cat->setUrlKey('advocado-discount');
|
1166 |
+
$cat->setIsActive(1);
|
1167 |
+
$cat->setIncludeInMenu(0);
|
1168 |
+
$cat->setDisplayMode('PRODUCTS');
|
1169 |
+
$cat->setIsAnchor(0);
|
1170 |
+
// we use the root catalog, so the parent ID is 0
|
1171 |
+
$parentCategory = Mage::getModel('catalog/category')
|
1172 |
+
->load(
|
1173 |
+
Mage::app()->getWebsite(1)
|
1174 |
+
->getDefaultStore()
|
1175 |
+
->getRootCategoryId()
|
1176 |
+
);
|
1177 |
+
Mage::log('parent category id = ' . $parentCategory->getId());
|
1178 |
+
$cat->setPath($parentCategory->getPath());
|
1179 |
+
$cat->save();
|
1180 |
+
return $cat;
|
1181 |
+
}
|
1182 |
+
|
1183 |
+
function getAdvocadoCategory() {
|
1184 |
+
|
1185 |
+
$all = Mage::getModel('catalog/category')->getCollection()
|
1186 |
+
->addAttributeToSelect('name')
|
1187 |
+
->addAttributeToSelect('is_active');
|
1188 |
+
|
1189 |
+
$advocCat = null;
|
1190 |
+
|
1191 |
+
foreach($all as $_cat) {
|
1192 |
+
if ($_cat->getName() == self::ADVOCADO_CATEGORY_NAME) {
|
1193 |
+
// For other purposes
|
1194 |
+
$advocCat = $_cat;
|
1195 |
+
break;
|
1196 |
+
}
|
1197 |
+
}
|
1198 |
+
if ($advocCat == null) {
|
1199 |
+
Mage::log('Creating advocado category');
|
1200 |
+
$advocCat = $this->createAdvocadoCategory();
|
1201 |
+
}
|
1202 |
+
return $advocCat;
|
1203 |
+
}
|
1204 |
+
|
1205 |
/**
|
1206 |
* @param $product1 Mage_Catalog_Model_Product
|
1207 |
* @param $product2 Mage_Catalog_Model_Product
|
1363 |
return $websiteIds;
|
1364 |
}
|
1365 |
|
1366 |
+
/**
|
1367 |
+
* Will attach a condition to coupon. In this case we want to
|
1368 |
+
* focus only on applying this coupon on a specific category.
|
1369 |
+
* @return $coupon (which was passed in as a parameter)
|
1370 |
+
*/
|
1371 |
+
function exclusiveToAdvocadoProducts($coupon) {
|
1372 |
+
$cat = $this->getAdvocadoCategory();
|
1373 |
+
// to understand what this means, i recommend this blogpost
|
1374 |
+
// http://mikebywaters.wordpress.com/2011/12/18/programmatically-create-shopping-cart-price-rules-with-conditions-and-actions/
|
1375 |
+
$actions = array(
|
1376 |
+
'1' => array(
|
1377 |
+
'type' => 'salesrule/rule_condition_product',
|
1378 |
+
'aggregator' => 'all',
|
1379 |
+
'value' => '1',
|
1380 |
+
'new_child' => false
|
1381 |
+
),
|
1382 |
+
|
1383 |
+
'1--1' => array(
|
1384 |
+
'type' => 'salesrule/rule_condition_product',
|
1385 |
+
'attribute' => 'category_ids',
|
1386 |
+
'operator' => '==',
|
1387 |
+
'value' => $cat->getId(),
|
1388 |
+
'is_value_processed' => false
|
1389 |
+
)
|
1390 |
+
);
|
1391 |
+
$rule = $coupon->getRule();
|
1392 |
+
$rule->setData('actions', $actions);
|
1393 |
+
$rule->loadPost($rule->getData());
|
1394 |
+
$rule->save();
|
1395 |
+
return $coupon;
|
1396 |
+
}
|
1397 |
+
|
1398 |
function createCartCoupon( $code, $amt, $toDate, $type='amt',
|
1399 |
$websiteIds=null ) {
|
1400 |
|
1432 |
->setIsActive(1)
|
1433 |
->setConditionsSerialized('')
|
1434 |
->setActionsSerialized('')
|
|
|
1435 |
->setCustomerGroupIds($this->_getAllCustomerGroups())
|
1436 |
->setStopRulesProcessing(0)
|
1437 |
->setIsAdvanced(1)
|
app/code/community/GozoLabs/Advocado/Model/Observer.php
CHANGED
@@ -168,8 +168,11 @@ class GozoLabs_Advocado_Model_Observer {
|
|
168 |
// delete
|
169 |
$coupon->delete();
|
170 |
} else {
|
171 |
-
Mage::log('backend failed to update coupon with ' .
|
172 |
-
|
|
|
|
|
|
|
173 |
}
|
174 |
} else {
|
175 |
// we would normally delete
|
168 |
// delete
|
169 |
$coupon->delete();
|
170 |
} else {
|
171 |
+
Mage::log('backend failed to update coupon with ' . 'code = ' . $couponCode );
|
172 |
+
$log = Mage::helper('gozolabs_advocado/analytics');
|
173 |
+
$log->track('Backend Error', array(
|
174 |
+
'Status' => 'Did not delete coupon with code=' . $couponCode
|
175 |
+
));
|
176 |
}
|
177 |
} else {
|
178 |
// we would normally delete
|
app/code/community/GozoLabs/Advocado/controllers/CampaignController.php
ADDED
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
function _log( $msg ) {
|
4 |
+
Mage::log( $msg );
|
5 |
+
}
|
6 |
+
|
7 |
+
function _helper() {
|
8 |
+
return Mage::helper('gozolabs_advocado');
|
9 |
+
}
|
10 |
+
|
11 |
+
class GozoLabs_Advocado_CampaignController extends Mage_Core_Controller_Front_Action {
|
12 |
+
|
13 |
+
const PARAM_WEBSITE_STORE_GROUP = 'website_store_group';
|
14 |
+
const PARAM_PRODUCTS_PAGE = 'page';
|
15 |
+
const PARAM_PRODUCTS_PAGE_LIMIT = 'limit';
|
16 |
+
|
17 |
+
private function getJsonResponse() {
|
18 |
+
return $this->getResponse()->setHeader('Content-Type',
|
19 |
+
'application/json');
|
20 |
+
}
|
21 |
+
|
22 |
+
private function jsonify($data) {
|
23 |
+
return Mage::helper('core')->jsonEncode($data);
|
24 |
+
}
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Authenticates with stored credentials to ensure that
|
28 |
+
* they are well and truly the same.
|
29 |
+
*
|
30 |
+
* IF at first they are not the same, we get the backend to
|
31 |
+
* refresh the credentials. If at the 2nd round of
|
32 |
+
* comparison they are still not the same, this test
|
33 |
+
* fails.
|
34 |
+
*
|
35 |
+
*/
|
36 |
+
private function authenticate($siteKey, $siteToken, $creds = null ) {
|
37 |
+
|
38 |
+
$be = Mage::helper('gozolabs_advocado/backend');
|
39 |
+
if ( ! $creds ) {
|
40 |
+
|
41 |
+
$helper = Mage::helper('gozolabs_advocado');
|
42 |
+
$websiteId = $helper->getCurrentWebsiteId();
|
43 |
+
$storeGroupId = $helper->getCurrentStoreGroupId();
|
44 |
+
|
45 |
+
$creds = $be->storeCredentials(
|
46 |
+
$websiteId,
|
47 |
+
$storeGroupId
|
48 |
+
);
|
49 |
+
// if still not there, means they never were
|
50 |
+
if ( ! $creds ) {
|
51 |
+
$data = $be->requestSiteToken();
|
52 |
+
if ( ! $data ) {
|
53 |
+
return False;
|
54 |
+
} else {
|
55 |
+
$creds = $be->storeCredentials(
|
56 |
+
$websiteId,
|
57 |
+
$storeGroupId
|
58 |
+
);
|
59 |
+
}
|
60 |
+
}
|
61 |
+
return $this->authenticate( $siteKey, $siteToken, $creds );
|
62 |
+
|
63 |
+
} else {
|
64 |
+
Mage::log('for store with id '
|
65 |
+
. $creds->getStoreId()
|
66 |
+
. ', site credentials exist: - siteKey: '
|
67 |
+
. $creds->getSiteKey()
|
68 |
+
. ', siteToken: '
|
69 |
+
. $creds->getSiteToken()
|
70 |
+
. '; cand_siteKey: '
|
71 |
+
. $siteKey
|
72 |
+
. ', cand_siteToken: '
|
73 |
+
. $siteToken
|
74 |
+
);
|
75 |
+
// test equality
|
76 |
+
if ( $siteToken == $creds->getSiteToken()
|
77 |
+
&& $siteKey == $creds->getSiteKey() ) {
|
78 |
+
return True;
|
79 |
+
}
|
80 |
+
}
|
81 |
+
return False;
|
82 |
+
}
|
83 |
+
|
84 |
+
private function doCategoryUpdate($type, $req) {
|
85 |
+
|
86 |
+
// should be a comma delimited
|
87 |
+
$csvProductIds = $req->getParam('product_ids');
|
88 |
+
$siteKey = $req->getParam('site_key');
|
89 |
+
$siteToken = $req->getParam('site_token');
|
90 |
+
|
91 |
+
if ($this->authenticate($siteKey, $siteToken)) {
|
92 |
+
|
93 |
+
$productIds = explode(',', $csvProductIds);
|
94 |
+
Mage::log('product Ids = ' . var_export($productIds, true));
|
95 |
+
$_ = Mage::helper('gozolabs_advocado');
|
96 |
+
$specialCat = $_->getAdvocadoCategory();
|
97 |
+
$catId = $specialCat->getId();
|
98 |
+
Mage::log('Advocado Category with ID = ' . $specialCat->getId());
|
99 |
+
$catApi = Mage::getSingleton('catalog/category_api');
|
100 |
+
|
101 |
+
// TODO: might need catch an exception here and return an
|
102 |
+
// appropriate response
|
103 |
+
foreach( $productIds as $pId ) {
|
104 |
+
// add the product to the category
|
105 |
+
if ($type == 'add') {
|
106 |
+
$catApi->assignProduct(
|
107 |
+
$specialCat->getId(),
|
108 |
+
$pId
|
109 |
+
);
|
110 |
+
} else if ($type == 'remove') {
|
111 |
+
// check product exists in category before removing
|
112 |
+
$product = Mage::getModel('catalog/product')->load($pId);
|
113 |
+
if (in_array($catId, $product->getCategoryIds())) {
|
114 |
+
$catApi->removeProduct($catId, $pId);
|
115 |
+
}
|
116 |
+
//$catApi->removeProduct(
|
117 |
+
//$specialCat->getId(),
|
118 |
+
//$pId
|
119 |
+
//);
|
120 |
+
} else {
|
121 |
+
$log = Mage::helper('gozolabs_advocado/analytics');
|
122 |
+
$log->track('Invalid category update type', array(
|
123 |
+
'Site Key' => $siteKey
|
124 |
+
));
|
125 |
+
}
|
126 |
+
}
|
127 |
+
|
128 |
+
$this->getJsonResponse()
|
129 |
+
->setHttpResponseCode(200);
|
130 |
+
} else {
|
131 |
+
$this->getJsonResponse()
|
132 |
+
->setHttpResponseCode(403)
|
133 |
+
->appendBody(
|
134 |
+
$this->jsonify(
|
135 |
+
array(
|
136 |
+
'error_code' => 403,
|
137 |
+
'error_msg' => 'Not allowed'
|
138 |
+
)
|
139 |
+
));
|
140 |
+
}
|
141 |
+
|
142 |
+
}
|
143 |
+
|
144 |
+
/** Places products under a special Advocado category so that
|
145 |
+
* they can receive a discount.
|
146 |
+
*/
|
147 |
+
public function addcategoryAction() {
|
148 |
+
|
149 |
+
$req = $this->getRequest();
|
150 |
+
Mage::log('Adding to advocado category');
|
151 |
+
$this->doCategoryUpdate('add', $req);
|
152 |
+
|
153 |
+
}
|
154 |
+
|
155 |
+
public function removecategoryAction() {
|
156 |
+
$req = $this->getRequest();
|
157 |
+
Mage::log('Removing from advocado category');
|
158 |
+
$this->doCategoryUpdate('remove', $req);
|
159 |
+
}
|
160 |
+
}
|
161 |
+
|
162 |
+
?>
|
app/code/community/GozoLabs/Advocado/controllers/V1Controller.php
CHANGED
@@ -200,6 +200,7 @@ class GozoLabs_Advocado_V1Controller extends Mage_Core_Controller_Front_Action {
|
|
200 |
* authentication with store credentials.
|
201 |
*/
|
202 |
public function ordersAction() {
|
|
|
203 |
$req = $this->getRequest();
|
204 |
$siteKey = $req->getParam('site_key');
|
205 |
$siteToken = $req->getParam('site_token');
|
@@ -292,6 +293,7 @@ class GozoLabs_Advocado_V1Controller extends Mage_Core_Controller_Front_Action {
|
|
292 |
|
293 |
}
|
294 |
|
|
|
295 |
private function _parseRawUrlEncodedBody( $request ) {
|
296 |
$raw = $request->getRawBody();
|
297 |
$pairs = explode( '&', $raw );
|
@@ -336,6 +338,39 @@ class GozoLabs_Advocado_V1Controller extends Mage_Core_Controller_Front_Action {
|
|
336 |
return $request->getParam('action');
|
337 |
}
|
338 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
339 |
/**
|
340 |
*
|
341 |
* Handles request related to coupons.
|
@@ -368,6 +403,13 @@ class GozoLabs_Advocado_V1Controller extends Mage_Core_Controller_Front_Action {
|
|
368 |
$req->getParam('type'),
|
369 |
$this->_getAdvocadoWebsiteIds());
|
370 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
371 |
$this->getJsonResponse()
|
372 |
->setHttpResponseCode(201)
|
373 |
->setBody( $this->jsonify(
|
@@ -440,6 +482,23 @@ class GozoLabs_Advocado_V1Controller extends Mage_Core_Controller_Front_Action {
|
|
440 |
)));
|
441 |
|
442 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
443 |
} else {
|
444 |
$this->getJsonResponse()
|
445 |
->setHttpResponseCode(405);
|
200 |
* authentication with store credentials.
|
201 |
*/
|
202 |
public function ordersAction() {
|
203 |
+
|
204 |
$req = $this->getRequest();
|
205 |
$siteKey = $req->getParam('site_key');
|
206 |
$siteToken = $req->getParam('site_token');
|
293 |
|
294 |
}
|
295 |
|
296 |
+
|
297 |
private function _parseRawUrlEncodedBody( $request ) {
|
298 |
$raw = $request->getRawBody();
|
299 |
$pairs = explode( '&', $raw );
|
338 |
return $request->getParam('action');
|
339 |
}
|
340 |
|
341 |
+
private function applyCouponCode($couponCode, $notice='') {
|
342 |
+
|
343 |
+
if ($notice == '') {
|
344 |
+
$notice = $this->__('Congratulations! You have been given a discount!');
|
345 |
+
}
|
346 |
+
|
347 |
+
if ($couponCode != '') {
|
348 |
+
Mage::getSingleton('checkout/session')->setData('coupon_code', $couponCode);
|
349 |
+
$cart = Mage::getSingleton('checkout/cart')
|
350 |
+
->getQuote()
|
351 |
+
->setCouponCode($couponCode)
|
352 |
+
->collectTotals()
|
353 |
+
->save();
|
354 |
+
|
355 |
+
// a success message to congratulate them
|
356 |
+
Mage::getSingleton('core/session')->addSuccess($notice);
|
357 |
+
return $cart;
|
358 |
+
|
359 |
+
} else {
|
360 |
+
Mage::getSingleton('checkout/session')->setData('coupon_code', '');
|
361 |
+
$cart = Mage::getSingleton('checkout/cart');
|
362 |
+
$items = Mage::getSingleton('checkout/session')
|
363 |
+
->getQuote()
|
364 |
+
->getItemsCollection();
|
365 |
+
|
366 |
+
foreach($items as $item) {
|
367 |
+
$cart->removeItem( $item->getId() );
|
368 |
+
}
|
369 |
+
$cart->save();
|
370 |
+
return null;
|
371 |
+
}
|
372 |
+
}
|
373 |
+
|
374 |
/**
|
375 |
*
|
376 |
* Handles request related to coupons.
|
403 |
$req->getParam('type'),
|
404 |
$this->_getAdvocadoWebsiteIds());
|
405 |
|
406 |
+
// find out if it's a special advocado
|
407 |
+
// coupon, only applicable to advocado
|
408 |
+
// products. If it is, lets make it so
|
409 |
+
if ($req->getParam('advocado_type') == 'instant_discount') {
|
410 |
+
$helper->exclusiveToAdvocadoProducts($result);
|
411 |
+
}
|
412 |
+
|
413 |
$this->getJsonResponse()
|
414 |
->setHttpResponseCode(201)
|
415 |
->setBody( $this->jsonify(
|
482 |
)));
|
483 |
|
484 |
}
|
485 |
+
} else if ($action == 'apply') {
|
486 |
+
|
487 |
+
// no need for authentication
|
488 |
+
$cart = $this->applyCouponCode($req->getParam('coupon_code'));
|
489 |
+
if ($cart == null) {
|
490 |
+
$response = $this->getJsonResponse()
|
491 |
+
->setHttpResponseCode(403)
|
492 |
+
->appendBody(
|
493 |
+
$this->jsonify(
|
494 |
+
array('error_code'=>403,
|
495 |
+
'error_msg' => 'Forbidden. Invalid.'
|
496 |
+
))
|
497 |
+
);
|
498 |
+
} else {
|
499 |
+
$response = $this->getJsonResponse()
|
500 |
+
->setHttpResponseCode(200);
|
501 |
+
}
|
502 |
} else {
|
503 |
$this->getJsonResponse()
|
504 |
->setHttpResponseCode(405);
|
app/code/community/GozoLabs/Advocado/etc/config.xml
CHANGED
@@ -47,14 +47,20 @@
|
|
47 |
<!--</gozolabs_advocado>-->
|
48 |
<!--</observers>-->
|
49 |
<!--</sales_quote_add_item>-->
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
<checkout_submit_all_after>
|
59 |
<observers>
|
60 |
<gozolabs_advocado>
|
47 |
<!--</gozolabs_advocado>-->
|
48 |
<!--</observers>-->
|
49 |
<!--</sales_quote_add_item>-->
|
50 |
+
<!-- the below observer was in version 1.1
|
51 |
+
however because there is no longer a
|
52 |
+
need to verify the share (just apply
|
53 |
+
the coupon code),
|
54 |
+
no point setting the discount
|
55 |
+
-->
|
56 |
+
<!--<sales_quote_item_set_product>-->
|
57 |
+
<!--<observers>-->
|
58 |
+
<!--<gozolabs_advocado>-->
|
59 |
+
<!--<class>gozolabs_advocado/observer</class>-->
|
60 |
+
<!--<method>addItemToCart</method>-->
|
61 |
+
<!--</gozolabs_advocado>-->
|
62 |
+
<!--</observers>-->
|
63 |
+
<!--</sales_quote_item_set_product>-->
|
64 |
<checkout_submit_all_after>
|
65 |
<observers>
|
66 |
<gozolabs_advocado>
|
app/design/frontend/base/default/layout/gozolabs_advocado.xml
CHANGED
@@ -4,7 +4,7 @@
|
|
4 |
<reference name="head">
|
5 |
<block name="advocado.setup" type="core/text">
|
6 |
<action method="setText">
|
7 |
-
<text><![CDATA[<script type="text/javascript" src="https://
|
8 |
</action>
|
9 |
</block>
|
10 |
</reference>
|
@@ -16,7 +16,7 @@
|
|
16 |
<reference name="head">
|
17 |
<block name="advocado.setup" type="core/text">
|
18 |
<action method="setText">
|
19 |
-
<text><![CDATA[<script type="text/javascript" src="https://
|
20 |
</action>
|
21 |
</block>
|
22 |
</reference>
|
4 |
<reference name="head">
|
5 |
<block name="advocado.setup" type="core/text">
|
6 |
<action method="setText">
|
7 |
+
<text><![CDATA[<script type="text/javascript" src="https://cdnw.getadvocado.com/js/magento/loader.min.js"></script>]]></text>
|
8 |
</action>
|
9 |
</block>
|
10 |
</reference>
|
16 |
<reference name="head">
|
17 |
<block name="advocado.setup" type="core/text">
|
18 |
<action method="setText">
|
19 |
+
<text><![CDATA[<script type="text/javascript" src="https://cdnw.getadvocado.com/js/magento/loader.min.js"></script>]]></text>
|
20 |
</action>
|
21 |
</block>
|
22 |
</reference>
|
lib/Analytics/Analytics.php
ADDED
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
if (!function_exists('json_encode')) {
|
4 |
+
throw new Exception('Analytics needs the JSON PHP extension.');
|
5 |
+
}
|
6 |
+
|
7 |
+
require(dirname(__FILE__) . '/Analytics/Client.php');
|
8 |
+
|
9 |
+
|
10 |
+
class Analytics {
|
11 |
+
|
12 |
+
private static $client;
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Initializes the default client to use. Uses the socket consumer by default.
|
16 |
+
* @param string $secret your project's secret key
|
17 |
+
* @param array $options passed straight to the client
|
18 |
+
*/
|
19 |
+
public static function init($secret, $options = array()) {
|
20 |
+
|
21 |
+
if (!$secret){
|
22 |
+
throw new Exception("Analytics::init Secret parameter is required");
|
23 |
+
}
|
24 |
+
|
25 |
+
self::$client = new Analytics_Client($secret, $options);
|
26 |
+
}
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Tracks a user action
|
30 |
+
* @param string $user_id user id string
|
31 |
+
* @param string $event name of the event
|
32 |
+
* @param array $properties properties associated with the event [optional]
|
33 |
+
* @param number $timestamp unix seconds since epoch (time()) [optional]
|
34 |
+
* @param array $context [optional]
|
35 |
+
* @return boolean whether the track call succeeded
|
36 |
+
*/
|
37 |
+
public static function track($user_id, $event, $properties = null,
|
38 |
+
$timestamp = null, $context = array()) {
|
39 |
+
self::check_client();
|
40 |
+
return self::$client->track($user_id, $event, $properties, $timestamp,
|
41 |
+
$context);
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Tags traits about the user.
|
46 |
+
* @param string $user_id
|
47 |
+
* @param array $traits
|
48 |
+
* @param number $timestamp unix seconds since epoch (time()) [optional]
|
49 |
+
* @param array $context [optional]
|
50 |
+
* @return boolean whether the track call succeeded
|
51 |
+
*/
|
52 |
+
public static function identify($user_id, $traits = array(),
|
53 |
+
$timestamp = null, $context = array()) {
|
54 |
+
self::check_client();
|
55 |
+
return self::$client->identify($user_id, $traits, $timestamp, $context);
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Aliases the user id from a temporary id to a permanent one
|
60 |
+
* @param string $from user id to alias from
|
61 |
+
* @param string $to user id to alias to
|
62 |
+
* @param number $timestamp unix seconds since epoch (time()) [optional]
|
63 |
+
* @param array $context [optional]
|
64 |
+
* @return boolean whether the alias call succeeded
|
65 |
+
*/
|
66 |
+
public static function alias($from, $to, $timestamp = null,
|
67 |
+
$context = array()) {
|
68 |
+
self::check_client();
|
69 |
+
return self::$client->alias($from, $to, $timestamp, $context);
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Ensures that the client is indeed set. Throws an exception when not set.
|
74 |
+
*/
|
75 |
+
private static function check_client() {
|
76 |
+
|
77 |
+
if (self::$client == null) {
|
78 |
+
throw new Exception("Analytics::init must be called " .
|
79 |
+
"before track or identify");
|
80 |
+
}
|
81 |
+
}
|
82 |
+
}
|
lib/Analytics/Analytics/Client.php
ADDED
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require(__DIR__ . '/Consumer.php');
|
4 |
+
require(__DIR__ . '/QueueConsumer.php');
|
5 |
+
require(__DIR__ . '/Consumer/File.php');
|
6 |
+
require(__DIR__ . '/Consumer/ForkCurl.php');
|
7 |
+
require(__DIR__ . '/Consumer/Socket.php');
|
8 |
+
|
9 |
+
class Analytics_Client {
|
10 |
+
|
11 |
+
private $consumer;
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Create a new analytics object with your app's secret
|
15 |
+
* key
|
16 |
+
*
|
17 |
+
* @param string $secret
|
18 |
+
* @param array $options array of consumer options [optional]
|
19 |
+
* @param string Consumer constructor to use, socket by default.
|
20 |
+
*/
|
21 |
+
public function __construct($secret, $options = array()) {
|
22 |
+
|
23 |
+
$consumers = array(
|
24 |
+
"socket" => "Analytics_Consumer_Socket",
|
25 |
+
"file" => "Analytics_Consumer_File",
|
26 |
+
"fork_curl" => "Analytics_Consumer_ForkCurl"
|
27 |
+
);
|
28 |
+
|
29 |
+
# Use our socket consumer by default
|
30 |
+
$consumer_type = isset($options["consumer"]) ? $options["consumer"] :
|
31 |
+
"socket";
|
32 |
+
$Consumer = $consumers[$consumer_type];
|
33 |
+
|
34 |
+
$this->consumer = new $Consumer($secret, $options);
|
35 |
+
}
|
36 |
+
|
37 |
+
public function __destruct() {
|
38 |
+
$this->consumer->__destruct();
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Tracks a user action
|
43 |
+
* @param [string] $user_id user id string
|
44 |
+
* @param [string] $event name of the event
|
45 |
+
* @param [array] $properties properties associated with the event [optional]
|
46 |
+
* @param [number] $timestamp unix seconds since epoch (time()) [optional]
|
47 |
+
* @return [boolean] whether the track call succeeded
|
48 |
+
*/
|
49 |
+
public function track($user_id, $event, $properties = null,
|
50 |
+
$timestamp = null, $context = array()) {
|
51 |
+
|
52 |
+
$context = array_merge($context, $this->getContext());
|
53 |
+
|
54 |
+
$timestamp = $this->formatTime($timestamp);
|
55 |
+
|
56 |
+
// json_encode will serialize as []
|
57 |
+
if (count($properties) == 0) {
|
58 |
+
$properties = null;
|
59 |
+
}
|
60 |
+
|
61 |
+
return $this->consumer->track($user_id, $event, $properties, $context,
|
62 |
+
$timestamp);
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Tags traits about the user.
|
67 |
+
* @param [string] $user_id
|
68 |
+
* @param [array] $traits
|
69 |
+
* @param [number] $timestamp unix seconds since epoch (time()) [optional]
|
70 |
+
* @return [boolean] whether the track call succeeded
|
71 |
+
*/
|
72 |
+
public function identify($user_id, $traits = array(), $timestamp = null,
|
73 |
+
$context = array()) {
|
74 |
+
|
75 |
+
$context = array_merge($context, $this->getContext());
|
76 |
+
|
77 |
+
$timestamp = $this->formatTime($timestamp);
|
78 |
+
|
79 |
+
// json_encode will serialize as []
|
80 |
+
if (count($traits) == 0) {
|
81 |
+
$traits = null;
|
82 |
+
}
|
83 |
+
|
84 |
+
return $this->consumer->identify($user_id, $traits, $context,
|
85 |
+
$timestamp);
|
86 |
+
}
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Aliases from one user id to another
|
90 |
+
* @param string $from
|
91 |
+
* @param string $to
|
92 |
+
* @param number $timestamp unix seconds since epoch (time()) [optional]
|
93 |
+
* @param array $context [optional]
|
94 |
+
* @return boolean whether the alias call succeeded
|
95 |
+
*/
|
96 |
+
public function alias($from, $to, $timestamp = null, $context = array()) {
|
97 |
+
|
98 |
+
$context = array_merge($context, $this->getContext());
|
99 |
+
|
100 |
+
$timestamp = $this->formatTime($timestamp);
|
101 |
+
|
102 |
+
return $this->consumer->alias($from, $to, $context, $timestamp);
|
103 |
+
}
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Formats a timestamp by making sure it is set, and then converting it to
|
107 |
+
* iso8601 format.
|
108 |
+
* @param time $timestamp - time in seconds (time())
|
109 |
+
*/
|
110 |
+
private function formatTime($timestamp) {
|
111 |
+
|
112 |
+
if ($timestamp == null) $timestamp = time();
|
113 |
+
|
114 |
+
# Format for iso8601
|
115 |
+
return date("c", $timestamp);
|
116 |
+
}
|
117 |
+
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Add the segment.io context to the request
|
121 |
+
* @return array additional context
|
122 |
+
*/
|
123 |
+
private function getContext () {
|
124 |
+
return array( "library" => "analytics-php" );
|
125 |
+
}
|
126 |
+
}
|
lib/Analytics/Analytics/Consumer.php
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
abstract class Analytics_Consumer {
|
3 |
+
|
4 |
+
protected $type = "Consumer";
|
5 |
+
|
6 |
+
protected $options;
|
7 |
+
protected $secret;
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Store our secret and options as part of this consumer
|
11 |
+
* @param string $secret
|
12 |
+
* @param array $options
|
13 |
+
*/
|
14 |
+
public function __construct($secret, $options = array()) {
|
15 |
+
$this->secret = $secret;
|
16 |
+
$this->options = $options;
|
17 |
+
}
|
18 |
+
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Tracks a user action
|
22 |
+
* @param string $user_id user id string
|
23 |
+
* @param string $event name of the event
|
24 |
+
* @param array $properties properties associated with the event
|
25 |
+
* @param string $timestamp iso8601 of the timestamp
|
26 |
+
* @return boolean whether the track call succeeded
|
27 |
+
*/
|
28 |
+
abstract public function track($user_id, $event, $properties, $context,
|
29 |
+
$timestamp);
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Tags traits about the user.
|
33 |
+
* @param string $user_id
|
34 |
+
* @param array $traits
|
35 |
+
* @param string $timestamp iso8601 of the timestamp
|
36 |
+
* @return boolean whether the track call succeeded
|
37 |
+
*/
|
38 |
+
abstract public function identify($user_id, $traits, $context, $timestamp);
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Aliases from one user id to another
|
42 |
+
* @param string $from
|
43 |
+
* @param string $to
|
44 |
+
* @param array $context
|
45 |
+
* @param string $timestamp iso8601 of the timestamp
|
46 |
+
* @return boolean whether the alias call succeeded
|
47 |
+
*/
|
48 |
+
abstract public function alias($from, $to, $context, $timestamp);
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Check whether debug mode is enabled
|
52 |
+
* @return boolean
|
53 |
+
*/
|
54 |
+
protected function debug() {
|
55 |
+
return isset($this->options["debug"]) ? $this->options["debug"] : false;
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Check whether we should connect to the API using SSL. This is enabled by
|
60 |
+
* default with connections which make batching requests. For connections
|
61 |
+
* which can save on round-trip times, we disable it.
|
62 |
+
* @return boolean
|
63 |
+
*/
|
64 |
+
protected function ssl() {
|
65 |
+
return isset($this->options["ssl"]) ? $this->options["ssl"] : false;
|
66 |
+
}
|
67 |
+
|
68 |
+
|
69 |
+
/**
|
70 |
+
* On an error, try and call the error handler, if debugging output to
|
71 |
+
* error_log as well.
|
72 |
+
* @param string $code
|
73 |
+
* @param string $msg
|
74 |
+
*/
|
75 |
+
protected function handleError($code, $msg) {
|
76 |
+
|
77 |
+
if (isset($this->options['error_handler'])) {
|
78 |
+
$handler = $this->options['error_handler'];
|
79 |
+
$handler($code, $msg);
|
80 |
+
}
|
81 |
+
|
82 |
+
if ($this->debug()) {
|
83 |
+
error_log("[Analytics][" . $this->type . "] " . $msg);
|
84 |
+
}
|
85 |
+
}
|
86 |
+
}
|
lib/Analytics/Analytics/Consumer/File.php
ADDED
@@ -0,0 +1,117 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Analytics_Consumer_File extends Analytics_Consumer {
|
4 |
+
|
5 |
+
private $file_handle;
|
6 |
+
protected $type = "File";
|
7 |
+
|
8 |
+
/**
|
9 |
+
* The file consumer writes track and identify calls to a file.
|
10 |
+
* @param string $secret
|
11 |
+
* @param array $options
|
12 |
+
* string "filename" - where to log the analytics calls
|
13 |
+
*/
|
14 |
+
public function __construct($secret, $options = array()) {
|
15 |
+
|
16 |
+
if (!isset($options["filename"]))
|
17 |
+
$options["filename"] = sys_get_temp_dir() . DIRECTORY_SEPARATOR . "analytics.log";
|
18 |
+
|
19 |
+
parent::__construct($secret, $options);
|
20 |
+
|
21 |
+
try {
|
22 |
+
$this->file_handle = fopen($options["filename"], "a");
|
23 |
+
chmod($options["filename"], 0777);
|
24 |
+
} catch (Exception $e) {
|
25 |
+
$this->handleError($e->getCode(), $e->getMessage());
|
26 |
+
}
|
27 |
+
}
|
28 |
+
|
29 |
+
public function __destruct() {
|
30 |
+
if ($this->file_handle &&
|
31 |
+
get_resource_type($this->file_handle) != "Unknown") {
|
32 |
+
fclose($this->file_handle);
|
33 |
+
}
|
34 |
+
}
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Tracks a user action
|
38 |
+
* @param [string] $user_id user id string
|
39 |
+
* @param [string] $event name of the event
|
40 |
+
* @param [array] $properties properties associated with the event
|
41 |
+
* @param [string] $timestamp iso8601 of the timestamp
|
42 |
+
* @return [boolean] whether the track call succeeded
|
43 |
+
*/
|
44 |
+
public function track($user_id, $event, $properties, $context, $timestamp) {
|
45 |
+
|
46 |
+
$body = array(
|
47 |
+
"secret" => $this->secret,
|
48 |
+
"user_id" => $user_id,
|
49 |
+
"event" => $event,
|
50 |
+
"properties" => $properties,
|
51 |
+
"timestamp" => $timestamp,
|
52 |
+
"context" => $context,
|
53 |
+
"action" => "track"
|
54 |
+
);
|
55 |
+
|
56 |
+
return $this->write($body);
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Tags traits about the user.
|
61 |
+
* @param [string] $user_id
|
62 |
+
* @param [array] $traits
|
63 |
+
* @param [string] $timestamp iso8601 of the timestamp
|
64 |
+
* @return [boolean] whether the track call succeeded
|
65 |
+
*/
|
66 |
+
public function identify($user_id, $traits, $context, $timestamp) {
|
67 |
+
|
68 |
+
$body = array(
|
69 |
+
"secret" => $this->secret,
|
70 |
+
"user_id" => $user_id,
|
71 |
+
"traits" => $traits,
|
72 |
+
"context" => $context,
|
73 |
+
"timestamp" => $timestamp,
|
74 |
+
"action" => "identify"
|
75 |
+
);
|
76 |
+
|
77 |
+
return $this->write($body);
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Aliases from one user id to another
|
82 |
+
* @param string $from
|
83 |
+
* @param string $to
|
84 |
+
* @param array $context
|
85 |
+
* @param string $timestamp iso8601 of the timestamp
|
86 |
+
* @return boolean whether the alias call succeeded
|
87 |
+
*/
|
88 |
+
public function alias($from, $to, $context, $timestamp) {
|
89 |
+
|
90 |
+
$body = array(
|
91 |
+
"secret" => $this->secret,
|
92 |
+
"from" => $from,
|
93 |
+
"to" => $to,
|
94 |
+
"context" => $context,
|
95 |
+
"timestamp" => $timestamp,
|
96 |
+
"action" => "alias"
|
97 |
+
);
|
98 |
+
|
99 |
+
return $this->write($body);
|
100 |
+
}
|
101 |
+
|
102 |
+
/**
|
103 |
+
* Writes the API call to a file as line-delimited json
|
104 |
+
* @param [array] $body post body content.
|
105 |
+
* @return [boolean] whether the request succeeded
|
106 |
+
*/
|
107 |
+
private function write($body) {
|
108 |
+
|
109 |
+
if (!$this->file_handle)
|
110 |
+
return false;
|
111 |
+
|
112 |
+
$content = json_encode($body);
|
113 |
+
$content.= "\n";
|
114 |
+
|
115 |
+
return fwrite($this->file_handle, $content) == strlen($content);
|
116 |
+
}
|
117 |
+
}
|
lib/Analytics/Analytics/Consumer/ForkCurl.php
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Analytics_Consumer_ForkCurl extends Analytics_QueueConsumer {
|
4 |
+
|
5 |
+
protected $type = "ForkCurl";
|
6 |
+
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Creates a new queued fork consumer which queues fork and identify
|
10 |
+
* calls before adding them to
|
11 |
+
* @param string $secret
|
12 |
+
* @param array $options
|
13 |
+
* boolean "debug" - whether to use debug output, wait for response.
|
14 |
+
* number "max_queue_size" - the max size of messages to enqueue
|
15 |
+
* number "batch_size" - how many messages to send in a single request
|
16 |
+
*/
|
17 |
+
public function __construct($secret, $options = array()) {
|
18 |
+
parent::__construct($secret, $options);
|
19 |
+
}
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Make an async request to our API. Fork a curl process, immediately send
|
23 |
+
* to the API. If debug is enabled, we wait for the response.
|
24 |
+
* @param array $messages array of all the messages to send
|
25 |
+
* @return boolean whether the request succeeded
|
26 |
+
*/
|
27 |
+
public function flushBatch($messages) {
|
28 |
+
|
29 |
+
$body = array(
|
30 |
+
"batch" => $messages,
|
31 |
+
"secret" => $this->secret
|
32 |
+
);
|
33 |
+
|
34 |
+
$payload = json_encode($body);
|
35 |
+
|
36 |
+
# Escape for shell usage.
|
37 |
+
$payload = escapeshellarg($payload);
|
38 |
+
|
39 |
+
$protocol = $this->ssl() ? "https://" : "http://";
|
40 |
+
$host = "api.segment.io";
|
41 |
+
$path = "/v1/import";
|
42 |
+
$url = $protocol . $host . $path;
|
43 |
+
|
44 |
+
$cmd = "curl -X POST -H 'Content-Type: application/json'";
|
45 |
+
$cmd.= " -d " . $payload . " '" . $url . "'";
|
46 |
+
|
47 |
+
if (!$this->debug()) {
|
48 |
+
$cmd .= " > /dev/null 2>&1 &";
|
49 |
+
}
|
50 |
+
|
51 |
+
exec($cmd, $output, $exit);
|
52 |
+
|
53 |
+
if ($exit != 0) {
|
54 |
+
$this->handleError($exit, $output);
|
55 |
+
}
|
56 |
+
|
57 |
+
return $exit == 0;
|
58 |
+
}
|
59 |
+
}
|
lib/Analytics/Analytics/Consumer/Socket.php
ADDED
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Analytics_Consumer_Socket extends Analytics_QueueConsumer {
|
4 |
+
|
5 |
+
protected $type = "Socket";
|
6 |
+
private $socket_failed;
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Creates a new socket consumer for dispatching async requests immediately
|
10 |
+
* @param string $secret
|
11 |
+
* @param array $options
|
12 |
+
* number "timeout" - the timeout for connecting
|
13 |
+
* function "error_handler" - function called back on errors.
|
14 |
+
* boolean "debug" - whether to use debug output, wait for response.
|
15 |
+
*/
|
16 |
+
public function __construct($secret, $options = array()) {
|
17 |
+
|
18 |
+
if (!isset($options["timeout"]))
|
19 |
+
$options["timeout"] = 0.5;
|
20 |
+
|
21 |
+
if (!isset($options["host"]))
|
22 |
+
$options["host"] = "api.segment.io";
|
23 |
+
|
24 |
+
parent::__construct($secret, $options);
|
25 |
+
}
|
26 |
+
|
27 |
+
|
28 |
+
public function flushBatch($batch) {
|
29 |
+
$socket = $this->createSocket();
|
30 |
+
|
31 |
+
if (!$socket)
|
32 |
+
return;
|
33 |
+
|
34 |
+
$payload = array("secret" => $this->secret,
|
35 |
+
"batch" => $batch );
|
36 |
+
|
37 |
+
$payload = json_encode($payload);
|
38 |
+
|
39 |
+
$body = $this->createBody($this->options["host"], $payload);
|
40 |
+
return $this->makeRequest($socket, $body);
|
41 |
+
}
|
42 |
+
|
43 |
+
|
44 |
+
private function createSocket() {
|
45 |
+
|
46 |
+
if ($this->socket_failed)
|
47 |
+
return false;
|
48 |
+
|
49 |
+
$protocol = $this->ssl() ? "ssl" : "tcp";
|
50 |
+
$host = $this->options["host"];
|
51 |
+
$port = $this->ssl() ? 443 : 80;
|
52 |
+
$timeout = $this->options["timeout"];
|
53 |
+
|
54 |
+
try {
|
55 |
+
# Open our socket to the API Server.
|
56 |
+
$socket = pfsockopen($protocol . "://" . $host, $port, $errno,
|
57 |
+
$errstr, $timeout);
|
58 |
+
|
59 |
+
# If we couldn't open the socket, handle the error.
|
60 |
+
if ($errno != 0) {
|
61 |
+
$this->handleError($errno, $errstr);
|
62 |
+
$this->socket_failed = true;
|
63 |
+
return false;
|
64 |
+
}
|
65 |
+
|
66 |
+
return $socket;
|
67 |
+
|
68 |
+
} catch (Exception $e) {
|
69 |
+
$this->handleError($e->getCode(), $e->getMessage());
|
70 |
+
$this->socket_failed = true;
|
71 |
+
return false;
|
72 |
+
}
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Attempt to write the request to the socket, wait for response if debug
|
77 |
+
* mode is enabled.
|
78 |
+
* @param stream $socket the handle for the socket
|
79 |
+
* @param string $req request body
|
80 |
+
* @return boolean $success
|
81 |
+
*/
|
82 |
+
private function makeRequest($socket, $req, $retry = true) {
|
83 |
+
|
84 |
+
$bytes_written = 0;
|
85 |
+
$bytes_total = strlen($req);
|
86 |
+
$closed = false;
|
87 |
+
|
88 |
+
# Write the request
|
89 |
+
while (!$closed && $bytes_written < $bytes_total) {
|
90 |
+
try {
|
91 |
+
$written = fwrite($socket, $req);
|
92 |
+
} catch (Exception $e) {
|
93 |
+
$this->handleError($e->getCode(), $e->getMessage());
|
94 |
+
$closed = true;
|
95 |
+
}
|
96 |
+
if (!isset($written) || !$written) {
|
97 |
+
$closed = true;
|
98 |
+
} else {
|
99 |
+
$bytes_written += $written;
|
100 |
+
}
|
101 |
+
}
|
102 |
+
|
103 |
+
# If the socket has been closed, attempt to retry a single time.
|
104 |
+
if ($closed) {
|
105 |
+
fclose($socket);
|
106 |
+
|
107 |
+
if ($retry) {
|
108 |
+
$socket = $this->createSocket();
|
109 |
+
if ($socket) return $this->makeRequest($socket, $req, false);
|
110 |
+
}
|
111 |
+
return false;
|
112 |
+
}
|
113 |
+
|
114 |
+
|
115 |
+
$success = true;
|
116 |
+
|
117 |
+
if ($this->debug()) {
|
118 |
+
$res = $this->parseResponse(fread($socket, 2048));
|
119 |
+
|
120 |
+
if ($res["status"] != "200") {
|
121 |
+
$this->handleError($res["status"], $res["message"]);
|
122 |
+
$success = false;
|
123 |
+
}
|
124 |
+
}
|
125 |
+
|
126 |
+
return $success;
|
127 |
+
}
|
128 |
+
|
129 |
+
|
130 |
+
/**
|
131 |
+
* Create the body to send as the post request.
|
132 |
+
* @param string $host
|
133 |
+
* @param string $content
|
134 |
+
* @return string body
|
135 |
+
*/
|
136 |
+
private function createBody($host, $content) {
|
137 |
+
|
138 |
+
$req = "";
|
139 |
+
$req.= "POST /v1/import HTTP/1.1\r\n";
|
140 |
+
$req.= "Host: " . $host . "\r\n";
|
141 |
+
$req.= "Content-Type: application/json\r\n";
|
142 |
+
$req.= "Accept: application/json\r\n";
|
143 |
+
$req.= "Content-length: " . strlen($content) . "\r\n";
|
144 |
+
$req.= "\r\n";
|
145 |
+
$req.= $content;
|
146 |
+
|
147 |
+
return $req;
|
148 |
+
}
|
149 |
+
|
150 |
+
|
151 |
+
/**
|
152 |
+
* Parse our response from the server, check header and body.
|
153 |
+
* @param string $res
|
154 |
+
* @return array
|
155 |
+
* string $status HTTP code, e.g. "200"
|
156 |
+
* string $message JSON response from the api
|
157 |
+
*/
|
158 |
+
private function parseResponse($res) {
|
159 |
+
|
160 |
+
$contents = explode("\n", $res);
|
161 |
+
|
162 |
+
# Response comes back as HTTP/1.1 200 OK
|
163 |
+
# Final line contains HTTP response.
|
164 |
+
$status = explode(" ", $contents[0], 3);
|
165 |
+
$result = $contents[count($contents) - 1];
|
166 |
+
|
167 |
+
return array(
|
168 |
+
"status" => isset($status[1]) ? $status[1] : null,
|
169 |
+
"message" => $result
|
170 |
+
);
|
171 |
+
}
|
172 |
+
}
|
lib/Analytics/Analytics/QueueConsumer.php
ADDED
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
abstract class Analytics_QueueConsumer extends Analytics_Consumer {
|
3 |
+
|
4 |
+
protected $type = "QueueConsumer";
|
5 |
+
|
6 |
+
protected $queue;
|
7 |
+
protected $max_queue_size = 1000;
|
8 |
+
protected $batch_size = 100;
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Store our secret and options as part of this consumer
|
12 |
+
* @param string $secret
|
13 |
+
* @param array $options
|
14 |
+
*/
|
15 |
+
public function __construct($secret, $options = array()) {
|
16 |
+
parent::__construct($secret, $options);
|
17 |
+
|
18 |
+
if (isset($options["max_queue_size"]))
|
19 |
+
$this->max_queue_size = $options["max_queue_size"];
|
20 |
+
|
21 |
+
if (isset($options["batch_size"]))
|
22 |
+
$this->batch_size = $options["batch_size"];
|
23 |
+
|
24 |
+
$this->queue = array();
|
25 |
+
}
|
26 |
+
|
27 |
+
public function __destruct() {
|
28 |
+
# Flush our queue on destruction
|
29 |
+
$this->flush();
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Tracks a user action
|
34 |
+
* @param string $user_id user id string
|
35 |
+
* @param string $event name of the event
|
36 |
+
* @param array $properties properties associated with the event
|
37 |
+
* @param string $timestamp iso8601 of the timestamp
|
38 |
+
* @return boolean whether the track call succeeded
|
39 |
+
*/
|
40 |
+
public function track($user_id, $event, $properties, $context, $timestamp) {
|
41 |
+
|
42 |
+
$body = array(
|
43 |
+
"secret" => $this->secret,
|
44 |
+
"userId" => $user_id,
|
45 |
+
"event" => $event,
|
46 |
+
"properties" => $properties,
|
47 |
+
"timestamp" => $timestamp,
|
48 |
+
"context" => $context,
|
49 |
+
"action" => "track"
|
50 |
+
);
|
51 |
+
|
52 |
+
return $this->enqueue($body);
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Tags traits about the user.
|
57 |
+
* @param string $user_id
|
58 |
+
* @param array $traits
|
59 |
+
* @param string $timestamp iso8601 of the timestamp
|
60 |
+
* @return boolean whether the track call succeeded
|
61 |
+
*/
|
62 |
+
public function identify($user_id, $traits, $context, $timestamp) {
|
63 |
+
|
64 |
+
$body = array(
|
65 |
+
"secret" => $this->secret,
|
66 |
+
"userId" => $user_id,
|
67 |
+
"traits" => $traits,
|
68 |
+
"context" => $context,
|
69 |
+
"timestamp" => $timestamp,
|
70 |
+
"action" => "identify"
|
71 |
+
);
|
72 |
+
|
73 |
+
return $this->enqueue($body);
|
74 |
+
}
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Aliases from one user id to another
|
78 |
+
* @param string $from
|
79 |
+
* @param string $to
|
80 |
+
* @param array $context
|
81 |
+
* @param string $timestamp iso8601 of the timestamp
|
82 |
+
* @return boolean whether the alias call succeeded
|
83 |
+
*/
|
84 |
+
public function alias($from, $to, $context, $timestamp) {
|
85 |
+
|
86 |
+
$body = array(
|
87 |
+
"secret" => $this->secret,
|
88 |
+
"from" => $from,
|
89 |
+
"to" => $to,
|
90 |
+
"context" => $context,
|
91 |
+
"timestamp" => $timestamp,
|
92 |
+
"action" => "alias"
|
93 |
+
);
|
94 |
+
|
95 |
+
return $this->enqueue($body);
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Adds an item to our queue.
|
100 |
+
* @param mixed $item
|
101 |
+
* @return boolean whether the queue has room
|
102 |
+
*/
|
103 |
+
protected function enqueue($item) {
|
104 |
+
|
105 |
+
$count = count($this->queue);
|
106 |
+
|
107 |
+
if ($count > $this->max_queue_size)
|
108 |
+
return false;
|
109 |
+
|
110 |
+
$count = array_push($this->queue, $item);
|
111 |
+
|
112 |
+
if ($count > $this->batch_size)
|
113 |
+
$this->flush();
|
114 |
+
|
115 |
+
return true;
|
116 |
+
}
|
117 |
+
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Flushes our queue of messages by batching them to the server
|
121 |
+
*/
|
122 |
+
protected function flush() {
|
123 |
+
|
124 |
+
$count = count($this->queue);
|
125 |
+
$success = true;
|
126 |
+
|
127 |
+
while($count > 0 && $success) {
|
128 |
+
|
129 |
+
$batch = array_splice($this->queue, 0, min($this->batch_size, $count));
|
130 |
+
$success = $this->flushBatch($batch);
|
131 |
+
|
132 |
+
$count = count($this->queue);
|
133 |
+
}
|
134 |
+
|
135 |
+
return $success;
|
136 |
+
}
|
137 |
+
|
138 |
+
/**
|
139 |
+
* Flushes a batch of messages.
|
140 |
+
* @param [type] $batch [description]
|
141 |
+
* @return [type] [description]
|
142 |
+
*/
|
143 |
+
abstract function flushBatch($batch);
|
144 |
+
}
|
package.xml
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
<?xml version="1.0"?>
|
2 |
<package>
|
3 |
<name>Advocado</name>
|
4 |
-
<version>1.0
|
5 |
<stability>stable</stability>
|
6 |
<license uri="http://www.opensource.org/licenses/mit-license.php">MITL</license>
|
7 |
<channel>community</channel>
|
@@ -24,11 +24,13 @@
|
|
24 |
<li>Generate more referrals - Reward your customers for every successful referral they make and drive more sales for your business.</li>
|
25 |
<li>Easy to set up - You can install our plugin or copy & paste a snippet of codes to get Advocado up and running. Our set up wizard will guide you through this.</li>
|
26 |
</ol></description>
|
27 |
-
<notes>
|
|
|
|
|
28 |
<authors><author><name>SY Quek</name><user>syquek</user><email>quek@getadvocado.com</email></author></authors>
|
29 |
-
<date>2013-
|
30 |
-
<time>
|
31 |
-
<contents><target name="magecommunity"><dir name="GozoLabs"><dir name="Advocado"><dir name="Block"><dir name="Adminhtml"><file name="Login.php" hash="
|
32 |
<compatible/>
|
33 |
<dependencies><required><php><min>5.1.0</min><max>6.0.0</max></php><package><name>Mage_Core_Modules</name><channel>community</channel><min>1.6.0.0</min><max>1.7.0.2</max></package></required></dependencies>
|
34 |
</package>
|
1 |
<?xml version="1.0"?>
|
2 |
<package>
|
3 |
<name>Advocado</name>
|
4 |
+
<version>1.1.0</version>
|
5 |
<stability>stable</stability>
|
6 |
<license uri="http://www.opensource.org/licenses/mit-license.php">MITL</license>
|
7 |
<channel>community</channel>
|
24 |
<li>Generate more referrals - Reward your customers for every successful referral they make and drive more sales for your business.</li>
|
25 |
<li>Easy to set up - You can install our plugin or copy & paste a snippet of codes to get Advocado up and running. Our set up wizard will guide you through this.</li>
|
26 |
</ol></description>
|
27 |
+
<notes>We've introduced a new mechanic to this extension. It does not allow double-dipping -- if a shopper gets an instant discount, they should not be able to redeem a coupon code for the same cart.
|
28 |
+

|
29 |
+
You can sign up for an account immediately after you register. Do let us know if you have any feedback or comments either through our website http://getadvocado.com, or via our email: dax@getadvocado.com</notes>
|
30 |
<authors><author><name>SY Quek</name><user>syquek</user><email>quek@getadvocado.com</email></author></authors>
|
31 |
+
<date>2013-08-14</date>
|
32 |
+
<time>03:56:22</time>
|
33 |
+
<contents><target name="magecommunity"><dir name="GozoLabs"><dir name="Advocado"><dir name="Block"><dir name="Adminhtml"><file name="Login.php" hash="39706986405f7348ef71192d1c86615d"/></dir><file name="Site.php" hash="3b62c41138ac5a90e1f9432a10e6d19e"/></dir><dir name="Helper"><file name="Admin.php" hash="bcda9a0a4e383c14b8c6f7372167a14d"/><file name="Analytics.php" hash="2bf2b9439ace050851ff54faf6734f31"/><file name="Backend.php" hash="125ee66f4aa5d43368679d960c165494"/><file name="Data.php" hash="c9d2abf77196411f3c618a6d5917f878"/></dir><dir name="Model"><file name="Credentials.php" hash="f7d6c7c82369b4e71fa1ef605c7d5736"/><file name="Observer.php" hash="f39c3df5aa69c724f48e4e28afdb7b06"/><dir name="Resource"><dir name="Credentials"><file name="Collection.php" hash="d7061008f932a933bff5a934133f4f58"/></dir><file name="Credentials.php" hash="db06bec94d7eaf9e9511ef87296f791a"/></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="AdvocadoController.php" hash="b47e8a4eb15cb6fe497a04afa9e146e3"/></dir><file name="CampaignController.php" hash="95d945d30e11561c06c63a65744f0998"/><file name="CartController.php" hash="e42cb1757de7760862d905b64c1a21f0"/><file name="IndexController.php" hash="105efc19158e33b8dae67e23682d08d5"/><file name="V1Controller.php" hash="1707a3e88ad6c53d39c387b4e52eda2d"/></dir><dir name="etc"><file name="adminhtml.xml" hash="7c94738fe2d40efca729d81311afa529"/><file name="config.xml" hash="9dba171f358f27c5f9e51de2d533b040"/></dir><dir name="sql"><dir name="gozolabs_advocado_setup"><file name="install-0.1.0.php" hash="db8f967eb2a9af200305bde91abe423a"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="gozolabs_advocado.xml" hash="8a3eee7e9e393ba02fea4d67a0ddcda1"/></dir><dir name="template"><dir name="gozolabs"><dir name="advocado"><file name="login.phtml" hash="8ade68e2f79c41c5b95d585a325cf883"/></dir></dir></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="gozolabs_advocado.xml" hash="5e560a16061cb5f792c0351b6c34bb69"/></dir><dir name="template"><dir name="gozolabs"><dir name="advocado"><file name="site.phtml" hash="a239ca877dd55c3c45943c428352df35"/></dir></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="GozoLabs_Advocado.xml" hash="5309e7603426b687ad46a42ab565c692"/></dir></target><target name="mageskin"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="css"><file name="gozolabs_advocado.css" hash="4177c19b32d7aed880d1ce695dfc0ad7"/><file name="animate.min.css" hash="bbe717113fde11700cb83ec3d79d9de0"/></dir><dir name="js"><dir name="gozolabs_advocado"><file name="gozolabs_advocado.js" hash="65327c4aa702cd15bf6e78dcd60e8fdf"/><file name="jquery.min.js" hash="e1288116312e4728f98923c79b034b67"/></dir></dir></dir></dir></dir></target><target name="magelib"><dir name="Analytics"><dir name="Analytics"><file name="Client.php" hash="0648505a1ad5e4700b0a20855bb34fac"/><dir name="Consumer"><file name="File.php" hash="602b0430e01b131ef4a07f89bb548956"/><file name="ForkCurl.php" hash="83fa57b1b0f09f592e726545d58f12bc"/><file name="Socket.php" hash="b3c6aeacfb0f73ee842288cf2b6e2d56"/></dir><file name="Consumer.php" hash="8299490437cd905bd32f9294ac60b64e"/><file name="QueueConsumer.php" hash="cc20ab42b8013847f06355f32b46e94f"/></dir><file name="Analytics.php" hash="f5703a127a85f014335624016716260d"/></dir></target></contents>
|
34 |
<compatible/>
|
35 |
<dependencies><required><php><min>5.1.0</min><max>6.0.0</max></php><package><name>Mage_Core_Modules</name><channel>community</channel><min>1.6.0.0</min><max>1.7.0.2</max></package></required></dependencies>
|
36 |
</package>
|