+ Post data when hook is triggered.

+ Add log.
This commit is contained in:
liugang
2017-10-24 18:01:56 +08:00
parent 29cd0d4b4e
commit a259217bdf
25 changed files with 656 additions and 218 deletions

View File

@@ -104,6 +104,8 @@ define('TABLE_TESTREPORT', '`' . $config->db->prefix . 'testreport`');
define('TABLE_ENTRY', '`' . $config->db->prefix . 'entry`');
define('TABLE_WEBHOOK', '`' . $config->db->prefix . 'webhook`');
define('TABLE_WEBHOOKDATAS', '`' . $config->db->prefix . 'webhookdatas`');
define('TABLE_LOG', '`' . $config->db->prefix . 'log`');
if(!defined('TABLE_LANG')) define('TABLE_LANG', '`' . $config->db->prefix . 'lang`');
$config->objectTables['product'] = TABLE_PRODUCT;

View File

@@ -18,12 +18,43 @@ CREATE TABLE IF NOT EXISTS `zt_webhook` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`url` varchar(255) NOT NULL,
`requestType` enum('post', 'get') NOT NULL DEFAULT 'get',
`params` text NOT NULL,
`contentType` enum('json','form') NOT NULL DEFAULT 'json',
`sendType` enum('sync','async') NOT NULL DEFAULT 'sync',
`params` varchar(100) NOT NULL,
`actions` text NOT NULL,
`desc` text NOT NULL,
`createdBy` varchar(30) NOT NULL,
`createdDate` datetime NOT NULL,
`editedBy` varchar(30) NOT NULL,
`editedDate` datetime NOT NULL,
PRIMARY KEY `id` (`id`)
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_webhookdatas`;
CREATE TABLE IF NOT EXISTS `zt_webhookdatas` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`webhook` mediumint(8) unsigned NOT NULL,
`action` mediumint(8) unsigned NOT NULL,
`data` text NOT NULL,
`status` enum('wait', 'sended') NOT NULL DEFAULT 'wait',
`createdBy` varchar(30) NOT NULL,
`createdDate` datetime NOT NULL,
PRIMARY KEY `id` (`id`),
UNIQUE KEY `uniq` (`webhook`, `action`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_log`;
CREATE TABLE IF NOT EXISTS `zt_log` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`objectType` varchar(30) NOT NULL,
`objectID` mediumint(8) unsigned NOT NULL,
`action` mediumint(8) unsigned NOT NULL,
`date` datetime NOT NULL,
`url` varchar(255) NOT NULL,
`contentType` varchar(40) NOT NULL,
`data` text NOT NULL,
`status` smallint(5) NOT NULL,
PRIMARY KEY `id` (`id`),
KEY `objectType` (`objectType`),
KEY `obejctID` (`objectID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

View File

@@ -139,7 +139,7 @@ $lang->action->label->blocked = '阻塞了';
$lang->action->label->resolved = '解决了';
$lang->action->label->reviewed = '评审了';
$lang->action->label->moved = '移动了';
$lang->action->label->confirmed = '确认了需求';
$lang->action->label->confirmed = '确认了需求';
$lang->action->label->bugconfirmed = '确认了';
$lang->action->label->tostory = '转需求';
$lang->action->label->frombug = '转需求';

View File

@@ -60,6 +60,8 @@ class actionModel extends model
$this->file->updateObjectID($this->post->uid, $objectID, $objectType);
$this->loadModel('webhook')->send($objectType, $objectID, $actionType, $actionID);
return $actionID;
}

View File

@@ -418,6 +418,7 @@ $lang->error->int = array("『%s』应当是数字。", "『%s』应
$lang->error->float = "『%s』应当是数字可以是小数。";
$lang->error->email = "『%s』应当为合法的EMAIL。";
$lang->error->date = "『%s』应当为合法的日期。";
$lang->error->code = "『%s』应当为字母或数字的组合。";
$lang->error->account = "『%s』应当为合法的用户名。";
$lang->error->passwordsame = "两次密码应当相等。";
$lang->error->passwordrule = "密码应该符合规则,长度至少为六位。";

View File

@@ -16,16 +16,19 @@ function createKey()
return false;
}
$('#allIP').change(function()
$(function()
{
if($(this).prop('checked'))
$('#allIP').change(function()
{
$('#ip').attr('disabled', 'disabled');
}
else
{
$('#ip').removeAttr('disabled');
}
})
$('#name').focus();
if($(this).prop('checked'))
{
$('#ip').attr('disabled', 'disabled');
}
else
{
$('#ip').removeAttr('disabled');
}
})
$('#name').focus();
});

View File

@@ -16,16 +16,19 @@ function createKey()
return false;
}
$('#allIP').change(function()
$(function()
{
if($(this).prop('checked'))
$('#allIP').change(function()
{
$('#ip').attr('disabled', 'disabled');
}
else
{
$('#ip').removeAttr('disabled');
}
})
$('#name').focus();
if($(this).prop('checked'))
{
$('#ip').attr('disabled', 'disabled');
}
else
{
$('#ip').removeAttr('disabled');
}
})
$('#name').focus();
});

View File

@@ -22,11 +22,13 @@ $lang->entry->createdDate = '创建时间';
$lang->entry->editedby = '最后编辑';
$lang->entry->editedDate = '编辑时间';
$lang->entry->apiIndex = '应用入口';
$lang->entry->saveSuccess = '保存成功';
$lang->entry->confirmDelete = '您确认要删除该应用吗?';
$lang->entry->note = new stdClass();
$lang->entry->note->name = '授权应用名称';
$lang->entry->note->code = '授权应用代号,必须为英文、数字或下划线的组合';
$lang->entry->note->code = '授权应用代号,必须为字母或数字的组合';
$lang->entry->note->ip = "允许访问应用的ip多个ip用逗号隔开。支持IP段如192.168.1.*";
$lang->entry->note->allIP = '无限制';
$lang->entry->note->api = 'moduleName、methodName以及参数列表替换成实际的值';

View File

@@ -27,7 +27,7 @@ class entryModel extends model
* Get entry list.
*
* @param string $orderBy
* @param obejct $pager
* @param object $pager
* @access public
* @return array
*/
@@ -54,6 +54,7 @@ class entryModel extends model
$this->dao->insert(TABLE_ENTRY)->data($entry)
->batchCheck($this->config->entry->create->requiredFields, 'notempty')
->check('code', 'code')
->check('code', 'unique')
->autoCheck()
->exec();
@@ -83,6 +84,7 @@ class entryModel extends model
$this->dao->update(TABLE_ENTRY)->data($entry)
->batchCheck($this->config->entry->edit->requiredFields, 'notempty')
->check('code', 'code')
->check('code', 'unique', "id!=$entryID")
->autoCheck()
->where('id')->eq($entryID)

View File

@@ -53,6 +53,11 @@
<td><?php echo html::textarea('desc', '', "rows='3' class='form-control'");?></td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->entry->apiIndex;?></th>
<td><?php echo common::getSysURL() . DS . "api.php?{$config->moduleVar}=moduleName&{$config->methodVar}=methodName&<span>params=params</span>";?></td>
<td></td>
</tr>
<tr>
<th></th>
<td><?php echo html::submitButton();?></td>

View File

@@ -53,6 +53,11 @@
<td><?php echo html::textarea('desc', $entry->desc, "rows='3' class='form-control'");?></td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->entry->apiIndex;?></th>
<td><?php echo common::getSysURL() . DS . "api.php?{$config->moduleVar}=moduleName&{$config->methodVar}=methodName&<span>params=params</span>";?></td>
<td></td>
</tr>
<tr>
<th></th>
<td><?php echo html::submitButton();?></td>

View File

@@ -15,8 +15,18 @@
<thead>
<tr>
<th class='w-120px'><?php echo $lang->action->date;?></th>
<th></th>
<th class='w-100px'><?php echo $lang->action->actor;?></th>
<th><?php echo $lang->entry->desc;?></th>
</tr>
</thead>
<tbody>
<?php foreach($actions as $action);?>
<tr>
<td><?php echo $action->date;?></td>
<td><?php echo zget($users, $action->actor);?></td>
<td><?php echo $action->extra;?></td>
</tr>
<?php endforeach;?>
</tbody>
</table>
<?php include '../../common/view/footer.html.php';?>

View File

@@ -5,5 +5,23 @@ $config->webhook->create->requiredFields = 'name, url';
$config->webhook->edit = new stdclass();
$config->webhook->edit->requiredFields = 'name, url';
$config->webhook->requestType['post'] = 'post';
$config->webhook->requestType['get'] = 'get';
$config->webhook->contentTypes['json'] = 'application/json';
$config->webhook->contentTypes['form'] = 'application/x-www-form-urlencoded';
$config->webhook->objectTypes['product'] = array('opened', 'edited', 'closed', 'undeleted');
$config->webhook->objectTypes['story'] = array('opened', 'edited', 'commented', 'frombug', 'changed', 'reviewed', 'closed', 'activated');
$config->webhook->objectTypes['productplan'] = array('opened', 'edited');
//$config->webhook->objectTypes['release'] = array('opened', 'edited', 'changestatus');
$config->webhook->objectTypes['project'] = array('opened', 'edited', 'started', 'delayed', 'suspended', 'closed', 'activated', 'undeleted');
$config->webhook->objectTypes['task'] = array('opened', 'edited', 'commented', 'assigned', 'confirmed', 'started', 'finished', 'editestimate', 'deleteestimate', 'paused', 'canceled', 'restarted', 'closed', 'activated');
//$config->webhook->objectTypes['build'] = array('opened', 'edited');
$config->webhook->objectTypes['bug'] = array('opened', 'edited', 'commented', 'assigned', 'confirmed', 'bugconfirmed', 'resolved', 'closed', 'activated');
$config->webhook->objectTypes['case'] = array('opened', 'edited', 'commented', 'reviewed', 'confirmed');
$config->webhook->objectTypes['testtask'] = array('opened', 'edited', 'started', 'blocked', 'closed', 'activated');
$config->webhook->objectTypes['todo'] = array('opened', 'edited', 'erased');
//$config->webhook->objectTypes['testsuite'] = array('opened', 'edited');
//$config->webhook->objectTypes['caselib'] = array('opened', 'edited');
//$config->webhook->objectTypes['testreport'] = array('opened', 'edited');
//$config->webhook->objectTypes['doc'] = array('created', 'edited', 'commented');
//$config->webhook->objectTypes['doclib'] = array('created', 'edited');
//$config->webhook->objectTypes['user'] = array('login', 'logout');

View File

@@ -12,29 +12,25 @@
class webhook extends control
{
/**
* Browse entries.
* Browse webhooks.
*
* @param string $orderBy
* @param int $recTotal
* @param int $recPerPage
* @param int $pageID
* @access public
* @return void
*/
public function browse($orderBy = 'id_desc', $recTotal = 0, $recPerPage = 10, $pageID = 1)
public function browse($orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
{
$pager = $this->app->loadClass('pager', $static = true);
$this->app->loadClass('pager', $static = true);
$pager = new pager($recTotal, $recPerPage, $pageID);
$this->view->title = $this->lang->webhook->api . $this->lang->colon . $this->lang->webhook->list;
$this->view->entries = $this->webhook->getList($orderBy, $pager);
$this->view->orderBy = $orderBy;
$this->view->pager = $pager;
$this->view->title = $this->lang->webhook->api . $this->lang->colon . $this->lang->webhook->list;
$this->view->webhooks = $this->webhook->getList($orderBy, $pager);
$this->view->orderBy = $orderBy;
$this->view->pager = $pager;
$this->display();
}
/**
* Create an webhook.
* Create a webhook.
*
* @access public
* @return void
@@ -43,85 +39,112 @@ class webhook extends control
{
if($_POST)
{
$webhookID = $this->webhook->create();
$this->webhook->create();
if(dao::isError()) $this->send(array('result' => 'fail', 'message' => dao::getError()));
$this->loadModel('action')->create('webhook', $webhookID, 'created');
$this->send(array('result' => 'success', 'message' => $this->lang->webhook->saveSuccess, 'locate' => inlink('browse')));
}
$this->view->title = $this->lang->webhook->api . $this->lang->colon . $this->lang->webhook->create;
$this->app->loadLang('action');
$this->view->title = $this->lang->webhook->api . $this->lang->colon . $this->lang->webhook->create;
$this->view->objectTypes = $this->webhook->getObjectTypes();
$this->view->objectActions = $this->webhook->getObjectActions();
$this->display();
}
/**
* Edit an webhook.
* Edit a webhook.
*
* @param int $webhookID
* @param int $id
* @access public
* @return void
*/
public function edit($webhookID)
public function edit($id)
{
if($_POST)
{
$changes = $this->webhook->update($webhookID);
$this->webhook->update($id);
if(dao::isError()) $this->send(array('result' => 'fail', 'message' => dao::getError()));
if($changes)
{
$actionID = $this->loadModel('action')->create('webhook', $webhookID, 'edited');
$this->action->logHistory($actionID, $changes);
}
$this->send(array('result' => 'success', 'message' => $this->lang->webhook->saveSuccess, 'locate' => inlink('browse')));
}
$webhook = $this->webhook->getById($webhookID);
$this->view->title = $this->lang->webhook->edit . $this->lang->colon . $webhook->name;
$this->view->webhook = $webhook;
$this->app->loadLang('action');
$webhook = $this->webhook->getByID($id);
$this->view->title = $this->lang->webhook->edit . $this->lang->colon . $webhook->name;
$this->view->objectTypes = $this->webhook->getObjectTypes();
$this->view->objectActions = $this->webhook->getObjectActions();
$this->view->webhook = $webhook;
$this->display();
}
/**
* Delete an webhook.
* Delete a webhook.
*
* @param int $webhookID
* @param int $id
* @access public
* @return void
*/
public function delete($webhookID)
public function delete($id)
{
$this->webhook->delete($webhookID);
$this->webhook->delete($id);
if(dao::isError()) $this->send(array('result' => 'fail', 'message' => dao::getError()));
$this->send(array('result' => 'success'));
}
public function log($webhookID)
/**
* Browse logs of a webhook.
*
* @param int $id
* @param string $orderBy
* @param int $recTotal
* @param int $recPerPage
* @param int $pageID
* @access public
* @return void
*/
public function log($id, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
{
$webhook = $this->webhook->getById($webhookID);
$this->app->loadClass('pager', $static = true);
$pager = new pager($recTotal, $recPerPage, $pageID);
$webhook = $this->webhook->getByID($id);
$this->view->title = $this->lang->webhook->log . $this->lang->colon . $webhook->name;
$this->view->actions = $this->loadModel('action')->getList('webhook', $webhookID);
$this->view->logs = $this->webhook->getLogList($id, $orderBy, $pager);
$this->view->webhook = $webhook;
$this->view->orderBy = $orderBy;
$this->view->pager = $pager;
$this->display();
}
public function actions($webhookID)
/**
* Send data by async.
*
* @access public
* @return void
*/
public function asyncSend()
{
if($_POST)
{
$this->webhook->saveActions($webhookID);
if(dao::isError()) $this->send(array('result' => 'fail', 'message' => dao::getError()));
$webhooks = $this->webhook->getList();
if(empty($hooks)) return false;
$dataList = $this->webhook->getDataList();
if(empty($dataList)) return true;
$this->send(array('result' => 'success', 'message' => $this->lang->webhook->saveSuccess, 'locate' => inlink('browse')));
$snoopy = $this->app->loadClass('snoopy');
foreach($dataList as $data)
{
$webhook = zget($webhooks, $data->webhook, '');
if($webhook)
{
$snoopy->_submit_type = zget($this->config->webhook->contentTypes, $webhook->contentType, 'application/json');
$snoopy->submit($webhook->url, $data->data);
$this->saveLog($data->webhook, $data->action, $webhook->url, $snoopy->_submit_type, $postData, $snoopy->status, $snoopy->error);
}
if($snoopy->status == 200) $this->dao->update(TABLE_WEBHOOKDATA)->set('status')->eq('sended')->where('id')->eq($data->id)->exec();
}
$webhook = $this->webhook->getById($webhookID);
$this->view->title = $this->lang->webhook->actions . $this->lang->colon . $webhook->name;
$this->view->actions = $this->webhook->getActions($webhookID);
$this->display();
}
public function ajaxGetActions($module)
{
$this->dao->delete()->from(TABLE_WEBHOOKDATA)->where('status')->eq('sended')->exec();
return true;
}
}

View File

@@ -0,0 +1 @@
.text {overflow: hidden; text-overflow: ellipsis;}

View File

@@ -0,0 +1,3 @@
.labelWidth label.checkbox-inline {width: 20%;}
.checkbox-inline + .checkbox-inline {margin-left: 0px;}
.objectType {margin-right: 5px !important;}

View File

@@ -0,0 +1,3 @@
.labelWidth label.checkbox-inline {width: 20%;}
.checkbox-inline + .checkbox-inline {margin-left: 0px;}
.objectType {margin-right: 5px !important;}

View File

@@ -1,31 +1,17 @@
/**
* create key for an entry.
*
* @access public
* @return void
*/
function createKey()
$(function()
{
var chars = '0123456789abcdefghiklmnopqrstuvwxyz'.split('');
var key = '';
for(var i = 0; i < 32; i ++)
{
key += chars[Math.floor(Math.random() * chars.length)];
}
$('#key').val(key);
return false;
}
$('#allIP').change(function()
{
if($(this).prop('checked'))
$('.objectType').click(function()
{
$('#ip').attr('disabled', 'disabled');
}
else
{
$('#ip').removeAttr('disabled');
}
})
if($(this).prop('checked'))
{
$(this).parent().parent().next().find('input[type=checkbox]').attr('checked', 'checked');
}
else
{
$(this).parent().parent().next().find('input[type=checkbox]').removeAttr('checked');
}
});
$('#name').focus();
$('#name').focus();
$('#paramsmessage').attr('disabled', 'disabled');
});

View File

@@ -1,31 +1,17 @@
/**
* create key for an entry.
*
* @access public
* @return void
*/
function createKey()
$(function()
{
var chars = '0123456789abcdefghiklmnopqrstuvwxyz'.split('');
var key = '';
for(var i = 0; i < 32; i ++)
{
key += chars[Math.floor(Math.random() * chars.length)];
}
$('#key').val(key);
return false;
}
$('#allIP').change(function()
{
if($(this).prop('checked'))
$('.objectType').click(function()
{
$('#ip').attr('disabled', 'disabled');
}
else
{
$('#ip').removeAttr('disabled');
}
})
if($(this).prop('checked'))
{
$(this).parent().parent().next().find('input[type=checkbox]').attr('checked', 'checked');
}
else
{
$(this).parent().parent().next().find('input[type=checkbox]').removeAttr('checked');
}
});
$('#name').focus();
$('#name').focus();
$('#paramsmessage').attr('disabled', 'disabled');
});

View File

@@ -1,31 +1,43 @@
<?php
$lang->webhook->common = 'webhook';
$lang->webhook->list = 'webhook列表';
$lang->webhook->list = '钩子列表';
$lang->webhook->api = '接口';
$lang->webhook->entry = '应用';
$lang->webhook->log = '日志';
$lang->webhook->action = '触发操作';
$lang->webhook->browse = '浏览webhook';
$lang->webhook->create = '添加webhook';
$lang->webhook->edit = '编辑webhook';
$lang->webhook->delete = '删除webhook';
$lang->webhook->browse = '浏览钩子';
$lang->webhook->create = '添加钩子';
$lang->webhook->edit = '编辑钩子';
$lang->webhook->delete = '删除钩子';
$lang->webhook->id = 'ID';
$lang->webhook->name = '名称';
$lang->webhook->url = '请求地址';
$lang->webhook->requestType = '请求类型';
$lang->webhook->url = 'Hook地址';
$lang->webhook->contentType = '内容类型';
$lang->webhook->sendType = '发送方式';
$lang->webhook->params = '参数';
$lang->webhook->action = '触发动作';
$lang->webhook->desc = '描述';
$lang->webhook->createdBy = '由谁创建';
$lang->webhook->createdDate = '创建时间';
$lang->webhook->editedby = '最后编辑';
$lang->webhook->editedDate = '编辑时间';
$lang->webhook->data = '数据';
$lang->webhook->status = '状态';
$lang->webhook->sendTypeList['sync'] = '同步';
$lang->webhook->sendTypeList['async'] = '异步';
$lang->webhook->paramsList['objectType'] = '对象类型';
$lang->webhook->paramsList['objectID'] = '对象ID';
$lang->webhook->paramsList['product'] = '所属产品';
$lang->webhook->paramsList['project'] = '所属项目';
$lang->webhook->paramsList['action'] = '动作';
$lang->webhook->paramsList['actor'] = '操作者';
$lang->webhook->paramsList['date'] = '操作日期';
$lang->webhook->paramsList['comment'] = '备注';
$lang->webhook->paramsList['message'] = '操作内容';
$lang->webhook->saveSuccess = '保存成功';
$lang->webhook->confirmDelete = '您确认要删除该webhook吗';
$lang->webhook->trimWords = '了';
$lang->webhook->note = new stdClass();
$lang->webhook->note->name = '授权webhook名称';
$lang->webhook->note->url = '授权webhook地址';
$lang->webhook->note->params = '参数列表,以 & 隔开';
$lang->webhook->note->async = '异步需要打开计划任务';

View File

@@ -12,89 +12,342 @@
class webhookModel extends model
{
/**
* Get an webhook by id.
* Get a webhook by id.
*
* @param int $webhookID
* @param int $id
* @access public
* @return array
*/
public function getById($webhookID)
public function getByID($id)
{
return $this->dao->select('*')->from(TABLE_WEBHOOK)->where('id')->eq($webhookID)->fetch();
$webhook = $this->dao->select('*')->from(TABLE_WEBHOOK)->where('id')->eq($id)->fetch();
$webhook->actions = json_decode($webhook->actions);
return $webhook;
}
/**
* Get webhook list.
*
* @param string $orderBy
* @param obejct $pager
* @param object $pager
* @access public
* @return array
*/
public function getList($orderBy = 'id_desc', $pager = null)
{
return $this->dao->select('*')->from(TABLE_WEBHOOK)->orderBy($orderBy)->page($pager)->fetchAll('id');
$webhooks = $this->dao->select('*')->from(TABLE_WEBHOOK)->orderBy($orderBy)->page($pager)->fetchAll('id');
foreach($webhooks as $webhook) $webhook->actions = json_decode($webhook->actions);
return $webhooks;
}
/**
* Create an webhook.
* Get log list of a webhook.
*
* @param int $id
* @param string $orderBy
* @param object $pager
* @access public
* @return array
*/
public function getLogList($id, $orderBy = 'date_desc', $pager = null)
{
$logs = $this->dao->select('*')->from(TABLE_LOG)
->where('objectType')->eq('webhook')
->andWhere('objectID')->eq($id)
->orderBy($orderBy)
->page($pager)
->fetchAll('id');
foreach($logs as $log) $log->data = json_decode($log->data);
return $logs;
}
/**
* Get saved data list.
*
* @access public
* @return bool | int
* @return array
*/
public function getDataList()
{
return $this->dao->select('*')->from(TABLE_WEBHOOKDATA)->where('status')->eq('wait')->orderBy('id')->fetchAll('id');
}
/**
* Get object types.
*
* @access public
* @return array
*/
public function getObjectTypes()
{
$objectTypes = array();
foreach($this->config->webhook->objectTypes as $objectType => $actions)
{
$objectTypes[$objectType] = $this->lang->action->objectTypes[$objectType];
}
return $objectTypes;
}
/**
* Get object actions.
*
* @access public
* @return array
*/
public function getObjectActions()
{
$objectActions = array();
foreach($this->config->webhook->objectTypes as $objectType => $actions)
{
foreach($actions as $action)
{
$objectActions[$objectType][$action] = str_replace($this->lang->webhook->trimWords, '', $this->lang->action->label->$action);
}
}
return $objectActions;
}
/**
* Create a webhook.
*
* @access public
* @return bool
*/
public function create()
{
$webhook = fixer::input('post')
->add('createdBy', $this->app->user->account)
->add('createdDate', helper::now())
->setForce('params', implode(',', $this->post->params) . ',message')
->setForce('actions', helper::jsonEncode($this->post->actions))
->skipSpecial('url,actions')
->get();
$this->dao->insert(TABLE_WEBHOOK)->data($webhook)
->batchCheck($this->config->webhook->create->requiredFields, 'notempty')
->autoCheck()
->exec();
if(dao::isError()) return false;
return $this->dao->lastInsertId();
return !dao::isError();
}
/**
* Update an webhook.
* Update a webhook.
*
* @param int $webhookID
* @param int $id
* @access public
* @return bool | array
* @return bool
*/
public function update($webhookID)
public function update($id)
{
$oldEntry = $this->getById($webhookID);
$webhook = fixer::input('post')
->add('editedBy', $this->app->user->account)
->add('editedDate', helper::now())
->setForce('params', implode(',', $this->post->params) . ',message')
->setForce('actions', helper::jsonEncode($this->post->actions))
->skipSpecial('url,actions')
->get();
$this->dao->update(TABLE_WEBHOOK)->data($webhook)
->batchCheck($this->config->webhook->edit->requiredFields, 'notempty')
->autoCheck()
->where('id')->eq($webhookID)
->where('id')->eq($id)
->exec();
if(dao::isError()) return false;
return common::createChanges($oldEntry, $webhook);
return !dao::isError();
}
/**
* Delete an webhook.
* Delete a webhook.
*
* @param int $webhookID
* @param int $null
* @param int $id
* @param object $null
* @access public
* @return bool
*/
public function delete($webhookID, $null = null)
public function delete($id, $null = null)
{
$this->dao->delete()->from(TABLE_WEBHOOK)->where('id')->eq($webhookID)->exec();
$this->dao->delete()->from(TABLE_WEBHOOK)->where('id')->eq($id)->exec();
$this->dao->delete()->from(TABLE_LOG)->where('objectType')->eq('webhook')->andWhere('objectID')->eq($id)->exec();
return !dao::isError();
}
/**
* Send data.
*
* @param string $objectType
* @param int $objectID
* @param string $actionType
* @param int $actionID
* @access public
* @return bool
*/
public function send($objectType, $objectID, $actionType, $actionID)
{
static $webhooks = array();
if(!$webhooks) $webhooks = $this->getList();
if(!$webhooks) return true;
$snoopy = $this->app->loadClass('snoopy');
foreach($webhooks as $id => $webhook)
{
if(!in_array($actionType, $webhook->actions->$objectType)) continue;
$postData = $this->buildData($objectType, $objectID, $actionType, $actionID, explode(',', $webhook->params));
if($webhook->sendType == 'async')
{
$this->saveData($id, $actionID, $postData);
continue;
}
$contentType = zget($this->config->webhook->contentTypes, $webhook->contentType, 'application/json');
$result = $this->fetchHook($contentType, $webhook->url, $postData);
$this->saveLog($id, $actionID, $webhook->url, $contentType, $postData, $result);
}
return !dao::isError();
}
/**
* Build data.
*
* @param string $objectType
* @param int $objectID
* @param string $actionType
* @param int $actionID
* @param array $params
* @access public
* @return string
*/
public function buildData($objectType, $objectID, $actionType, $actionID, $params)
{
static $users = array();
if(empty($users)) $users = $this->loadModel('user')->getPairs('noletter');
if(!isset($this->lang->action->label)) $this->loadModel('action');
if(!isset($this->lang->action->label->$actionType)) return false;
if(empty($this->config->objectTables[$objectType])) return false;
$action = $this->dao->select('*')->from(TABLE_ACTION)->where('id')->eq($actionID)->fetch();
$object = $this->dao->select('*')->from($this->config->objectTables[$objectType])->where('id')->eq($objectID)->fetch();
$field = $this->config->action->objectNameFields[$objectType];
$title = $object->$field;
$oldOnlyBody = '';
if(isset($_GET['onlybody']) and $_GET['onlybody'] == 'yes')
{
$oldOnlyBody = 'yes';
unset($_GET['onlybody']);
}
$viewLink = helper::createLink($objectType, 'view', "id=$objectID");
if($oldOnlyBody) $_GET['onlybody'] = $oldOnlyBody;
$host = common::getSysURL();
$data = new stdclass();
foreach($params as $param)
{
if($param == 'message')
{
$data->text = $this->app->user->realname . $this->lang->action->label->$actionType . $this->lang->action->objectTypes[$objectType] . ' ' . "[#{$objectID}::{$title}](" . $host . $viewLink . ")";
if($actionType == 'assigned') $data->text .= ' ' . $this->lang->webhooks->assigned . ' ' . zget($users, $object->assignedTo);
}
else
{
$data->$param = $action->$param;
}
}
if(!empty($_FILES['files']['name'][0]))
{
$this->loadModel('file');
$files = $this->dao->select('*')->from(TABLE_FILE)->where('objectType')->eq($objectType)->andWhere('objectID')->eq($objectID)->orderBy('addedDate_desc,id_desc')->limit(count($_FILES['files']['name']))->fetchAll();
if($files)
{
foreach($files as $file)
{
$attachment = array();
$attachment['title'] = $file->title;
$attachment['images'][]['url'] = $data->host . $this->file->webPath . $file->pathname;
$data->attachments[] = $attachment;
}
}
}
return helper::jsonEncode($data);
}
/**
* Post hook data.
*
* @param string $contentType
* @param string $url
* @param string $sendData
* @access public
* @return int
*/
public function fetchHook($contentType, $url, $sendData)
{
$header[] = "Content-Type: $contentType";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $sendData);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $httpCode;
}
/**
* Save datas.
*
* @param int $webhookID
* @param int $actionID
* @param string $data
* @access public
* @return bool
*/
public function saveData($webhookID, $actionID, $data)
{
$webhookData = new stdclass();
$webhookData->webhook = $webhookID;
$webhookData->action = $actionID;
$webhookData->data = $data;
$webhookData->createdBy = $this->app->user->account;
$webhookData->createdDate = helper::now();
$this->dao->insert(TABLE_WEBHOOKDATA)->data($webhookData)->exec();
return !dao::isError();
}
/**
* Save log.
*
* @param int $webhookID
* @param int $actionID
* @param string $url
* @param string $contentType
* @param string $data
* @param int $status
* @param string $error
* @access public
* @return bool
*/
public function saveLog($webhookID, $actionID, $url, $contentType, $data, $status, $error = '')
{
$log = new stdclass();
$log->objectType = 'webhook';
$log->objectID = $webhookID;
$log->action = $actionID;
$log->date = helper::now();
$log->url = $url;
$log->contentType = $contentType;
$log->data = $data;
$log->status = $status;
$log->error = $error;
$this->dao->insert(TABLE_LOG)->data($log)->exec();
return !dao::isError();
}
}

View File

@@ -13,36 +13,29 @@
<?php include 'header.html.php';?>
<?php js::set('confirmDelete', $lang->webhook->confirmDelete);?>
<form id='ajaxForm' method='post'>
<table id='webhookList' class='table table-condensed table-hover table-striped tablesorter'>
<table id='webhookList' class='table table-condensed table-hover table-striped table-fixed'>
<thead>
<tr>
<?php $vars = "orderBy=%s&recTotal=$pager->recTotal&recPerPage=$pager->recPerPage&pageID=$pager->pageID";?>
<th class='w-80px'><?php common::printOrderLink('id', $orderBy, $vars, $lang->webhook->id);?></th>
<th class='w-200px'><?php common::printOrderLink('name', $orderBy, $vars, $lang->webhook->name);?></th>
<th class='w-200px'><?php common::printOrderLink('url', $orderBy, $vars, $lang->webhook->url);?></th>
<th class='w-100px'><?php common::printOrderLink('requestType', $orderBy, $vars, $lang->webhook->requestType);?></th>
<th class='w-200px'><?php common::printOrderLink('params', $orderBy, $vars, $lang->webhook->params);?></th>
<th><?php echo common::printOrderLink('desc', $orderBy, $vars, $lang->webhook->desc);?></th>
<th class='w-100px'><?php echo html::a('###', $lang->actions);?></th>
<th class='w-40px'><?php echo $lang->webhook->id;?></th>
<th><?php echo $lang->webhook->name;?></th>
<th><?php echo $lang->webhook->url;?></th>
<th class='w-100px'><?php echo $lang->actions;?></th>
</tr>
</thead>
<tbody>
<?php foreach($entries as $webhook):?>
<?php $index = 1;?>
<?php foreach($webhooks as $id => $webhook):?>
<tr>
<td class='text-center'><?php echo $webhook->id;?></td>
<td title='<?php echo $webhook->name;?>'><?php echo $webhook->name;?></td>
<td><?php echo $webhook->url;?></td>
<td title='<?php echo $webhook->requestType;?>'><?php echo $webhook->requestType;?></td>
<td title='<?php echo $webhook->params;?>'><?php echo $webhook->params;?></td>
<td title='<?php echo $webhook->desc;?>'><?php echo $webhook->desc;?></td>
<td class='text-center'><?php echo $index++;?></td>
<td class='text' title='<?php echo $webhook->name;?>'><?php echo $webhook->name;?></td>
<td class='text' title='<?php echo $webhook->url;?>'><?php echo $webhook->url;?></td>
<td class='text-right'>
<?php
common::printIcon('webhook', 'log', "webhookID=$webhook->id", '', 'list', 'file-text-o');
common::printIcon('webhook', 'action', "webhookID=$webhook->id", '', 'list', 'cog');
common::printIcon('webhook', 'edit', "webhookID=$webhook->id", '', 'list');
common::printIcon('webhook', 'log', "webhookID=$id", '', 'list', 'file-text-o');
common::printIcon('webhook', 'edit', "webhookID=$id", '', 'list');
if(common::hasPriv('webhook', 'delete'))
{
$deleteURL = $this->createLink('webhook', 'delete', "webhookID=$webhook->id&confirm=yes");
$deleteURL = $this->createLink('webhook', 'delete', "webhookID=$id&confirm=yes");
echo html::a("javascript:ajaxDelete(\"$deleteURL\",\"webhookList\",confirmDelete)", '<i class="icon-remove"></i>', '', "title='{$lang->webhook->delete}' class='btn-icon'");
}
?>
@@ -52,7 +45,7 @@
</tbody>
<tfoot>
<tr>
<td colspan='7'><?php $pager->show();?></td>
<td colspan='4'><?php $pager->show();?></td>
</tr>
</tfoot>
</table>

View File

@@ -12,7 +12,7 @@
?>
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/form.html.php';?>
<div class='container mw-800px'>
<div class='container mw-1400px'>
<div id="titlebar">
<div class="heading">
<strong><?php echo $lang->webhook->api;?></strong>
@@ -23,26 +23,48 @@
<table class='table table-form'>
<tr>
<th class='w-80px'><?php echo $lang->webhook->name;?></th>
<td><?php echo html::input('name', '', "class='form-control' placeholder='{$lang->webhook->note->name}'");?></td>
<td class='w-120px'></td>
<td class='w-p50'><?php echo html::input('name', '', "class='form-control'");?></td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->webhook->url;?></th>
<td><?php echo html::input('url', '', "class='form-control' placeholder='{$lang->webhook->note->url}'");?></td>
<td><?php echo html::input('url', '', "class='form-control'");?></td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->webhook->requestType;?></th>
<td><?php echo html::select('requestType', $config->webhook->requestType, '', "class='form-control'");?></td>
<th><?php echo $lang->webhook->contentType;?></th>
<td><?php echo html::select('contentType', $config->webhook->contentTypes, '', "class='form-control'");?></td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->webhook->sendType;?></th>
<td><?php echo html::select('sendType', $lang->webhook->sendTypeList, '', "class='form-control'");?></td>
<td><?php echo $lang->webhook->note->async;?></td>
</tr>
<tr>
<th><?php echo $lang->webhook->params;?></th>
<td><?php echo html::input('params', '', "class='form-control' title='{$lang->webhook->note->params}' placeholder='{$lang->webhook->note->params}'");?></td>
<td class='labelWidth' colspan='2'><?php echo html::checkbox('params', $lang->webhook->paramsList, 'message');?></td>
</tr>
<tr>
<th><?php echo $lang->webhook->action;?></th>
<td colspan='2'>
<table class='table table-bordered'>
<?php foreach($config->webhook->objectTypes as $objectType => $actions):?>
<tr>
<td class='w-90px'>
<label class='checkbox-inline'>
<input type='checkbox' class='objectType'><strong><?php echo $objectTypes[$objectType];?></strong>
</label>
</td>
<td class='labelWidth'><?php echo html::checkbox("actions[$objectType]", $objectActions[$objectType]);?></td>
</tr>
<?php endforeach;?>
</table>
</td>
</tr>
<tr>
<th><?php echo $lang->webhook->desc;?></th>
<td><?php echo html::textarea('desc', '', "rows='3' class='form-control'");?></td>
<td></td>
<td colspan='2'><?php echo html::textarea('desc', '', "rows='3' class='form-control'");?></td>
</tr>
<tr>
<th></th>

View File

@@ -12,7 +12,7 @@
?>
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/form.html.php';?>
<div class='container mw-800px'>
<div class='container mw-1400px'>
<div id="titlebar">
<div class="heading">
<strong><?php echo $lang->webhook->api;?></strong>
@@ -23,26 +23,49 @@
<table class='table table-form'>
<tr>
<th class='w-80px'><?php echo $lang->webhook->name;?></th>
<td><?php echo html::input('name', $webhook->name, "class='form-control' placeholder='{$lang->webhook->note->name}'");?></td>
<td class='w-120px'></td>
<td class='w-p50'><?php echo html::input('name', $webhook->name, "class='form-control'");?></td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->webhook->url;?></th>
<td><?php echo html::input('url', $webhook->url, "class='form-control' placeholder='{$lang->webhook->note->url}'");?></td>
<td><?php echo html::input('url', $webhook->url, "class='form-control'");?></td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->webhook->requestType;?></th>
<td><?php echo html::select('requestType', $config->webhook->requestType, $webhook->requestType, "class='form-control'");?></td>
<th><?php echo $lang->webhook->contentType;?></th>
<td><?php echo html::select('contentType', $config->webhook->contentTypes, $webhook->contentType, "class='form-control'");?></td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->webhook->sendType;?></th>
<td><?php echo html::select('sendType', $lang->webhook->sendTypeList, $webhook->sendType, "class='form-control'");?></td>
<td><?php echo $lang->webhook->note->async;?></td>
</tr>
<tr>
<th><?php echo $lang->webhook->params;?></th>
<td><?php echo html::input('params', $webhook->params, "class='form-control' title='{$lang->webhook->note->params}' placeholder='{$lang->webhook->note->params}'");?></td>
<td class='labelWidth' colspan='2'><?php echo html::checkbox('params', $lang->webhook->paramsList, $webhook->params);?></td>
</tr>
<tr>
<th><?php echo $lang->webhook->action;?></th>
<td colspan='2'>
<table class='table table-bordered'>
<?php foreach($config->webhook->objectTypes as $objectType => $actions):?>
<tr>
<td class='w-90px'>
<label class='checkbox-inline'>
<?php $checked = isset($webhook->actions->$objectType) ? "checked='checked'" : '';?>
<input type='checkbox' <?php echo $checked;?> class='objectType'><strong><?php echo $objectTypes[$objectType];?></strong>
</label>
</td>
<td class='labelWidth'><?php echo html::checkbox("actions[$objectType]", $objectActions[$objectType], isset($webhook->actions->$objectType) ? $webhook->actions->$objectType : '');?></td>
</tr>
<?php endforeach;?>
</table>
</td>
</tr>
<tr>
<th><?php echo $lang->webhook->desc;?></th>
<td><?php echo html::textarea('desc', $webhook->desc, "rows='3' class='form-control'");?></td>
<td></td>
<td colspan='2'><?php echo html::textarea('desc', $webhook->desc, "rows='3' class='form-control'");?></td>
</tr>
<tr>
<th></th>

View File

@@ -0,0 +1,49 @@
<?php
/**
* The log view file of log module of ZenTaoPMS.
*
* @copyright Copyright 2009-2017 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Gang Liu <liugang@cnezsoft.com>
* @package log
* @version $Id$
* @link http://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<div id="titlebar">
<div class="heading">
<strong><?php echo html::a(inlink('browse'), $lang->webhook->common);?></strong>
<small class="text-muted"> <?php echo $webhook->name;?> </small>
<small class="text-muted"> <?php echo $lang->webhook->log;?> <i class="icon-file-text-o"></i></small>
</div>
</div>
<table id='logList' class='table table-condensed table-hover table-striped tablesorter table-fixed'>
<thead>
<tr>
<?php $vars = "id={$webhook->id}&orderBy=%s&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}";?>
<th class='w-60px'><?php common::printOrderLink('id', $orderBy, $vars, $lang->webhook->id);?></th>
<th><?php common::printOrderLink('url', $orderBy, $vars, $lang->webhook->url);?></th>
<th class='w-300px'><?php common::printOrderLink('action', $orderBy, $vars, $lang->webhook->action);?></th>
<th class='w-200px'><?php common::printOrderLink('contentType', $orderBy, $vars, $lang->webhook->contentType);?></th>
<th class='w-80px'><?php common::printOrderLink('status', $orderBy, $vars, $lang->webhook->status);?></th>
</tr>
</thead>
<tbody>
<?php foreach($logs as $id => $log):?>
<tr>
<td class='text-center'><?php echo $id;?></td>
<td class='text' title='<?php echo $log->url;?>'><?php echo $log->url;?></td>
<td class='text' title='<?php echo $log->data->text;?>'><?php echo $log->data->text;?></td>
<td class='text-center'><?php echo $log->contentType;?></td>
<td><?php echo $log->status;?></td>
</tr>
<?php endforeach;?>
</tbody>
<tfoot>
<tr>
<td colspan='5'><?php $pager->show();?></td>
</tr>
</tfoot>
</table>
<?php include '../../common/view/footer.html.php';?>