This commit is contained in:
sunguangming
2023-04-28 08:50:07 +08:00
47 changed files with 856 additions and 421 deletions
Vendored
+1 -1
View File
@@ -37,7 +37,7 @@ pipeline {
container('sonar') {
withSonarQubeEnv('sonarqube') {
sh 'git config --global --add safe.directory $(pwd)'
sh 'sonar-scanner -Dsonar.inclusions=$(git diff --name-only HEAD~1|tr "\\n" ",") -Dsonar.analysis.user=$(git show -s --format=%an)'
sh 'sonar-scanner -Dsonar.analysis.user=$(git show -s --format=%an)'
}
}
}
+1
View File
@@ -1,4 +1,5 @@
ALTER TABLE `zt_block` ADD `dashboard` varchar(20) NOT NULL DEFAULT '' AFTER `account`;
UPDATE `zt_block` SET `dashboard` = `module`;
UPDATE `zt_block` SET `module` = IF(`source` != '', `source`, `block`);
ALTER TABLE `zt_todo` CHANGE `idvalue` `objectID` mediumint(8) unsigned default '0' NOT NULL AFTER `type`;
+9 -1
View File
@@ -283,8 +283,16 @@ $config->block->modules['doc']->moreLinkList->projectdoc = 'doc|projectspac
$config->block->form = new stdclass();
$config->block->form->create = array();
$config->block->form->create['module'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->block->form->create['title'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->block->form->create['block'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->block->form->create['title'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->block->form->create['grid'] = array('type' => 'int', 'required' => false, 'default' => '4');
$config->block->form->create['hidden'] = array('type' => 'int', 'required' => false, 'default' => '0');
$config->block->form->create['params'] = array('type' => 'array', 'required' => false, 'default' => array());
$config->block->form = new stdclass();
$config->block->form->create = array();
$config->block->form->create['module'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->block->form->create['block'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->block->form->create['title'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->block->form->create['grid'] = array('type' => 'int', 'required' => false, 'default' => '4');
$config->block->form->create['params'] = array('type' => 'array', 'required' => false, 'default' => array());
+21 -7
View File
@@ -26,7 +26,7 @@ class block extends control
}
/**
* Create a block.
* Create a block under a dashboard.
*
* @param string $dashboard
* @param string $module
@@ -50,9 +50,9 @@ class block extends control
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => true, 'closeModal' => true, 'callback' => 'loadCurrentPage()'));
}
$this->view->title = $this->lang->block->createBlock;
$this->view->dashboard = $dashboard;
$this->view->module = $module;
$this->view->block = $block;
$this->view->modules = $this->blockZen->getAvailableModules($dashboard);
$this->view->blocks = $this->blockZen->getAvailableBlocks($dashboard, $module);
@@ -64,20 +64,34 @@ class block extends control
* Update a block.
*
* @param string $dashboard
* @param int $blockID
* @param string $module
* @param string $block
* @access public
* @return void
*/
public function edit(string $dashboard, int $blockID)
public function edit(string $blockID, string $module = '', string $block = '')
{
$blockID = (int)$blockID;
if($_POST)
{
$formData = form::use($this->config->example->edit)->get();
$formData = form::data($this->config->block->form->edit)->get();
$formData->id = $blockID;
$formData->params = helper::jsonEncode($formData->params);
$this->block->update($formData);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => 'reload'));
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => true, 'closeModal' => true, 'callback' => 'loadCurrentPage()'));
}
$this->blockZen->buildCreateForm($dashboard);
$blockData = $this->block->getByID($blockID);
$this->view->title = $this->lang->block->editBlock;
$this->view->blockData = $blockData;
$this->view->block = $block ? $block : $blockData->block;
$this->view->module = $module ? $module : $blockData->module;
$this->view->modules = $this->blockZen->getAvailableModules($blockData->dashboard);
$this->view->blocks = $this->blockZen->getAvailableBlocks($blockData->dashboard, $this->view->module);
$this->view->params = $this->blockZen->getAvailableParams($blockData->dashboard, $this->view->module, $this->view->block);
$this->display();
}
+8
View File
@@ -0,0 +1,8 @@
function getForm(event)
{
const field = $(event.target).attr('id');
const module = $('#module').val();
const block = field == 'module' ? '' : $('#block').val();
const url = $.createLink('block', 'edit', 'blockID=' + blockID + '&module=' + module + '&block=' + (block ? block : ''));
loadPage(url, '#blockRow, #paramsRow');
}
+3 -3
View File
@@ -187,10 +187,10 @@ class blockModel extends model
* @access public
* @return string
*/
public function getParams(string $type, string $module): string
public function getParams(string $block, string $module): string
{
$type = $type == 'todo' ? $module : $type;
$params = zget($this->config->block->params, $type, '');
$block = $block == 'todo' ? $module : $block;
$params = zget($this->config->block->params, $block, '');
return json_encode($params);
}
+1 -1
View File
@@ -22,7 +22,7 @@ function initData()
/**
title=14:11:23 ERROR: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry &
title=测试 block 模块 model下的 create 方法
timeout=0
cid=39
@@ -18,4 +18,4 @@ global $config;
$block = new blockTest();
$data = $block->getClosedBlockPairsTest('');
r($data) && p('massage') && e('未获取到关闭的区域'); //测试获取关闭的区块键值对
r($data) && p('massage') && e('未获取到关闭的区域'); //测试获取关闭的区块键值对
@@ -0,0 +1,36 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . "/test/lib/init.php";
include dirname(__FILE__, 2) . '/block.class.php';
su('admin');
function initData()
{
$block = zdTable('block');
$block->id->range('2-3');
$block->account->range('admin');
$block->vision->range('rnd');
$block->module->range('test,my');
$block->title->prefix('区块')->range('3,2');
$block->hidden->range('0-1');
$block->order->range('3-2');
$block->dashboard->range('test,my');
$block->gen(2);
}
/**
title=测试 block 模块 model下的 getMyDashboard 方法
timeout=0
cid=39
*/
global $tester;
$tester->loadModel('block');
initData();
r($tester->block->getMyDashboard('test')) && p('2:account,title') && e('admin,区块3');
r($tester->block->getMyDashboard('my', 1)) && p('3:account,title') && e('admin,区块2');
+2 -2
View File
@@ -67,7 +67,7 @@ form
set::id('paramsRow'),
set::class('form-grid'),
$paramsRows,
$block
(($module and $block) or ($module and !$blocks))
? formGroup
(
set::label($lang->block->name),
@@ -75,7 +75,7 @@ form
set::class('form-row'),
set::control('input')
) : null,
$block
(($module and $block) or ($module and !$blocks))
? formGroup
(
set::label($lang->block->grid),
+2 -2
View File
@@ -29,7 +29,7 @@ foreach($longBlocks as $index => $block)
set::items
([
['text' => $lang->block->refresh, 'url' => ''],
['text' => $lang->edit, 'url' => $this->createLink("block", "edit", "dashboard=$dashboard&blockID=$block->id"), 'data-toggle' => 'modal'],
['text' => $lang->edit, 'url' => $this->createLink("block", "edit", "blockID=$block->id"), 'data-toggle' => 'modal'],
['text' => $lang->block->hidden, 'url' => ''],
['text' => $lang->block->createBlock, 'url' => $this->createLink("block", "create", "dashboard=$dashboard"), 'data-toggle' => 'modal'],
['text' => $lang->block->reset, 'url' => ''],
@@ -77,7 +77,7 @@ foreach($shortBlocks as $index => $block)
set::items
([
['text' => $lang->block->refresh, 'url' => ''],
['text' => $lang->edit, 'url' => $this->createLink("block", "edit", "dashboard=$dashboard&blockID=$block->id"), 'data-toggle' => 'modal'],
['text' => $lang->edit, 'url' => $this->createLink("block", "edit", "blockID=$block->id"), 'data-toggle' => 'modal'],
['text' => $lang->block->hidden, 'url' => ''],
['text' => $lang->block->createBlock, 'url' => $this->createLink("block", "create", "dashboard=$dashboard"), 'data-toggle' => 'modal'],
['text' => $lang->block->reset, 'url' => ''],
+97
View File
@@ -0,0 +1,97 @@
<?php
declare(strict_types=1);
/**
* The ui file of block module of ZenTaoPMS.
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author liuruogu<liuruogu@easycorp.ltd>
* @package block
* @link http://www.zentao.net
*/
namespace zin;
set::title($title);
jsVar('blockID', $blockData->id);
$paramsRows = array();
foreach($params as $code => $row)
{
$paramsRows[] = formGroup
(
set::label($row['name']),
set::name('params'),
set::class('form-row'),
set::value($blockData->params->{$code}),
set::control(array
(
'type' => $row['control'],
'items' => isset($row['options']) ? $row['options'] : null
))
);
}
form
(
on::change('#module', 'getForm'),
on::change('#block', 'getForm'),
formGroup
(
set::label($lang->block->lblModule),
set::name('module'),
set::value($blockData->module),
set::control(array
(
'type' => 'select',
'items' => $modules
))
),
div
(
set::id('blockRow'),
set::class('form-row'),
$blocks
? formGroup
(
set::label($lang->block->lblBlock),
set::name('block'),
set::value($block),
set::control(array
(
'type' => 'select',
'items' => array('') + $blocks
))
) : null
),
div
(
set::id('paramsRow'),
set::class('form-grid'),
$paramsRows,
(($module and $block) or ($module and !$blocks))
? formGroup
(
set::label($lang->block->name),
set::name('title'),
set::class('form-row'),
set::value($blockData->title),
set::control('input')
) : null,
(($module and $block) or ($module and !$blocks))
? formGroup
(
set::label($lang->block->grid),
set::name("grid"),
set::class('form-row'),
set::value($blockData->grid),
set::control(array
(
'type' => 'select',
'items' => $lang->block->gridOptions
))
) : null,
)
);
render('modalDialog');
+13 -3
View File
@@ -3,7 +3,7 @@ class blockZen extends block
{
/**
* Get module options when adding or editing blocks.
* 添加或编辑区块时获取模块选项
* 添加或编辑区块时获取可使用的模块选项
*
* @param string $dashboard
* @access protected
@@ -52,7 +52,7 @@ class blockZen extends block
/**
* Get block options when adding or editing blocks.
* 添加或编辑区块时获取区块选项
* 添加或编辑区块时获取可使用的区块选项
*
* @param string $dashboard
* @param string $module
@@ -61,6 +61,16 @@ class blockZen extends block
*/
protected function getAvailableBlocks($dashboard, $module): array|bool
{
if(!$this->selfCall)
{
$lang = str_replace('_', '-', $this->get->lang);
$this->app->setClientLang($lang);
$this->app->loadLang('common');
$this->app->loadLang('block');
if(!$this->block->checkAPI($this->get->hash)) return array();
}
$blocks = $this->block->getAvailableBlocks($dashboard, $module);
if(!$this->selfCall)
@@ -80,7 +90,7 @@ class blockZen extends block
* @param string $module
* @param string $block
* @access protected
* @return array[]
* @return array
*/
protected function getAvailableParams(string $dashboard, string $module = '', string $block = ''): array
{
+8 -22
View File
@@ -1,5 +1,4 @@
<?php
declare(strict_types=1);
/**
* The control file of product module of ZenTaoPMS.
*
@@ -17,10 +16,12 @@ class product extends control
/**
* Construct function.
*
* @param moduleName
* @param methodName
* @access public
* @return void
*/
public function __construct($moduleName = '', $methodName = '')
public function __construct(string $moduleName = '', string $methodName = ''): void
{
parent::__construct($moduleName, $methodName);
@@ -394,8 +395,8 @@ class product extends control
}
/**
* 创建产品。可以是顶级产品,也可以是项目集下的产品。
* Create a product.
* 创建产品。可以是顶级产品,也可以是项目集下的产品。
*
* @param int $programID
* @param string $extra
@@ -410,26 +411,11 @@ class product extends control
{
$data = form::data($this->config->product->form->create);
$data = $this->productZen->prepareCreateExtras($data);
if(!$data) return $this->productZen->errorBeforeEdit();
if(!$data) return $this->productZen->sendError4Create();
$result = $this->product->create($data);
if(!$result) return $this->productZen->errorAfterEdit();
return $this->productZen->responseAfterEdit($result);
$productID = $this->product->create();
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
$this->loadModel('action')->create('product', $productID, 'opened');
$message = $this->executeHooks($productID);
if($message) $this->lang->saveSuccess = $message;
if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $productID));
$tab = $this->app->tab;
$moduleName = $tab == 'program'? 'program' : $this->moduleName;
$methodName = $tab == 'program'? 'product' : 'browse';
$param = $tab == 'program' ? "programID=$programID" : "productID=$productID";
$locate = isonlybody() ? 'parent' : $this->createLink($moduleName, $methodName, $param);
if($tab == 'doc') $locate = $this->createLink('doc', 'productSpace', "objectID=$productID");
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $locate));
$productID = $this->product->create($data);
if(!$productID) return $this->productZen->sendError4Create();
return $this->productZen->responseAfterCreate($productID, $data);
}
$this->productZen->setMenu4Create($programID);
+75 -90
View File
@@ -319,13 +319,13 @@ class productModel extends model
/**
* Get product pairs.
*
* @param string $mode
* @param string $mode nocode
* @param string $programID
* @param string|array $append
* @param string|int $shadow all | 0 | 1
* @return array
*/
public function getPairs($mode = '', $programID = 0, $append = '', $shadow = 0)
public function getPairs(string $mode = '', int $programID = 0, string|array $append = '', string|int $shadow = 0): array
{
if(defined('TUTORIAL')) return $this->loadModel('tutorial')->getProductPairs();
@@ -678,103 +678,22 @@ class productModel extends model
/**
* Create a product.
* 直接用对象数据创建产品
*
* @param object $product
* @access public
* @return int
* @return int|false
*/
public function create()
public function create(object $product): int|false
{
$product = fixer::input('post')
->callFunc('name', 'trim')
->setDefault('status', 'normal')
->setDefault('line', 0)
->setDefault('createdBy', $this->app->user->account)
->setDefault('createdDate', helper::now())
->setDefault('createdVersion', $this->config->version)
->setIF($this->post->acl == 'open', 'whitelist', '')
->setIF(!isset($_POST['whitelist']), 'whitelist', '')
->stripTags($this->config->product->editor->create['id'], $this->config->allowedTags)
->join('whitelist', ',')
->join('reviewer', ',')
->remove('uid,newLine,lineName,contactListMenu')
->get();
$this->lang->error->unique = $this->lang->error->repeat;
$product = $this->loadModel('file')->processImgURL($product, $this->config->product->editor->create['id'], $this->post->uid);
/* Lean mode relation defaultProgram. */
$programID = isset($product->program) ? $product->program : 0;
if($this->config->systemMode == 'light')
{
$programID = $this->config->global->defaultProgram;
$product->program = $this->config->global->defaultProgram;
}
$this->dao->insert(TABLE_PRODUCT)->data($product)->autoCheck()
->batchCheck($this->config->product->create->requiredFields, 'notempty')
->checkIF(!empty($product->name), 'name', 'unique', "`program` = $programID and `deleted` = '0'")
->checkIF(!empty($product->name), 'name', 'unique', "`program` = {$product->program} and `deleted` = '0'")
->checkIF(!empty($product->code), 'code', 'unique', "`deleted` = '0'")
->checkFlow()
->exec();
if(!dao::isError())
{
$productID = $this->dao->lastInsertID();
if(!empty($_POST['lineName']))
{
/* Create product line. */
$maxOrder = $this->dao->select("max(`order`) as maxOrder")->from(TABLE_MODULE)->where('type')->eq('line')->fetch('maxOrder');
$maxOrder = $maxOrder ? $maxOrder + 10 : 0;
$line = new stdClass();
$line->type = 'line';
$line->parent = 0;
$line->grade = 1;
$line->name = $this->post->lineName;
$line->root = $this->config->systemMode == 'ALM' ? $product->program : 0;
$line->order = $maxOrder;
$lines = $this->dao->select('name')->from(TABLE_MODULE)->where('type')->eq('line')->andWhere('root')->eq($line->root)->andWhere('name')->eq($line->name)->fetch();
if(!empty($lines))
{
dao::$errors['lineName'] = sprintf($this->lang->product->nameIsDuplicated, $line->name);
return false;
}
$this->dao->insert(TABLE_MODULE)->data($line)->exec();
if(!dao::isError())
{
$lineID = $this->dao->lastInsertID();
$path = ",$lineID,";
$this->dao->update(TABLE_MODULE)->set('path')->eq($path)->where('id')->eq($lineID)->exec();
$this->dao->update(TABLE_PRODUCT)->set('line')->eq($lineID)->where('id')->eq($productID)->exec();
}
}
$this->file->updateObjectID($this->post->uid, $productID, 'product');
$this->dao->update(TABLE_PRODUCT)->set('`order`')->eq($productID * 5)->where('id')->eq($productID)->exec();
$whitelist = explode(',', $product->whitelist);
$this->loadModel('personnel')->updateWhitelist($whitelist, 'product', $productID);
if($product->acl != 'open') $this->loadModel('user')->updateUserView($productID, 'product');
/* Create doc lib. */
$this->app->loadLang('doc');
$lib = new stdclass();
$lib->product = $productID;
$lib->name = $this->lang->doclib->main['product'];
$lib->type = 'product';
$lib->main = '1';
$lib->acl = 'default';
$lib->addedBy = $this->app->user->account;
$lib->addedDate = helper::now();
$this->dao->insert(TABLE_DOCLIB)->data($lib)->exec();
return $productID;
}
if(dao::isError()) return false;
return $this->dao->lastInsertID();
}
/**
@@ -1025,6 +944,72 @@ class productModel extends model
}
}
/**
* Create product line.
* 创建产品线。
*
* @param int programID
* @access public
* @return int|false
*/
public function createLine(int $programID): int|false
{
if($programID <= 0) return false;
if(empty($_POST['lineName'])) return false;
$line = new stdClass();
$line->type = 'line';
$line->parent = 0;
$line->grade = 1;
$line->name = htmlSpecialString($this->post->lineName);
$line->root = $programID;
$existedLineID = $this->dao->select('id')->from(TABLE_MODULE)->where('type')->eq('line')->andWhere('root')->eq($line->root)->andWhere('name')->eq($line->name)->fetch('id');
if($existedLineID) return $existedLineID;
$this->dao->insert(TABLE_MODULE)->data($line)->exec();
if(dao::isError()) return false;
$lineID = $this->dao->lastInsertID();
$path = ",$lineID,";
$this->dao->update(TABLE_MODULE)->set('path')->eq($path)->set('`order`')->eq($lineID)->where('id')->eq($lineID)->exec();
return $lineID;
}
/**
* Create main lib for product
* 关联创建产品主库
*
* @param int productID
* @access public
* @return int|false
*/
public function createMainLib(int $productID): int|false
{
if($productID <= 0) return false;
$existedLibID = $this->dao->select('id')->from(TABLE_DOCLIB)->where('product')->eq($productID)
->andWhere('type')->eq('product')
->andWhere('main')->eq('1')
->fetch('id');
if($existedLibID) return $existedLibID;
$this->app->loadLang('doc');
$lib = new stdclass();
$lib->product = $productID;
$lib->name = $this->lang->doclib->main['product'];
$lib->type = 'product';
$lib->main = '1';
$lib->acl = 'default';
$lib->addedBy = $this->app->user->account;
$lib->addedDate = helper::now();
$this->dao->insert(TABLE_DOCLIB)->data($lib)->exec();
if(dao::isError())return false;
return $this->dao->lastInsertID();
}
/**
* Get stories.
*
-1
View File
@@ -235,5 +235,4 @@ class productTao extends productModel
return $closedBugs;
}
}
@@ -47,7 +47,3 @@ $stories2 = array($story4, $story5, $story6);
$stories3 = array($story7, $story8, $story9);
$product = new productTest('admin');
r($product->batchGetStoryStageTest($stories1)) && p('1;2;3') && e('wait;planned;projected'); // 测试获取需求1 2 3的阶段
r($product->batchGetStoryStageTest($stories2)) && p('4;5;6') && e('developing;developed;testing'); // 测试获取需求4 5 6的阶段
r($product->batchGetStoryStageTest($stories3)) && p('7;8;9') && e('tested;verified;released'); // 测试获取需求7 8 9的阶段
+11 -16
View File
@@ -4,6 +4,7 @@ include dirname(__FILE__, 5) . "/test/lib/init.php";
include dirname(__FILE__, 2) . '/product.class.php';
#su('admin');
zdTable('product')->gen(0);
/**
@@ -24,20 +25,14 @@ pid=1
$product = new productTest('admin');
$t_create = array('name' => 'case1', 'code' => 'testcase1');
$t_noid = array('name' => 'case2');
$t_repeat = array('name' => 'case1', 'code' => 'testcase1');
$t_noname = array('code' => 'testcase1');
$t_namecode = array('name' => 'case3', 'code' => 'testcase3');
$t_pronamecode = array('program' => '3', 'name' => 'case4', 'code' => 'testcase4');
$t_intypestatus = array('program' => '4', 'name' => 'case5', 'code' => 'testcase5', 'type' => 'branch', 'status' => 'closed');
$t_noacl = array('name' => 'case12', 'code' => 'testcase1', 'acl' => '');
$create = array('name' => 'case1', 'code' => 'testcase1');
$repeat = array('name' => 'case1', 'code' => 'testcase1');
$namecode = array('name' => 'case3', 'code' => 'testcase3');
$pronamecode = array('program' => '3', 'name' => 'case4', 'code' => 'testcase4');
$intypestatus = array('program' => '4', 'name' => 'case5', 'code' => 'testcase5', 'type' => 'branch', 'status' => 'closed');
r($product->createObject($t_create)) && p('name') && e('case1'); // 测试正常的创建
r($product->createObject($t_noid)) && p('code:0') && e('『产品代号』不能为空。'); // 测试不填产品代号的情况
r($product->createObject($t_repeat)) && p('code:0') && e('『产品代号』已经有『testcase1』这条记录了。'); // 测试创建重复的产品
r($product->createObject($t_noname)) && p('name:0') && e('『产品名称』不能为空。'); // 测试不填产品名称的情况
r($product->createObject($t_namecode)) && p('name,code') && e('case3,testcase3'); // 测试传入name和code
r($product->createObject($t_pronamecode)) && p('program,name,code') && e('3,case4,testcase4'); // 测试传入program、name、code
r($product->createObject($t_intypestatus)) && p('program,type,status') && e('4,branch,closed'); // 测试传入program、name、code、type、status
r($product->createObject($t_noacl)) && p('acl:0') && e('『访问控制』不符合格式,应当为:『/open|private|custom/』。'); // 测试不填权限控制的情况
r($product->createObject($create)) && p('name') && e('case1'); // 测试正常的创建
r($product->createObject($repeat)) && p('code:0') && e('『产品代号』已经有『testcase1』这条记录了。'); // 测试创建重复的产品
r($product->createObject($namecode)) && p('name,code') && e('case3,testcase3'); // 测试传入name和code
r($product->createObject($pronamecode)) && p('program,name,code') && e('3,case4,testcase4'); // 测试传入program、name、code
r($product->createObject($intypestatus)) && p('program,type,status') && e('4,branch,closed'); // 测试传入program、name、code、type、status
+21
View File
@@ -0,0 +1,21 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . "/test/lib/init.php";
include dirname(__FILE__, 2) . '/product.class.php';
zdTable('module')->gen(0);
/**
title=productModel->createLine();
cid=1
pid=1
*/
$product = new productTest('admin');
r($product->createLineTest('1', 'test line1')) && p('root,name') && e('1,test line1');
r($product->createLineTest('0', 'test line1')) && p() && e('0');
r($product->createLineTest('1', '')) && p() && e('0');
r($product->createLineTest('1', "<script>alert('test')</script>")) && p('root,name') && e('1,&lt;script&gt;alert(&#039;test&#039;)&lt;/script&gt;');
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . "/test/lib/init.php";
include dirname(__FILE__, 2) . '/product.class.php';
zdTable('doclib')->gen(0);
/**
title=productModel->createmainlib();
cid=1
pid=1
*/
$product = new productTest('admin');
r($product->createMainLibTest('-1')) && p() && e('0');
r($product->createMainLibTest('0')) && p() && e('0');
r($product->createMainLibTest('1')) && p('product,name,type,main') && e('1,产品主库,product,1');
+69 -10
View File
@@ -22,19 +22,28 @@ class productTest
*
* @param array $param
* @access public
* @return object
* @return object|array
*/
public function createObject($param = array()): object
public function createObject(array $param = array()): object|array
{
global $createFields;
$whitelist = array();
$createFields = array('program' => 1, 'line' => 0, 'lineName' => '', 'newLine' => 0, 'name' => '', 'code' => '', 'PO' => 'admin', 'QD' => '', 'RD' => '',
'reviewer' => '', 'type' => 'normal', 'status' => 'normal', 'desc' => '', 'acl' => 'open', 'uid' => '');
foreach($createFields as $field => $defaultValue) $_POST[$field] = $defaultValue;
foreach($param as $key => $value) $_POST[$key] = $value;
$createFields = array();
$createFields['program'] = 1;
$createFields['line'] = 0;
$createFields['name'] = '';
$createFields['code'] = '';
$createFields['PO'] = 'admin';
$createFields['QD'] = '';
$createFields['RD'] = '';
$createFields['reviewer'] = '';
$createFields['type'] = 'normal';
$createFields['status'] = 'normal';
$createFields['desc'] = '';
$createFields['acl'] = 'open';
$objectID = $this->objectModel->create();
unset($_POST);
$data = new stdclass();
foreach($createFields as $field => $defaultValue) $data->$field = zget($param, $field, $defaultValue);
$objectID = $this->objectModel->create($data);
if(dao::isError())
{
@@ -1113,4 +1122,54 @@ class productTest
return $object;
}
}
/**
* 测试创建产品线
* Test for create line.
*
* @param int programID
* @param string lineName
* @access public
* @return object|array
*/
public function createLineTest(int $programID, string $lineName): object|array
{
$_POST['lineName'] = $lineName;
$lineID = $this->objectModel->createLine($programID);
if(dao::isError())
{
return dao::getError();
}
else
{
if(!$lineID) return array();
$object = $this->objectModel->dao->select('*')->from(TABLE_MODULE)->where('id')->eq($lineID)->fetch();
return $object;
}
}
/**
* 测试创建产品主库
* Test for create main lib.
*
* @param int productID
* @access public
* @return object|array
*/
public function createMainLibTest(int $productID): object|array
{
$libID = $this->objectModel->createMainLib($productID);
if(dao::isError())
{
return dao::getError();
}
else
{
if(!$libID) return array();
$object = $this->objectModel->dao->select('*')->from(TABLE_DOCLIB)->where('id')->eq($libID)->fetch();
return $object;
}
}
}
+193
View File
@@ -32,6 +32,84 @@ class productZen extends product
}
}
/**
* Set menu for create product page.
* 为创建产品设置导航数据,主要是替换占位符。
*
* @param int $programID
* @access protected
* @return void
*/
protected function setMenu4Create(int $program): void
{
if($this->app->tab == 'program') $this->loadModel('program')->setMenu($programID);
if($this->app->tab == 'doc') unset($this->lang->doc->menu->product['subMenu']);
if($this->app->getViewType() != 'mhtml') return;
if($this->app->rawModule == 'projectstory' and $this->app->rawMethod == 'story')
{
$this->loadModel('project')->setMenu();
return;
}
$this->product->setMenu();
}
/**
* Get goback link for create by extra.
* 通过extra获取返回链接。
*
* @param string $extra
* @access private
* @return string
*/
private function getBackLink4Create(string $extra): string
{
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
parse_str($extra, $output);
$backLink = '';
$from = zget($output, 'from', '');
if($from == 'qa') $backLink = $this->createLink('qa', 'index');
if($from == 'global') $backLink = $this->createLink('product', 'all');
return $backLink;
}
/**
* Get form fields for create.
* 获取创建产品页面的表单配置。
*
* @param int $programID
* @access private
* @return array
*/
private function getFormFields4Create(int $programID = 0): array
{
$fields = $this->config->product->form->create;
$this->loadModel('user');
$poUsers = $this->user->getPairs('nodeleted|pofirst|noclosed');
$qdUsers = $this->user->getPairs('nodeleted|qdfirst|noclosed');
$rdUsers = $this->user->getPairs('nodeleted|devfirst|noclosed');
$users = $this->user->getPairs('nodeleted|noclosed');
foreach($fields as $field => $attr)
{
if(isset($attr['options']) and $attr['options'] == 'users') $fields[$field]['options'] = $users;
$fields[$field]['name'] = $field;
$fields[$field]['title'] = $this->lang->product->$field;
}
$fields['program']['options'] = array('') + $this->loadModel('program')->getTopPairs('', 'noclosed');
$fields['PO']['options'] = $poUsers;
$fields['QD']['options'] = $qdUsers;
$fields['RD']['options'] = $rdUsers;
if($programID) $fields['line']['options'] = array('') + $this->product->getLinePairs($programID);
if(empty($programID) or $this->config->systemMode != 'ALM') unset($fields['line']);
return $fields;
}
/**
* Get product lines and product lines of program.
*
@@ -54,4 +132,119 @@ class productZen extends product
return array($productLines, $programLines);
}
/**
* Build form fields for create.
* 构建创建产品页面数据。
*
* @param int $programID
* @param string $extra
* @access protected
* @return void
*/
protected function buildCreateForm(int $programID = 0, string $extra = ''): void
{
$this->view->title = $this->lang->product->create;
$this->view->gobackLink = $this->getBackLink4Create($extra);
$this->view->programID = $programID;
$this->view->fields = $this->getFormFields4Create($programID);
unset($this->lang->product->typeList['']);
$this->display();
}
/**
* Prepare data for create.
* 追加创建信息,处理白名单、评审者、项目集字段,还有富文本内容处理。
*
* @param int $programID
* @param string $extra
* @access protected
* @return object
*/
protected function prepareCreateExtras(object $data): object
{
$product = $data->setDefault('createdBy', $this->app->user->account)
->setDefault('createdDate', helper::now())
->setDefault('createdVersion', $this->config->version)
->setIF($this->config->systemMode == 'light', 'program', (int)zget($this->config->global, 'defaultProgram', 0))
->setIF($this->post->acl == 'open', 'whitelist', '')
->stripTags($this->config->product->editor->create['id'], $this->config->allowedTags)
->join('whitelist', ',')
->join('reviewer', ',')
->remove('uid,newLine,lineName,contactListMenu')
->get();
$product = $this->loadModel('file')->processImgURL($product, $this->config->product->editor->create['id'], $this->post->uid);
return $product;
}
/**
* Process after create product.
* 成功插入产品数据后,其他的额外操作。
*
* @param int $productID
* @param object $product
* @access protected
* @return void
*/
protected function responseAfterCreate(int $productID, object $product): void
{
$fixData = new stdclass();
$fixData->order = $productID * 5;
if(!empty($_POST['lineName']))
{
$lineID = $this->product->createLine((int)$product->program);
if($lineID) $fixData->line = $lineID;
}
$this->dao->update(TABLE_PRODUCT)->data($fixData)->where('id')->eq($productID)->exec();
$this->file->updateObjectID($this->post->uid, $productID, 'product');
$this->loadModel('personnel')->updateWhitelist(explode(',', $product->whitelist), 'product', $productID);
if($product->acl != 'open') $this->loadModel('user')->updateUserView($productID, 'product');
$this->product->createMainLib($productID);
$this->loadModel('action')->create('product', $productID, 'opened');
$message = $this->executeHooks($productID);
if($message) $this->lang->saveSuccess = $message;
if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $productID));
$this->sendCreateLocate($productID, (int)$product->program);
}
/**
* Locate after create product.
* 创建完成后,做页面跳转。
*
* @param int $productID
* @param int $programID
* @access private
* @return void
*/
private function sendCreateLocate(int $productID, int $programID): void
{
$tab = $this->app->tab;
$moduleName = $tab == 'program'? 'program' : $this->moduleName;
$methodName = $tab == 'program'? 'product' : 'browse';
$param = $tab == 'program' ? "programID=$programID" : "productID=$productID";
$locate = isonlybody() ? 'true' : $this->createLink($moduleName, $methodName, $param);
if($tab == 'doc') $locate = $this->createLink('doc', 'productSpace', "objectID=$productID");
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => $locate));
}
/**
* Send error for create.
* 输出创建产品产生的错误。
*
* @access protected
* @return void
*/
protected function sendError4Create(): void
{
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
}
}
+23 -11
View File
@@ -193,13 +193,14 @@ class project extends control
/**
* Ajax get unlink tips when unlink team member.
*
* @param int $projectID
* @param int $account
* @param string $projectID
* @param string $account
* @access public
* @return void
*/
public function ajaxGetUnlinkTips($projectID, $account)
public function ajaxGetUnlinkTips(string $projectID, string $account)
{
$projectID = (int)$projectID;
$project = $this->project->getByID($projectID);
if(!$project->multiple) return;
@@ -271,6 +272,7 @@ class project extends control
if(!empty($objectID))
{
$objectID = (int)$objectID;
$object = $objectType == 'project' ? $this->project->getByID($objectID) : $this->loadModel('program')->getByID($objectID);
if(isset($availableBudget)) $availableBudget = $object->parent == $selectedProgramID ? $availableBudget + (int)$object->budget : $availableBudget;
@@ -325,6 +327,7 @@ class project extends control
$this->project->setMenu($projectID);
$projectID = (int)$projectID;
$project = $this->project->getByID($projectID);
/* Locate to task when set no execution. */
@@ -549,6 +552,7 @@ class project extends control
$this->loadModel('program');
$this->loadModel('execution');
$projectID = (int)$projectID;
$project = $this->project->getByID($projectID);
$programID = $project->parent;
$this->project->setMenu($projectID);
@@ -889,6 +893,7 @@ class project extends control
*/
public function dynamic($projectID = 0, $type = 'today', $param = '', $recTotal = 0, $date = '', $direction = 'next')
{
$projectID = (int)$projectID;
$this->loadModel('execution');
$this->project->setMenu($projectID);
@@ -974,6 +979,7 @@ class project extends control
if($this->cookie->showTask) $this->session->set('taskList', $this->app->getURI(true), 'project');
$projectID = (int)$projectID;
$projects = $this->project->getPairsByProgram();
$projectID = $this->project->saveState($projectID, $projects);
$project = $this->project->getByID($projectID);
@@ -1057,11 +1063,12 @@ class project extends control
$this->session->set('bugList', $this->app->getURI(true), 'project');
$this->project->setMenu($projectID);
$product = $this->product->getById($productID);
$project = $this->project->getByID($projectID);
$type = strtolower($type);
$queryID = ($type == 'bysearch') ? (int)$param : 0;
$products = $this->product->getProducts($projectID);
$projectID = (int)$projectID;
$product = $this->product->getById($productID);
$project = $this->project->getByID($projectID);
$type = strtolower($type);
$queryID = ($type == 'bysearch') ? (int)$param : 0;
$products = $this->product->getProducts($projectID);
if(!$project->multiple) unset($this->config->bug->datatable->fieldList['execution']);
if(!$project->hasProduct)
@@ -1258,6 +1265,7 @@ class project extends control
$this->session->set('testtaskList', $this->app->getURI(true), 'qa');
$this->session->set('buildList', $this->app->getURI(true), 'execution');
$projectID = (int)$projectID;
$this->project->setMenu($projectID);
/* Load pager. */
@@ -1301,6 +1309,7 @@ class project extends control
/* Load module and get project. */
$this->loadModel('build');
$this->loadModel('product');
$projectID = (int)$projectID;
$project = $this->project->getByID($projectID);
$this->project->setMenu($projectID);
@@ -1459,7 +1468,7 @@ class project extends control
$this->view->version = $version;
/* Unset not project privs. */
$project = $this->project->getByID($group->project);
$project = $this->project->getByID((int)$group->project);
if($project->hasProduct)
{
if($this->config->URAndSR) unset($this->lang->resource->requirement);
@@ -1650,7 +1659,7 @@ class project extends control
}
$group = $this->group->getById($groupID);
$project = $this->project->getByID($group->project);
$project = $this->project->getByID((int)$group->project);
$groupUsers = $this->group->getUserPairs($groupID);
$allUsers = $this->loadModel('dept')->getDeptUserPairs($deptID);
$otherUsers = array_diff_assoc($allUsers, $groupUsers);
@@ -1806,6 +1815,7 @@ class project extends control
public function close($projectID)
{
$this->loadModel('action');
$projectID = (int)$projectID;
if(!empty($_POST))
{
@@ -1841,7 +1851,8 @@ class project extends control
{
$this->loadModel('action');
$this->app->loadLang('execution');
$project = $this->project->getByID($projectID);
$projectID = (int)$projectID;
$project = $this->project->getByID($projectID);
if(!empty($_POST))
{
@@ -1883,6 +1894,7 @@ class project extends control
*/
public function delete($projectID, $confirm = 'no', $from = 'browse')
{
$projectID = (int)$projectID;
if($confirm == 'no')
{
$project = $this->project->getByID($projectID);
+3 -2
View File
@@ -1,5 +1,6 @@
<?php
declare(strict_types=1);
helper::import(dirname(__FILE__) . 'config/form.php');
$config->todo = new stdclass();
$config->todo->batchCreate = 8;
@@ -21,7 +22,7 @@ $config->todo->editor->edit = array('id' => 'desc', 'tools' => 'simpleTools');
$config->todo->editor->view = array('id' => 'comment,lastComment', 'tools' => 'simpleTools');
$config->todo->list = new stdclass();
$config->todo->list->exportFields = 'id, account, date, begin, end, type, idvalue, pri, name, desc, status, private';
$config->todo->list->exportFields = 'id, account, date, begin, end, type, objectID, pri, name, desc, status, private';
$config->todo->list->customBatchCreateFields = 'type,pri,desc,beginAndEnd';
$config->todo->list->customBatchEditFields = 'pri,beginAndEnd,status';
@@ -41,4 +42,4 @@ $config->todo->objectList = array();
$config->todo->objectList['bug'] = 'bugs';
$config->todo->objectList['task'] = 'tasks';
$config->todo->objectList['story'] = 'stories';
$config->todo->objectList['testtask'] = 'testtasks';
$config->todo->objectList['testtask'] = 'testtasks';
+4
View File
@@ -21,3 +21,7 @@ $config->todo->create->form['uid'] = array('required' => false, 'type'
$config->todo->edit->form = array();
$config->todo->edit->form['name'] = array('required' => true, 'type' => 'string');
$config->todo->batchClose = new stdclass;
$config->todo->batchClose->form = array();
$config->todo->batchClose->form['todoIDList'] = array('required' => true, 'type' => 'array');
+32 -27
View File
@@ -1,13 +1,14 @@
<?php
declare(strict_types=1);
/**
* The control file of todo module of ZenTaoPMS.
* The control file of example module of ZenTaoPMS.
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author lanzongjun@easycorp.ltd;
* @author Lanzongjun <lanzongjun@easycorp.ltd>
* @package todo
* @link http://www.zentao.net
* @link https://www.zentao.net
*/
class todo extends control
{
@@ -20,6 +21,7 @@ class todo extends control
public function __construct()
{
parent::__construct();
$this->app->loadClass('date');
$this->loadModel('task');
$this->loadModel('bug');
@@ -33,7 +35,7 @@ class todo extends control
* @param string $date
* @param string $from todo|feedback|block
* @access public
* @return void
* @return int|void
*/
public function create(string $date = 'today', string $from = 'todo')
{
@@ -41,20 +43,21 @@ class todo extends control
if(!empty($_POST))
{
$formData = form::data($this->config->todo->create->form);
$todo = form::data($this->config->todo->create->form)
->remove(implode(',', $this->config->todo->moduleList) . ',uid')
->stripTags($this->config->todo->editor->create['id'], $this->config->allowedTags)
->get();
$todo = $this->todoZen->beforeCreate($formData);
$todoID = $this->todoZen->doCreate($todo);
$todoID = $this->todo->create($todo);
if($todoID === false) return print(js::error(dao::getError()));
$todo->id = $todoID;
$this->todoZen->afterCreate($todo);
if(!empty($_POST['idvalue'])) return $this->send(array('result' => 'success'));
if(!empty($_POST['objectID'])) return $this->send(array('result' => 'success'));
if($from == 'block')
{
// TODO
$todo = $this->todo->getById($todoID);
$todo->begin = date::formatTime($todo->begin);
return $this->send(array('result' => 'success', 'id' => $todoID, 'name' => $todo->name, 'pri' => $todo->pri, 'priName' => $this->lang->todo->priList[$todo->pri], 'time' => date(DT_DATE4, strtotime($todo->date)) . ' ' . $todo->begin));
@@ -214,7 +217,7 @@ class todo extends control
if($todo->type != 'custom')
{
if(!isset($objectIDList[$todo->type])) $objectIDList[$todo->type] = array();
$objectIDList[$todo->type][$todo->idvalue] = $todo->idvalue;
$objectIDList[$todo->type][$todo->objectID] = $todo->objectID;
}
}
}
@@ -486,13 +489,13 @@ class todo extends control
{
$confirmNote = 'confirm' . ucfirst($todo->type);
$okTarget = isonlybody() ? 'parent' : 'window.parent.$.apps.open';
$confirmURL = $this->createLink($todo->type, 'view', "id=$todo->idvalue");
$confirmURL = $this->createLink($todo->type, 'view', "id=$todo->objectID");
if($todo->type == 'bug') $app = 'qa';
if($todo->type == 'task') $app = 'execution';
if($todo->type == 'story') $app = 'product';
$cancelURL = $this->server->HTTP_REFERER;
if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success', 'message' => sprintf($this->lang->todo->$confirmNote, $todo->idvalue), 'locate' => $confirmURL));
return print(strpos($cancelURL, 'calendar') ? json_encode(array(sprintf($this->lang->todo->$confirmNote, $todo->idvalue), $confirmURL)) : js::confirm(sprintf($this->lang->todo->$confirmNote, $todo->idvalue), $confirmURL, $cancelURL, $okTarget, 'parent', $app));
if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success', 'message' => sprintf($this->lang->todo->$confirmNote, $todo->objectID), 'locate' => $confirmURL));
return print(strpos($cancelURL, 'calendar') ? json_encode(array(sprintf($this->lang->todo->$confirmNote, $todo->objectID), $confirmURL)) : js::confirm(sprintf($this->lang->todo->$confirmNote, $todo->objectID), $confirmURL, $cancelURL, $okTarget, 'parent', $app));
}
if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success'));
if(isonlybody()) return print(js::reload('parent.parent'));
@@ -519,17 +522,19 @@ class todo extends control
}
/**
* Batch close todos.
* Batch close todos. The status of todo which need to close should be done.
*
* @access public
* @return void
*/
public function batchClose()
public function batchClose(): void
{
$waitIdList = array();
foreach($_POST['todoIDList'] as $todoID)
$todoIdlist = form::data($this->config->todo->batchClose->form)->get('todoIDList');
foreach($todoIdlist as $todoID)
{
$todo = $this->todo->getById($todoID);
$todoID = (int) $todoID;
$todo = $this->todo->getById($todoID);
if($todo->status == 'done') $this->todo->close($todoID);
if($todo->status != 'done' and $todo->status != 'closed') $waitIdList[] = $todoID;
}
@@ -578,7 +583,7 @@ class todo extends control
$fields[$fieldName] = isset($todoLang->$fieldName) ? $todoLang->$fieldName : $fieldName;
unset($fields[$key]);
}
unset($fields['idvalue']);
unset($fields['objectID']);
unset($fields['private']);
/* Get bugs. */
@@ -609,18 +614,18 @@ class todo extends control
$type = $todo->type;
if(isset($users[$todo->account])) $todo->account = $users[$todo->account];
if($type == 'bug') $todo->name = isset($bugs[$todo->idvalue]) ? $bugs[$todo->idvalue] . "(#$todo->idvalue)" : '';
if($type == 'story') $todo->name = isset($stories[$todo->idvalue]) ? $stories[$todo->idvalue] . "(#$todo->idvalue)" : '';
if($type == 'task') $todo->name = isset($tasks[$todo->idvalue]) ? $tasks[$todo->idvalue] . "(#$todo->idvalue)" : '';
if($type == 'bug') $todo->name = isset($bugs[$todo->objectID]) ? $bugs[$todo->objectID] . "(#$todo->objectID)" : '';
if($type == 'story') $todo->name = isset($stories[$todo->objectID]) ? $stories[$todo->objectID] . "(#$todo->objectID)" : '';
if($type == 'task') $todo->name = isset($tasks[$todo->objectID]) ? $tasks[$todo->objectID] . "(#$todo->objectID)" : '';
if($this->config->edition == 'max')
{
if($type == 'issue') $todo->name = isset($issues[$todo->idvalue]) ? $issues[$todo->idvalue] . "(#$todo->idvalue)" : '';
if($type == 'risk') $todo->name = isset($risks[$todo->idvalue]) ? $risks[$todo->idvalue] . "(#$todo->idvalue)" : '';
if($type == 'opportunity') $todo->name = isset($opportunities[$todo->idvalue]) ? $opportunities[$todo->idvalue] . "(#$todo->idvalue)" : '';
if($type == 'issue') $todo->name = isset($issues[$todo->objectID]) ? $issues[$todo->objectID] . "(#$todo->objectID)" : '';
if($type == 'risk') $todo->name = isset($risks[$todo->objectID]) ? $risks[$todo->objectID] . "(#$todo->objectID)" : '';
if($type == 'opportunity') $todo->name = isset($opportunities[$todo->objectID]) ? $opportunities[$todo->objectID] . "(#$todo->objectID)" : '';
}
if($type == 'testtask') $todo->name = isset($testTasks[$todo->idvalue]) ? $testTasks[$todo->idvalue] . "(#$todo->idvalue)" : '';
if($type == 'review' && isset($this->config->qcVersion)) $todo->name = isset($reviews[$todo->idvalue]) ? $reviews[$todo->idvalue] . "(#$todo->idvalue)" : '';
if($type == 'testtask') $todo->name = isset($testTasks[$todo->objectID]) ? $testTasks[$todo->objectID] . "(#$todo->objectID)" : '';
if($type == 'review' && isset($this->config->qcVersion)) $todo->name = isset($reviews[$todo->objectID]) ? $reviews[$todo->objectID] . "(#$todo->objectID)" : '';
if(isset($todoLang->typeList[$type])) $todo->type = $todoLang->typeList[$type];
if(isset($todoLang->priList[$todo->pri])) $todo->pri = $todoLang->priList[$todo->pri];
@@ -628,7 +633,7 @@ class todo extends control
if($todo->private == 1) $todo->desc = $this->lang->todo->thisIsPrivate;
/* drop some field that is not needed. */
unset($todo->idvalue);
unset($todo->objectID);
unset($todo->private);
}
if($this->config->edition != 'open') list($fields, $todos) = $this->loadModel('workflowfield')->appendDataFromFlow($fields, $todos);
+5 -5
View File
@@ -14,11 +14,11 @@ function switchDateTodo(switcher)
* @param type $type Type of selected todo.
* @param id $id ID of selected todo.
* @param defaultType $defaultType Default type of selected todo.
* @param idvalue $idvalue ID of the closed todo type.
* @param objectID $objectID ID of the closed todo type.
* @access public
* @return void
*/
function loadList(type, id, defaultType, idvalue)
function loadList(type, id, defaultType, objectID)
{
if(id)
{
@@ -34,7 +34,7 @@ function loadList(type, id, defaultType, idvalue)
id = id ? id : '';
var param = 'userID=' + userID + '&id=' + id;
if(type == "task") param += '&status=wait,doing';
if(type == defaultType && idvalue != 0) param += '&idvalue=' + idvalue;
if(type == defaultType && objectID != 0) param += '&objectID=' + objectID;
if(moduleList.indexOf(type) !== -1)
{
@@ -45,7 +45,7 @@ function loadList(type, id, defaultType, idvalue)
if(data.length != 0)
{
$(divClass).html(data).find('select').chosen();
if(config.currentMethod == 'edit' || type == 'feedback') $(divClass).find('select').val(idvalue).trigger('chosen:updated');
if(config.currentMethod == 'edit' || type == 'feedback') $(divClass).find('select').val(objectID).trigger('chosen:updated');
if($(divClass + " select").val() == null) $(divClass + " select").attr("data-placeholder", noOptions.replace("%s", chosenType[type])).trigger('chosen:updated');
}
else
@@ -68,7 +68,7 @@ function loadList(type, id, defaultType, idvalue)
}
else
{
$('#nameBoxLabel').text(nameBoxLabel.idvalue);
$('#nameBoxLabel').text(nameBoxLabel.objectID);
}
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
$(function()
{
loadList($('#type').val(), '', defaultType, idvalue);
loadList($('#type').val(), '', defaultType, objectID);
$('#pri').on('change', function()
{
+1 -1
View File
@@ -51,7 +51,7 @@ $lang->todo->end = 'Ende';
$lang->todo->beginAB = 'Start';
$lang->todo->endAB = 'Ende';
$lang->todo->beginAndEnd = 'Dauer';
$lang->todo->idvalue = 'Link ID';
$lang->todo->objectID = 'Link ID';
$lang->todo->type = 'Typ';
$lang->todo->pri = 'Priorität';
$lang->todo->name = 'Titel';
+1 -1
View File
@@ -51,7 +51,7 @@ $lang->todo->end = 'End';
$lang->todo->beginAB = 'Begin';
$lang->todo->endAB = 'End';
$lang->todo->beginAndEnd = 'Begin and End';
$lang->todo->idvalue = 'Link ID';
$lang->todo->objectID = 'Link ID';
$lang->todo->type = 'Type';
$lang->todo->pri = 'Priority';
$lang->todo->name = 'Title';
+1 -1
View File
@@ -51,7 +51,7 @@ $lang->todo->end = 'Fin';
$lang->todo->beginAB = 'Début';
$lang->todo->endAB = 'Fin';
$lang->todo->beginAndEnd = 'Début et Fin';
$lang->todo->idvalue = 'Link ID';
$lang->todo->objectID = 'Link ID';
$lang->todo->type = 'Type';
$lang->todo->pri = 'Priorité';
$lang->todo->name = 'Titre';
+1 -1
View File
@@ -49,7 +49,7 @@ $lang->todo->end = 'Kết thúc';
$lang->todo->beginAB = 'Bắt đầu';
$lang->todo->endAB = 'Kết thúc';
$lang->todo->beginAndEnd = 'Thời gian';
$lang->todo->idvalue = 'Liên kết ID';
$lang->todo->objectID = 'Liên kết ID';
$lang->todo->type = 'Loại';
$lang->todo->pri = 'Ưu tiên';
$lang->todo->name = 'Tiêu đề';
+1 -1
View File
@@ -51,7 +51,7 @@ $lang->todo->end = '结束';
$lang->todo->beginAB = '开始';
$lang->todo->endAB = '结束';
$lang->todo->beginAndEnd = '起止时间';
$lang->todo->idvalue = '关联编号';
$lang->todo->objectID = '关联编号';
$lang->todo->type = '类型';
$lang->todo->pri = '优先级';
$lang->todo->name = '待办名称';
+1 -1
View File
@@ -50,7 +50,7 @@ $lang->todo->end = '結束';
$lang->todo->beginAB = '開始';
$lang->todo->endAB = '結束';
$lang->todo->beginAndEnd = '起止時間';
$lang->todo->idvalue = '關聯編號';
$lang->todo->objectID = '關聯編號';
$lang->todo->type = '類型';
$lang->todo->pri = '優先順序';
$lang->todo->name = '待辦名稱';
+67 -135
View File
@@ -1,13 +1,14 @@
<?php
declare(strict_types=1);
/**
* The model file of todo module of ZenTaoPMS.
* The model file of example module of ZenTaoPMS.
*
* @copyright Copyright 2009-2015 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
* @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Lanzongjun <lanzongjun@easycorp.ltd>
* @package todo
* @version $Id: model.php 5035 2013-07-06 05:21:58Z wyd621@gmail.com $
* @link http://www.zentao.net
* @link https://www.zentao.net
*/
class todoModel extends model
{
@@ -18,10 +19,13 @@ class todoModel extends model
* @param object $todo
* @return int|false
*/
public function create(object $todo): int|bool
public function create(object $todo): int|false
{
$todoID = $this->todoTao->insert($todo);
/* 处理 $todo 信息 */
$processedTodo = $this->todoTao->beforeCreate($todo);
if(!$processedTodo) return false;
$todoID = $this->todoTao->insert($processedTodo);
if(dao::isError()) return false;
return $todoID;
@@ -74,18 +78,18 @@ class todoModel extends model
$todo->end = isset($todos->ends[$i]) ? $todos->ends[$i] : 2400;
$todo->status = "wait";
$todo->private = 0;
$todo->idvalue = 0;
$todo->objectID = 0;
$todo->assignedTo = $assignedTo;
$todo->assignedBy = $this->app->user->account;
$todo->assignedDate = $now;
$todo->vision = $this->config->vision;
if(in_array($todo->type, $this->config->todo->moduleList)) $todo->idvalue = isset($todos->{$this->config->todo->objectList[$todo->type]}[$i + 1]) ? $todos->{$this->config->todo->objectList[$todo->type]}[$i + 1] : 0;
if(in_array($todo->type, $this->config->todo->moduleList)) $todo->objectID = isset($todos->{$this->config->todo->objectList[$todo->type]}[$i + 1]) ? $todos->{$this->config->todo->objectList[$todo->type]}[$i + 1] : 0;
if($todo->type != 'custom' and $todo->idvalue)
if($todo->type != 'custom' and $todo->objectID)
{
$type = $todo->type;
$object = $this->loadModel($type)->getByID($todo->idvalue);
$object = $this->loadModel($type)->getByID($todo->objectID);
if(isset($object->name)) $todo->name = $object->name;
if(isset($object->title)) $todo->name = $object->title;
}
@@ -140,7 +144,7 @@ class todoModel extends model
$this->loadModel('file')->updateObjectID($todo->uid, $todoID, 'todo');
if(!empty($oldTodo->cycle)) $this->createByCycle(array($todoID => $todo));
if(($this->config->edition == 'biz' || $this->config->edition == 'max') && $todo->type == 'feedback' && $todo->idvalue) $this->loadModel('feedback')->updateStatus('todo', $todo->idvalue, $todo->status);
if(($this->config->edition == 'biz' || $this->config->edition == 'max') && $todo->type == 'feedback' && $todo->objectID) $this->loadModel('feedback')->updateStatus('todo', $todo->objectID, $todo->status);
return common::createChanges($oldTodo, (array)$todo);
}
@@ -177,7 +181,7 @@ class todoModel extends model
if(in_array($todo->type, $this->config->todo->moduleList))
{
$todo->idvalue = isset($data->{$this->config->todo->objectList[$todo->type]}[$todoID]) ? $data->{$this->config->todo->objectList[$todo->type]}[$todoID] : 0;
$todo->objectID = isset($data->{$this->config->todo->objectList[$todo->type]}[$todoID]) ? $data->{$this->config->todo->objectList[$todo->type]}[$todoID] : 0;
}
if($todo->end < $todo->begin) return print(js::alert(sprintf($this->lang->error->gt, $this->lang->todo->end, $this->lang->todo->begin)));
@@ -191,15 +195,15 @@ class todoModel extends model
$this->dao->update(TABLE_TODO)->data($todo)
->autoCheck()
->checkIF(!in_array($todo->type, $this->config->todo->moduleList), $this->config->todo->edit->requiredFields, 'notempty')
->checkIF($todo->type == 'bug' and $todo->idvalue == 0, 'idvalue', 'notempty')
->checkIF($todo->type == 'task' and $todo->idvalue == 0, 'idvalue', 'notempty')
->checkIF($todo->type == 'story' and $todo->idvalue == 0, 'idvalue', 'notempty')
->checkIF($todo->type == 'issue' and $todo->idvalue == 0, 'idvalue', 'notempty')
->checkIF($todo->type == 'risk' and $todo->idvalue == 0, 'idvalue', 'notempty')
->checkIF($todo->type == 'opportunity' and $todo->idvalue == 0, 'idvalue', 'notempty')
->checkIF($todo->type == 'review' and $todo->idvalue == 0, 'idvalue', 'notempty')
->checkIF($todo->type == 'testtask' and $todo->idvalue == 0, 'idvalue', 'notempty')
->checkIF($todo->type == 'feedback' and $todo->idvalue == 0, 'idvalue', 'notempty')
->checkIF($todo->type == 'bug' and $todo->objectID == 0, 'objectID', 'notempty')
->checkIF($todo->type == 'task' and $todo->objectID == 0, 'objectID', 'notempty')
->checkIF($todo->type == 'story' and $todo->objectID == 0, 'objectID', 'notempty')
->checkIF($todo->type == 'issue' and $todo->objectID == 0, 'objectID', 'notempty')
->checkIF($todo->type == 'risk' and $todo->objectID == 0, 'objectID', 'notempty')
->checkIF($todo->type == 'opportunity' and $todo->objectID == 0, 'objectID', 'notempty')
->checkIF($todo->type == 'review' and $todo->objectID == 0, 'objectID', 'notempty')
->checkIF($todo->type == 'testtask' and $todo->objectID == 0, 'objectID', 'notempty')
->checkIF($todo->type == 'feedback' and $todo->objectID == 0, 'objectID', 'notempty')
->where('id')->eq($todoID)
->exec();
@@ -207,10 +211,10 @@ class todoModel extends model
if(!dao::isError())
{
if(($this->config->edition == 'biz' || $this->config->edition == 'max') && $todo->type == 'feedback' && $todo->idvalue && !isset($feedbacks[$todo->idvalue]))
if(($this->config->edition == 'biz' || $this->config->edition == 'max') && $todo->type == 'feedback' && $todo->objectID && !isset($feedbacks[$todo->objectID]))
{
$feedbacks[$todo->idvalue] = $todo->idvalue;
$this->loadModel('feedback')->updateStatus('todo', $todo->idvalue, $todo->status);
$feedbacks[$todo->objectID] = $todo->objectID;
$this->loadModel('feedback')->updateStatus('todo', $todo->objectID, $todo->status);
}
$allChanges[$todoID] = common::createChanges($oldTodo, $todo);
@@ -264,7 +268,7 @@ class todoModel extends model
if(($this->config->edition == 'biz' || $this->config->edition == 'max'))
{
$feedbackID = $this->dao->select('idvalue')->from(TABLE_TODO)->where('id')->eq($todoID)->andWhere('type')->eq('feedback')->fetch('idvalue');
$feedbackID = $this->dao->select('objectID')->from(TABLE_TODO)->where('id')->eq($todoID)->andWhere('type')->eq('feedback')->fetch('objectID');
if($feedbackID) $this->loadModel('feedback')->updateStatus('todo', $feedbackID, 'done');
}
return true;
@@ -286,15 +290,15 @@ class todoModel extends model
if(!$todo) return false;
$todo = $this->loadModel('file')->replaceImgURL($todo, 'desc');
if($setImgSize) $todo->desc = $this->file->setImgSize($todo->desc);
if($todo->type == 'story') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_STORY)->fetch('title');
if($todo->type == 'task') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_TASK)->fetch('name');
if($todo->type == 'bug') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_BUG)->fetch('title');
if($todo->type == 'issue' and $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_ISSUE)->fetch('title');
if($todo->type == 'risk' and $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_RISK)->fetch('name');
if($todo->type == 'opportunity' and $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_OPPORTUNITY)->fetch('name');
if($todo->type == 'review' and $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_REVIEW)->fetch('title');
if($todo->type == 'testtask') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_TESTTASK)->fetch('name');
if($todo->type == 'feedback') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_FEEDBACK)->fetch('title');
if($todo->type == 'story') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_STORY)->fetch('title');
if($todo->type == 'task') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_TASK)->fetch('name');
if($todo->type == 'bug') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_BUG)->fetch('title');
if($todo->type == 'issue' and $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_ISSUE)->fetch('title');
if($todo->type == 'risk' and $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_RISK)->fetch('name');
if($todo->type == 'opportunity' and $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_OPPORTUNITY)->fetch('name');
if($todo->type == 'review' and $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_REVIEW)->fetch('title');
if($todo->type == 'testtask') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_TESTTASK)->fetch('name');
if($todo->type == 'feedback') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_FEEDBACK)->fetch('title');
$todo->date = str_replace('-', '', $todo->date);
return $todo;
}
@@ -404,15 +408,15 @@ class todoModel extends model
while($todo = $stmt->fetch())
{
if($todo->type == 'story') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_STORY)->fetch('title');
if($todo->type == 'task') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_TASK)->fetch('name');
if($todo->type == 'bug') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_BUG)->fetch('title');
if($todo->type == 'testtask') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_TESTTASK)->fetch('name');
if($todo->type == 'issue' && $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_ISSUE)->fetch('title');
if($todo->type == 'risk' && $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_RISK)->fetch('name');
if($todo->type == 'opportunity' && $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_OPPORTUNITY)->fetch('name');
if($todo->type == 'review' && $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_REVIEW)->fetch('title');
if($todo->type == 'feedback' and $this->config->edition != 'open') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_FEEDBACK)->fetch('title');
if($todo->type == 'story') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_STORY)->fetch('title');
if($todo->type == 'task') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_TASK)->fetch('name');
if($todo->type == 'bug') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_BUG)->fetch('title');
if($todo->type == 'testtask') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_TESTTASK)->fetch('name');
if($todo->type == 'issue' && $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_ISSUE)->fetch('title');
if($todo->type == 'risk' && $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_RISK)->fetch('name');
if($todo->type == 'opportunity' && $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_OPPORTUNITY)->fetch('name');
if($todo->type == 'review' && $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_REVIEW)->fetch('title');
if($todo->type == 'feedback' and $this->config->edition != 'open') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_FEEDBACK)->fetch('title');
$todo->begin = date::formatTime($todo->begin);
$todo->end = date::formatTime($todo->end);
@@ -467,22 +471,23 @@ class todoModel extends model
}
/**
* CreateByCycle
* Create todo by cycle.
*
* @param int $todoList
* @param array $todoList
* @access public
* @return void
*/
public function createByCycle($todoList)
public function createByCycle(array $todoList): void
{
$this->loadModel('action');
$today = helper::today();
$now = helper::now();
$lastCycleList = $this->dao->select('*')->from(TABLE_TODO)->where('type')->eq('cycle')->andWhere('deleted')->eq('0')->andWhere('idvalue')->in(array_keys($todoList))->orderBy('date_asc')->fetchAll('idvalue');
$activedUsers = $this->dao->select('account')->from(TABLE_USER)->where('deleted')->eq(0)->fetchPairs('account', 'account');
$today = helper::today();
$now = helper::now();
$cycleList = $this->todoTao->getCycleList($todoList);
$validUsers = $this->dao->select('account')->from(TABLE_USER)->where('deleted')->eq(0)->fetchPairs('account', 'account');
foreach($todoList as $todoID => $todo)
{
if(!isset($activedUsers[$todo->account])) continue;
if(!isset($validUsers[$todo->account])) continue;
$todo->config = json_decode($todo->config);
$begin = $todo->config->begin;
@@ -491,19 +496,7 @@ class todoModel extends model
if(!empty($beforeDays) && $beforeDays > 0) $begin = date('Y-m-d', strtotime("$begin -{$beforeDays} days"));
if($today < $begin or (!empty($end) && $today > $end)) continue;
$newTodo = new stdclass();
$newTodo->account = $todo->account;
$newTodo->begin = $todo->begin;
$newTodo->end = $todo->end;
$newTodo->type = 'cycle';
$newTodo->idvalue = $todoID;
$newTodo->pri = $todo->pri;
$newTodo->name = $todo->name;
$newTodo->desc = $todo->desc;
$newTodo->status = 'wait';
$newTodo->private = isset($todo->private) ? $todo->private : '';
$newTodo->assignedTo = isset($todo->assignedTo) ? $todo->assignedTo : '';
$newTodo->assignedBy = isset($todo->assignedBy) ? $todo->assignedBy : '';
$newTodo = $this->todoTao->buildCycleTodo($todo);
if(isset($todo->assignedTo) and $todo->assignedTo) $newTodo->assignedDate = $now;
$start = strtotime($begin);
@@ -511,83 +504,22 @@ class todoModel extends model
foreach(range($start, $finish, 86400) as $today)
{
$today = date('Y-m-d', $today);
$lastCycle = zget($lastCycleList, $todoID, '');
$date = '';
$lastCycle = zget($cycleList, $todoID, '');
if($todo->config->type == 'day')
{
if(isset($todo->config->day))
{
$day = (int)$todo->config->day;
if($day <= 0) continue;
/* If no data, judge the interval from the begin time. */
if(empty($lastCycle))
{
$todayTime = new DateTime($today);
$beginTime = new DateTime($todo->config->begin);
$interval = $todayTime->diff($beginTime)->days;
if($interval != $day) continue;
$date = $today;
}
/* If have data, judge the interval from the last cycle time. */
if(!empty($lastCycle->date))
{
$todayTime = new DateTime($today);
$lastCycleTime = new DateTime($lastCycle->date);
$interval = $todayTime->diff($lastCycleTime)->days;
if($interval != $day) continue;
$date = date('Y-m-d', strtotime("{$lastCycle->date} +{$day} days"));
}
}
if(isset($todo->config->specifiedDate))
{
$date = $today;
$specifiedDate = $todo->config->specify->month + 1 . '-' . $todo->config->specify->day;
/* If not set cycle every year and have data, continue. */
if(!empty($lastCycle) and !isset($todo->config->cycleYear)) continue;
/* If set specified date, only judge month and day. */
if(date('m-d', strtotime($date)) != $specifiedDate) continue;
}
}
elseif($todo->config->type == 'week')
{
$week = date('w', strtotime($today));
if(strpos(",{$todo->config->week},", ",{$week},") !== false)
{
if(empty($lastCycle)) $date = $today;
if($lastCycle and $lastCycle->date < $today) $date = $today;
}
}
elseif($todo->config->type == 'month')
{
$day = date('j', strtotime($today));
if(strpos(",{$todo->config->month},", ",{$day},") !== false)
{
if(empty($lastCycle)) $date = $today;
if($lastCycle and $lastCycle->date < $today) $date = $today;
}
}
$date = $this->todoTao->getCycleTodoDate($todo, $lastCycle, $today);
if($date === false) continue;
if(!$date) continue;
if($date < $todo->config->begin) continue;
if($date < date('Y-m-d')) continue;
if($date > date('Y-m-d', $finish)) continue;
if($date < date('Y-m-d')) continue;
if($date > date('Y-m-d', $finish)) continue;
if(!empty($end) && $date > $end) continue;
if($lastCycle and ($date == $lastCycle->date)) continue;
$newTodo->date = $date;
$this->dao->insert(TABLE_TODO)->data($newTodo)->exec();
$this->todoTao->insert($newTodo);
$this->action->create('todo', $this->dao->lastInsertID(), 'opened', '', '', $newTodo->account);
$lastCycleList[$todoID] = $newTodo;
$cycleList[$todoID] = $newTodo;
}
}
}
@@ -625,7 +557,7 @@ class todoModel extends model
if(($this->config->edition == 'biz' || $this->config->edition == 'max'))
{
$feedbackID = $this->dao->select('idvalue')->from(TABLE_TODO)->where('id')->eq($todoID)->andWhere('type')->eq('feedback')->fetch('idvalue');
$feedbackID = $this->dao->select('objectID')->from(TABLE_TODO)->where('id')->eq($todoID)->andWhere('type')->eq('feedback')->fetch('objectID');
if($feedbackID) $this->loadModel('feedback')->updateStatus('todo', $feedbackID, 'closed');
}
return true;
+2 -2
View File
@@ -15,7 +15,7 @@ class todoTao extends todoModel
$this->dao->insert(TABLE_TODO)->data($todo)
->autoCheck()
->checkIF(!in_array($todo->type, $this->config->todo->moduleList), $this->config->todo->create->requiredFields, 'notempty')
->checkIF(in_array($todo->type, $this->config->todo->moduleList) && $todo->idvalue == 0, 'idvalue', 'notempty')
->checkIF(in_array($todo->type, $this->config->todo->moduleList) && $todo->objectID == 0, 'objectID', 'notempty')
->exec();
return (int)$this->dao->lastInsertID();
@@ -34,7 +34,7 @@ class todoTao extends todoModel
$this->dao->update(TABLE_TODO)->data($todo)
->autoCheck()
->checkIF(in_array($todo->type, array('custom', 'feedback')), $this->config->todo->edit->requiredFields, 'notempty')
->checkIF(in_array($todo->type, $this->config->todo->moduleList) && $todo->idvalue == 0, 'idvalue', 'notempty')
->checkIF(in_array($todo->type, $this->config->todo->moduleList) && $todo->objectID == 0, 'objectID', 'notempty')
->where('id')->eq($todoID)
->exec();
+10 -10
View File
@@ -7,8 +7,8 @@ su('admin');
function initData()
{
$todo = zdTable('todo');
$todo->id->range('1-4');
$todo->account->prefix('admin')->range('1-4');
$todo->id->range('1-3');
$todo->account->prefix('admin')->range('1-3');
$todo->begin->range('1710');
$todo->end->range('1740');
$todo->feedback->range('0');
@@ -16,18 +16,18 @@ function initData()
$todo->cycle->range('0');
$todo->idvalue->range('0');
$todo->pri->range("3");
$todo->name->prefix('测试待办')->range('1-4');
$todo->name->prefix('测试待办')->range('1-3');
$todo->desc->range('描述');
$todo->status->range('wait');
$todo->status->range('wait{1},doing{1},done{1}');
$todo->private->range('0');
$todo->assignedTo->prefix('admin')->range('1-4');
$todo->assignedBy->prefix('admin')->range('1-4');
$todo->finishedBy->prefix('admin')->range('1-4');
$todo->closedBy->prefix('admin')->range('1-4');
$todo->assignedTo->prefix('admin')->range('1-3');
$todo->assignedBy->prefix('admin')->range('1-3');
$todo->finishedBy->prefix('admin')->range('1-3');
$todo->closedBy->prefix('admin')->range('1-3');
$todo->deleted->range('0');
$todo->vision->range('1.0');
$todo->gen(4);
$todo->gen(3);
}
/**
@@ -54,4 +54,4 @@ initData();
r($todo->activateTest($todoIDList[0])) && p('status') && e('wait'); // 激活一个状态为wait的todo
r($todo->activateTest($todoIDList[1])) && p('status') && e('wait'); // 激活一个状态为doing的todo
r($todo->activateTest($todoIDList[2])) && p('status') && e('wait'); // 激活一个状态为done的todo
r($todo->activateTest($todoIDList[2])) && p('status') && e('wait'); // 激活一个状态为done的todo
+2 -2
View File
@@ -36,5 +36,5 @@ $except_create = array('types' => $types, 'pris' => $pris, 'names' => $names, 'd
$todo = new todoTest();
r($todo->batchCreateTest($noname_create)) && p('2006:name,desc,pri,type,idvalue;2007:name,desc,pri,type,idvalue;2008:name,desc,pri,type,idvalue') && e('批量创建待办1,desc1,1,custom,0;批量创建待办2,desc2,2,custom,0;批量创建待办3,desc4,4,custom,0'); // 批量创建有个没有名字的待办
r($todo->batchCreateTest($except_create)) && p('2009:name,desc,pri,type,idvalue;2010:name,desc,pri,type,idvalue;2011:name,desc,pri,type,idvalue;2012:name,desc,pri,type,idvalue') && e('测试单转Bug13,desc1,1,bug,313;软件需求版本一551,desc2,2,story,1;开发任务11,desc3,3,task,1;测试单1,desc4,4,testtask,1'); // 批量创建的待办
r($todo->batchCreateTest($noname_create)) && p('2006:name,desc,pri,type,objectID;2007:name,desc,pri,type,objectID;2008:name,desc,pri,type,objectID') && e('批量创建待办1,desc1,1,custom,0;批量创建待办2,desc2,2,custom,0;批量创建待办3,desc4,4,custom,0'); // 批量创建有个没有名字的待办
r($todo->batchCreateTest($except_create)) && p('2009:name,desc,pri,type,objectID;2010:name,desc,pri,type,objectID;2011:name,desc,pri,type,objectID;2012:name,desc,pri,type,objectID') && e('测试单转Bug13,desc1,1,bug,313;软件需求版本一551,desc2,2,story,1;开发任务11,desc3,3,task,1;测试单1,desc4,4,testtask,1'); // 批量创建的待办
+8 -13
View File
@@ -13,23 +13,18 @@ cid=1
pid=1
*/
function initData()
{
$todo = zdTable('todo');
$todo->id->range('1');
$todo->name->prefix("待办")->range('1');
$todo->date->range('`2023-04-23`');
$todo->type->range('custom');
$todo->status->range('wait');
$todo->gen(1, '', true);
}
initData();
global $tester;
$tester->loadModel('todo');
$todo = zdTable('todo');
$todo->id->range('1');
$todo->name->prefix("待办")->range('1');
$todo->date->range('`2023-04-23`');
$todo->type->range('custom');
$todo->status->range('wait');
$todo->gen(1, '', true);
r($tester->todo->getByID(1)) && p('status') && e('wait');
r($tester->todo->close(1)) && p() && e(1);
r($tester->todo->close(1)) && p() && e(1);
r($tester->todo->getByID(1)) && p('status') && e('closed');
+18 -14
View File
@@ -7,8 +7,8 @@ su('admin');
function initData()
{
$todo = zdTable('todo');
$todo->id->range('1-5');
$todo->account->prefix('admin')->range('1-5');
$todo->id->range('1-3');
$todo->account->prefix('admin')->range('1-3');
$todo->begin->range('1710');
$todo->end->range('1740');
$todo->feedback->range('0');
@@ -16,18 +16,18 @@ function initData()
$todo->cycle->range('0');
$todo->idvalue->range('0');
$todo->pri->range("3");
$todo->name->prefix('测试待办')->range('1-5');
$todo->name->prefix('测试待办')->range('1-3');
$todo->desc->range('描述');
$todo->status->range('wait');
$todo->status->range('wait{1},doing{1},done{1}');
$todo->private->range('0');
$todo->assignedTo->prefix('admin')->range('1-5');
$todo->assignedBy->prefix('admin')->range('1-5');
$todo->finishedBy->prefix('admin')->range('1-5');
$todo->closedBy->prefix('admin')->range('1-5');
$todo->assignedTo->prefix('admin')->range('1-3');
$todo->assignedBy->prefix('admin')->range('1-3');
$todo->finishedBy->prefix('admin')->range('1-3');
$todo->closedBy->prefix('admin')->range('1-3');
$todo->deleted->range('0');
$todo->vision->range('1.0');
$todo->gen(5);
$todo->gen(3);
}
/**
@@ -36,9 +36,12 @@ title=测试 todoModel->start();
timeout=0
cid=1
读取文件/var/www/html/studyProject/zin//var/www/html/studyProject/zin/module/todo/test/model/data/todo_start.yaml失败。
- 执行todo模块的start方法,参数是1,属性status @doing
- 执行todo模块的start方法,参数是2,属性status @doing
- 执行todo模块的start方法,参数是1属性status @doing
- 执行todo模块的start方法,参数是2属性status @doing
- 执行todo模块的start方法,参数是3属性status @doing
*/
@@ -47,5 +50,6 @@ $todo = new todoTest();
initData();
r($todo->startTest(1)) && p('status') && e('doing');
r($todo->startTest(2)) && p('status') && e('doing');
r($todo->startTest(1)) && p('status') && e('doing'); //开启一个状态为wait的todo
r($todo->startTest(2)) && p('status') && e('doing'); //开启一个状态为doing的todo
r($todo->startTest(3)) && p('status') && e('doing'); //开启一个状态为done的todo
+1 -1
View File
@@ -46,7 +46,7 @@ $tester->loadModel('todo');
initData();
$t_upname = array('name' => 'john');
$t_uptype = array('type' => 'bug', 'idvalue' => '1');
$t_uptype = array('type' => 'bug', 'objectID' => '1');
$t_unname = array('name' => 'john');
$todo = new todoTest();
+2 -2
View File
@@ -270,7 +270,7 @@ class todoTest
$todo->begin = '0830';
$todo->end = '0900';
$todo->account = 'admin';
$todo->idvalue = '0';
$todo->objectID = '0';
$todo->vision = 'rnd';
$todo->assignedTo = 'admin';
$todo->assignedBy = 'admin';
@@ -285,7 +285,7 @@ class todoTest
$this->objectModel->createByCycle(array($todoID => $todo));
$objects = $tester->dao->select('id')->from(TABLE_TODO)->where('idvalue')->eq($todoID)->andWhere('deleted')->eq('0')->fetchAll();
$objects = $tester->dao->select('id')->from(TABLE_TODO)->where('objectID')->eq($todoID)->andWhere('deleted')->eq('0')->fetchAll();
if(dao::isError()) return dao::getError();
+10 -10
View File
@@ -62,7 +62,7 @@
}
else
{
echo html::select("types[$todo->id]", $lang->todo->typeList, $todo->type, "onchange='loadList(this.value, {$todo->id}, \"{$todo->type}\", {$todo->idvalue})' class='form-control'");
echo html::select("types[$todo->id]", $lang->todo->typeList, $todo->type, "onchange='loadList(this.value, {$todo->id}, \"{$todo->type}\", {$todo->objectID})' class='form-control'");
}
?>
</td>
@@ -77,39 +77,39 @@
}
elseif($todo->type == 'task')
{
echo html::select("tasks[$todo->id]", $tasks, $todo->idvalue, 'class="form-control chosen"');
echo html::select("tasks[$todo->id]", $tasks, $todo->objectID, 'class="form-control chosen"');
}
elseif($todo->type == 'bug')
{
echo html::select("bugs[$todo->id]", $bugs, $todo->idvalue, 'class="form-control chosen"');
echo html::select("bugs[$todo->id]", $bugs, $todo->objectID, 'class="form-control chosen"');
}
elseif($todo->type == 'story')
{
echo html::select("stories[$todo->id]", $storys, $todo->idvalue, 'class="form-control chosen"');
echo html::select("stories[$todo->id]", $storys, $todo->objectID, 'class="form-control chosen"');
}
elseif($todo->type == 'issue')
{
echo html::select("issues[$todo->id]", $issues, $todo->idvalue, 'class="form-control chosen"');
echo html::select("issues[$todo->id]", $issues, $todo->objectID, 'class="form-control chosen"');
}
elseif($todo->type == 'risk')
{
echo html::select("risks[$todo->id]", $risks, $todo->idvalue, 'class="form-control chosen"');
echo html::select("risks[$todo->id]", $risks, $todo->objectID, 'class="form-control chosen"');
}
elseif($todo->type == 'review')
{
echo html::select("reviews[$todo->id]", $reviews, $todo->idvalue, 'class="form-control chosen"');
echo html::select("reviews[$todo->id]", $reviews, $todo->objectID, 'class="form-control chosen"');
}
elseif($todo->type == 'testtask')
{
echo html::select("testtasks[$todo->id]", $testtasks, $todo->idvalue, 'class="form-control chosen"');
echo html::select("testtasks[$todo->id]", $testtasks, $todo->objectID, 'class="form-control chosen"');
}
elseif($todo->type == 'opportunity')
{
echo html::select("opportunities[$todo->id]", $opportunities, $todo->idvalue, 'class="form-control chosen"');
echo html::select("opportunities[$todo->id]", $opportunities, $todo->objectID, 'class="form-control chosen"');
}
elseif($todo->type == 'feedback')
{
echo html::select("feedbacks[$todo->id]", $feedbacks, $todo->idvalue, 'class="form-control chosen"');
echo html::select("feedbacks[$todo->id]", $feedbacks, $todo->objectID, 'class="form-control chosen"');
}
?>
</div>
+1 -1
View File
@@ -16,7 +16,7 @@
<?php js::set('noTodo', $lang->todo->noTodo);?>
<?php js::set('moduleList', $config->todo->moduleList)?>
<?php js::set('objectsMethod', $config->todo->getUserObjectsMethod)?>
<?php js::set('nameBoxLabel', array('custom' => $lang->todo->name, 'idvalue' => $lang->todo->idvalue));?>
<?php js::set('nameBoxLabel', array('custom' => $lang->todo->name, 'objectID' => $lang->todo->objectID));?>
<?php js::set('vision', $config->vision);?>
<?php js::set('noOptions', $lang->todo->noOptions);?>
<?php js::set('chosenType', $lang->todo->typeList);?>
+4 -4
View File
@@ -15,9 +15,9 @@
<?php include '../../common/view/kindeditor.html.php';?>
<?php js::set('moduleList', $config->todo->moduleList)?>
<?php js::set('objectsMethod', $config->todo->getUserObjectsMethod)?>
<?php js::set('idvalue', $todo->idvalue);?>
<?php js::set('objectID', $todo->objectID);?>
<?php js::set('defaultType', $todo->type);?>
<?php js::set('nameBoxLabel', array('custom' => $lang->todo->name, 'idvalue' => $lang->todo->idvalue));?>
<?php js::set('nameBoxLabel', array('custom' => $lang->todo->name, 'objectID' => $lang->todo->objectID));?>
<?php js::set('vision', $config->vision);?>
<?php js::set('noOptions', $lang->todo->noOptions);?>
<?php js::set('chosenType', $lang->todo->typeList);?>
@@ -127,7 +127,7 @@
<div class="row form-group">
<label class="col-sm-1"><?php echo $lang->todo->type;?></label>
<div class="col-sm-4 dateWidth">
<?php echo html::select('type', $lang->todo->typeList, $todo->type, "onchange='loadList(this.value, \"\", \"{$todo->type}\", {$todo->idvalue})' class='form-control'");?>
<?php echo html::select('type', $lang->todo->typeList, $todo->type, "onchange='loadList(this.value, \"\", \"{$todo->type}\", {$todo->objectID})' class='form-control'");?>
</div>
</div>
<?php endif;?>
@@ -138,7 +138,7 @@
</div>
</div>
<div class="row form-group">
<label id='nameBoxLabel' class="col-sm-1"><?php echo ($todo->type == 'custom' or $config->vision == 'rnd') ? $lang->todo->name : $lang->todo->idvalue;?></label>
<label id='nameBoxLabel' class="col-sm-1"><?php echo ($todo->type == 'custom' or $config->vision == 'rnd') ? $lang->todo->name : $lang->todo->objectID;?></label>
<div class="col-sm-10">
<div id='nameBox' class='hidden'><?php echo html::input('name', $todo->name, "class='form-control'");?></div>
<div class='input-group title-group required'>
+3 -3
View File
@@ -31,9 +31,9 @@
<div class='detail-title'>
<?php
echo $lang->todo->desc;
if($todo->type == 'bug') common::printLink('bug', 'view', "id={$todo->idvalue}", ' BUG#' . $todo->idvalue);
if($todo->type == 'task') common::printLink('task', 'view', "id={$todo->idvalue}", ' TASK#' . $todo->idvalue);
if($todo->type == 'story') common::printLink('story', 'view', "id={$todo->idvalue}", ' STORY#' . $todo->idvalue);
if($todo->type == 'bug') common::printLink('bug', 'view', "id={$todo->objectID}", ' BUG#' . $todo->objectID);
if($todo->type == 'task') common::printLink('task', 'view', "id={$todo->objectID}", ' TASK#' . $todo->objectID);
if($todo->type == 'story') common::printLink('story', 'view', "id={$todo->objectID}", ' STORY#' . $todo->objectID);
?>
</div>
<div class='detail-content article-content'><?php echo $todo->desc;?></div>
+62 -8
View File
@@ -3,6 +3,60 @@ declare(strict_types=1);
class todoZen extends todo
{
/**
* 处理请求数据
* Processing request data.
*
* @param object $formData
* @return object|false
*/
protected function beforeCreate(object $formData): object|bool
{
$formData = $formData->remove(implode(',', $this->config->todo->moduleList) . ',uid')->stripTags($this->config->todo->editor->create['id'], $this->config->allowedTags)->get();
$objectID = 0;
$hasObject = in_array($formData->type, $this->config->todo->moduleList);
if($hasObject && $formData->type) $objectID = $formData->uid ? $formData->type : $formData->objectID;
$formData->account = $this->app->user->account;
$formData->assignedTo = zget($formData, 'assignedTo', $this->app->user->account);
$formData->assignedBy = zget($formData, 'assignedBy', $this->app->user->account);
if($hasObject && $formData->type) $formData->objectID = $objectID;
if($formData->status == 'done') $formData->finishedBy = $this->app->user->account;
if($formData->status == 'done') $formData->finishedDate = helper::now();
if(!isset($formData->pri) and in_array($formData->type, $this->config->todo->moduleList) and $formData->type !== 'review' and $formData->type !== 'feedback')
{
// TODO
$formData->pri = $this->dao->select('pri')->from($this->config->objectTables[$formData->type])->where('id')->eq($formData->objectID)->fetch('pri');
if($formData->pri == 'high') $formData->pri = 1;
if($formData->pri == 'middle') $formData->pri = 2;
if($formData->pri == 'low') $formData->pri = 3;
}
if($formData->type != 'custom' and $formData->objectID)
{
$type = $formData->type;
$object = $this->loadModel($type)->getByID($formData->$type);
if(isset($object->name)) $formData->name = $object->name;
if(isset($object->title)) $formData->name = $object->title;
}
if($formData->end < $formData->begin)
{
dao::$errors[] = sprintf($this->lang->error->gt, $this->lang->todo->end, $this->lang->todo->begin);
return false;
}
if(!empty($formData->cycle)) $formData = $this->setCycle($formData);
else unset($formData->config);
$formData = $this->loadModel('file')->processImgURL($formData, $this->config->todo->editor->create['id'], $this->post->uid);
return $formData;
}
/**
* 创建待办
* Create a todo.
@@ -24,7 +78,7 @@ class todoZen extends todo
*/
protected function afterCreate(object $todo): object
{
$this->file->updateObjectID($this->post->uid, $todo->id, 'todo');
$this->loadModel('file')->updateObjectID($this->post->uid, $todo->id, 'todo');
$this->loadModel('score')->create('todo', 'create', $todo->id);
@@ -47,20 +101,20 @@ class todoZen extends todo
* @param object $formData
* @return object|false
*/
protected function beforeEdit(int $todoID, object $formData)
protected function beforeEdit(int $todoID, object $formData): object|false
{
$oldTodo = $this->dao->findById($todoID)->from(TABLE_TODO)->fetch();
$idvalue = 0;
$objectID = 0;
$rowData = $formData->rawdata;
$objectType = $rowData->type;
$hasObject = in_array($objectType, $this->config->todo->moduleList);
if($hasObject && $objectType) $idvalue = $rowData->uid ? $rowData->$objectType : $rowData->idvalue;
if($hasObject && $objectType) $objectID = $rowData->uid ? $rowData->$objectType : $rowData->objectID;
$todo = $formData->add('account', $oldTodo->account)
->cleanInt('pri, begin, end, private')
->setIF(in_array($rowData->type, array('bug', 'task', 'story')), 'name', '')
->setIF($hasObject && $objectType, 'idvalue', $idvalue)
->setIF($hasObject && $objectType, 'objectID', $objectID)
->setIF($rowData->date == false, 'date', '2030-01-01')
->setIF($rowData->begin == false, 'begin', '2400')
->setIF($rowData->end == false, 'end', '2400')
@@ -70,7 +124,7 @@ class todoZen extends todo
->remove(implode(',', $this->config->todo->moduleList) . ',uid')
->get();
$todo = (object) array_merge((array) $todo, (array) $rowData);
$todo = (object) array_merge((array) $rowData, (array) $todo);
if(in_array($todo->type, $this->config->todo->moduleList))
{
@@ -196,12 +250,12 @@ class todoZen extends todo
protected function printConfirm(object $todo): int
{
$confirmNote = 'confirm' . ucfirst($todo->type);
$confirmURL = $this->createLink($todo->type, 'view', "id=$todo->idvalue");
$confirmURL = $this->createLink($todo->type, 'view', "id=$todo->objectID");
$okTarget = isonlybody() ? 'parent' : 'window.parent.$.apps.open';
if($todo->type == 'bug') $app = 'qa';
if($todo->type == 'task') $app = 'execution';
if($todo->type == 'story') $app = 'product';
$cancelURL = $this->server->HTTP_REFERER;
return print(js::confirm(sprintf($this->lang->todo->$confirmNote, $todo->idvalue), $confirmURL, $cancelURL, $okTarget, 'parent', $app));
return print(js::confirm(sprintf($this->lang->todo->$confirmNote, $todo->objectID), $confirmURL, $cancelURL, $okTarget, 'parent', $app));
}
}