This commit is contained in:
liyuchun
2022-06-06 01:20:49 +00:00
59 changed files with 3480 additions and 3310 deletions
+10 -204
View File
@@ -1,205 +1,11 @@
Z PUBLIC LICENSE 1.2
本仓库的源代码由以下双重许可涵盖:
(1) Z PUBLIC LICENSE(以下简称ZPL) v1.2。
(2) Affero General Public License(以下简称AGPL) 授权协议。
默认授权协议为ZPL协议。
您也可以选择遵守AGPL协议使用我们的源代码。
许可
Z PUBLIC LICENSE 由青岛易软天创网络科技有限公司(www.cnezsoft.com)起草,简称ZPL协议。
任何人均可使用该协议来发布开源软件,并可对下面协议正文中以下划线标注的空白部分做相应修改,
除此之外的任何内容不得做任何修改。青岛易软天创网络科技有限公司拥有对该协议条款的最终解释权。
前言:
禅道项目管理软件(以下简称该软件)由 青岛易软天创网络科技有限公司(www.cnezsoft.com)开发(以下简称我)。我依法拥有该软件的所有版权。
本着共享开放的角度,我以开放源代码的形式发布该软件。您可以在遵守该协议的前提下使用该软件。
自您安装该软件开始,您和我之间的合同关系自动成立。除非您停止使用该软件或与我有签署额外合同,
您须认真遵循该授权协议约定的每一条款。
我的联系方式:
联系人:徐先生
电话: 4006-8899-23
Email co@cnezsoft.com
QQ 1492153927
地址: 青岛开发区井冈山路东方银座 C座 1106
约定:
下述条款中所指该软件的标志包括如下方面:
该软件源代码及文档中关于该软件的版权提示、文字、图片和链接。
该软件运行时界面上呈现出来的有关该软件的文字、图片和链接。
不包括如下方面:
该软件提供的演示数据中关于该软件的文字、图片和链接。
一、免责
该软件是以开放源代码的方式发行,您使用该软件无需任何费用,因此在使用该软件前,您须知晓:
1.1 我没有对该软件提供任何技术支持的义务,您可联系我购买商业的技术支持。
1.2 我对因使用该软件而产生直接或间接的任何问题不负任何责任。
1.3 开源不等于免费,开源不等于无版权,开源软件的发展需要您我共同的努力。
二、自用该软件
2.1 您个人或您就职的公司(组织)可自由使用该软件,我不对您或您就职公司(组织)的性质做任何限制。
2.2 您可以在您个人或您就职公司(组织)任意数量的电脑上运行该软件,我不对电脑的数量做任何限制。
2.3 您可以对该软件源代码进行修改以适应您个人或您所在公司(组织)使用的要求,您做的改动无需对外发布。
2.4 您个人或您就职公司(组织)使用该软件时,必须保留该软件的所有标志,不得以任何方式隐藏或遮掩任一标志。
三、为用户定制
3.1 您可以使用该软件为您的用户部署各种形式的应用,我不对应用的性质做任何限制。
3.2 您可以使用该软件为您的用户部署任意数量的应用,我不对应用的数量做任何限制。
3.3 您可以对该软件源代码进行修改以适应您的用户的要求,您做的改动无需对外发布。
3.4 您对该软件源代码所做的修改可以源代码或二进制的方式提供给您的用户。
3.5 您使用该软件为您的任一用户部署的任一应用都必须保留该软件所有的标志。
3.6 您使用该软件为您的任一用户部署的任一应用都不得以任何方式隐藏或遮掩该软件任一标志。
四、提供在线服务
4.1 您可以使用该软件搭建在线服务,为您的用户提供服务,我不对该服务及该服务用户的性质做任何限制。
4.2 您可以使用该软件搭建在线服务,为您的用户提供服务,我不对该服务的用户数量做任何限制。
4.3 您可以对该软件源代码进行修改以适应在线服务的要求,您做的改动无需对外发布。
4.4 您使用该软件搭建在线服务时,必须以明确的方式告知您的用户该服务是基于该软件搭建的。
4.5 您使用该软件搭建在线服务为您的任一用户部署的任一应用必须保留该软件所有的标志。
4.6 您使用该软件搭建在线服务为您的任一用户部署的任一应用不得以任何方式隐藏或遮掩该软件任一标志。
4.7 您使用该软件搭建在线服务时,不得为您的用户提供去除、隐藏或遮掩该软件任一标志的功能。
五、无改动发布或集成该软件
5.1 我欢迎并感谢您将该软件发布在您的个人网站、企业官网或者其他的第三方网站。
5.2 我欢迎并感谢您将该软件集成在其他系统中一起发布,比如云服务镜像、操作系统发行版等。
5.3 您在发布或者集成该软件的时候,不得对该软件源码做任何改动。
5.4 您在发布或者集成该软件的时候,须保留该软件的所有标志。
六、发布基于该软件的衍生作品
6.1 我欢迎并感谢您为该软件开发衍生作品。
6.2 您开发的衍生作品中涉及到对该软件源代码改动的地方,须遵循如下条款:
6.2.1 如修改了该软件的源代码,须依据本协议发布修改后的源代码。
6.2.2 如修改了该软件的源代码,须保留代码里面该软件原有的所有标志。
6.2.3 您可以在代码中追加您自己的标志。
6.2.4 您可以对您开发的衍生作品进行收费。
6.2.5 第三方的用户可在遵循6.2所有条款下可继续在您开发的衍生作品基础上进行修改并发布。
6.3 您开发的衍生作品中独立于本软件开发的代码,可以源代码或二进制的方式进行发布,可免费或收费发布。
6.4 您开发的衍生作品不得以任何方式去除、隐藏或遮掩该软件的任一标志。
七、发布基于该软件API的应用
7.1 我欢迎并感谢您为该软件开发基于API的各种应用,比如客户端软件等。
7.2 您基于该软件API机制开发的应用,可以源代码或者二进制的方式进行发布,我对此没有任何限制。
7.3 您基于该软件API机制开发的应用,授权协议可以自行约定,我对此没有任何限制。
7.4 您基于该软件API机制开发的应用,可以免费或者收费发布,我对此没有任何限制。
八、授权例外
如果上述条款无法满足您使用该软件的要求,可联系我签署额外的合同以获得更灵活的授权许可。
九、合同约束
9.1 如果您违反了该协议的任一条款,该授权协议将自动终止,我保留通过法律手段追究责任的权利。
Z PUBLIC LICENSE 1.2
Authorization
Z PUBLIC LICENSE, also known as ZPL Agreement, is drafted by QingDao Nature Easy Soft Network Technology Co,LTD. (,www.cnezsoft.com).
Anyone can use the agreement to publish open source software, and modify the blank underlined part of the following text of the agreement accordingly.
No other text of the agreement shall be changed. QingDao Nature Easy Soft Network Technology Co,LTD has the final authority to interpret the terms of the agreement.
Preface
ZenTaoPMS (Hereinafter referred to as "the software") developed by Nature EasySoft Network Tecnology Co.ltd, QingDao, China (www.cnezsoft.com) (hereinafter referred to I). I'm entitled to all copyright of the software.
The software is released as open source software. You are authorized to use the software as long as you are in compliance with this agreement.
By installation of the software, you agree that a contractual relationship between you and me is automatically established.
You are obliged to fully comply with all the terms of this agreement unless you choose to stop using the software or you have signed additional contracts with me.
My Contact:
Contact: Mr. Xu
Phone: 4006-8899-23
Email: co@cnezsoft.com
QQ: 1492153927
Address: Qingdao Development Zone, the Oriental Kenzo C 1106
We agree:
Indications of the software include:
Notes, texts, pictures and links showing copyright attribution of the software in the source code and related documentation.
and texts, picture and links on the interface of the software when running.
Excluding
texts, picture and links on the interface of the demo versions of the software.
1. Disclaimer
The software is an open-source software, so you are authorized to use the software without paying a fee. Before you start to use it, please note:
1.1 I do not have any obligation to provide technical support for the software. You can contact me to purchase technical support service.
1.2 I'm not responsible for any liability caused by your using the software directly or indirectly.
1.3 Open source software does not mean it's free of charge, neither does it mean the software does not enjoy copyright.
2. For personal use
2.1 You or your company/organization are authorized to use the software for your internal use for both commercial and non-commercial purposes..
2.2 You or your company/organization are authorized to run the software on any number of computers.
2.3 You or your company/organization are authorized to modify the source code of the software to meet your requirements. You do not need to release the modified codes.
2.4 You or your company/organization must keep all the indications of the software when using it. None of the indications can be removed, hidden or obscured in any way.
3. For customized software
3.1 You are authorized to use the software to deploy various forms of application for your users in any way you like.
3.2 You are authorized to use the software to deploy any number of applications for your users.
3.3 You are authorized to modify the source code to meet your user's requirements without releasing the modified codes.
3.4 You are authorized to provide the modified codes to your users in either source code form or binary.
3.5 You must keep all the indications of the software when providing applications to your users.
3.6 None of the indications of the software may be removed, hidden or obscured in any way when you provide applications to your users.
4. Online service
4.1 You are authorized to use the software to build your online service for your users in any way you like.
4.2 You are authorized to use the software to build your online service for any number of your users.
4.3 You are authorized to modify the source codes of the software to meet your user's requirements on online service without releasing the modified codes.
4.4 You must notify your users clearly that your service is based on the software when you use it to build your online service.
4.5 You must keep all the indications of the software when providing online service to your users.
4.6 You must keep all the indications of the software in any application you make for your users. None of the indications can be hidden or obscured in any way.
4.7 You are forbidden from assisting your users by providing tools for your users to remove, hide or obscure any indication of the software when you use the software to build your online service.
5. Publish or integrate the software without modification
5.1 You are authorized to publish the software on your personal sites, corporate official website or other third-party sites.
5.2 You are authorized to integrate the software with other systems, such as cloud virtual machine images, operating system images and so on.
5.3 Do not modify the source code of the software when you publish or integrate it.
5.4 All indications of the software must be kept the same when you publish or integrate the software.
6. Publish derived work based on the software
6.1 You are authorized to develop derived work based on the software.
6.2 The modified codes of the software in your derived work must follow the following terms:
6.2.1 The source codes must be released if you make any modification to the software.
6.2.2 All indications of the software must be kept the same.
6.2.3 You are entitled to add your indications to the modified codes.
6.2.4 You are entitled to charge fees for the derived work you developed based on the software.
6.2.5 You agree to authorize third party users to modify and release the derived work in compliance with 6.2.
6.3 If the codes of the work are independently developed by yourself, You are authorized to release the work in either source code form or binary. You are entitled to charge your users or make it free.
6.4 None of the indications of the software can be removed, hidden or obscured in any way in the derived work you developed.
7. Publish applications based on API of the software
7.1 You are authorized to develop your applications based on the API of the software, for example, client software.
7.2 You are authorized to publish applications you developed based on the API in either source code form or binary.
7.3 You are authorized to use your own license to release applications you developed based on the API.
7.4 You are entitled to release applications you developed based on the API either free or with a charge.
8. Exceptions
If the terms above do not meet your requirements when using the software, please contact me for a more flexible license.
9. Termination
9.1 Violation of any of the terms of the agreement will result in immediate termination of this license. I reserve all rights to take legal actions in case of dispute.
The source code of this repository is covered by the following dual licenses
(1) Z PUBLIC LICENSE(ZPL) v1.2
(2) Affero General Public License(AGPL)
The default license agreement is the ZPL.
Or you can choose to use our source code under the AGPL.
Regular → Executable
+13 -8
View File
@@ -149,8 +149,10 @@ $filter->todo->export = new stdclass();
$filter->upgrade->license = new stdclass();
$filter->user->login = new stdclass();
$filter->user->edit = new stdclass();
$filter->user->export = new stdclass();
$filter->webhook->bind = new stdclass();
$filter->user->ajaxgetmore = new stdclass();
$filter->user->export = new stdclass();
$filter->repo->ajaxsynccommit = new stdclass();
$filter->repo->apigetrepobyurl = new stdclass();
$filter->search->index = new stdclass();
@@ -320,7 +322,8 @@ $filter->testtask->default->cookie['preProductID'] = 'int';
$filter->todo->export->cookie['checkedItem'] = 'reg::checked';
$filter->user->login->cookie['keepLogin'] = 'equal::on';
$filter->user->login->cookie['keepLogin'] = 'equal::on';
$filter->user->export->cookie['checkedItem'] = 'reg::any';
$filter->block->default->get['hash'] = 'reg::md5';
$filter->block->main->get['blockid'] = 'code';
@@ -359,13 +362,15 @@ $filter->sso->logout->get['token'] = 'reg::md5';
$filter->upgrade->license->get['agree'] = 'equal::true';
$filter->user->login->get['account'] = 'account';
$filter->user->login->get['lang'] = 'reg::lang';
$filter->user->login->get['password'] = 'reg::any';
$filter->user->edit->get['from'] = 'reg::word';
$filter->user->ajaxgetmore->get['search'] = 'reg::any';
$filter->user->ajaxgetmore->get['limit'] = 'int';
$filter->user->ajaxgetmore->get['params'] = 'reg::base64';
$filter->user->export->cookie['checkedItem'] = 'reg::checked';
$filter->user->login->cookie['keepLogin'] = 'equal::on';
$filter->user->login->get['account'] = 'account';
$filter->user->login->get['lang'] = 'reg::lang';
$filter->user->login->get['password'] = 'reg::any';
$filter->user->edit->get['from'] = 'reg::word';
$filter->user->ajaxgetmore->get['search'] = 'reg::any';
$filter->user->ajaxgetmore->get['limit'] = 'int';
$filter->user->ajaxgetmore->get['params'] = 'reg::base64';
$filter->git->cat->get['repoUrl'] = 'reg::base64';
$filter->git->diff->get['repoUrl'] = 'reg::base64';
+16 -16
View File
@@ -7,28 +7,28 @@ function ioncube_event_handler($err_code, $params)
<head>
<meta http-equiv='content-type' content='text/html; charset=utf-8' />
<style>
.btn {min-width: 120px; color: #fff; background-color: #0c64eb; border-color: transparent; display: inline-block; padding: 6px 12px; margin-bottom: 0; font-size: 13px; font-weight: 400; line-height: 18px; text-align: center; white-space: nowrap; vertical-align: middle; cursor: pointer; user-select: none; border: 1px solid transparent; border-radius: 4px; transition: .4s cubic-bezier(.175,.885,.32,1);}
.extension-btn {min-width: 120px; color: #fff; background-color: #0c64eb; border-color: transparent; display: inline-block; padding: 6px 12px; margin-bottom: 0; font-size: 13px; font-weight: 400; line-height: 18px; text-align: center; white-space: nowrap; vertical-align: middle; cursor: pointer; user-select: none; border: 1px solid transparent; border-radius: 4px; transition: .4s cubic-bezier(.175,.885,.32,1);}
a {text-decoration: none;}
</style>
<title>error</title>
</head>
<body>
<body style='font-size: 13px;'>
<h2 style='color:red;text-align:center'>您使用的插件已经过期</h2>
<p style='text-align:left; margin: 0px 20%;'>您的插件已过期,如果需要继续使用,请点击下载更新按钮,跳转到禅道官网插件页面进行下载后再更新插件。</p>
<p style='text-align:left; margin: 0px 20%;'>如果不需要继续使用,可以点击卸载插件按钮,跳转到插件页面卸载插件。</p>
<p style='text-align:left; margin: 0px 20%;'>如果您无法操作,请联系系统管理员进行处理。</p>
<p style='text-align:center'>
<a href='https://www.zentao.net/extension-browse.html' target='_blank' class='btn' style='margin-right: 20px;'>下载更新</a>
<a href='{$extensionLink}' target='_top' class='btn' style='background-color: #fff; border-color: #d6dae3; color: #3c4353;'>卸载插件</a>
<p style='text-align:center; margin: 13px 0px;'>
<a href='https://www.zentao.net/extension-browse.html' target='_blank' class='btn btn-wide btn-primary extension-btn' style='margin-right: 20px;'>下载更新</a>
<a href='{$extensionLink}' target='_top' class='btn btn-wide extension-btn' style='background-color: #fff; border-color: #d6dae3; color: #3c4353;'>卸载插件</a>
</p>
<br /> <br /> <br />
<h2 style='color:red;text-align:center'>Your plugin has expired</h2>
<p style='text-align:left; margin: 0px 20%;'>Your plugin has expired. If you need to keep using it, please click the 'Download Update' button to jump to the ZenTao plugin page to download and update.</p>
<p style='text-align:left; margin: 0px 20%;'>If you decide not to use the plugin, please click the 'Delete Plugin' button to jump to the plugins page to delete it.</p>
<p style='text-align:left; margin: 0px 20%;'>If you do not have permission, please contact the system administrator to deal with it.</p>
<p style='text-align:center'>
<a href='https://www.zentao.net/extension-browse.html' target='_blank' class='btn' style='margin-right: 20px;'>Download Update</a>
<a href='{$extensionLink}' target='_top' class='btn' style='background-color: #fff; border-color: #d6dae3; color: #3c4353;'>Delete Plugin</a>
<p style='text-align:center; margin: 13px 0px;'>
<a href='https://www.zentao.net/extension-browse.html' target='_blank' class='btn btn-wide btn-primary extension-btn' style='margin-right: 20px;'>Download Update</a>
<a href='{$extensionLink}' target='_top' class='btn btn-wide extension-btn' style='background-color: #fff; border-color: #d6dae3; color: #3c4353;'>Delete Plugin</a>
</p>
</body>
</html>
@@ -38,24 +38,24 @@ function ioncube_event_handler($err_code, $params)
<head>
<meta http-equiv='content-type' content='text/html; charset=utf-8' />
<style>
.btn {min-width: 120px; color: #fff; background-color: #0c64eb; border-color: transparent; display: inline-block; padding: 6px 12px; margin-bottom: 0; font-size: 13px; font-weight: 400; line-height: 18px; text-align: center; white-space: nowrap; vertical-align: middle; cursor: pointer; user-select: none; border: 1px solid transparent; border-radius: 4px; transition: .4s cubic-bezier(.175,.885,.32,1);}
.extension-btn {min-width: 120px; color: #fff; background-color: #0c64eb; border-color: transparent; display: inline-block; padding: 6px 12px; margin-bottom: 0; font-size: 13px; font-weight: 400; line-height: 18px; text-align: center; white-space: nowrap; vertical-align: middle; cursor: pointer; user-select: none; border: 1px solid transparent; border-radius: 4px; transition: .4s cubic-bezier(.175,.885,.32,1);}
a {text-decoration: none;}
</style>
<title>error</title>
</head>
<body>
<body style='font-size: 13px;'>
<h2 style='color:red;text-align:center'>错误的IP地址或MAC地址,或错误的域名访问</h2>
<p style='text-align:left; margin: 0px 20%;'>软件授权的IP地址或MAC地址和当前系统的IP地址或MAC地址不一致,请使用最初授权的服务器。或你访问的域名与绑定的域名不一致。</p>
<p style='text-align:center'>
<a href='https://www.zentao.net/extension-browse.html' target='_blank' class='btn' style='margin-right: 20px;'>下载更新</a>
<a href='{$extensionLink}' target='_top' class='btn' style='background-color: #fff; border-color: #d6dae3; color: #3c4353;'>卸载插件</a>
<p style='text-align:center; margin: 13px 0px;'>
<a href='https://www.zentao.net/extension-browse.html' target='_blank' class='btn btn-wide btn-primary extension-btn' style='margin-right: 20px;'>下载更新</a>
<a href='{$extensionLink}' target='_top' class='btn btn-wide extension-btn' style='background-color: #fff; border-color: #d6dae3; color: #3c4353;'>卸载插件</a>
</p>
<br /> <br /> <br />
<h2 style='color:red;text-align:center'>Wrong IP, MAC address, or domains!</h2>
<p style='text-align:left; margin: 0px 20%;'>The IP, MAC address, or the domains of your server is not the same one in your license.</p>
<p style='text-align:center'>
<a href='https://www.zentao.net/extension-browse.html' target='_blank' class='btn' style='margin-right: 20px;'>Download Update</a>
<a href='{$extensionLink}' target='_top' class='btn' style='background-color: #fff; border-color: #d6dae3; color: #3c4353;' data-app='execution'>Delete Plugin</a>
<p style='text-align:center; margin: 13px 0px;'>
<a href='https://www.zentao.net/extension-browse.html' target='_blank' class='btn btn-wide btn-primary extension-btn' style='margin-right: 20px;'>Download Update</a>
<a href='{$extensionLink}' target='_top' class='btn btn-wide extension-btn' style='background-color: #fff; border-color: #d6dae3; color: #3c4353;'>Delete Plugin</a>
</p>
</body>
</html>
+2939 -2896
View File
File diff suppressed because one or more lines are too long
+44 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
a:2:{i:0;O:8:"stdClass":12:{s:2:"id";s:1:"1";s:3:"lib";s:1:"0";s:4:"name";s:3:"aaa";s:4:"type";s:8:"formData";s:4:"desc";s:0:"";s:7:"version";s:1:"1";s:9:"attribute";s:137:"[{"field":"aaa","paramsType":"object","required":"","desc":"","structType":"formData","sub":1,"key":"l11gznwwu2chih9mc28","children":[]}]";s:7:"addedBy";s:5:"admin";s:9:"addedDate";s:19:"2022-03-22 09:40:40";s:8:"editedBy";s:5:"admin";s:10:"editedDate";s:19:"2022-03-22 09:40:40";s:7:"deleted";s:1:"0";}i:1;O:8:"stdClass":12:{s:2:"id";s:1:"2";s:3:"lib";s:2:"10";s:4:"name";s:4:"user";s:4:"type";s:4:"json";s:4:"desc";s:0:"";s:7:"version";s:1:"2";s:9:"attribute";s:537:"[{"field":"id","paramsType":"int","required":"","desc":"","structType":"json","sub":1,"key":"kwoq04srulxevt93a3h","children":[]},{"field":"account","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0a387on1wpuwntd","children":[]},{"field":"realname","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0i4g80qyu8lqp28","children":[]},{"field":"avatar","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0le57o2p6vxc8ov","children":[]}]";s:7:"addedBy";s:5:"admin";s:9:"addedDate";s:19:"2022-03-29 09:22:00";s:8:"editedBy";s:5:"admin";s:10:"editedDate";s:19:"2022-03-29 09:22:00";s:7:"deleted";s:1:"0";}}
a:2:{i:0;O:8:"stdClass":12:{s:2:"id";s:1:"5";s:3:"lib";s:2:"19";s:4:"name";s:3:"aaa";s:4:"type";s:8:"formData";s:4:"desc";s:0:"";s:7:"version";s:1:"1";s:9:"attribute";s:137:"[{"field":"aaa","paramsType":"object","required":"","desc":"","structType":"formData","sub":1,"key":"l11gznwwu2chih9mc28","children":[]}]";s:7:"addedBy";s:5:"admin";s:9:"addedDate";s:19:"2022-06-06 08:19:35";s:8:"editedBy";s:5:"admin";s:10:"editedDate";s:19:"2022-06-06 08:19:35";s:7:"deleted";s:1:"0";}i:1;O:8:"stdClass":12:{s:2:"id";s:1:"6";s:3:"lib";s:2:"19";s:4:"name";s:4:"user";s:4:"type";s:4:"json";s:4:"desc";s:0:"";s:7:"version";s:1:"2";s:9:"attribute";s:537:"[{"field":"id","paramsType":"int","required":"","desc":"","structType":"json","sub":1,"key":"kwoq04srulxevt93a3h","children":[]},{"field":"account","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0a387on1wpuwntd","children":[]},{"field":"realname","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0i4g80qyu8lqp28","children":[]},{"field":"avatar","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0le57o2p6vxc8ov","children":[]}]";s:7:"addedBy";s:5:"admin";s:9:"addedDate";s:19:"2022-06-06 08:19:35";s:8:"editedBy";s:5:"admin";s:10:"editedDate";s:19:"2022-06-06 08:19:35";s:7:"deleted";s:1:"0";}}
+1 -1
View File
@@ -1 +1 @@
a:3:{i:0;O:8:"stdClass":8:{s:2:"id";s:1:"1";s:4:"name";s:3:"aaa";s:4:"type";s:8:"formData";s:4:"desc";s:0:"";s:9:"attribute";s:137:"[{"field":"aaa","paramsType":"object","required":"","desc":"","structType":"formData","sub":1,"key":"l11gznwwu2chih9mc28","children":[]}]";s:7:"version";s:1:"1";s:7:"addedBy";s:5:"admin";s:9:"addedDate";s:19:"2022-03-22 09:40:40";}i:1;O:8:"stdClass":8:{s:2:"id";s:1:"2";s:4:"name";s:4:"user";s:4:"type";s:4:"json";s:4:"desc";s:0:"";s:9:"attribute";s:537:"[{"field":"id","paramsType":"int","required":"","desc":"","structType":"json","sub":1,"key":"kwoq04srulxevt93a3h","children":[]},{"field":"account","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0a387on1wpuwntd","children":[]},{"field":"realname","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0i4g80qyu8lqp28","children":[]},{"field":"avatar","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0le57o2p6vxc8ov","children":[]}]";s:7:"version";s:1:"1";s:7:"addedBy";s:5:"admin";s:9:"addedDate";s:19:"2022-03-29 09:22:00";}i:2;O:8:"stdClass":8:{s:2:"id";s:1:"3";s:4:"name";s:4:"user";s:4:"type";s:4:"json";s:4:"desc";s:0:"";s:9:"attribute";s:537:"[{"field":"id","paramsType":"int","required":"","desc":"","structType":"json","sub":1,"key":"kwoq04srulxevt93a3h","children":[]},{"field":"account","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0a387on1wpuwntd","children":[]},{"field":"realname","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0i4g80qyu8lqp28","children":[]},{"field":"avatar","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0le57o2p6vxc8ov","children":[]}]";s:7:"version";s:1:"2";s:7:"addedBy";s:5:"admin";s:9:"addedDate";s:19:"2022-03-29 09:22:00";}}
a:3:{i:0;O:8:"stdClass":8:{s:2:"id";s:1:"9";s:4:"name";s:4:"user";s:4:"type";s:4:"json";s:4:"desc";s:0:"";s:9:"attribute";s:537:"[{"field":"id","paramsType":"int","required":"","desc":"","structType":"json","sub":1,"key":"kwoq04srulxevt93a3h","children":[]},{"field":"account","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0a387on1wpuwntd","children":[]},{"field":"realname","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0i4g80qyu8lqp28","children":[]},{"field":"avatar","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0le57o2p6vxc8ov","children":[]}]";s:7:"version";s:1:"2";s:7:"addedBy";s:5:"admin";s:9:"addedDate";s:19:"2022-06-06 08:19:35";}i:1;O:8:"stdClass":8:{s:2:"id";s:1:"7";s:4:"name";s:3:"aaa";s:4:"type";s:8:"formData";s:4:"desc";s:0:"";s:9:"attribute";s:137:"[{"field":"aaa","paramsType":"object","required":"","desc":"","structType":"formData","sub":1,"key":"l11gznwwu2chih9mc28","children":[]}]";s:7:"version";s:1:"1";s:7:"addedBy";s:5:"admin";s:9:"addedDate";s:19:"2022-06-06 08:19:35";}i:2;O:8:"stdClass":8:{s:2:"id";s:1:"8";s:4:"name";s:4:"user";s:4:"type";s:4:"json";s:4:"desc";s:0:"";s:9:"attribute";s:537:"[{"field":"id","paramsType":"int","required":"","desc":"","structType":"json","sub":1,"key":"kwoq04srulxevt93a3h","children":[]},{"field":"account","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0a387on1wpuwntd","children":[]},{"field":"realname","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0i4g80qyu8lqp28","children":[]},{"field":"avatar","paramsType":"string","required":"","desc":"","structType":"json","sub":1,"key":"kwoq0le57o2p6vxc8ov","children":[]}]";s:7:"version";s:1:"1";s:7:"addedBy";s:5:"admin";s:9:"addedDate";s:19:"2022-06-06 08:19:35";}}
+1 -1
View File
@@ -1 +1 @@
a:14:{i:0;O:8:"stdClass":13:{s:2:"id";s:2:"19";s:4:"root";s:2:"10";s:6:"branch";s:1:"0";s:4:"name";s:6:"需求";s:6:"parent";s:1:"0";s:4:"path";s:4:",19,";s:5:"grade";s:1:"1";s:5:"order";s:2:"70";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:1;O:8:"stdClass":13:{s:2:"id";s:2:"18";s:4:"root";s:2:"10";s:6:"branch";s:1:"0";s:4:"name";s:6:"任务";s:6:"parent";s:1:"0";s:4:"path";s:4:",18,";s:5:"grade";s:1:"1";s:5:"order";s:3:"110";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:2;O:8:"stdClass":13:{s:2:"id";s:2:"17";s:4:"root";s:2:"10";s:6:"branch";s:1:"0";s:4:"name";s:3:"Bug";s:6:"parent";s:1:"0";s:4:"path";s:4:",17,";s:5:"grade";s:1:"1";s:5:"order";s:3:"120";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:3;O:8:"stdClass":13:{s:2:"id";s:2:"16";s:4:"root";s:2:"10";s:6:"branch";s:1:"0";s:4:"name";s:6:"用例";s:6:"parent";s:1:"0";s:4:"path";s:4:",16,";s:5:"grade";s:1:"1";s:5:"order";s:3:"130";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:4;O:8:"stdClass":13:{s:2:"id";s:2:"15";s:4:"root";s:2:"10";s:6:"branch";s:1:"0";s:4:"name";s:12:"产品计划";s:6:"parent";s:1:"0";s:4:"path";s:4:",15,";s:5:"grade";s:1:"1";s:5:"order";s:2:"50";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:5;O:8:"stdClass":13:{s:2:"id";s:2:"14";s:4:"root";s:2:"10";s:6:"branch";s:1:"0";s:4:"name";s:6:"发布";s:6:"parent";s:1:"0";s:4:"path";s:4:",14,";s:5:"grade";s:1:"1";s:5:"order";s:2:"60";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:6;O:8:"stdClass":13:{s:2:"id";s:2:"13";s:4:"root";s:2:"10";s:6:"branch";s:1:"0";s:4:"name";s:9:"测试单";s:6:"parent";s:1:"0";s:4:"path";s:4:",13,";s:5:"grade";s:1:"1";s:5:"order";s:3:"140";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:7;O:8:"stdClass":13:{s:2:"id";s:2:"12";s:4:"root";s:2:"10";s:6:"branch";s:1:"0";s:4:"name";s:6:"版本";s:6:"parent";s:1:"0";s:4:"path";s:4:",12,";s:5:"grade";s:1:"1";s:5:"order";s:2:"90";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:8;O:8:"stdClass":13:{s:2:"id";s:2:"11";s:4:"root";s:2:"10";s:6:"branch";s:1:"0";s:4:"name";s:6:"用户";s:6:"parent";s:1:"0";s:4:"path";s:4:",11,";s:5:"grade";s:1:"1";s:5:"order";s:2:"20";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:9;O:8:"stdClass":13:{s:2:"id";s:2:"20";s:4:"root";s:2:"10";s:6:"branch";s:1:"0";s:4:"name";s:6:"执行";s:6:"parent";s:1:"0";s:4:"path";s:4:",20,";s:5:"grade";s:1:"1";s:5:"order";s:3:"100";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:10;O:8:"stdClass":13:{s:2:"id";s:2:"21";s:4:"root";s:2:"10";s:6:"branch";s:1:"0";s:4:"name";s:6:"项目";s:6:"parent";s:1:"0";s:4:"path";s:4:",21,";s:5:"grade";s:1:"1";s:5:"order";s:2:"80";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:11;O:8:"stdClass":13:{s:2:"id";s:2:"22";s:4:"root";s:2:"10";s:6:"branch";s:1:"0";s:4:"name";s:6:"产品";s:6:"parent";s:1:"0";s:4:"path";s:4:",22,";s:5:"grade";s:1:"1";s:5:"order";s:2:"40";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:12;O:8:"stdClass":13:{s:2:"id";s:2:"23";s:4:"root";s:2:"10";s:6:"branch";s:1:"0";s:4:"name";s:9:"项目集";s:6:"parent";s:1:"0";s:4:"path";s:4:",23,";s:5:"grade";s:1:"1";s:5:"order";s:2:"30";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:13;O:8:"stdClass":13:{s:2:"id";s:2:"24";s:4:"root";s:2:"10";s:6:"branch";s:1:"0";s:4:"name";s:5:"Token";s:6:"parent";s:1:"0";s:4:"path";s:4:",24,";s:5:"grade";s:1:"1";s:5:"order";s:2:"10";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}}
a:14:{i:0;O:8:"stdClass":13:{s:2:"id";s:2:"56";s:4:"root";s:2:"19";s:6:"branch";s:1:"0";s:4:"name";s:9:"项目集";s:6:"parent";s:1:"0";s:4:"path";s:4:",56,";s:5:"grade";s:1:"1";s:5:"order";s:2:"30";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:1;O:8:"stdClass":13:{s:2:"id";s:2:"55";s:4:"root";s:2:"19";s:6:"branch";s:1:"0";s:4:"name";s:6:"产品";s:6:"parent";s:1:"0";s:4:"path";s:4:",55,";s:5:"grade";s:1:"1";s:5:"order";s:2:"40";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:2;O:8:"stdClass":13:{s:2:"id";s:2:"54";s:4:"root";s:2:"19";s:6:"branch";s:1:"0";s:4:"name";s:6:"项目";s:6:"parent";s:1:"0";s:4:"path";s:4:",54,";s:5:"grade";s:1:"1";s:5:"order";s:2:"80";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:3;O:8:"stdClass":13:{s:2:"id";s:2:"53";s:4:"root";s:2:"19";s:6:"branch";s:1:"0";s:4:"name";s:6:"执行";s:6:"parent";s:1:"0";s:4:"path";s:4:",53,";s:5:"grade";s:1:"1";s:5:"order";s:3:"100";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:4;O:8:"stdClass":13:{s:2:"id";s:2:"52";s:4:"root";s:2:"19";s:6:"branch";s:1:"0";s:4:"name";s:6:"用户";s:6:"parent";s:1:"0";s:4:"path";s:4:",52,";s:5:"grade";s:1:"1";s:5:"order";s:2:"20";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:5;O:8:"stdClass":13:{s:2:"id";s:2:"51";s:4:"root";s:2:"19";s:6:"branch";s:1:"0";s:4:"name";s:6:"版本";s:6:"parent";s:1:"0";s:4:"path";s:4:",51,";s:5:"grade";s:1:"1";s:5:"order";s:2:"90";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:6;O:8:"stdClass":13:{s:2:"id";s:2:"50";s:4:"root";s:2:"19";s:6:"branch";s:1:"0";s:4:"name";s:9:"测试单";s:6:"parent";s:1:"0";s:4:"path";s:4:",50,";s:5:"grade";s:1:"1";s:5:"order";s:3:"140";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:7;O:8:"stdClass":13:{s:2:"id";s:2:"49";s:4:"root";s:2:"19";s:6:"branch";s:1:"0";s:4:"name";s:6:"发布";s:6:"parent";s:1:"0";s:4:"path";s:4:",49,";s:5:"grade";s:1:"1";s:5:"order";s:2:"60";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:8;O:8:"stdClass":13:{s:2:"id";s:2:"48";s:4:"root";s:2:"19";s:6:"branch";s:1:"0";s:4:"name";s:12:"产品计划";s:6:"parent";s:1:"0";s:4:"path";s:4:",48,";s:5:"grade";s:1:"1";s:5:"order";s:2:"50";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:9;O:8:"stdClass":13:{s:2:"id";s:2:"47";s:4:"root";s:2:"19";s:6:"branch";s:1:"0";s:4:"name";s:6:"用例";s:6:"parent";s:1:"0";s:4:"path";s:4:",47,";s:5:"grade";s:1:"1";s:5:"order";s:3:"130";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:10;O:8:"stdClass":13:{s:2:"id";s:2:"46";s:4:"root";s:2:"19";s:6:"branch";s:1:"0";s:4:"name";s:3:"Bug";s:6:"parent";s:1:"0";s:4:"path";s:4:",46,";s:5:"grade";s:1:"1";s:5:"order";s:3:"120";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:11;O:8:"stdClass":13:{s:2:"id";s:2:"45";s:4:"root";s:2:"19";s:6:"branch";s:1:"0";s:4:"name";s:6:"任务";s:6:"parent";s:1:"0";s:4:"path";s:4:",45,";s:5:"grade";s:1:"1";s:5:"order";s:3:"110";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:12;O:8:"stdClass":13:{s:2:"id";s:2:"44";s:4:"root";s:2:"19";s:6:"branch";s:1:"0";s:4:"name";s:6:"需求";s:6:"parent";s:1:"0";s:4:"path";s:4:",44,";s:5:"grade";s:1:"1";s:5:"order";s:2:"70";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}i:13;O:8:"stdClass":13:{s:2:"id";s:2:"57";s:4:"root";s:2:"19";s:6:"branch";s:1:"0";s:4:"name";s:5:"Token";s:6:"parent";s:1:"0";s:4:"path";s:4:",57,";s:5:"grade";s:1:"1";s:5:"order";s:2:"10";s:4:"type";s:3:"api";s:5:"owner";s:0:"";s:9:"collector";s:0:"";s:5:"short";s:0:"";s:7:"deleted";s:1:"0";}}
+15 -7
View File
@@ -1,3 +1,11 @@
禅道项目管理软件使用 Z PUBLIC LICENSE(以下简称ZPL) 1.2 和 Affero General Public License(以下简称AGPL) 双授权协议。
默认使用ZPL协议,您也可以选择遵守AGPL协议使用我们的软件。
ZenTao Project Management Software is licensed under the Z PUBLIC LICENSE (ZPL) 1.2 and the Affero General Public License (AGPL).
The ZPL is applied by default, or you can choose to use our software under the AGPL.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
Z PUBLIC LICENSE 1.2
许可
@@ -18,7 +26,7 @@ Z PUBLIC LICENSE 由青岛易软天创网络科技有限公司(www.easycorp.cn
电话: 4006-8899-23
Email co@zentao.net
QQ 1492153927
地址: 青岛开发区长江路232号国贸中心C座2单元2902室
地址: 青岛开发区长江路金石国际广场A座3205
约定:
@@ -35,8 +43,8 @@ QQ 1492153927
该软件是以开放源代码的方式发行,您使用该软件无需任何费用,因此在使用该软件前,您须知晓:
1.1 我没有对该软件提供任何技术支持的义务,您可联系我购买商业的技术支持。
1.2 我对因使用该软件而产生直接或间接的任何问题不负任何责任。
1.1 我没有对该软件提供任何技术支持的义务,您可联系我购买商业的技术支持。
1.2 我对因使用该软件而产生直接或间接的任何问题不负任何责任。
1.3 开源不等于免费,开源不等于无版权,开源软件的发展需要您我共同的努力。
二、自用该软件
@@ -77,10 +85,10 @@ QQ 1492153927
6.1 我欢迎并感谢您为该软件开发衍生作品。
6.2 您开发的衍生作品中涉及到对该软件源代码改动的地方,须遵循如下条款:
6.2.1 如修改了该软件的源代码,须依据本协议发布修改后的源代码。
6.2.2 如修改了该软件的源代码,须保留代码里面该软件原有的所有标志。
6.2.3 您可以在代码中追加您自己的标志。
6.2.4 您可以对您开发的衍生作品进行收费。
6.2.1 如修改了该软件的源代码,须依据本协议发布修改后的源代码。
6.2.2 如修改了该软件的源代码,须保留代码里面该软件原有的所有标志。
6.2.3 您可以在代码中追加您自己的标志。
6.2.4 您可以对您开发的衍生作品进行收费。
6.2.5 第三方的用户可在遵循6.2所有条款下可继续在您开发的衍生作品基础上进行修改并发布。
6.3 您开发的衍生作品中独立于本软件开发的代码,可以源代码或二进制的方式进行发布,可免费或收费发布。
+1
View File
@@ -359,6 +359,7 @@ class gitlab
if($parent == '.') $parent = '/';
if($parent == '') $parent = '/';
$list = $this->tree($parent, 0);
$file = new stdclass();
foreach($list as $node) if($node->path == $entry) $file = $node;
+2
View File
@@ -0,0 +1,2 @@
.c-leftStories {width: 95px;}
.c-leftTasks, .c-consumed, .c-leftBugs {width: 85px;}
+4 -4
View File
@@ -14,11 +14,11 @@
<th class='c-status'><?php echo $lang->project->status;?></th>
<?php if($longBlock):?>
<th class='c-number'><?php echo $lang->project->teamCount;?></th>
<th class='c-number text-right'><?php echo $lang->task->consumed;?></th>
<th class='c-number text-right c-consumed'><?php echo $lang->task->consumed;?></th>
<th class='c-budget text-right'><?php echo $lang->project->budget;?></th>
<th class='c-number'><?php echo $lang->project->leftStories;?></th>
<th class='c-number'><?php echo $lang->project->leftTasks;?></th>
<th class='c-number'><?php echo $lang->project->leftBugs;?></th>
<th class='c-number c-leftStories'><?php echo $lang->project->leftStories;?></th>
<th class='c-number c-leftTasks'><?php echo $lang->project->leftTasks;?></th>
<th class='c-number c-leftBugs'><?php echo $lang->project->leftBugs;?></th>
<?php endif;?>
</tr>
</thead>
+13 -2
View File
@@ -982,8 +982,15 @@ class bug extends control
$executionID = $bug->execution;
$projectID = $bug->project;
$currentModuleID = $bug->module;
$product = $this->loadModel('product')->getByID($productID);
$this->bug->checkBugExecutionPriv($bug);
if(!isset($this->products[$bug->product]))
{
$this->products[$bug->product] = $product->name;
$this->view->products = $this->products;
}
/* Set the menu. */
if($this->app->tab == 'project') $this->loadModel('project')->setMenu($bug->project);
if($this->app->tab == 'execution') $this->loadModel('execution')->setMenu($bug->execution);
@@ -1010,7 +1017,7 @@ class bug extends control
{
$products = array();
$productList = $this->config->CRProduct ? $this->product->getOrderedProducts('all', 40, $bug->project) : $this->product->getOrderedProducts('normal', 40, $bug->project);
foreach($productList as $product) $products[$product->id] = $product->name;
foreach($productList as $productInfo) $products[$productInfo->id] = $productInfo->name;
$this->view->products = $products;
}
@@ -1020,7 +1027,6 @@ class bug extends control
$this->view->position[] = $this->lang->bug->edit;
/* Assign. */
$product = $this->loadModel('product')->getByID($productID);
$allBuilds = $this->loadModel('build')->getBuildPairs($productID, 'all', 'noempty');
if($executionID)
{
@@ -1064,6 +1070,11 @@ class bug extends control
$branchOption[$branchInfo->id] = $branchInfo->name;
$branchTagOption[$branchInfo->id] = $branchInfo->name . ($branchInfo->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : '');
}
if(!isset($branchTagOption[$bug->branch]))
{
$bugBranch = $this->branch->getById($bug->branch, $bug->product, '');
$branchTagOption[$bug->branch] = $bug->branch == BRANCH_MAIN ? $bugBranch : ($bugBranch->name . ($bugBranch->status == 'closed' ? ' (' . $this->lang->branch->statusList['closed'] . ')' : ''));
}
$moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0, $bug->branch);
if(!isset($moduleOptionMenu[$bug->module])) $moduleOptionMenu += $this->tree->getModulesName($bug->module);
+3 -2
View File
@@ -629,7 +629,8 @@ function loadProductBranches(productID, param)
$('#branch').next('.picker').remove();
var branchStatus = page == 'create' ? 'active' : 'all';
var param = "productID=" + productID + "&oldBranch=0&param=" + branchStatus;
var oldBranch = page == 'edit' ? bugBranch : 0;
var param = "productID=" + productID + "&oldBranch=" + oldBranch + "&param=" + branchStatus;
if(typeof(tab) != 'undefined' && (tab == 'execution' || tab == 'project')) param += "&projectID=" + objectID;
$.get(createLink('branch', 'ajaxGetBranches', param), function(data)
{
@@ -713,7 +714,7 @@ function notice()
if(typeof(branch) == 'undefined') branch = 0;
var link = createLink('release', 'create', 'productID=' + $('#product').val() + '&branch=' + branch);
if(config.onlybody != 'yes') link += link.indexOf('?') >= 0 ? '&onlybody=yes' : '?onlybody=yes';
html += '<a href="' + link + '" data-toggle="modal" data-type="iframe" style="padding-right:5px">' + createBuild + '</a> ';
html += '<a href="' + link + '" data-toggle="modal" data-type="iframe" style="padding-right:5px">' + createRelease + '</a> ';
html += '<a href="javascript:loadProductBuilds(' + $('#product').val() + ')">' + refresh + '</a>';
}
else
+1
View File
@@ -27,6 +27,7 @@ js::set('oldResolvedBuild' , $bug->resolvedBuild);
js::set('systemMode' , $config->systemMode);
js::set('confirmUnlinkBuild' , sprintf($lang->bug->confirmUnlinkBuild, zget($resolvedBuilds, $bug->resolvedBuild)));
js::set('tab' , $this->app->tab);
js::set('bugBranch' , $bug->branch);
if($this->app->tab == 'execution') js::set('objectID', $bug->execution);
if($this->app->tab == 'project') js::set('objectID', $bug->project);
?>
+1
View File
@@ -1 +1,2 @@
#branch_chosen .chosen-single {border-left: 0px;}
#noProduct {display: inline-block; width: 110%;}
+1 -1
View File
@@ -46,7 +46,7 @@ $lang->collapseMenu = 'Collapse';
$lang->preference = 'Preference';
$lang->tutorialAB = 'Tutorial';
$lang->runInfo = "<div class='row'><div class='u-1 a-center' id='debugbar'>Time %s MS, Memory %s KB, Query %s. </div></div>";
$lang->agreement = "I have read and agreed to the terms and conditions of <a href='http://zpl.pub/page/zplv12.html' target='_blank'> Z PUBLIC LICENSE 1.2 </a>. <span class='text-danger'>Without authorization, I should not remove, hide or cover any logos/links of ZenTao.</span>";
$lang->agreement = "I have read and agreed to the terms and conditions. <span class='text-danger'>Without authorization, I should not remove, hide or cover any logos/links of ZenTao.</span>";
$lang->designedByAIUX = "<a href='https://api.zentao.net/goto.php?item=aiux' class='link-aiux' target='_blank'><i class='icon icon-aiux'></i> AIUX</a>";
$lang->reset = 'Reset';
+1 -1
View File
@@ -46,7 +46,7 @@ $lang->collapseMenu = '收起导航';
$lang->preference = '个性化设置';
$lang->tutorialAB = '新手引导';
$lang->runInfo = "<div class='row'><div class='u-1 a-center' id='debugbar'>时间: %s 毫秒, 内存: %s KB, 查询: %s. </div></div>";
$lang->agreement = "已阅读并同意<a href='http://zpl.pub/page/zplv12.html' target='_blank'>《Z PUBLIC LICENSE授权协议1.2》</a>。<span class='text-danger'>未经许可,不得去除、隐藏或遮掩禅道软件的任何标志及链接。</span>";
$lang->agreement = "已阅读并同意。<span class='text-danger'>未经许可,不得去除、隐藏或遮掩禅道软件的任何标志及链接。</span>";
$lang->designedByAIUX = "<a href='https://api.zentao.net/goto.php?item=aiux' class='link-aiux' target='_blank'><i class='icon icon-aiux'></i> 艾体验设计</a>";
$lang->reset = '重填';
+6
View File
@@ -2404,6 +2404,12 @@ EOD;
$rights = $app->user->rights['rights'];
$acls = $app->user->rights['acls'];
/* White list of import method. */
if(in_array($module, array('user', 'task', 'story', 'bug', 'testcase')) and $method == 'showimport')
{
if(isset($rights[$module]['import']) and commonModel::hasDBPriv($object, $module, 'import')) return true;
}
if(isset($rights[$module][$method]))
{
if(!commonModel::hasDBPriv($object, $module, $method)) return false;
+3
View File
@@ -73,6 +73,9 @@ class company extends control
/* Get users. */
$users = $this->company->getUsers($browseType, $type, $queryID, $deptID, $sort, $pager);
/* Process the sql, get the conditon partion, save it to session. */
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'user', true);
/* Remove passwd. */
foreach($users as $user) unset($user->password);
+2
View File
@@ -5,3 +5,5 @@
#userList tbody td {white-space: nowrap; overflow: hidden;}
.space-sm + .text-center {display: none;}
.c-role, .c-company, .c-visits {width: 90px;}
.btn-group a.btn-primary {border-right: 1px solid rgba(255,255,255,0.3);}
+24 -12
View File
@@ -29,19 +29,31 @@ js::set('confirmDelete', $lang->user->confirmDelete);
<a class="btn btn-link querybox-toggle" id='bysearchTab'><i class="icon icon-search muted"></i> <?php echo $lang->user->search;?></a>
</div>
<div class='btn-toolbar pull-right'>
<?php common::printLink('user', 'batchCreate', "dept={$deptID}", "<i class='icon icon-plus'></i> " . $lang->user->batchCreate, '', "class='btn btn-secondary'");?>
<?php if(commonModel::isTutorialMode()):?>
<?php
if(commonModel::isTutorialMode())
{
$wizardParams = helper::safe64Encode("dept=$deptID");
$link = $this->createLink('tutorial', 'wizard', "module=user&method=create&params=$wizardParams");
echo html::a($link, "<i class='icon icon-plus'></i> {$lang->user->create}", '', "class='btn btn-primary create-user-btn'");
}
else
{
common::printLink('user', 'create', "dept={$deptID}", "<i class='icon icon-plus'></i> " . $lang->user->create, '', "class='btn btn-primary create-user-btn'");
}
$wizardParams = helper::safe64Encode("dept=$deptID");
$link = $this->createLink('tutorial', 'wizard', "module=user&method=create&params=$wizardParams");
echo html::a($link, "<i class='icon icon-plus'></i> {$lang->user->create}", '', "class='btn btn-primary create-user-btn'");
?>
<?php else:?>
<?php if(common::hasPriv('user', 'create') and common::hasPriv('user', 'batchCreate')):?>
<?php
$createUserLink = $this->createLink('user', 'create', "dept={$deptID}");
$batchCreateUserLink = $this->createLink('user', 'batchCreate', "dept={$deptID}");
?>
<div class='btn-group dropdown'>
<?php common::printLink('user', 'create', "dept={$deptID}", "<i class='icon icon-plus'></i> " . $lang->user->create, '', "class='btn btn-primary create-user-btn'");?>
<button type='button' class='btn btn-primary dropdown-toggle' data-toggle='dropdown'><span class='caret'></span></button>
<ul class='dropdown-menu'>
<li><?php echo html::a($createUserLink, $lang->user->create);?></li>
<li><?php echo html::a($batchCreateUserLink, $lang->user->batchCreate);?></li>
</ul>
</div>
<?php else:?>
<?php common::printLink('user', 'batchCreate', "dept={$deptID}", "<i class='icon icon-plus'></i> " . $lang->user->batchCreate, '', "class='btn btn-secondary'");?>
<?php common::printLink('user', 'create', "dept={$deptID}", "<i class='icon icon-plus'></i> " . $lang->user->create, '', "class='btn btn-primary'");?>
<?php endif;?>
<?php endif;?>
</div>
</div>
<div id='mainContent' class='main-row fade'>
@@ -93,7 +105,7 @@ js::set('confirmDelete', $lang->user->confirmDelete);
<tr>
<td class='c-id'>
<?php if($canBatchEdit):?>
<?php echo html::checkbox('users', array($user->account => '')) . sprintf('%03d', $user->id);?>
<?php echo html::checkbox('users', array($user->id => '')) . sprintf('%03d', $user->id);?>
<?php else:?>
<?php printf('%03d', $user->id);?>
<?php endif;?>
+1 -1
View File
@@ -562,7 +562,7 @@ class custom extends control
{
if($_POST)
{
$this->loadModel('setting')->setItem("system.common.CRKanban@{$this->config->vision}", $this->post->kanban);
$this->loadModel('setting')->setItem("system.common.CRKanban", $this->post->kanban);
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => 'reload'));
}
-12
View File
@@ -527,12 +527,6 @@ class doc extends control
if(!(defined('RUN_MODE') && RUN_MODE == 'api')) $this->locate($browseLink);
}
if($doc->contentType == 'markdown')
{
$doc->content = commonModel::processMarkdown($doc->content);
$doc->digest = commonModel::processMarkdown($doc->digest);
}
/* Check priv when lib is product or project. */
$lib = $this->doc->getLibByID($doc->lib);
$type = $lib->type;
@@ -998,12 +992,6 @@ class doc extends control
$doc->keywords = str_replace("", ',', $doc->keywords);
$doc->keywords = explode(',', $doc->keywords);
}
if($doc->contentType == 'markdown')
{
$doc->content = commonModel::processMarkdown($doc->content);
$doc->digest = commonModel::processMarkdown($doc->digest);
}
}
if(isset($doc) and ($doc->type == 'text' || $doc->type == 'article'))
+2
View File
@@ -18,6 +18,8 @@
#content .title {max-width: 54%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
#content .detail-content {padding-left: 10px;}
#mainContent .scrollbar-hover {max-height: 2000px; overflow: scroll;}
#content .editor-preview {background: #fff}
#content .CodeMirror{border: none}
#sidebar {width: 275px;}
#sidebar>.cell {width: 100%;}
#sidebar>.sidebar-toggle {left: 3px; right: auto;}
+19
View File
@@ -100,6 +100,10 @@
echo "</div></div>";
}
}
elseif($doc->contentType == 'markdown')
{
echo "<textarea id='markdownContent' /></textarea>";
}
else
{
echo $doc->content;
@@ -283,3 +287,18 @@
</div>
<?php endif;?>
<?php include '../../common/view/syntaxhighlighter.html.php';?>
<?php if($doc->contentType == 'markdown'):?>
<?php css::import($jsRoot . "markdown/simplemde.min.css");?>
<?php js::import($jsRoot . 'markdown/simplemde.min.js'); ?>
<?php js::set('markdownText', $doc->content);?>
<script>
$(function()
{
var simplemde = new SimpleMDE({element: $("#markdownContent")[0],toolbar:false, status: false});
simplemde.value(markdownText);
simplemde.togglePreview();
$('#content .CodeMirror .editor-preview a').attr('target', '_blank');
})
</script>
<?php endif;?>
+7 -5
View File
@@ -4,7 +4,7 @@
.table tbody > tr.table-children.table-child-top {border-top: 2px solid #cbd0db;}
.table tbody > tr.table-children.table-child-bottom {border-bottom: 2px solid #cbd0db;}
.table td.has-child > a:not(.plan-toggle) {max-width: 90%; max-width: calc(100% - 30px); display: inline-block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
.table td.has-child > .plan-toggle {color: #838a9d; position: relative; top: 1px;}
.table td.has-child > .plan-toggle {color: #838a9d; position: relative; top: 1px;overflow: initial !important;}
.table td.has-child > .plan-toggle:hover {color: #006af1; cursor: pointer;}
.table td.has-child > .plan-toggle > .icon {font-size: 16px; display: inline-block; transition: transform .2s; -ms-transform:rotate(-90deg); -moz-transform:rotate(-90deg); -o-transform:rotate(-90deg); -webkit-transform:rotate(-90deg); transform: rotate(-90deg);}
.table td.has-child > .plan-toggle > .icon:before {text-align: left;}
@@ -14,17 +14,19 @@
td.hours {text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
td.flex {display: flex; flex-flow: row nowrap; justify-content: flex-start; align-items: center;}
td.flex span.label-badge {margin-left: 5px; min-width: 50px;}
td.flex span.label-badge.label-light {min-width: 22px;}
td.flex span.project-type-label {margin-left: 5px; min-width: 36px;}
@-moz-document url-prefix() {.main-table tbody > tr.table-children > td:first-child::before {width: 4px;}}
.c-status, .c-date, .c-percent, .c-attribute {width: 80px;}
.c-status, .c-date, .c-percent, .c-attribute, .c-end, .c-begin {width: 80px;}
.c-estimate, .c-consumed, .c-left, .c-pm {width: 70px;}
.c-progress, .c-burn {width: 60px;}
.c-code, .c-percent, .c-realBegan, .c-end, .c-begin, .c-realEnd{width: 100px;}
.c-action {text-align: center;}
.c-progress {width: 40px;}
.c-burn {width: 60px;}
.c-code, .c-percent, .c-realBegan, .c-realEnd{width: 90px;}
.c-name > span {margin-right: 2px;}
td.flex span.project-type-label {min-width: 40px;}
.label-children {min-width:22px !important;}
.c-name > a, .table-children .text-left > a {padding-left: 5px;}
.has-child > span {margin-right: 5px;}
.c-name > .text-ellipsis {text-overflow: clip}
+33 -24
View File
@@ -51,6 +51,23 @@ function changeStatus(executionStatus)
}
}
/**
* Hide all action.
*
* @access public
* @return void
*/
function hideAction()
{
$('.actions').hide();
$('.action').hide();
$('.avatar').removeAttr('data-toggle');
$('.kanban-group-header').hide();
$(".title").attr("disabled", true).css("pointer-events", "none");
$(".avatar").attr("disabled", true).css("pointer-events", "none");
window.sortableDisabled = true;
}
/**
* Display the kanban in full screen.
*
@@ -68,21 +85,8 @@ function fullScreen()
{
$('#kanbanContainer').addClass('fullscreen')
.on('scroll', tryUpdateKanbanAffix);
$('.actions').hide();
$('.action').hide();
$('.avatar').removeAttr('data-toggle');
$('#kanbanContainer a.iframe').each(function()
{
if($(this).hasClass('iframe'))
{
var href = $(this).attr('href');
$(this).removeClass('iframe');
$(this).attr('href', 'javascript:void(0)');
$(this).attr('href-bak', href);
}
})
$('.kanban-group-header').hide();
$(".title").attr("disabled", true).css("pointer-events", "none");
hideAction();
$.cookie('isFullScreen', 1);
};
@@ -123,17 +127,10 @@ function exitFullScreen()
$('.actions').show();
$('.action').show();
$('.avatar').attr('data-toggle', 'modal');
$('#kanbanContainer a').each(function()
{
var hrefBak = $(this).attr('href-bak');
if(hrefBak)
{
$(this).addClass('iframe');
$(this).attr('href', hrefBak);
}
})
$('.kanban-group-header').show();
$(".title").attr("disabled", false).css("pointer-events", "auto");
$(".avatar").attr("disabled", false).css("pointer-events", "auto");
window.sortableDisabled = false;
$.cookie('isFullScreen', 0);
}
@@ -519,6 +516,8 @@ function renderStoryItem(item, $item, col)
}
}
if($.cookie('isFullScreen') == 1) hideAction();
return $item.attr('data-type', 'story').addClass('kanban-item-story');
}
@@ -583,6 +582,8 @@ function renderBugItem(item, $item, col)
}
}
if($.cookie('isFullScreen') == 1) hideAction();
return $item.attr('data-type', 'bug').addClass('kanban-item-bug');
}
@@ -648,6 +649,8 @@ function renderTaskItem(item, $item, col)
$item.attr('data-type', 'task').addClass('kanban-item-task');
if($.cookie('isFullScreen') == 1) hideAction();
return $item;
}
@@ -1413,6 +1416,10 @@ $(function()
return $ele.parent().children('.kanban-lane');
}
},
before: function()
{
return !window.sortableDisabled;
},
start: function(e)
{
if(sortType == 'region')
@@ -1430,6 +1437,8 @@ $(function()
},
finish: function(e)
{
if(!e.changed) return;
var url = '';
var orders = [];
+23 -20
View File
@@ -132,6 +132,7 @@ function renderStoryItem(item, $item, col)
}
}
if($.cookie('isFullScreen') == 1) hideAllAction();
return $item.attr('data-type', 'story').addClass('kanban-item-story');
}
@@ -196,6 +197,7 @@ function renderBugItem(item, $item, col)
}
}
if($.cookie('isFullScreen') == 1) hideAllAction();
return $item.attr('data-type', 'bug').addClass('kanban-item-bug');
}
@@ -261,6 +263,7 @@ function renderTaskItem(item, $item, col)
$item.attr('data-type', 'task').addClass('kanban-item-task');
if($.cookie('isFullScreen') == 1) hideAllAction();
return $item;
}
@@ -389,6 +392,24 @@ function createKanban(kanbanID, data, options)
$kanban.kanban($.extend({data: data, calcColHeight: calcColHeight, displayCards: displayCards}, options));
}
/**
* Hide all actions.
*
* @access public
* @return void
*/
function hideAllAction()
{
$('.actions').hide();
$(".title, .avatar.iframe").attr("disabled", true).css("pointer-events", "none");
}
/**
* Display the kanban in full screen.
*
* @access public
* @return void
*/
function fullScreen()
{
$('#kanbans .kanban-header').addClass('headerTop');
@@ -399,17 +420,7 @@ function fullScreen()
var afterEnterFullscreen = function()
{
$('#kanbanContainer').addClass('scrollbar-hover');
$('.actions').hide();
$('#kanbanContainer a.iframe').each(function()
{
if($(this).hasClass('iframe'))
{
var href = $(this).attr('href');
$(this).removeClass('iframe');
$(this).attr('href', 'javascript:void(0)');
$(this).attr('href-bak', href);
}
})
hideAllAction();
$.cookie('isFullScreen', 1);
}
@@ -448,15 +459,7 @@ function exitFullScreen()
$('#kanbans .kanban-header').removeClass('headerTop');
$('#kanbanContainer').removeClass('scrollbar-hover');
$('.actions').show();
$('#kanbanContainer a').each(function()
{
var hrefBak = $(this).attr('href-bak');
if(hrefBak)
{
$(this).addClass('iframe');
$(this).attr('href', hrefBak);
}
})
$(".title, .avatar.iframe").attr("disabled", false).css("pointer-events", "auto");
$.cookie('isFullScreen', 0);
}
+5 -5
View File
@@ -97,7 +97,7 @@
<th class='c-end'><?php common::printOrderLink('end', $orderBy, $vars, $lang->execution->end);?></th>
<th class='c-realBegan'><?php common::printOrderLink('realBegan', $orderBy, $vars, $lang->execution->realBegan);?></th>
<th class='c-realEnd'><?php common::printOrderLink('realEnd', $orderBy, $vars, $lang->execution->realEnd);?></th>
<th class='c-action'><?php echo $lang->actions;?></th>
<th class='c-actions-6 text-center'><?php echo $lang->actions;?></th>
<?php else:;?>
<th class='c-begin'><?php common::printOrderLink('begin', $orderBy, $vars, $lang->execution->begin);?></th>
<th class='c-end'><?php common::printOrderLink('end', $orderBy, $vars, $lang->execution->end);?></th>
@@ -139,7 +139,7 @@
<?php
$executionLink = $execution->projectModel == 'kanban' ? html::a($this->createLink('execution', 'kanban', 'executionID=' . $execution->id), $executionName, '', "class='text-ellipsis'") : html::a($this->createLink('execution', 'task', 'execution=' . $execution->id), $executionName, '', "class='text-ellipsis'");
if($onlyChildStage) echo "<span class='label label-badge label-light label-children'>{$lang->programplan->childrenAB}</span> ";
echo !empty($execution->children) ? $execution->name : $executionLink;
echo !empty($execution->children) ? "<span class='text-ellipsis'>$execution->name</span>" : $executionLink;
if(isset($execution->delay)) echo "<span class='label label-danger label-badge'>{$lang->execution->delayed}</span> ";
?>
<?php if(!empty($execution->children)):?>
@@ -169,7 +169,7 @@
<td><?php echo helper::isZeroDate($execution->end) ? '' : $execution->end;?></td>
<td><?php echo helper::isZeroDate($execution->realBegan) ? '' : $execution->realBegan;?></td>
<td><?php echo helper::isZeroDate($execution->realEnd) ? '' : $execution->realEnd;?></td>
<td class="c-actions text-center c-actions">
<td class="c-actions text-center">
<?php
common::printIcon('execution', 'start', "executionID={$execution->id}", $execution, 'list', '', '', 'iframe', true);
$class = !empty($execution->children) ? 'disabled' : '';
@@ -230,10 +230,10 @@
<?php endif;?>
<?php printf('%03d', $child->id);?>
</td>
<td class='text-left' title='<?php echo $child->name?>'>
<td class='text-left c-name flex' title='<?php echo $child->name?>'>
<?php
echo "<span class='label label-badge label-light' title='{$lang->programplan->children}'>{$lang->programplan->childrenAB}</span>";
echo html::a($this->createLink('execution', 'task', 'execution=' . $child->id), $child->name);
echo html::a($this->createLink('execution', 'task', 'execution=' . $child->id), $child->name, '', "class='text-ellipsis'");
if(isset($child->delay)) echo "<span class='label label-danger label-badge'>{$lang->execution->delayed}</span> ";
?>
</td>
+29 -3
View File
@@ -24,12 +24,13 @@
<div class='detail-title'><?php echo $lang->execution->linkedProducts;?></div>
<div class='detail-content row'>
<?php $i = 0;?>
<?php $attr = $execution->grade == 2 ? "disabled='disabled'" : '';?>
<?php $attr = '';?>
<?php foreach($allProducts as $productID => $productName):?>
<?php if(isset($linkedProducts[$productID])):?>
<?php foreach($linkedBranches[$productID] as $branchID):?>
<?php if(($execution->grade < 2 and in_array($productID, $unmodifiableProducts) and in_array($branchID, $unmodifiableBranches)) and !empty($linkedStoryIDList[$productID][$branchID])) $attr = "disabled='disabled'";?>
<?php if($execution->grade < 2 and (!(in_array($productID, $unmodifiableProducts) and in_array($branchID, $unmodifiableBranches)) or empty($linkedStoryIDList[$productID][$branchID]))) $attr = '';?>
<?php if((in_array($productID, $unmodifiableProducts) and in_array($branchID, $unmodifiableBranches)) and !empty($linkedStoryIDList[$productID][$branchID])) $attr = "disabled='disabled'";?>
<?php if((!(in_array($productID, $unmodifiableProducts) and in_array($branchID, $unmodifiableBranches)) or empty($linkedStoryIDList[$productID][$branchID]))) $attr = '';?>
<?php if($execution->grade == '2' and ($linkedProducts[$productID]->type == 'normal' or $branchID == 0)) $attr = "disabled='disabled'";?>
<?php $title = (in_array($productID, $unmodifiableProducts) and in_array($branchID, $unmodifiableBranches) and !empty($linkedStoryIDList[$productID][$branchID])) ? sprintf($lang->execution->notAllowRemoveProducts, $linkedStoryIDList[$productID][$branchID]) : $productName;?>
<?php $checked = 'checked';?>
<div class='col-sm-4'>
@@ -75,6 +76,31 @@
<?php if(common::canModify('execution', $execution)) echo html::submitButton();?>
</div>
<?php endif;?>
<?php if($execution->grade == 2):?>
<div class='detail'>
<div class='detail-title'><?php echo $lang->execution->unlinkedProducts;?></div>
<div class='detail-content row'>
<?php foreach($allProducts as $productID => $productName):?>
<?php if(isset($linkedProducts[$productID]) and $linkedProducts[$productID]->type != 'normal'):?>
<div class='col-sm-4'>
<div class='product<?php echo isset($branchGroups[$productID]) ? ' has-branch' : ''?>'>
<div class="checkbox-primary" title='<?php echo $productName;?>'>
<?php echo "<input type='checkbox' name='products[$i]' value='$productID' id='products{$productID}'>";?>
<label class='text-ellipsis checkbox-inline' for='<?php echo 'products' . $productID;?>'><?php echo $productName;?></label>
</div>
<?php if(isset($branchGroups[$productID])) echo html::select("branch[$i]", $branchGroups[$productID], '', "class='form-control chosen'");?>
</div>
</div>
<?php $i++;?>
<?php endif;?>
<?php endforeach;?>
</div>
</div>
<div class="detail text-center form-actions">
<?php echo html::hidden("post", 'post');?>
<?php if(common::canModify('execution', $execution)) echo html::submitButton();?>
</div>
<?php endif;?>
</form>
</div>
</div>
+1 -1
View File
@@ -23,7 +23,7 @@ $lang->install->start = 'Start';
$lang->install->keepInstalling = 'Continue installing this version';
$lang->install->seeLatestRelease = 'View the latest version';
$lang->install->welcome = 'Thanks for choosing ZenTao!';
$lang->install->license = 'ZenTao is under Z PUBLIC LICENSE(ZPL) 1.2';
$lang->install->license = 'License';
$lang->install->desc = <<<EOT
ZenTao ALM is an open source software released under <a href='http://zpl.pub/page/zplv12.html' target='_blank'>Z Public License</a>. It integrates with Product Management, Project Management, Test Management, Document Management, CI Management, etc. ZenTao is a perfect choice for managing software development projects.
+1 -1
View File
@@ -23,7 +23,7 @@ $lang->install->start = '开始安装';
$lang->install->keepInstalling = '继续安装当前版本';
$lang->install->seeLatestRelease = '看看最新的版本';
$lang->install->welcome = '欢迎使用禅道项目管理软件!';
$lang->install->license = '禅道项目管理软件使用 Z PUBLIC LICENSE(ZPL) 1.2 授权协议';
$lang->install->license = '禅道项目管理软件授权协议';
$lang->install->desc = <<<EOT
禅道项目管理软件(ZenTaoPMS)是一款国产的,基于<a href='http://zpl.pub' target='_blank'>ZPL</a>协议,开源免费的项目管理软件,它集产品管理、项目管理、测试管理于一体,同时还包含了事务管理、组织管理等诸多功能,是中小型企业项目管理的首选。
+20 -7
View File
@@ -19,6 +19,22 @@ function loadMore(type, regionID)
});
}
/**
* Hide kanban actions.
*
* @access public
* @return void
*/
function hideAllAction()
{
$('.actions').hide();
$('.action').hide();
$('.kanban-group-header').hide();
$(".title").attr("disabled", true).css("pointer-events", "none");
$('.kanban-col.kanban-header-col').css('padding', '0px 0px 0px 0px');
window.sortableDisabled = true;
}
/**
* Display the kanban in full screen.
*
@@ -36,12 +52,7 @@ function fullScreen()
{
$('#kanbanContainer').addClass('fullscreen')
.on('scroll', tryUpdateKanbanAffix);
$('.actions').hide();
$('.action').hide();
$('.kanban-group-header').hide();
$(".title").attr("disabled", true).css("pointer-events", "none");
$('.kanban-col.kanban-header-col').css('padding', '0px 0px 0px 0px');
window.sortableDisabled = true;
hideAllAction();
$.cookie('isFullScreen', 1);
};
@@ -219,7 +230,7 @@ function renderLaneName($lane, lane, $kanban, columns, kanban)
$lane.parent().toggleClass('sort', canSort);
if(!$lane.children('.actions').length && (canSet || canDelete) && (CRKanban || kanbanInfo.status != 'closed') )
if(!$lane.children('.actions').length && (canSet || canDelete) && (CRKanban || kanbanInfo.status != 'closed'))
{
$([
'<div class="actions" title="' + kanbanLang.more + '">',
@@ -229,6 +240,7 @@ function renderLaneName($lane, lane, $kanban, columns, kanban)
'</div>'
].join('')).appendTo($lane);
}
if($.cookie('isFullScreen') == 1) hideAllAction();
}
/**
@@ -414,6 +426,7 @@ function renderKanbanItem(item, $item)
$title.css('color', '');
$title.children('.label-finish').hide();
}
if($.cookie('isFullScreen') == 1) hideAllAction();
}
/**
+10 -8
View File
@@ -1595,9 +1595,6 @@ class kanbanModel extends model
if(!isset($groupByList[$item->$groupBy])) $groupByList[$item->$groupBy] = $item->$groupBy;
}
if(in_array($groupBy, array('module', 'story', 'pri', 'severity'))) $objectPairs[0] = $this->lang->$browseType->$groupBy . ': ' . $this->lang->kanban->noGroup;
if(in_array($groupBy, array('assignedTo', 'type', 'category', 'source'))) $objectPairs[''] = $this->lang->$browseType->$groupBy . ': ' . $this->lang->kanban->noGroup;
if(in_array($groupBy, array('module', 'story', 'assignedTo')))
{
if($groupBy == 'module')
@@ -1626,17 +1623,22 @@ class kanbanModel extends model
}
else
{
unset($this->lang->$browseType->{$groupBy . 'List'}[0]);
unset($this->lang->$browseType->{$groupBy . 'List'}['']);
$objectPairs += $this->lang->$browseType->{$groupBy . 'List'};
}
if(in_array($groupBy, array('module', 'story', 'pri', 'severity'))) $objectPairs[0] = $this->lang->$browseType->$groupBy . ': ' . $this->lang->kanban->noGroup;
if(in_array($groupBy, array('assignedTo', 'source'))) $objectPairs[] = $this->lang->$browseType->$groupBy . ': ' . $this->lang->kanban->noGroup;
$laneColor = 0;
$order = 1;
foreach($objectPairs as $objectID => $objectName)
foreach($objectPairs as $objectType => $objectName)
{
if(!isset($groupByList[$objectID]) and $objectID) continue;
if(!isset($groupByList[$objectType]) and $objectType and !in_array($objectType, array('feature', 'design'))) continue;
$lane = new stdclass();
$lane->id = $groupBy . $objectID;
$lane->id = $groupBy . $objectType;
$lane->type = $browseType;
$lane->execution = $executionID;
$lane->name = $objectName;
@@ -1646,7 +1648,7 @@ class kanbanModel extends model
$order += 1;
$laneColor += 1;
if($laneColor == count($this->config->kanban->laneColorList)) $laneColor = 0;
$lanes[$objectID] = $lane;
$lanes[$objectType] = $lane;
}
return $lanes;
@@ -2062,7 +2064,7 @@ class kanbanModel extends model
$this->dao->insert(TABLE_KANBAN)->data($kanban)
->autoCheck()
->batchCheck($this->config->kanban->create->requiredFields, 'notempty')
->check('name', 'unique')
->check('name', 'unique', "space = {$kanban->space}")
->exec();
if(!dao::isError())
+2 -1
View File
@@ -2,7 +2,8 @@
#projectList .c-actions {overflow: visible;}
#projectTableList > tr:last-child .c-actions .dropdown-menu {top: auto; bottom: 100%; margin-bottom: -5px;}
.c-budget {width: 100px;}
.c-date {width: 80px;}
.c-budget {width: 80px;}
.label-warning, .label-info {width: 60px !important;}
.project-type-label.label-outline {width: 50px; min-width: 50px;}
.c-date {width: 120px;}
+2
View File
@@ -0,0 +1,2 @@
.c-begin {width: 120px;}
.c-end {width: 100px;}
+2 -2
View File
@@ -39,8 +39,8 @@
<?php if($status == 'openedbyme'):?>
<th class='c-status'><?php common::printOrderLink('status', $orderBy, $vars, $lang->project->status);?></th>
<?php endif;?>
<th class='c-date'><?php common::printOrderLink('begin', $orderBy, $vars, $lang->project->begin);?></th>
<th class='c-date'><?php common::printOrderLink('end', $orderBy, $vars, $lang->project->end);?></th>
<th class='c-date c-begin'><?php common::printOrderLink('begin', $orderBy, $vars, $lang->project->begin);?></th>
<th class='c-date c-end'><?php common::printOrderLink('end', $orderBy, $vars, $lang->project->end);?></th>
<th class='text-right c-budget'><?php common::printOrderLink('budget', $orderBy, $vars, $lang->project->budget);?></th>
<th class='c-user'><?php common::printOrderLink('PM', $orderBy, $vars, $lang->project->PM);?></th>
<th class='text-center c-actions-6'><?php echo $lang->actions;?></th>
+21 -21
View File
@@ -135,33 +135,30 @@ class programModel extends model
* @access public
* @return array
*/
public function getList($status = 'all', $orderBy = 'id_asc', $pager = NULL, $type = '', $topIdList = '')
public function getList($status = 'all', $orderBy = 'id_asc', $pager = NULL, $type = '', $topIdList = array())
{
$userViewIdList = trim($this->app->user->view->programs, ',') . ',' . trim($this->app->user->view->projects, ',');
$userViewIdList = array_filter(explode(',', $userViewIdList));
$objectIdList = array();
if(!$this->app->user->admin)
if($this->app->rawMethod == 'browse')
{
$objectIdList = trim($this->app->user->view->programs, ',') . ',' . trim($this->app->user->view->projects, ',');
$objectIdList = array_filter(explode(',', $objectIdList));
asort($objectIdList);
$pathList = $this->dao->select('id,path')->from(TABLE_PROJECT)
->where('type')->in('program,project')
->beginIF(!$this->app->user->admin)->andWhere('id')->in($userViewIdList)->fi()
->andWhere('deleted')->eq(0)
->orderBy('id_asc')
->fetchPairs('id');
if($this->app->rawMethod == 'browse')
foreach($pathList as $path)
{
$pathList = $this->dao->select('id,path')->from(TABLE_PROJECT)
->where('id')->in($objectIdList)
->andWhere('deleted')->eq(0)
->fetchPairs('id');
$objectIdList = array();
foreach($pathList as $path)
if($type == 'child' and !empty($topIdList))
{
if($type == 'child' and !empty($topIdList))
{
$topID = $this->getTopByPath($path);
if(!in_array($topID, $topIdList)) continue;
}
foreach(explode(',', trim($path, ',')) as $pathID) $objectIdList[$pathID] = $pathID;
$topID = $this->getTopByPath($path);
if(!in_array($topID, $topIdList)) continue;
}
foreach(explode(',', trim($path, ',')) as $pathID) $objectIdList[$pathID] = $pathID;
}
}
@@ -171,8 +168,11 @@ class programModel extends model
->andWhere('vision')->eq($this->config->vision)
->beginIF($status != 'all')->andWhere('status')->eq($status)->fi()
->beginIF(!$this->cookie->showClosed)->andWhere('status')->ne('closed')->fi()
->beginIF($this->app->rawMethod == 'browse')
->beginIF($type === 'top')->andWhere('parent')->eq(0)->fi()
->beginIF(!$this->app->user->admin)->andWhere('id')->in($objectIdList)->fi()
->beginIF($type === 'child' or !$this->app->user->admin)->andWhere('id')->in($objectIdList)->fi()
->fi()
->beginIF(!$this->app->user->admin and $this->app->rawMethod != 'browse')->andWhere('id')->in($userViewIdList)->fi()
->orderBy($orderBy)
->page($pager)
->fetchAll('id');
+2
View File
@@ -60,6 +60,8 @@ $lang->project->daysGreaterProject = 'Days cannot be greater than days of projec
$lang->project->errorHours = 'Hours/Day cannot be greater than『24』';
$lang->project->workdaysExceed = 'No more than『%s』working days';
$lang->project->teamMembersCount = ', there are %s team members.';
$lang->project->budgetNumber = '『Budget』must be numbers.';
$lang->project->budgetGe0 = '『Budget』must be greater than or equal to 0.';
/* Fields. */
$lang->project->common = 'Project';
+2
View File
@@ -60,6 +60,8 @@ $lang->project->daysGreaterProject = '可用工日不能大于项目的可用工
$lang->project->errorHours = '可用工时/天不能大于『24』';
$lang->project->workdaysExceed = '可用工作日不能超过『%s』天';
$lang->project->teamMembersCount = ',团队成员共%s人。';
$lang->project->budgetNumber = '『预算』金额必须为数字。';
$lang->project->budgetGe0 = '『预算』金额必须大于等于0。';
/* Fields. */
$lang->project->common = '项目';
+20 -2
View File
@@ -99,13 +99,14 @@ class projectModel extends model
* @access public
* @return array
*/
public function getBudgetUnitList()
{
$budgetUnitList = array();
if($this->config->vision != 'lite')
{
foreach(explode(',', $this->config->project->unitList) as $unit) $budgetUnitList[$unit] = zget($this->lang->project->unitList, $unit, '');
}
}
return $budgetUnitList;
}
@@ -1055,7 +1056,6 @@ class projectModel extends model
->setIF($this->post->delta == 999, 'end', LONG_TIME)
->setIF($this->post->delta == 999, 'days', 0)
->setIF($this->post->acl == 'open', 'whitelist', '')
->setIF($this->post->budget != 0, 'budget', round((float)$this->post->budget, 2))
->setIF(!isset($_POST['whitelist']), 'whitelist', '')
->setDefault('openedBy', $this->app->user->account)
->setDefault('openedDate', helper::now())
@@ -1116,6 +1116,24 @@ class projectModel extends model
return false;
}
if(!empty($project->budget))
{
if(!is_numeric($project->budget))
{
dao::$errors['budget'] = sprintf($this->lang->project->budgetNumber);
return false;
}
else if(is_numeric($project->budget) and ($project->budget < 0))
{
dao::$errors['budget'] = sprintf($this->lang->project->budgetGe0);
return false;
}
else
{
$project->budget = round((float)$this->post->budget, 2);
}
}
/* When select create new product, product name cannot be empty and duplicate. */
if(isset($_POST['newProduct']))
{
+3
View File
@@ -109,6 +109,9 @@ class projectreleaseModel extends model
$oldRelease = $this->dao->select('*')->from(TABLE_RELEASE)->where('id')->eq($releaseID)->fetch();
$branch = $this->dao->select('branch')->from(TABLE_BUILD)->where('id')->eq((int)$this->post->build)->fetch('branch');
/* Check build if build is required. */
if(strpos($this->config->release->edit->requiredFields, 'build') !== false and $this->post->build == false) return dao::$errors['build'] = sprintf($this->lang->error->notempty, $this->lang->release->build);
$release = fixer::input('post')->stripTags($this->config->release->editor->edit['id'], $this->config->allowedTags)
->add('branch', (int)$branch)
->join('mailto', ',')
+1 -1
View File
@@ -3,7 +3,7 @@ $config->release = new stdclass();
$config->release->create = new stdclass();
$config->release->edit = new stdclass();
$config->release->create->requiredFields = 'name,date';
$config->release->edit->requiredFields = 'name,date';
$config->release->edit->requiredFields = 'name,build,date';
$config->release->editor = new stdclass();
$config->release->editor->create = array('id' => 'desc', 'tools' => 'simpleTools');
+25 -8
View File
@@ -2996,13 +2996,30 @@ class storyModel extends model
*/
public function getPlanStories($planID, $status = 'all', $orderBy = 'id_desc', $pager = null)
{
$stories = $this->dao->select('distinct t1.story, t1.plan, t1.order, t2.*')
->from(TABLE_PLANSTORY)->alias('t1')
->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id')
->where('t1.plan')->eq($planID)
->beginIF($status and $status != 'all')->andWhere('t2.status')->in($status)->fi()
->andWhere('t2.deleted')->eq(0)
->orderBy($orderBy)->page($pager)->fetchAll('id');
if(strpos($orderBy, 'module') !== false)
{
$orderBy = (strpos($orderBy, 'module_asc') !== false) ? 't3.path asc' : 't3.path desc';
$stories = $this->dao->select('distinct t1.story, t1.plan, t1.order, t2.*')
->from(TABLE_PLANSTORY)->alias('t1')
->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id')
->leftJoin(TABLE_MODULE)->alias('t3')->on('t2.module = t3.id')
->where('t1.plan')->eq($planID)
->beginIF($status and $status != 'all')->andWhere('t2.status')->in($status)->fi()
->andWhere('t2.deleted')->eq(0)
->orderBy($orderBy)->page($pager)
->fetchAll('id');
}
else
{
$stories = $this->dao->select('distinct t1.story, t1.plan, t1.order, t2.*')
->from(TABLE_PLANSTORY)->alias('t1')
->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id')
->where('t1.plan')->eq($planID)
->beginIF($status and $status != 'all')->andWhere('t2.status')->in($status)->fi()
->andWhere('t2.deleted')->eq(0)
->orderBy($orderBy)->page($pager)
->fetchAll('id');
}
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'story', false);
@@ -3881,7 +3898,7 @@ class storyModel extends model
$menu .= "<div class='divider'></div>";
$menu .= $this->buildMenu('story', 'edit', $params, $story, $type);
$menu .= $this->buildMenu('story', 'create', "productID=$story->product&branch=$story->branch&moduleID=$story->module&{$params}&executionID=0&bugID=0&planID=0&todoID=0&extra=&type=$story->type", $story, $type, 'copy', '', '', ' ', "data-width='1050'");
$menu .= $this->buildMenu('story', 'create', "productID=$story->product&branch=$story->branch&moduleID=$story->module&{$params}&executionID=0&bugID=0&planID=0&todoID=0&extra=&type=$story->type", $story, $type, 'copy', '', '', '', "data-width='1050'");
$menu .= $this->buildMenu('story', 'delete', $params, $story, 'button', 'trash', 'hiddenwin', 'showinonlybody', true);
}
+28 -9
View File
@@ -396,15 +396,27 @@ class testcaseModel extends model
foreach($case as $key => $value) if(strpos($key, 'Date') !== false and !(int)substr($value, 0, 4)) $case->$key = '';
/* Get project and execution. */
$objects = $this->dao->select('t1.*, t1.project as objectID, t2.type')->from(TABLE_PROJECTCASE)->alias('t1')
->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.project=t2.id')
->where('t1.case')->eq($caseID)
->fetchAll('objectID');
foreach($objects as $objectID => $object)
if($this->app->tab == 'project')
{
if($object->type == 'project') $case->project = $objectID;
if(in_array($object->type, array('sprint', 'stage'))) $case->execution = $objectID;
$case->project = $this->session->project;
}
elseif($this->app->tab == 'execution')
{
$case->execution = $this->session->execution;
$case->project = $this->dao->select('project')->from(TABLE_PROJECT)->where('id')->eq($case->execution)->fetch('project');
}
else
{
$objects = $this->dao->select('t1.*, t1.project as objectID, t2.type')->from(TABLE_PROJECTCASE)->alias('t1')
->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.project=t2.id')
->where('t1.case')->eq($caseID)
->fetchAll('objectID');
foreach($objects as $objectID => $object)
{
if($object->type == 'project') $case->project = $objectID;
if(in_array($object->type, array('sprint', 'stage', 'kanban'))) $case->execution = $objectID;
}
}
if($case->story)
@@ -422,9 +434,16 @@ class testcaseModel extends model
if($case->linkCase or $case->fromCaseID) $case->linkCaseTitles = $this->dao->select('id,title')->from(TABLE_CASE)->where('id')->in($case->linkCase)->orWhere('id')->eq($case->fromCaseID)->fetchPairs();
if($version == 0) $version = $case->version;
$case->steps = $this->dao->select('*')->from(TABLE_CASESTEP)->where('`case`')->eq($caseID)->andWhere('version')->eq($version)->orderBy('id')->fetchAll('id');
$case->files = $this->loadModel('file')->getByObject('testcase', $caseID);
$case->currentVersion = $version ? $version : $case->version;
$case->steps = $this->dao->select('*')->from(TABLE_CASESTEP)->where('`case`')->eq($caseID)->andWhere('version')->eq($version)->orderBy('id')->fetchAll('id');
foreach($case->steps as $key => $step)
{
$step->desc = html_entity_decode($step->desc);
$step->expect = html_entity_decode($step->expect);
}
return $case;
}
+12 -2
View File
@@ -752,6 +752,12 @@ class testtask extends control
$this->loadModel('qa')->setMenu($this->products, $productID, $task->branch, $taskID);
}
if(!isset($this->products[$productID]))
{
$product = $this->product->getByID($productID);
$this->products[$productID] = $product->name;
}
$this->view->title = $this->products[$productID] . $this->lang->colon . $this->lang->testtask->edit;
$this->view->position[] = html::a($this->createLink('testtask', 'browse', "productID=$productID"), $this->products[$productID]);
$this->view->position[] = $this->lang->testtask->common;
@@ -762,11 +768,15 @@ class testtask extends control
$projectID = $this->lang->navGroup->testtask == 'qa' ? 0 : $this->session->project;
$executions = empty($productID) ? array() : $this->product->getExecutionPairsByProduct($productID, 0, 'id_desc', $projectID);
$executionID = $task->execution;
$builds = empty($productID) ? array() : $this->loadModel('build')->getBuildPairs($productID, 'all', 'noempty,notrunk', $executionID, 'execution');
if(!isset($executions[$executionID]))
{
$appendExecution = $this->loadModel('execution')->getByID($executionID);
$executions[$executionID] = $appendExecution->name;
}
$this->view->task = $task;
$this->view->executions = $executions;
$this->view->builds = $builds;
$this->view->builds = empty($productID) ? array() : $this->loadModel('build')->getBuildPairs($productID, 'all', 'noempty,notrunk', $executionID, 'execution');
$this->view->testreports = $this->loadModel('testreport')->getPairs($task->product, $task->testreport);
$this->view->users = $this->loadModel('user')->getPairs('nodeleted|noclosed', $task->owner);
$this->view->contactLists = $this->user->getContactLists($this->app->user->account, 'withnote');
+2
View File
@@ -1360,6 +1360,8 @@ class testtaskModel extends model
foreach($relatedStep as $stepID => $step)
{
$relatedStep[$stepID] = (array)$step;
$relatedStep[$stepID]['desc'] = html_entity_decode($relatedStep[$stepID]['desc']);
$relatedStep[$stepID]['expect'] = html_entity_decode($relatedStep[$stepID]['expect']);
if(isset($result->stepResults[$stepID]))
{
$relatedStep[$stepID]['result'] = $result->stepResults[$stepID]['result'];
Regular → Executable
+1 -1
View File
@@ -658,7 +658,7 @@ class user extends control
{
if(isset($_POST['users']))
{
$this->view->users = $this->dao->select('*')->from(TABLE_USER)->where('account')->in($this->post->users)->orderBy('id')->fetchAll('id');
$this->view->users = $this->dao->select('*')->from(TABLE_USER)->where('id')->in($this->post->users)->orderBy('id')->fetchAll('id');
}
elseif($_POST)
{
+40 -6
View File
@@ -56,13 +56,20 @@ class groupTest
* @access public
* @return void
*/
public function copyTest($groupID)
public function copyTest($groupID, $param)
{
foreach($param as $k => $v) $_POST[$k] = $v;
$objects = $this->objectModel->copy($groupID);
unset($_POST);
if(dao::isError()) return dao::getError();
return $objects;
$newGroupID = $this->objectModel->dao->lastInsertID();
$object = $this->objectModel->getByID($newGroupID);
$this->objectModel->delete($newGroupID);
return $object;
}
/**
@@ -79,7 +86,22 @@ class groupTest
if(dao::isError()) return dao::getError();
return $objects;
$fromPrivs = $this->objectModel->getPrivs($fromGroup);
$toPrivs = $this->objectModel->getPrivs($toGroup);
$result = true;
foreach($fromPrivs as $group => $privs)
{
foreach($privs as $key => $priv)
{
if(!isset($toPrivs[$group][$key]) or $toPrivs[$group][$key] != $fromPrivs[$group][$key])
{
$result = false;
break;
}
}
}
return $result;
}
/**
@@ -96,7 +118,19 @@ class groupTest
if(dao::isError()) return dao::getError();
return $objects;
$fromUsers = $this->objectModel->getUserPairs($fromGroup);
$toUsers = $this->objectModel->getUserPairs($toGroup);
$result = true;
foreach($fromUsers as $account => $name)
{
if(!isset($toUsers[$account]) or $toUsers[$account] != $fromUsers[$account])
{
$result = false;
break;
}
}
return $result;
}
/**
@@ -268,11 +302,11 @@ class groupTest
*/
public function deleteTest($groupID, $null = null)
{
$objects = $this->objectModel->delete($groupID, $null = null);
$this->objectModel->delete($groupID, $null = null);
if(dao::isError()) return dao::getError();
return $objects;
return true;
}
/**
+10
View File
@@ -30,6 +30,16 @@ fields:
- field: desc
range: 1-10000
prefix: "迭代描述"
- field: begin
range: "(-2M)-(+M):1D"
type: timestamp
format: "YY/MM/DD"
postfix: "\t"
- field: end
range: "(+1w)-(+2M):1D"
type: timestamp
format: "YY/MM/DD"
postfix: "\t"
- field: grade
range: 1
- field: parent
+10
View File
@@ -39,6 +39,16 @@ fields:
- field: code
range: 1-10000
prefix: "program"
- field: begin
range: "(-5M)-(+M):1D"
type: timestamp
format: "YY/MM/DD"
postfix: "\t"
- field: end
range: "(+10w)-(+2M):1D"
type: timestamp
format: "YY/MM/DD"
postfix: "\t"
- field: desc
range: 1-10000
prefix: "项目集描述"
+2 -2
View File
@@ -56,12 +56,12 @@ fields:
range: 1-10000
prefix: "project"
- field: begin
range: "(-2M)-(+M):1D"
range: "(-3M)-(+M):1D"
type: timestamp
format: "YY/MM/DD"
postfix: "\t"
- field: end
range: "(+1w)-(+2M):1D"
range: "(+5w)-(+2M):1D"
type: timestamp
format: "YY/MM/DD"
postfix: "\t"
+10 -3
View File
@@ -42,9 +42,16 @@ fields:
- field: parent
range: 0
- field: path
range: 731-750
prefix: ","
postfix: ","
fields:
- field: path1
prefix: ","
range: 731-750
- field: path2
range: []
postfix: ","
- field: path3
range: []
postfix: ","
- field: grade
range: "1"
- field: code
+1 -1
View File
@@ -18,8 +18,8 @@ $builder->extension = array('rows' => 10, 'extends' => array('extension'));
$builder->program = array('rows' => 10, 'extends' => array('project', 'program'));
$builder->project = array('rows' => 90, 'extends' => array('project', 'project'));
$builder->projectalone = array('rows' => 20, 'extends' => array('project', 'projectalone'));
$builder->sprint = array('rows' => 600, 'extends' => array('project', 'execution'));
$builder->projectalone = array('rows' => 20, 'extends' => array('project', 'projectalone'));
$builder->story = array('rows' => 400, 'extends' => array('story'));
$builder->childstory = array('rows' => 50, 'extends' => array('story','childstory'));
+10 -2
View File
@@ -10,8 +10,16 @@ title=测试 groupModel->copy();
cid=1
pid=1
复制id为2的分组 >> 这是一个复制的分组
复制名字已存在的分组 >> 『分组名称』已经有『我是一个分组』这条记录了。如果您确定该记录已删除,请到后台-系统-数据-回收站还原。
*/
$group = new groupTest();
$groupID = 2;
r($group->copyTest()) && p() && e();
$data = array('name' => '这是一个复制的分组');
$existData = array('name' => '我是一个分组');
$group = new groupTest();
r($group->copyTest($groupID, $data)) && p('name') && e('这是一个复制的分组'); // 这是一个复制的分组
r($group->copyTest($groupID, $existData)) && p('name:0') && e('『分组名称』已经有『我是一个分组』这条记录了。如果您确定该记录已删除,请到后台-系统-数据-回收站还原。'); // 『分组名称』已经有『我是一个分组』这条记录了。如果您确定该记录已删除,请到后台-系统-数据-回收站还原。
+6 -2
View File
@@ -10,8 +10,12 @@ title=测试 groupModel->copyPriv();
cid=1
pid=1
复制分组6权限到分组7 >> 1
*/
$group = new groupTest();
$fromGroup = 6;
$toGroup = 7;
r($group->copyPrivTest()) && p() && e();
$group = new groupTest();
r($group->copyPrivTest($fromGroup, $toGroup)) && p() && e('1'); // 复制分组6权限到分组7
+7 -1
View File
@@ -10,8 +10,14 @@ title=测试 groupModel->copyUser();
cid=1
pid=1
复制分组6用户到分组7 >> 1
*/
$fromGroup = 6;
$toGroup = 7;
$group = new groupTest();
r($group->copyUserTest()) && p() && e();
r($group->copyUserTest($fromGroup, $toGroup)) && p() && e('1'); // 复制分组6用户到分组7
system("./ztest init");
+8 -2
View File
@@ -10,8 +10,14 @@ title=测试 groupModel->delete();
cid=1
pid=1
删除id为10的组 >> 1
删除id为0的组 >> 1
*/
$group = new groupTest();
$groupID = 10;
r($group->deleteTest()) && p() && e();
$group = new groupTest();
r($group->deleteTest($groupID)) && p() && e('1'); // 删除id为10的组
r($group->deleteTest(0)) && p() && e('1'); // 删除id为0的组
system("./ztest init");