* Finish task#44172,task#44273.
This commit is contained in:
+2
-2
@@ -371,8 +371,8 @@ $filter->repo->diff->cookie['repoPairs'] = 'array';
|
||||
$filter->repo->view->cookie['repoPairs'] = 'array';
|
||||
$filter->repo->ajaxsynccommit->cookie['syncBranch'] = 'reg::any';
|
||||
|
||||
$filter->webhook->bind->get['selectedDepts'] = 'reg::checked';
|
||||
$filter->webhook->bind->cookie['selectedDepts'] = 'reg::checked';
|
||||
$filter->webhook->bind->get['selectedDepts'] = 'reg::any';
|
||||
$filter->webhook->bind->cookie['selectedDepts'] = 'reg::any';
|
||||
|
||||
$filter->search->index->get['words'] = 'reg::any';
|
||||
$filter->search->index->get['type'] = 'code';
|
||||
|
||||
@@ -142,6 +142,9 @@ $config->openMethods[] = 'my.changepassword';
|
||||
$config->openMethods[] = 'my.profile';
|
||||
$config->openMethods[] = 'my.settutorialconfig';
|
||||
$config->openMethods[] = 'doc.selectlibtype';
|
||||
$config->openMethods[] = 'sso.getfeishusso';
|
||||
$config->openMethods[] = 'sso.feishuauthen';
|
||||
$config->openMethods[] = 'sso.feishulogin';
|
||||
|
||||
/* Define the tables. */
|
||||
define('TABLE_COMPANY', '`' . $config->db->prefix . 'company`');
|
||||
|
||||
@@ -136,7 +136,7 @@ class dingapi
|
||||
$node['id'] = $deptID;
|
||||
$node['pId'] = $parentID;
|
||||
$node['name'] = $deptName;
|
||||
if($parentID == 0) $node['open'] = true;
|
||||
$node['open'] = true;
|
||||
|
||||
$tree[] = $node;
|
||||
}
|
||||
|
||||
@@ -52,17 +52,23 @@ class feishuapi
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getAllUsers()
|
||||
public function getAllUsers($selectedDepts = '')
|
||||
{
|
||||
$selectedDepts = trim($selectedDepts);
|
||||
if(empty($selectedDepts)) return array('result' => 'fail', 'message' => 'nodept');
|
||||
|
||||
set_time_limit(0);
|
||||
|
||||
$users = array();
|
||||
$depts = $this->getDepts();
|
||||
$depts = explode(',', $selectedDepts);
|
||||
$depts = array_flip($depts);
|
||||
unset($depts[1]);
|
||||
if(empty($depts)) return array('result' => 'fail', 'message' => 'nodept');
|
||||
|
||||
/* Get users by dept. */
|
||||
foreach($depts as $deptID => $count)
|
||||
{
|
||||
if($deptID and empty($count)) continue;
|
||||
if(empty($deptID)) continue;
|
||||
|
||||
$pageToken = '';
|
||||
while(true)
|
||||
@@ -138,6 +144,46 @@ class feishuapi
|
||||
return $depts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get department tree structure.
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getDeptTree()
|
||||
{
|
||||
$depts = array('result' => 'success', 'data' => array());
|
||||
|
||||
/* Gets the enterprise name. */
|
||||
$response = $this->queryAPI($this->apiUrl . "tenant/v2/tenant/query", '', array(CURLOPT_CUSTOMREQUEST => "GET"));
|
||||
$company = array('id' => '1', 'pId' => '0', 'name' => $response->data->tenant->name, 'open' => 1);
|
||||
$data = array($company);
|
||||
|
||||
/* Get depts by parent dept. */
|
||||
$pageToken = '';
|
||||
while(true)
|
||||
{
|
||||
$response = $this->queryAPI($this->apiUrl . "contact/v3/departments?parent_department_id=0" . ($pageToken ? "&page_token={$pageToken}" : '') . "&fetch_child=true", '', array(CURLOPT_CUSTOMREQUEST => "GET"));
|
||||
if(isset($response->data->items))
|
||||
{
|
||||
foreach($response->data->items as $key => $dept)
|
||||
{
|
||||
$key ++;
|
||||
$data[$key]['id'] = $dept->open_department_id;
|
||||
$data[$key]['pId'] = empty($dept->parent_department_id) ? 1 : $dept->parent_department_id;
|
||||
$data[$key]['name'] = $dept->name;
|
||||
$data[$key]['open'] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isset($response->data->page_token)) break;
|
||||
$pageToken = $response->data->page_token;
|
||||
}
|
||||
|
||||
$depts['data'] = $data;
|
||||
return $depts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send message
|
||||
*
|
||||
@@ -179,6 +225,11 @@ class feishuapi
|
||||
|
||||
if(empty($response)) $this->errors = $errors;
|
||||
if(isset($response->code)) $this->errors[$response->code] = "Errcode:{$response->code}, Errmsg:{$response->msg}";
|
||||
if(!empty($this->errors))
|
||||
{
|
||||
echo js::error(array_shift($this->errors));
|
||||
die(js::locate(helper::createLink('webhook', 'browse')));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+11
-2
@@ -2506,15 +2506,24 @@ EOD;
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public static function http($url, $data = null, $options = array(), $headers = array())
|
||||
public static function http($url, $data = null, $options = array(), $headers = array(), $dataType = 'data')
|
||||
{
|
||||
global $lang, $app;
|
||||
if(!extension_loaded('curl')) return json_encode(array('result' => 'fail', 'message' => $lang->error->noCurlExt));
|
||||
if(!extension_loaded('curl'))
|
||||
{
|
||||
if($dataType == 'json') die($this->lang->error->noCurlExt);
|
||||
return json_encode(array('result' => 'fail', 'message' => $lang->error->noCurlExt));
|
||||
}
|
||||
|
||||
commonModel::$requestErrors = array();
|
||||
|
||||
if(!is_array($headers)) $headers = (array)$headers;
|
||||
$headers[] = "API-RemoteIP: " . zget($_SERVER, 'REMOTE_ADDR', '');
|
||||
if($dataType == 'json')
|
||||
{
|
||||
$headers[] = 'Content-Type: application/json;charset=utf-8';
|
||||
if(!empty($data)) $data = json_encode($data);
|
||||
}
|
||||
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
|
||||
|
||||
@@ -305,4 +305,127 @@ class sso extends control
|
||||
$datas['bug'] = $this->dao->select("id, title")->from(TABLE_BUG)->where('assignedTo')->eq($account)->andWhere('status')->eq('active')->andWhere('deleted')->eq(0)->fetchPairs();
|
||||
die(json_encode($datas));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the link to the Feishu single sign-on configuration.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function getFeishuSSO()
|
||||
{
|
||||
$httpType = ((isset($_SERVER['HTTPS']) and $_SERVER['HTTPS'] == 'on') or (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) and $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ? 'https://' : 'http://';
|
||||
$applicationHome = $httpType . $_SERVER['HTTP_HOST'] . $this->createLink('sso', 'feishuAuthen');
|
||||
$redirectLink = $httpType . $_SERVER['HTTP_HOST'] . $this->createLink('sso', 'feishuLogin');
|
||||
|
||||
echo $this->lang->sso->homeURL . $applicationHome;
|
||||
echo '<br>';
|
||||
echo $this->lang->sso->redirectURL . $redirectLink;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pre-authorization code for Feishu code.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function feishuAuthen()
|
||||
{
|
||||
$httpType = ((isset($_SERVER['HTTPS']) and $_SERVER['HTTPS'] == 'on') or (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) and $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ? 'https://' : 'http://';
|
||||
$redirectURI = $httpType . $_SERVER['HTTP_HOST'] . $this->createLink('sso', 'feishuLogin');
|
||||
$redirectURI = urlencode($redirectURI);
|
||||
|
||||
$feishuConfig = $this->loadModel('webhook')->getByType('feishuuser');
|
||||
if(empty($feishuConfig)) $this->showError($this->lang->sso->feishuConfigEmpty);
|
||||
|
||||
$appConfig = json_decode($feishuConfig->secret);
|
||||
$appID = $appConfig->appId;
|
||||
|
||||
$url = "https://open.feishu.cn/open-apis/authen/v1/index?redirect_uri=%s&app_id=%s";
|
||||
$url = sprintf($url, $redirectURI, $appID, $state);
|
||||
header("location: $url");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the identity of the logged-in user.
|
||||
*
|
||||
* @param string $code
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function feishuLogin($code = '')
|
||||
{
|
||||
if($this->config->requestType == 'PATH_INFO')
|
||||
{
|
||||
$params = $_SERVER["QUERY_STRING"];
|
||||
parse_str($params, $params);
|
||||
if(isset($params['code'])) $code = $params['code'];
|
||||
}
|
||||
|
||||
$feishuConfig = $this->loadModel('webhook')->getByType('feishuuser');
|
||||
if(empty($feishuConfig)) $this->showError($this->lang->sso->feishuConfigEmpty);
|
||||
$appConfig = json_decode($feishuConfig->secret);
|
||||
|
||||
/* Obtain the access credentials of the Feishu app. */
|
||||
$appUrl = 'https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal';
|
||||
$appParams = array('app_id' => $appConfig->appId, 'app_secret' => $appConfig->appSecret);
|
||||
$appResult = common::http($appUrl, $appParams, array(), array(), 'json');
|
||||
|
||||
if(empty($appResult)) $this->showError($this->lang->sso->feishuResponseEmpty);
|
||||
$appInfo = json_decode($appResult);
|
||||
|
||||
if(!isset($appInfo->msg) or $appInfo->msg != 'ok') $this->showError($appResult);
|
||||
$accessToken = $appInfo->app_access_token;
|
||||
|
||||
/* Verify the identity of the logged in user. */
|
||||
$tokenUrl = 'https://open.feishu.cn/open-apis/authen/v1/refresh_access_token';
|
||||
$tokenHeaders = array('Authorization: Bearer ' . $accessToken);
|
||||
$tokenParams = array('grant_type' => 'authorization_code', 'code' => $code);
|
||||
$tokenResult = common::http($tokenUrl, $tokenParams, array(), $tokenHeaders, 'json');
|
||||
|
||||
if(empty($tokenResult)) $this->showError($this->lang->sso->feishuResponseEmpty);
|
||||
$tokenInfo = json_decode($tokenResult);
|
||||
|
||||
if(!isset($tokenInfo->msg) or $tokenInfo->msg != 'success') $this->showError($tokenResult);
|
||||
$userToken = $tokenInfo->data->access_token;
|
||||
|
||||
/* Get login user information. */
|
||||
$userUrl = 'https://open.feishu.cn/open-apis/authen/v1/user_info';
|
||||
$userHeaders = array('Authorization: Bearer ' . $userToken);
|
||||
$userResult = common::http($userUrl, array(), array(), $userHeaders, 'json');
|
||||
|
||||
if(empty($userResult)) $this->showError($this->lang->sso->feishuResponseEmpty);
|
||||
$userInfo = json_decode($userResult);
|
||||
|
||||
if(!isset($userInfo->msg) or $userInfo->msg != 'success') $this->showError($userResult);
|
||||
$openID = $userInfo->data->open_id;
|
||||
|
||||
/* Get the user relationship bound in webhook. */
|
||||
$account = $this->loadModel('webhook')->getBindAccount($feishuConfig->id, 'webhook', $openID);
|
||||
if(empty($account)) $this->showError($this->lang->sso->unbound);
|
||||
|
||||
$user = $this->loadModel('user')->getById($account);
|
||||
$password = $user->password;
|
||||
$this->session->set('rand', '');
|
||||
$user = $this->user->identify($account, $password);
|
||||
$this->user->login($user);
|
||||
|
||||
$indexUrl = $this->createLink('my', 'index');
|
||||
header("location: $indexUrl");
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the error message.
|
||||
*
|
||||
* @param string $message
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function showError($message = '')
|
||||
{
|
||||
$this->view->title = $this->lang->sso->deny;
|
||||
$this->view->message = $message;
|
||||
$this->display('sso', 'error');
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,14 @@ $lang->sso->help = <<<EOD
|
||||
<p>1、接口地址的填写,如果是PATH_INFO :http://ZDOO网址/sys/sso-check.html,如果是GET:http://ZDOO网址/sys/index.php?m=sso&f=check</p>
|
||||
<p>2、代号和密钥必须与ZDOO后台设置的一致。</p>
|
||||
EOD;
|
||||
$lang->sso->deny = '访问受限';
|
||||
$lang->sso->bindNotice = '添加的新用户暂时没有权限,需要联系禅道管理员,给该用户分配权限。';
|
||||
$lang->sso->bindNoPassword = '密码不能为空';
|
||||
$lang->sso->bindNoUser = '该用户的登录密码错误,或该用户不存在!';
|
||||
$lang->sso->bindHasAccount = '该用户名已经存在,请更换用户名,或直接绑定到该用户。';
|
||||
|
||||
$lang->sso->homeURL = '飞书主页配置URL:';
|
||||
$lang->sso->redirectURL = '飞书重定向配置URL:';
|
||||
$lang->sso->feishuConfigEmpty = '请在[后台][通知][Webhook]功能中配置(飞书工作消息通知)';
|
||||
$lang->sso->feishuResponseEmpty = '请求响应信息为空';
|
||||
$lang->sso->unbound = '当前飞书用户未在禅道webhook功能中进行用户关系绑定';
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* The html template file of deny method of user module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
|
||||
* @package ZenTaoPMS
|
||||
* @version $Id: deny.html.php 4129 2013-01-18 01:58:14Z wwccss $
|
||||
*/
|
||||
include '../../common/view/header.lite.html.php';
|
||||
?>
|
||||
<div class='container'>
|
||||
<div class='modal-dialog'>
|
||||
<div class='modal-header'><strong><?php echo $lang->sso->deny;?></strong></div>
|
||||
<div class='modal-body'>
|
||||
<div class='alert with-icon alert-pure'>
|
||||
<i class='icon-exclamation-sign'></i>
|
||||
<div class='content'><?php echo $message;?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -211,14 +211,14 @@ class webhook extends control
|
||||
elseif($webhook->type == 'wechatuser')
|
||||
{
|
||||
$this->app->loadClass('wechatapi', true);
|
||||
$wechatApi = new wechatapi($webhook->secret->appKey, $webhook->secret->appSecret, $webhook->secret->agentId);
|
||||
$response = $wechatApi->getAllUsers();
|
||||
$wechatApi = new wechatapi($webhook->secret->appKey, $webhook->secret->appSecret, $webhook->secret->agentId);
|
||||
$response = $wechatApi->getAllUsers();
|
||||
}
|
||||
elseif($webhook->type == 'feishuuser')
|
||||
{
|
||||
$this->app->loadClass('feishuapi', true);
|
||||
$feishuApi = new feishuapi($webhook->secret->appId, $webhook->secret->appSecret);
|
||||
$response = $feishuApi->getAllUsers();
|
||||
$feishuApi = new feishuapi($webhook->secret->appId, $webhook->secret->appSecret);
|
||||
$response = $feishuApi->getAllUsers($selectedDepts);
|
||||
}
|
||||
|
||||
if($response['result'] == 'fail')
|
||||
@@ -275,7 +275,7 @@ class webhook extends control
|
||||
public function chooseDept($id)
|
||||
{
|
||||
$webhook = $this->webhook->getById($id);
|
||||
if($webhook->type != 'dinguser' && $webhook->type != 'wechatuser')
|
||||
if($webhook->type != 'dinguser' && $webhook->type != 'wechatuser' && $webhook->type != 'feishuuser')
|
||||
{
|
||||
echo js::alert($this->lang->webhook->note->bind);
|
||||
die(js::locate($this->createLink('webhook', 'browse')));
|
||||
@@ -289,6 +289,13 @@ class webhook extends control
|
||||
$response = $dingapi->getDeptTree();
|
||||
}
|
||||
|
||||
if($webhook->type == 'feishuuser')
|
||||
{
|
||||
$this->app->loadClass('feishuapi', true);
|
||||
$feishuApi = new feishuapi($webhook->secret->appId, $webhook->secret->appSecret);
|
||||
$response = $feishuApi->getDeptTree();
|
||||
}
|
||||
|
||||
if($response['result'] == 'fail')
|
||||
{
|
||||
echo js::error($response['message']);
|
||||
|
||||
@@ -24,6 +24,32 @@ class webhookModel extends model
|
||||
return $webhook;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a webhook by type.
|
||||
*
|
||||
* @param int $type
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function getByType($type)
|
||||
{
|
||||
$webhook = $this->dao->select('*')->from(TABLE_WEBHOOK)->where('type')->eq($type)->fetch();
|
||||
return $webhook;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a webhook by type.
|
||||
*
|
||||
* @param int $type
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function getBindAccount($webhookID, $webhookType, $openID)
|
||||
{
|
||||
$account = $this->dao->select('account')->from(TABLE_OAUTH)->where('providerID')->eq($webhookID)->andWhere('providerType')->eq($webhookType)->andWhere('openID')->eq($openID)->fetch('account');
|
||||
return $account;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get webhook list.
|
||||
*
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
<td class='text' title='<?php echo $webhook->url;?>'><?php echo $webhook->url;?></td>
|
||||
<td class='c-actions text-right'>
|
||||
<?php
|
||||
if($webhook->type == 'dinguser') common::printIcon('webhook', 'chooseDept', "webhookID=$id", '', 'list', 'link');
|
||||
if($webhook->type == 'wechatuser' or $webhook->type == 'feishuuser') common::printIcon('webhook', 'bind', "webhookID=$id", '', 'list', 'link');
|
||||
if($webhook->type == 'dinguser' or $webhook->type == 'feishuuser') common::printIcon('webhook', 'chooseDept', "webhookID=$id", '', 'list', 'link');
|
||||
if($webhook->type == 'wechatuser') common::printIcon('webhook', 'bind', "webhookID=$id", '', 'list', 'link');
|
||||
common::printIcon('webhook', 'log', "webhookID=$id", '', 'list', 'file-text');
|
||||
common::printIcon('webhook', 'edit', "webhookID=$id", '', 'list');
|
||||
if(common::hasPriv('webhook', 'delete'))
|
||||
|
||||
@@ -28,9 +28,13 @@
|
||||
<script>
|
||||
$(function()
|
||||
{
|
||||
var ztreeSettings =
|
||||
var ztreeSettings =
|
||||
{
|
||||
check:
|
||||
view:
|
||||
{
|
||||
showIcon: false
|
||||
},
|
||||
check:
|
||||
{
|
||||
enable: true,
|
||||
chkStyle: "checkbox",
|
||||
|
||||
Reference in New Issue
Block a user