v7‰PNG
IHDR Ÿ f Õ†C1 sRGB ®Îé gAMA ±üa pHYs à ÃÇo¨d GIDATx^íÜL”÷ð÷Yçªö("Bh_ò«®¸¢§q5kÖ*:þ0AºšÖ¥]VkJ¢M»¶f¸±8\k2íll£1]q®ÙÔ‚ÆT
PK V\(Q Q db.xmlnu [
PK V\ library/Webhook.phpnu [
array(
'title' => 'Access record inserted',
'description' => '',
'params' => array('access'),
'nested' => array('user'),
),
Am_Event::ACCESS_AFTER_DELETE =>
array(
'title' => 'Access record deleted',
'description' => '',
'params' => array('access'),
'nested' => array('user'),
),
Am_Event::ACCESS_AFTER_UPDATE =>
array(
'title' => 'Access record updated',
'description' => '',
'params' => array('access','old'),
'nested' => array('user'),
),
Am_Event::INVOICE_AFTER_CANCEL =>
array(
'title' => 'Called after invoice cancelation',
'description' => '',
'params' => array('invoice'),
'nested' => array('user'),
),
Am_Event::INVOICE_AFTER_DELETE =>
array(
'title' => 'Called after invoice deletion',
'description' => '',
'params' => array('invoice'),
'nested' => array('user'),
),
Am_Event::INVOICE_AFTER_INSERT =>
array(
'title' => 'Called after invoice insertion',
'description' => '',
'params' => array('invoice'),
'nested' => array('user'),
),
Am_Event::INVOICE_PAYMENT_REFUND =>
array(
'title' => 'Called after invoice payment refund (or chargeback)',
'description' => '',
'params' => array('invoice','refund'),
'nested' => array('user'),
),
Am_Event::INVOICE_STARTED =>
array(
'title' => 'Called when an invoice becomes active_recuirring or paid, or free trial is started',
'description' => '',
'params' => array('user','invoice','transaction','payment')
),
Am_Event::INVOICE_STATUS_CHANGE =>
array(
'title' => 'Called when invoice status is changed',
'description' => '',
'params' => array('invoice','status','oldStatus'),
'nested' => array('user'),
),
Am_Event::PAYMENT_AFTER_INSERT =>
array(
'title' => 'Payment record insered into database. Is not called for free subscriptions',
'description' => '',
'params' => array('invoice','payment','user'),
),
/*Am_Event::PAYMENT_WITH_ACCESS_AFTER_INSERT =>
array(
'title' => 'Payment record with access insered into database. Is not called for free subscriptions. Required to get access records',
'description' => '',
'params' => array('invoice','payment','user'),
),*/
Am_Event::USER_AFTER_INSERT =>
array(
'title' => 'Called after user record is inserted into table',
'description' => '',
'params' => array('user'),
),
Am_Event::USER_AFTER_UPDATE =>
array(
'title' => 'Called after user record is updated in database',
'description' => '',
'params' => array('user','oldUser'),
),
Am_Event::USER_AFTER_DELETE =>
array(
'title' => 'Called after customer record deletion',
'description' => '',
'params' => array('user'),
),
Am_Event::SUBSCRIPTION_ADDED => array(
'title' => 'Called when user receives a subscription to product he was not subscribed earlier',
'description' => '',
'params' => array('user', 'product'),
),
Am_Event::SUBSCRIPTION_DELETED => array(
'title' => 'Called when user subscription access is expired',
'description' => '',
'params' => array('user', 'product'),
)
);
function onGetPermissionsList(Am_Event $event)
{
$event->addReturn(___('Can manage webhooks'), self::ADMIN_PERM_ID);
}
function onInitFinished(Am_Event $event)
{
foreach ($this->getTypes() as $k => $v)
$this->getDi()->hook->add($k, array($this, 'doWork'));
}
function onAdminMenu(Am_Event $event)
{
$event->getMenu()->addPage(array(
'id' => 'webhooks',
'uri' => 'javascript:;',
'label' => ___('Webhooks'),
'resource' => self::ADMIN_PERM_ID,
'pages' => array_merge(array(
array(
'id' => 'webhooks-configuration',
'controller' => 'admin',
'module' => 'webhooks',
'label' => ___('Configuration'),
'resource' => self::ADMIN_PERM_ID,
),
array(
'id' => 'webhooks-queue',
'controller' => 'admin-queue',
'module' => 'webhooks',
'label' => ___("Queue"),
'resource' => self::ADMIN_PERM_ID,
)
)
)));
}
function getTypes()
{
return $this->types;
}
function getConfiguredWebhooks()
{
if (!$this->webhooksLoaded)
{
$this->webhooks = array();
$rows = $this->getDi()->db->select("SELECT * FROM ?_webhook WHERE is_disabled=0");
foreach ($rows as $row)
{
$this->webhooks[$row['event_id']][] = $row;
}
$this->webhooksLoaded = true;
}
return $this->webhooks;
}
public function getObjectData($obj)
{
if ($obj instanceof Am_Record) {
$ret = $obj->toRow();
if ($obj instanceof User) {
unset($ret['last_session']);
}
return $ret;
} elseif (is_object($obj)) {
return get_object_vars($obj);
} else {
return (string)$obj;
}
}
public function prepareData(Am_Event $event, $data = array())
{
$id = $event->getId();
$data['am-webhooks-version'] = '1.0';
$data['am-event'] = $id;
$data['am-timestamp'] = date('c');
$data['am-root-url'] = ROOT_URL;
$types = $this->getTypes();
$fields = $types[$id]['params'];
$nestedFields = isset($types[$id]['nested']) ? $types[$id]['nested'] : array();
$parent = $fields[0];
foreach($fields as $field)
{
$field_ = call_user_func(array($event, 'get'.ucfirst($field)));
if($parent == $field)
$parent = $field_;
$data = array_merge($data, array($field => $this->getObjectData($field_)));
}
foreach ($nestedFields as $nfield)
{
$nfield_ = call_user_func(array($parent, 'get'.ucfirst($nfield)));
$data = array_merge($data, array($nfield => $this->getObjectData($nfield_)));
}
return $data;
}
public function doWork(Am_Event $event, $data = array())
{
$webhooks = $this->getConfiguredWebhooks();
$id = $event->getId();
if(empty($webhooks[$id])) return;
$data = $this->prepareData($event, $data);
foreach($webhooks[$id] as $webhook)
{
$queue = $this->getDi()->webhookQueueRecord;
$queue->url = $webhook['url'];
$queue->event_id = $webhook['event_id'];
$queue->params = serialize($data);
$queue->added = $this->getDi()->time;
$queue->insert();
}
}
}PK V\Nd?
module.xmlnu [
webhooks
Webhooks
send data to remote addresses for configured events
5.0.5
PK V\b٧܁
$ controllers/AdminQueueController.phpnu [ hasPermission(Bootstrap_Webhooks::ADMIN_PERM_ID);
}
function createGrid()
{
$ds = new Am_Query($this->getDi()->webhookQueueTable);
$grid = new Am_Grid_Editable('_w', ___('Webhooks Queue'), $ds, $this->getRequest(), $this->getView(), $this->getDi());
$grid->setPermissionId(Bootstrap_Webhooks::ADMIN_PERM_ID);
$grid->actionDelete('edit');
$grid->actionDelete('insert');
$grid->actionAdd(new Am_Grid_Action_Group_Delete);
$grid->addField(new Am_Grid_Field_Date('added', ___('Added')));
$grid->addField(new Am_Grid_Field_Date('sent', ___('Sent')));
$grid->addField('event_id', ___('Event'));
$grid->addField('url', ___('Url'));
$grid->addField('failures', ___('Failures'));
$grid->addField('last_error', ___('Last Error'));
$grid->addField(new Am_Grid_Field_Expandable('params', ___('Params'), false))
->setAjax($this->getDi()->url('webhooks/admin-queue/get-queue-details?id={webhook_queue_id}',null,false));
$grid->setFilter(new Am_Grid_Filter_WebhookQueue);
return $grid;
}
function getQueueDetailsAction()
{
$log = $this->getDi()->webhookQueueTable->load($this->getParam('id'));
echo $this->renderQueueDetails($log);
}
public function renderQueueDetails(WebhookQueue $obj)
{
$ret = "";
$ret .= "
\n";
if (empty($obj->params)) {
$rows = array();
} else {
$rows = unserialize($obj->params);
}
$open = count($rows) == 1 ? 'open' : '';
foreach ($rows as $name => $array)
{
$ret .= "\t
\n";
$ret .= "\t\t
$name
\n";
$ret .= "\t\t
\n";
$ret .= "\t
\n";
}
$ret .= "
\n\n";
return $ret;
}
}
class Am_Grid_Filter_WebhookQueue extends Am_Grid_Filter_Abstract
{
protected $title = "Filter by Event";
function applyFilter()
{
$this->grid->getDataSource()
->getDataSourceQuery()
->addWhere('event_id=?', $this->getParam('filter'));
}
function renderInputs()
{
$k = array_keys($this->grid->getDi()->modules->loadGet('webhooks')->getTypes());
return $this->renderInputSelect('filter', array(''=>'') + array_combine($k, $k));
}
}PK V\Gv9 9 controllers/AdminController.phpnu [ hasPermission(Bootstrap_Webhooks::ADMIN_PERM_ID);
}
function createGrid()
{
$ds = new Am_Query($this->getDi()->webhookTable);
$grid = new Am_Grid_Editable('_w', ___('Browse Webhooks'), $ds, $this->getRequest(), $this->getView(), $this->getDi());
$grid->setPermissionId(Bootstrap_Webhooks::ADMIN_PERM_ID);
$grid->addCallback(Am_Grid_ReadOnly::CB_TR_ATTRIBS, array($this, 'getTrAttribs'));
$grid->addField(new Am_Grid_Field('webhook_id', '#', true, '', null, '1%'));
$grid->addField('event_id', ___('Event'));
$grid->addField('url', ___('Url'));
$grid->setForm(array($this, 'createForm'));
$grid->setRecordTitle('WebHook');
$grid->addCallback(Am_Grid_Editable::CB_RENDER_CONTENT, function(& $out, Am_Grid_Editable $grid) {
$cron_url = $this->getDi()->url('webhooks/cron',null,true,2);
$out = '' . "It is required to setup a cron job to run each minute to trigger sending of webhooks
* * * * * /usr/bin/curl $cron_url
" . '
' . $out;
});
return $grid;
}
public function getTrAttribs(& $ret, $record)
{
if ($record->is_disabled) {
$ret['class'] = isset($ret['class']) ? $ret['class'] . ' disabled' : 'disabled';
}
}
function renderStatus(Webhook $webhook)
{
return $webhook->is_disabled ? 'Disabled' : 'Active';
}
function createForm()
{
$keys = array_keys($this->getModule()->getTypes());
$form = new Am_Form_Admin('webhooks');
$gr = $form->addGroup()->setLabel(___('Event'));
$sel = $gr->addSelect('event_id');
$sel->setLabel(___('Event'))
->loadOptions(array_merge(array('' => ___('-- Please select --')),array_combine($keys,$keys)));
$sel->addRule('required');
$gr->addElement('static')->setContent('
');
$js_ = '';
foreach ($this->getModule()->getTypes() as $k => $v)
{
$desc = array($v['title']);
if(isset($v['description']))
$desc[] = $v['description'];
$params = array();
if(!is_array($v['params']))
$params = array($v['params']);
else
$params = $v['params'];
if(isset($v['nested']))
{
if(!is_array($v['nested']))
$params = array_merge($params,array($v['nested']));
else
$params = array_merge($params,$v['nested']);
}
$desc[] = 'List of parameters:['.implode(',', $params).']';
$js_.="webhooksCache.{$k} = '". implode('
', $desc) ."';
";
}
$id_ = $sel->getId();
$gr->addElement('static')->setContent(
<<
var webhooksCache = {"" : {} };
$js_
jQuery(document).ready(function($) {
function onWebhookChange() {
$("#webhook_info").html(webhooksCache[$(this).val()]);
}
$("#$id_").change(onWebhookChange);
});
EOF
);
$form->addText('url',array('class'=>'el-wide'))->setLabel(___("Url\n" .
'url of the page POST data will be sent to'))->addRule('required');
$form->addAdvcheckbox('is_disabled')->setLabel(___('Is Disabled?'));
return $form;
}
}
PK V\Y Y controllers/CronController.phpnu [ getDi()->db->selectCell("SELECT GET_LOCK(?, 0)", self::getLockId())) {
$this->getDi()->errorLogTable->log("Could not obtain MySQL's GET_LOCK() to run webhooks cron. Probably attempted to execute two cron processes simultaneously. ");
return;
}
$start = time();
foreach($this->getDi()->webhookQueueTable->findBy(array('sent' => null)) as $webhook_queue)
{
if(time() - $start >= $time_limit) break;
try{
$req = new Am_HttpRequest($webhook_queue->url, Am_HttpRequest::METHOD_POST);
$params = unserialize($webhook_queue->params);
foreach($params as $name => $data) {
if (is_array($data)) {
unset($params[$name]);
foreach($data as $k => $v) {
$params[$name . '[' . $k . ']'] = $v;
}
}
}
$req->addPostParameter($params);
$res = $req->send();
$st = $res->getStatus();
if($st == 200) {
$webhook_queue->updateQuick(array('sent' => $this->getDi()->time));
} else {
$webhook_queue->updateQuick(array('last_error'=>$st, 'failures'=>$webhook_queue->failures + 1));
}
} catch(Exception $e) {
$this->getDi()->errorLogTable->logException($e);
}
}
//release lock
$this->getDi()->db->query("SELECT RELEASE_LOCK(?)", self::getLockId());
}
static function getLockId()
{
return 'webhooks-cron-lock-' . md5(__FILE__);
}
}PK V\(Q Q db.xmlnu [ PK V\ library/Webhook.phpnu [ PK V\͡