Стартовый commit: добавить ZenTao files
This commit is contained in:
parent
9829f6a06b
commit
831d985b11
173
CLAUDE.md
Normal file
173
CLAUDE.md
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Interactive
|
||||
Always reply in Chinese.
|
||||
|
||||
## Project Overview
|
||||
|
||||
ZenTao is a comprehensive, open-source project management software written in PHP that covers the main PM process from product and project management to quality management, documentation management, organization management, and office management. It follows a modular MVC architecture pattern.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Core Structure
|
||||
- **framework/**: Core framework classes (control, model, router, helper)
|
||||
- **module/**: Modular architecture with each module containing:
|
||||
- `control.php` - Controller logic
|
||||
- `model.php` - Data layer and business logic
|
||||
- `zen.php` - New architecture layer (when present)
|
||||
- `tao.php` - Extended business logic layer (when present)
|
||||
- `config/` - Module-specific configuration
|
||||
- `lang/` - Internationalization files
|
||||
- `view/` - Traditional view templates
|
||||
- `ui/` - Modern UI components
|
||||
- `css/` and `js/` - Frontend assets
|
||||
- **lib/**: Third-party libraries and utility classes
|
||||
- **config/**: Global configuration files
|
||||
- **www/**: Web entry point and public assets
|
||||
- **db/**: Database schemas and migration scripts
|
||||
- **extension/**: Extension system for customization
|
||||
|
||||
### Database
|
||||
- Uses MySQL/MariaDB with custom DAO layer in `lib/dao/`
|
||||
- Database schemas in `db/` directory with versioned SQL files
|
||||
- Supports multiple database engines including experimental DuckDB support
|
||||
|
||||
### Frontend
|
||||
- Mix of traditional PHP templates and modern UI components
|
||||
- Uses ZUI framework (custom UI library)
|
||||
- jQuery-based JavaScript
|
||||
- CSS organized per module
|
||||
|
||||
## Development Commands
|
||||
|
||||
### Build System
|
||||
```bash
|
||||
# Full build process
|
||||
make all
|
||||
|
||||
# Clean build artifacts
|
||||
make clean
|
||||
|
||||
# Common build (core functionality)
|
||||
make common
|
||||
|
||||
# Package for distribution
|
||||
make package
|
||||
|
||||
# Create distribution packages
|
||||
make pms # Standard package
|
||||
make ci # CI build with all packages
|
||||
```
|
||||
|
||||
### Testing
|
||||
The project uses a custom testing framework located in `test/`:
|
||||
```bash
|
||||
# Run tests (navigate to test directory first)
|
||||
cd test
|
||||
php spider.php
|
||||
|
||||
# UI testing configuration available in test/config/config.php
|
||||
```
|
||||
|
||||
### Code Quality
|
||||
- PHP compatibility checks via `misc/compatibility/`
|
||||
- Downgrade scripts for PHP version compatibility in `misc/rector/`
|
||||
- Code minification: `php misc/minifyfront.php`
|
||||
|
||||
## Key Modules
|
||||
|
||||
### Core Business Modules
|
||||
- **product/**: Product management
|
||||
- **project/**: Project management (includes execution/)
|
||||
- **story/**: User story management
|
||||
- **task/**: Task management
|
||||
- **bug/**: Bug tracking
|
||||
- **testcase/**: Test case management
|
||||
- **build/**: Build management
|
||||
|
||||
### Administrative Modules
|
||||
- **user/**: User management
|
||||
- **group/**: Permission groups
|
||||
- **company/**: Organization management
|
||||
- **dept/**: Department structure
|
||||
|
||||
### Integration Modules
|
||||
- **git/, gitlab/, gitea/, gogs/**: Source control integration
|
||||
- **jenkins/**: CI/CD integration
|
||||
- **api/**: API management
|
||||
- **webhook/**: Webhook support
|
||||
|
||||
### Reporting & Analytics
|
||||
- **report/**: Standard reports
|
||||
- **chart/**: Charting functionality
|
||||
- **metric/**: Metrics calculation
|
||||
- **bi/**: Business intelligence
|
||||
|
||||
## Configuration
|
||||
|
||||
### Database Configuration
|
||||
- Main config: `config/config.php`
|
||||
- Database settings typically in `config/my.php` (not tracked)
|
||||
|
||||
### Extension System
|
||||
- Custom extensions in `extension/custom/`
|
||||
- Configuration extensions in `config/ext/`
|
||||
|
||||
### Internationalization
|
||||
- Language files in each module's `lang/` directory
|
||||
- Supported languages: zh-cn, zh-tw, en, de, fr
|
||||
|
||||
## File Patterns
|
||||
|
||||
### Naming Conventions
|
||||
- Controllers: `control.php`
|
||||
- Models: `model.php`
|
||||
- Views: `view/*.html.php`
|
||||
- UI Components: `ui/*.html.php`
|
||||
- Configurations: `config/*.php`
|
||||
- Language files: `lang/{locale}.php`
|
||||
|
||||
### Architecture Layers
|
||||
- **zen.php**: New architecture implementation
|
||||
- **tao.php**: Business logic extension layer
|
||||
- Traditional MVC for legacy code
|
||||
|
||||
## Development Notes
|
||||
|
||||
### PHP Requirements
|
||||
- Minimum PHP 5.6, supports up to PHP 8.1+
|
||||
- Uses strict types declaration in newer files
|
||||
- Extensive use of custom framework classes
|
||||
|
||||
### Security
|
||||
- Custom authentication and authorization system
|
||||
- Input filtering via `lib/filter/`
|
||||
- SQL injection protection through DAO layer
|
||||
|
||||
### Performance
|
||||
- Built-in caching system in `lib/cache/`
|
||||
- Database query optimization
|
||||
- File-based session management
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Adding New Features
|
||||
1. Create module directory structure in `module/`
|
||||
2. Implement controller, model, and views
|
||||
3. Add language files for internationalization
|
||||
4. Configure routing if needed
|
||||
5. Add database tables via SQL files in `db/`
|
||||
|
||||
### Database Changes
|
||||
1. Add migration SQL to `db/update*.sql`
|
||||
2. Update schema in `db/zentao.sql`
|
||||
3. Test with different database engines if needed
|
||||
|
||||
### Testing Changes
|
||||
1. Add test data to `test/data/`
|
||||
2. Create test cases using the custom framework
|
||||
3. Run compatibility checks for PHP versions
|
||||
|
||||
This codebase represents a mature, enterprise-level project management system with extensive customization capabilities and multi-language support.
|
||||
6
COPYING
Normal file
6
COPYING
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
The source code of zentao is covered by the following dual licenses:
|
||||
|
||||
(1) ZPL 1.2: http://zpl.pub/page/zplv12.html
|
||||
(2) AGPL 3.0: https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
You can choose ZPL or AGPL to use zentao.
|
||||
18
Caddyfile
Normal file
18
Caddyfile
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
:80 {
|
||||
root www/
|
||||
file_server
|
||||
php_server {
|
||||
env PATH_INFO {http.matchers.file.remainder}
|
||||
env SCRIPT_NAME {path}
|
||||
|
||||
try_files {path} index.php{path}
|
||||
worker {
|
||||
file www/index.php
|
||||
}
|
||||
}
|
||||
|
||||
log {
|
||||
output file www/tmp/caddy.log
|
||||
level INFO
|
||||
}
|
||||
}
|
||||
107
LICENSE.CN
Normal file
107
LICENSE.CN
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
禅道项目管理软件使用 Z PUBLIC LICENSE(以下简称ZPL) 1.2 和 Affero General Public License(以下简称AGPL) 双授权协议。
|
||||
您可以选择ZPL协议或AGPL协议使用我们的软件。
|
||||
|
||||
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
Z PUBLIC LICENSE(ZPL) 1.2
|
||||
|
||||
许可
|
||||
|
||||
Z PUBLIC LICENSE 由禅道软件(青岛)有限公司(www.chandao.com)起草,简称ZPL协议。
|
||||
任何人均可使用该协议来发布开源软件,并可对下面协议正文中以下划线标注的空白部分做相应修改,
|
||||
除此之外的任何内容不得做任何修改。禅道软件(青岛)有限公司拥有对该协议条款的最终解释权。
|
||||
|
||||
前言:
|
||||
|
||||
禅道项目管理软件(以下简称该软件)由 禅道软件(青岛)有限公司(www.chandao.com)开发(以下简称我)。我依法拥有该软件的所有版权。
|
||||
本着共享开放的角度,我以开放源代码的形式发布该软件。您可以在遵守该协议的前提下使用该软件。
|
||||
自您安装该软件开始,您和我之间的合同关系自动成立。除非您停止使用该软件或与我有签署额外合同,
|
||||
您须认真遵循该授权协议约定的每一条款。
|
||||
|
||||
我的联系方式:
|
||||
联系人:徐先生
|
||||
电话: 4006-8899-23
|
||||
Email: co@zentao.net
|
||||
QQ: 1492153927
|
||||
地址: 山东省青岛市黄岛区长江西路118号青铁广场18楼
|
||||
|
||||
约定:
|
||||
|
||||
下述条款中所指该软件的标志包括如下方面:
|
||||
|
||||
该软件源代码及文档中关于该软件的版权提示、文字、图片和链接。
|
||||
该软件运行时界面上呈现出来的有关该软件的文字、图片和链接。
|
||||
|
||||
不包括如下方面:
|
||||
|
||||
该软件提供的演示数据中关于该软件的文字、图片和链接。
|
||||
|
||||
一、免责
|
||||
|
||||
该软件是以开放源代码的方式发行,您使用该软件无需任何费用,因此在使用该软件前,您须知晓:
|
||||
|
||||
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 如果您违反了该协议的任一条款,该授权协议将自动终止,我保留通过法律手段追究责任的权利。
|
||||
108
LICENSE.EN
Normal file
108
LICENSE.EN
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
The source code of zentao is covered by the following dual licenses:
|
||||
|
||||
(1) ZPL 1.2: http://zpl.pub/page/zplv12.html
|
||||
(2) AGPL 3.0: https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
The default license agreement is the ZPL, or you can choose to use our source code under the AGPL.
|
||||
|
||||
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
Z PUBLIC LICENSE(ZPL) 1.2
|
||||
|
||||
Authorization
|
||||
|
||||
Z PUBLIC LICENSE, also known as ZPL Agreement, is drafted by ZenTao Software(www.easycorp.ltd).
|
||||
Anyone can use the agreement to publish open source software, and modify the blank in the following text of the agreement accordingly.
|
||||
No other text of the agreement shall be changed. ZenTao Software has the final interpretation of the terms in the agreement.
|
||||
|
||||
Preface
|
||||
|
||||
ZenTao ALM (Hereinafter referred to as "the software") developed by ZenTao Software (www.easycorp.ltd) (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 agreement with me.
|
||||
|
||||
My Contact:
|
||||
Email: support@zentaoalm.com
|
||||
Site: https://www.zentao.pm
|
||||
|
||||
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.
|
||||
452
Makefile
Normal file
452
Makefile
Normal file
|
|
@ -0,0 +1,452 @@
|
|||
VERSION = $(shell head -n 1 VERSION)
|
||||
XUANVERSION = $(shell jq -r .pkg.xuanxuan.gitVersion < ci.json)
|
||||
XVERSION = $(shell jq -r .pkg.xuanxuan.version < ci.json)
|
||||
SUITEVERSION = $(shell jq -r .pkg.blocksuite.version < ci.json)
|
||||
XHPROF_VERSION = 2.3.9
|
||||
|
||||
XUANPATH := $(XUANXUAN_SRC_PATH)
|
||||
BUILD_KIND := $(if $(BUILD_KIND),$(BUILD_KIND),auto)
|
||||
BUILD_PATH := $(if $(ZENTAO_BUILD_PATH),$(ZENTAO_BUILD_PATH),$(shell pwd))
|
||||
RELEASE_PATH := $(if $(ZENTAO_RELEASE_PATH),$(ZENTAO_RELEASE_PATH),$(shell pwd))
|
||||
XUAN_WEB_PATH := $(ZENTAO_BUILD_PATH)/web
|
||||
DELETE_TEST := $(DELETE_TEST)
|
||||
|
||||
all:
|
||||
make clean
|
||||
make ci
|
||||
clean:
|
||||
rm -fr zentaopms
|
||||
rm -fr zentaostory
|
||||
rm -fr zentaotask
|
||||
rm -fr zentaotest
|
||||
rm -fr *.tar.gz
|
||||
rm -fr *.tar.xz
|
||||
rm -fr *.zip
|
||||
rm -fr build/linux/lampp
|
||||
rm -rf buildroot/
|
||||
rm -fr lampp
|
||||
rm -fr zentaoxx
|
||||
rm -fr tmp/
|
||||
rm -f *.sh
|
||||
rm -f *.deb *.rpm
|
||||
common:
|
||||
mkdir zentaopms
|
||||
cp LICENSE.CN zentaopms/
|
||||
cp LICENSE.EN zentaopms/
|
||||
cp -fr api zentaopms/
|
||||
cp -fr bin zentaopms/
|
||||
cp -fr config zentaopms/ && rm -fr zentaopms/config/my.php
|
||||
cp -fr db zentaopms/
|
||||
cp -fr doc zentaopms/ && rm -fr zentaopms/doc/phpdoc zentaopms/doc/doxygen zentaopms/doc/LICENSE.LITE.* zentaopms/doc/standard.php
|
||||
cp -fr framework zentaopms/
|
||||
cp -fr lib zentaopms/
|
||||
cp -fr module zentaopms/
|
||||
cp -fr extension zentaopms/
|
||||
cp -fr sdk zentaopms/
|
||||
cp -fr roadrunner zentaopms/
|
||||
cp -fr www zentaopms && rm -fr zentaopms/www/data/ && mkdir -p zentaopms/www/data/upload && mkdir zentaopms/www/data/course
|
||||
# 删除不需要的包和文件
|
||||
cd zentaopms/lib/; rm -fr composer.json composer.lock patches vendor/bin vendor/cweagans vendor/laminas vendor/markbaker vendor/paragonie vendor/phpseclib vendor/symfony
|
||||
cd zentaopms/lib/vendor/box/spout; rm -fr appveyor.yml composer.json PATCHES.txt README.md UPGRADE-3.0.md
|
||||
cd zentaopms/lib/vendor/dragonmantank/cron-expression; rm -fr tests CHANGELOG.md composer.json README.md
|
||||
cd zentaopms/lib/vendor/erusev/parsedown; rm -fr composer.json PATCHES.txt README.md
|
||||
cd zentaopms/lib/vendor/ezyang/htmlpurifier; rm -fr composer.json CREDITS README.md VERSION
|
||||
cd zentaopms/lib/vendor/gorhill/php-fine-diff; rm -fr composer.json PATCHES.txt sample_from.txt sample_to.txt viewdiff-ex.php viewdiff.php
|
||||
cd zentaopms/lib/vendor/gregwar/captcha; rm -fr composer.json README.md
|
||||
cd zentaopms/lib/vendor/masterexploder/phpthumb; rm -fr examples tests composer.json PATCHES.txt phpunit.xml.dist README.md
|
||||
cd zentaopms/lib/vendor/mobiledetect/mobiledetectlib; rm -fr tests composer.json docker-compose.yml phpcs.xml README.md
|
||||
cd zentaopms/lib/vendor/mustangostang/spyc; rm -fr examples php4 tests composer.json PATCHES.txt phpunit.xml README.md spyc.yaml
|
||||
cd zentaopms/lib/vendor/overtrue/pinyin; rm -fr composer.json README.md
|
||||
cd zentaopms/lib/vendor/pclzip/pclzip; rm -fr composer.json PATCHES.txt readme.txt
|
||||
cd zentaopms/lib/vendor/phpmailer/phpmailer; rm -fr COMMITMENT composer.json README.md SECURITY.md SMTPUTF8.md VERSION; find language -type f -not -name '*zh*' -delete
|
||||
cd zentaopms/lib/vendor/phpoffice/phpspreadsheet; rm -fr bin docs samples CHANGELOG.md CHANGELOG.PHPExcel.md composer.json composer.lock CONTRIBUTING.md mkdocs.yml PATCHES.txt phpunit.xml.dist
|
||||
cd zentaopms/lib/vendor/phpoffice/phpword; rm -fr CHANGELOG.md composer.json CONTRIBUTING.md COPYING COPYING.LESSER phpword.ini.dist README.md sonar-project.properties
|
||||
cd zentaopms/lib/vendor/psr/simple-cache; rm -fr composer.json README.md
|
||||
cd zentaopms/lib/vendor/rmccue/requests; rm -fr CHANGELOG.md composer.json README.md
|
||||
# 清理自动加载文件,移除已删除包的引用
|
||||
php misc/cleanup_autoload.php zentaopms/lib/vendor > /dev/null
|
||||
# 把隐式可空类型声明 Type $param = null 改为显式可空类型声明 ?Type $param = null
|
||||
php misc/fix_nullable_types.php zentaopms/lib/vendor > /dev/null && rm misc/nullable_types_fix_*.log
|
||||
if [ ! -d "zentaopms/www/js/zui3/editor" ]; then mkdir -p zentaopms/www/js/zui3/editor; fi
|
||||
curl https://$(GITFOX_HOST)/_artifacts/zentao/raw/zui3/static/blocksuite/$(SUITEVERSION)/blocksuite-$(SUITEVERSION).tar.gz | tar zxf - -C zentaopms/www/js/zui3/editor/
|
||||
# disable the autoExclude function.
|
||||
sed -i 's/\$$autoExclude = true;/\$$autoExclude = false;/' zentaopms/lib/base/dao/dao.class.php
|
||||
mkdir zentaopms/tmp
|
||||
mkdir zentaopms/tmp/cache/
|
||||
mkdir zentaopms/tmp/duckdb/
|
||||
mkdir zentaopms/tmp/extension/
|
||||
mkdir zentaopms/tmp/log/
|
||||
mkdir zentaopms/tmp/model/
|
||||
mv zentaopms/www/install.php.tmp zentaopms/www/install.php
|
||||
mv zentaopms/www/upgrade.php.tmp zentaopms/www/upgrade.php
|
||||
cp VERSION zentaopms/
|
||||
# create index.html of each folder.
|
||||
find zentaopms/ -type d -not -path "zentaopms/lib*" -exec touch {}/index.html \;
|
||||
rm zentaopms/www/index.html
|
||||
# combine js and css files.
|
||||
cp -fr misc zentaopms/misc && cd zentaopms/misc/ && php ./minifyfront.php
|
||||
rm -fr zentaopms/misc
|
||||
# delete the cache file.
|
||||
rm -fr zentaopms/www/cache.php
|
||||
# create the restart file for svn.
|
||||
# touch zentaopms/module/svn/restart
|
||||
# delete the unused files.
|
||||
find zentaopms -name .gitkeep |xargs rm -fr
|
||||
find zentaopms -name tests |xargs rm -fr
|
||||
if [ "$(DELETE_TEST)" != "false" ]; then find zentaopms -name test |xargs rm -fr; fi
|
||||
# notify.zip.
|
||||
mkdir zentaopms/www/data/notify/
|
||||
zentaoxx:
|
||||
#xuanxuan
|
||||
mkdir -p zentaoxx/config/ext
|
||||
mkdir -p zentaoxx/lib
|
||||
mkdir -p zentaoxx/extension/xuan
|
||||
mkdir -p zentaoxx/framework
|
||||
mkdir -p zentaoxx/db
|
||||
mkdir -p zentaoxx/www
|
||||
mkdir -p zentaoxx/extension/xuan/common/ext/model/
|
||||
cd $(XUANPATH); git archive --format=zip --prefix=xuan/ $(XUANVERSION) > xuan.zip
|
||||
mv $(XUANPATH)/xuan.zip .
|
||||
unzip -q xuan.zip
|
||||
cp xuan/xxb/config/ext/_0_xuanxuan.php zentaoxx/config/ext/
|
||||
cp -r xuan/xxb/lib/phpaes zentaoxx/lib/
|
||||
cp -r xuan/xxb/framework/xuanxuan.class.php zentaoxx/framework/
|
||||
cp -r xuan/xxb/db/*.sql zentaoxx/db/
|
||||
cp -r xuan/xxb/module/im zentaoxx/extension/xuan/
|
||||
cp -r xuan/xxb/module/client zentaoxx/extension/xuan/
|
||||
cp -r xuan/xxb/module/conference zentaoxx/extension/xuan/
|
||||
cp -r xuan/xxb/module/watermark zentaoxx/extension/xuan/
|
||||
cp -r xuan/xxb/module/log zentaoxx/extension/xuan/
|
||||
cp -r xuan/xxb/module/integration zentaoxx/extension/xuan/
|
||||
mkdir -p zentaoxx/extension/xuan/common/view
|
||||
cp -r xuan/xxb/module/common/view/header.modal.html.php zentaoxx/extension/xuan/common/view
|
||||
cp -r xuan/xxb/module/common/view/marked.html.php zentaoxx/extension/xuan/common/view
|
||||
cp -r xuan/xxb/module/common/view/footer.modal.html.php zentaoxx/extension/xuan/common/view
|
||||
cp -r xuan/xxb/module/common/view/version.html.php zentaoxx/extension/xuan/common/view
|
||||
mkdir -p zentaoxx/www/js/
|
||||
cp -r xuan/xxb/www/js/markedjs zentaoxx/www/js/
|
||||
cp -r xuan/xxb/www/js/version.js zentaoxx/www/js/
|
||||
cp -r xuan/xxb/www/x.php zentaoxx/www/
|
||||
mkdir zentaoxx/extension/xuan/action
|
||||
cp -r xuan/xxb/module/action/ext zentaoxx/extension/xuan/action
|
||||
cp -r xuan/xxb/config/ext/_1_maps.php zentaoxx/config/ext/
|
||||
cp -r extension/xuanxuan/config/* zentaoxx/config/
|
||||
cp -r extension/xuanxuan/extension/xuan/* zentaoxx/extension/xuan/
|
||||
cp -r extension/xuanxuan/www/* zentaoxx/www/
|
||||
cp -r $(XUAN_WEB_PATH) zentaoxx/www/data/xuanxuan/
|
||||
rm -rf zentaoxx/www/data/xuanxuan/web/node_modules zentaoxx/www/data/xuanxuan/web/*.json zentaoxx/www/data/xuanxuan/web/resources zentaoxx/www/data/xuanxuan/web/media/img zentaoxx/www/data/xuanxuan/web/media/twemoji zentaoxx/www/data/xuanxuan/web/assets/draft.dev.js
|
||||
find zentaoxx/www/data/xuanxuan/web/media/sound -not -name 'message.mp3' -type f -delete
|
||||
find zentaoxx/www/data/xuanxuan/web/lang -not -name 'zh-*.json' -not -name 'en.json' -type f -delete
|
||||
mv zentaoxx/db/ zentaoxx/db_bak
|
||||
mkdir zentaoxx/db/
|
||||
sed -i "s/datetime NOT NULL DEFAULT '0000-00-00 00:00:00'/datetime NULL/" zentaoxx/db_bak/*.sql
|
||||
sed -i "s/datetime NOT NULL/datetime NULL/" zentaoxx/db_bak/*.sql
|
||||
sed -i "s/text NOT NULL DEFAULT ''/text NULL/" zentaoxx/db_bak/*.sql
|
||||
sed -i "s/text NOT NULL/text NULL/" zentaoxx/db_bak/*.sql
|
||||
sed -i "s/ENGINE=MyISAM/ENGINE=InnoDB/" zentaoxx/db_bak/*.sql
|
||||
sed -i "s/utf8/utf8mb4/g" zentaoxx/db_bak/*.sql
|
||||
sed -i "/`xxb_user` ADD `clientStatus`/d; /`xxb_user` ADD `clientLang`/d; /`xxb_file` CHANGE `pathname`/d" zentaoxx/db_bak/xuanxuan.sql
|
||||
cp zentaoxx/db_bak/upgradexuanxuan*.sql zentaoxx/db_bak/xuanxuan.sql zentaoxx/db/
|
||||
rm -rf zentaoxx/db_bak/
|
||||
sed -i "s/\$$accountAdmin = \$$this->dao->select('account, admin')->from(TABLE_USER)->where('id')->eq(\$$userID)->fetch();/\$$accountAdmin = \$$this->dao->select('account')->from(TABLE_USER)->where('id')->eq(\$$userID)->fetch();\n\$$sysAdmins = \$$this->dao->select('admins')->from(TABLE_COMPANY)->where('id')->eq(\$$this->app->company->id)->fetch('admins');\n\$$sysAdminArray = explode(',', \$$sysAdmins);\n\$$accountAdmin->admin = in_array(\$$accountAdmin->account, \$$sysAdminArray) ? 'super' : '';\n/" zentaoxx/extension/xuan/im/model/chat.php
|
||||
sed -i "s/\$$sysAdmins = \$$this->dao->select('id')->from(TABLE_USER)->where('admin')->eq('super')->fetchPairs();/\$$account = \$$this->loadModel('user')->getById(\$$userID);\n\$$admins = \$$this->dao->select('admins')->from(TABLE_COMPANY)->where('id')->eq(\$$this->app->company->id)->fetch('admins');\n\$$adminArray = explode(',', \$$admins);\nreturn in_array(\$$account, \$$adminArray);\n/" zentaoxx/extension/xuan/im/model/chat.php
|
||||
sed -i "/->on('tc.ownedBy=tu.account')/{ N ; s/type/tc.type/}" zentaoxx/extension/xuan/im/model/chat.php
|
||||
sed -i "/\$$this->dao->update(TABLE_IM_CHAT)->data(\$$chat)->where('gid')->eq(\$$chat->gid)/i foreach(array('dismissDate', 'mergedDate', 'archiveDate') as \$$nullable) if(isset(\$$chat->\$$nullable) && empty(\$$chat->\$$nullable)) \$$chat->\$$nullable = null;" zentaoxx/extension/xuan/im/model/chat.php
|
||||
sed -i -z "s/\$$account = \$$this->dao->select('account')->from(TABLE_USER)->where('id')->eq(\$$userID)->fetch('account');\s*\$$this->setting->setItem(\"\$$account\./\$$account = \$$this->dao->select('account')->from(TABLE_USER)->where('id')->eq(\$$userID)->fetch('account');\nif(\!isset(\$$this->app->user)) \$$this->app->user = new stdclass();\n\$$this->app->user->account = \$$account;\n\$$this->setting->setItem(\"\$$account\./" zentaoxx/extension/xuan/im/model/chat.php
|
||||
sed -i "s/owner=system\&module=chat\§ion=settings\&key=\$$account/owner=\$$account\&module=chat\§ion=clientSettings\&key=settings/g" zentaoxx/extension/xuan/im/control.php
|
||||
sed -i "s/system.chat.settings.\$$account/\$$account.chat.clientSettings.settings/g" zentaoxx/extension/xuan/im/control.php
|
||||
sed -i 's/\$$this->setting->setItem("\$$account/\$$this->app->user = (object)array("account" => \$$account); \$$this->setting->setItem("\$$account/' zentaoxx/extension/xuan/im/control.php
|
||||
sed -i "s/\$$super = \$$this->dao->select('admin')->from(TABLE_USER)->where('id')->eq(\$$userID)->fetch('admin');/\$$account = \$$this->dao->select('account')->from(TABLE_USER)->where('id')->eq(\$$userID)->fetch('account');\n\$$sysAdmins = \$$this->dao->select('admins')->from(TABLE_COMPANY)->where('id')->eq(\$$this->app->company->id)->fetch('admins');\n\$$sysAdminArray = explode(',', \$$sysAdmins);\n\$$super = in_array(\$$account, \$$sysAdminArray) ? 'super' : '';/g" zentaoxx/extension/xuan/im/control.php
|
||||
sed -i "/foreach(\$$users as \$$user)/i \$$admins = \$$this->dao->select('admins')->from(TABLE_COMPANY)->where('id')->eq(\$$this->app->company->id)->fetch('admins');\$$adminArray = explode(',', \$$admins);" zentaoxx/extension/xuan/im/model/user.php
|
||||
sed -i "/if(\!isset(\$$user->signed)) \$$user->signed = 0;/a \$$user->admin = in_array(\$$user->account, \$$adminArray) ? 'super' : '';" zentaoxx/extension/xuan/im/model/user.php
|
||||
sed -i "/updateUser->ping/d" zentaoxx/extension/xuan/im/model/user.php
|
||||
sed -i "s/\$$file->fullURL/\$$file->webPath/" zentaoxx/extension/xuan/im/control.php
|
||||
sed -i 's/XXBVERSION/$(XVERSION)/g' zentaoxx/config/ext/_0_xuanxuan.php
|
||||
sed -i "/\$$config->xuanxuan->backend /c\\\$$config->xuanxuan->backend = 'zentao';" zentaoxx/config/ext/_0_xuanxuan.php
|
||||
sed -i 's/site,//' zentaoxx/extension/xuan/im/model/user.php
|
||||
sed -i 's/admin, g/g/' zentaoxx/extension/xuan/im/model/user.php
|
||||
sed -i '/password = md5/d' zentaoxx/extension/xuan/im/model/user.php
|
||||
sed -i 's/md5(\$$user->password.*$$/\$$user->password;/g' zentaoxx/extension/xuan/im/model/user.php
|
||||
sed -i '/getSignedTime/d' zentaoxx/extension/xuan/im/control.php
|
||||
sed -i "/loadModel('push')/d" zentaoxx/extension/xuan/im/control.php
|
||||
sed -i "/this->push/d" zentaoxx/extension/xuan/im/control.php
|
||||
sed -i "s/(int)(microtime/(double)(microtime/" zentaoxx/extension/xuan/im/control.php
|
||||
sed -i -z 's/class im extends control\n{/class im extends control\n{ public function __construct($$moduleName = "", $$methodName = "") { parent::__construct($$moduleName, $$methodName); $$this->dao->exec("SET @@sql_mode='\'''\''"); }/' zentaoxx/extension/xuan/im/control.php # use strict mode later.
|
||||
sed -i 's/$$output->data\s*= $$fileID;/$$output->data = "$$fileID";/' zentaoxx/extension/xuan/im/control.php
|
||||
sed -i "s/'yahoo', //g" zentaoxx/extension/xuan/im/config.php
|
||||
sed -i "s/'gtalk', //g" zentaoxx/extension/xuan/im/config.php
|
||||
sed -i "s/'wangwang', //g" zentaoxx/extension/xuan/im/config.php
|
||||
sed -i "s/'site', //g" zentaoxx/extension/xuan/im/config.php
|
||||
sed -i 's/xuanim.com/zentao.net/g' zentaoxx/extension/xuan/im/config.php
|
||||
sed -i 's/xuanxuan/zentaoclient/g' zentaoxx/extension/xuan/im/config.php
|
||||
sed -i "s/'reload'/inlink('browse')/g" zentaoxx/extension/xuan/client/control.php
|
||||
sed -i 's/tree/dept/' zentaoxx/extension/xuan/im/model.php
|
||||
sed -i 's/tree/dept/' zentaoxx/extension/xuan/im/control.php
|
||||
sed -i 's/im_/zt_im_/g' zentaoxx/db/*.sql
|
||||
sed -i 's/xxb_user/zt_user/g' zentaoxx/db/*.sql
|
||||
sed -i 's/xxb_file/zt_file/g' zentaoxx/db/*.sql
|
||||
sed -i '/xxb_entry/d' zentaoxx/db/*.sql
|
||||
sed -i '/deviceToken/d' zentaoxx/db/*.sql
|
||||
sed -i '/deviceType/d' zentaoxx/db/*.sql
|
||||
sed -i 's/xxb_/zt_/g' zentaoxx/db/*.sql
|
||||
sed -i "/fetch('push', 'pushMessage');/d" zentaoxx/extension/xuan/im/control.php
|
||||
#sed -i "s/marked\.html\.php';?>/marked\.html\.php';?>\n<div id='mainMenu' class='clearfix'><div class='btn-toolbar pull-left'><?php common::printAdminSubMenu('xuanxuan');?><\/div><\/div>/g" zentaoxx/extension/xuan/client/view/checkupgrade.html.php
|
||||
sed -i '/var serverVersions/d' zentaoxx/extension/xuan/client/js/checkupgrade.js
|
||||
sed -i '/var currentVersion/d' zentaoxx/extension/xuan/client/js/checkupgrade.js
|
||||
sed -i '/setRequiredFields(/d' zentaoxx/extension/xuan/common/view/header.modal.html.php
|
||||
sed -i 's/header.html.php/header.lite.html.php/g' zentaoxx/extension/xuan/common/view/header.modal.html.php
|
||||
sed -i 's/footer.html.php/footer.lite.html.php/g' zentaoxx/extension/xuan/common/view/footer.modal.html.php
|
||||
sed -i 's/v\.//g' zentaoxx/extension/xuan/im/js/debug.js
|
||||
sed -i 's/helper::jsonEncode(/json_encode(/g' zentaoxx/framework/xuanxuan.class.php
|
||||
sed -i 's/moduleRoot/getExtensionRoot() . "xuan\/"/' zentaoxx/framework/xuanxuan.class.php
|
||||
sed -i 's/getDefaultParams/getFunctionParams/' zentaoxx/framework/xuanxuan.class.php
|
||||
sed -i "s/lang->goback,/lang->goback, '',/g" zentaoxx/extension/xuan/im/view/debug.html.php
|
||||
sed -i 's/v\.//g' zentaoxx/extension/xuan/client/js/checkupgrade.js
|
||||
sed -i 's/commonModel::getLicensePropertyValue/extCommonModel::getLicensePropertyValue/g' zentaoxx/extension/xuan/im/control.php
|
||||
sed -i 's/commonModel::getLicensePropertyValue/extCommonModel::getLicensePropertyValue/g' zentaoxx/extension/xuan/im/model/conference.php
|
||||
sed -i 's/commonModel::isLicensedMethod/extCommonModel::ilMethod/g' zentaoxx/extension/xuan/conference/model.php
|
||||
sed -i "s#\$this->app->getModuleRoot() . 'im/apischeme.json'#\$this->app->getExtensionRoot() . 'xuan/im/apischeme.json'#g" zentaoxx/extension/xuan/im/model.php
|
||||
sed -i "s/'..\/..\/common\/view\/header.html.php'/\$$app->getModuleRoot() . 'common\/view\/header.html.php'/g" zentaoxx/extension/xuan/conference/view/admin.html.php
|
||||
sed -i "s/'..\/..\/common\/view\/footer.html.php'/\$$app->getModuleRoot() . 'common\/view\/footer.html.php'/g" zentaoxx/extension/xuan/conference/view/admin.html.php
|
||||
sed -i "s/\$$this->im->userGetChangedPassword()/array()/" zentaoxx/extension/xuan/im/control.php
|
||||
sed -i "s/->app->getModuleExtPath('', /->app->getModuleExtPath(/g" zentaoxx/extension/xuan/im/model/bot.php
|
||||
sed -i "s/\$$this->getModuleExtPath('', /\$$this->getModuleExtPath(/g" zentaoxx/framework/xuanxuan.class.php
|
||||
sed -i 's/parent::__construct();/parent::__construct();dao::\$$autoExclude = false;/' zentaoxx/extension/xuan/im/model.php
|
||||
sed -i "s/, \$$version)\$$/, \$$version = '')/g" zentaoxx/extension/xuan/im/model.php
|
||||
sed -i "s/, \$$version)\$$/, \$$version = '')/g" zentaoxx/extension/xuan/im/model/conference.php
|
||||
sed -i 's/$$conferenceData->\(start\|end\)Time\s*=\s*$$\(start\|end\)Time;/if(!empty($$\1Time)) &/g' zentaoxx/extension/xuan/im/model/conference.php
|
||||
sed -i "/.*->getAllDepts();/d" zentaoxx/extension/xuan/im/ext/bot/default.bot.php
|
||||
sed -i "s/lang->user->status/lang->user->clientStatus/" zentaoxx/extension/xuan/im/ext/bot/default.bot.php
|
||||
sed -i "s/.*->getRoleList();/\$$depts = \$$this->im->loadModel('dept')->getDeptPairs();\n\$$deptList = array_map(function(\$$k, \$$v) {return (object)array('id' => \$$k, 'name' => \$$v);}, array_keys(\$$depts), \$$depts);\n\$$roleList = \$$this->im->lang->user->roleList;/" zentaoxx/extension/xuan/im/ext/bot/default.bot.php
|
||||
echo "\$$config->xuanxuan->enabledMethods['im']['getaipermission'] = 'getAiPermission';" >> zentaoxx/config/ext/_0_xuanxuan.php
|
||||
echo "\$$config->xuanxuan->enabledMethods['im']['chatwithai'] = 'chatWithAi';" >> zentaoxx/config/ext/_0_xuanxuan.php
|
||||
echo "\$$config->xuanxuan->enabledMethods['im']['clearaichatcontext'] = 'clearAiChatContext';" >> zentaoxx/config/ext/_0_xuanxuan.php
|
||||
echo "\$$config->xuanxuan->enabledMethods['im']['getaiassistant'] = 'getAiAssistant';" >> zentaoxx/config/ext/_0_xuanxuan.php
|
||||
echo "\$$config->xuanxuan->enabledMethods['im']['getaichat'] = 'getAiChat';" >> zentaoxx/config/ext/_0_xuanxuan.php
|
||||
find zentaoxx/extension/xuan/ -name '*.php' -exec sed -i -r 's|->ne(["'\'']0000-00-00 00:00:00["'\''])|->notZeroDatetime()|g; s|["'\'']\)->eq\(["'\'']0000-00-00( 00:00:00)?| is null|g; s|([=!]=) ?["'\'']0000-00-00( 00:00:00)?["'\'']|\1 null|g; s|([^!=]=) ?["'\'']0000-00-00( 00:00:00)?["'\'']|\1 null|g; s|(["'\''])(,.*)\)->eq\(["'\'']0000-00-00( 00:00:00)?["'\'']| is null\1\2|g; s|["'\'']0000-00-00 00:00:00["'\'']|null|g' {} +
|
||||
perl -i -0777 -pe 's/(\$$query[^\n]*?=[^\n]*?(TABLE_\w+).*?\$$this->dao->query\(\$$query\);)/$$1 \$$this->dao->setCache(trim($$2, "`"));/gs' zentaoxx/extension/xuan/im/model/*.php
|
||||
mkdir zentaoxx/misc; cp misc/cn2tw.php zentaoxx/misc; cd zentaoxx/misc; php cn2tw.php
|
||||
cp misc/en2other.php zentaoxx/misc; cd zentaoxx/misc; php en2other.php ../
|
||||
rm -rf zentaoxx/misc
|
||||
rm -rf zentaoxx/extension/xuanxuan
|
||||
#zip -rqm -9 zentaoxx.$(VERSION).zip zentaoxx/*
|
||||
#rm -rf xuan.zip xuan zentaoxx
|
||||
rm -rf xuan.zip xuan
|
||||
package:
|
||||
# change mode.
|
||||
chmod -R 777 zentaopms/tmp/
|
||||
chmod -R 777 zentaopms/www/data
|
||||
chmod -R 777 zentaopms/config
|
||||
chmod -R 777 zentaopms/extension/custom
|
||||
chmod 777 zentaopms/extension
|
||||
chmod 777 zentaopms/module
|
||||
chmod 777 zentaopms/www
|
||||
chmod a+rx zentaopms/bin/*
|
||||
if [ ! -d "zentaopms/config/ext" ]; then mkdir zentaopms/config/ext; fi
|
||||
find zentaopms/ -name ext |xargs chmod -R 777
|
||||
mkdir zentaopms/misc; cp misc/cn2tw.php zentaopms/misc; cd zentaopms/misc; php cn2tw.php
|
||||
#rm -r zentaopms/module/misc/ext
|
||||
rm -rf zentaopms/misc
|
||||
rm -rf zentaopms/extension/xuanxuan
|
||||
if [ "$(DELETE_TEST)" != "false" ]; then find zentaopms/module -type d -name 'test' -maxdepth 2 -exec rm -rf {} +; fi
|
||||
pms:
|
||||
make common
|
||||
make zentaoxx
|
||||
unzip zentaoxx.*.zip
|
||||
cp zentaoxx/* zentaopms/ -r
|
||||
make package
|
||||
zip -rq -9 ZenTaoPMS.$(VERSION).zip zentaopms
|
||||
rm -fr zentaopms zentaoxx zentaoxx.*.zip
|
||||
deb:
|
||||
mkdir buildroot
|
||||
cp -r build/debian/DEBIAN buildroot
|
||||
sed -i '/^Version/cVersion: ${VERSION}' buildroot/DEBIAN/control
|
||||
mkdir buildroot/opt
|
||||
mkdir buildroot/etc/apache2/sites-enabled/ -p
|
||||
cp build/debian/zentaopms.conf buildroot/etc/apache2/sites-enabled/
|
||||
cp ZenTaoPMS.${VERSION}.zip buildroot/opt
|
||||
cd buildroot/opt; unzip ZenTaoPMS.${VERSION}.zip; mv zentaopms zentao; rm ZenTaoPMS.${VERSION}.zip
|
||||
sed -i 's/index.php/\/zentao\/index.php/' buildroot/opt/zentao/www/.htaccess
|
||||
sudo dpkg -b buildroot/ ZenTaoPMS.${VERSION}.1.all.deb
|
||||
rm -rf buildroot
|
||||
rpm:
|
||||
mkdir ~/rpmbuild/SPECS -p
|
||||
cp build/rpm/zentaopms.spec ~/rpmbuild/SPECS
|
||||
sed -i '/^Version/cVersion:${VERSION}' ~/rpmbuild/SPECS/zentaopms.spec
|
||||
mkdir ~/rpmbuild/SOURCES
|
||||
cp ZenTaoPMS.${VERSION}.zip ~/rpmbuild/SOURCES
|
||||
mkdir ~/rpmbuild/SOURCES/etc/httpd/conf.d/ -p
|
||||
cp build/debian/zentaopms.conf ~/rpmbuild/SOURCES/etc/httpd/conf.d/
|
||||
mkdir ~/rpmbuild/SOURCES/opt/ -p
|
||||
cd ~/rpmbuild/SOURCES; unzip ZenTaoPMS.${VERSION}.zip; mv zentaopms opt/zentao;
|
||||
sed -i 's/index.php/\/zentao\/index.php/' ~/rpmbuild/SOURCES/opt/zentao/www/.htaccess
|
||||
cd ~/rpmbuild/SOURCES; tar -czvf zentaopms-${VERSION}.tar.gz etc opt; rm -rf ZenTaoPMS.${VERSION}.zip etc opt;
|
||||
rpmbuild -ba ~/rpmbuild/SPECS/zentaopms.spec
|
||||
cp ~/rpmbuild/RPMS/noarch/zentaopms-${VERSION}-1.noarch.rpm ./
|
||||
rm -rf ~/rpmbuild
|
||||
en:
|
||||
make common
|
||||
cd zentaopms/; grep -rl 'zentao.net'|xargs sed -i 's/zentao.net/zentao.pm/g';
|
||||
cd zentaopms/; grep -rl 'http://www.zentao.pm'|xargs sed -i 's/http:\/\/www.zentao.pm/https:\/\/www.zentao.pm/g';
|
||||
cd zentaopms/config/; echo >> config.php; echo '$$config->isINT = true;' >> config.php
|
||||
make zentaoxx
|
||||
unzip zentaoxx.*.zip
|
||||
cp zentaoxx/* zentaopms/ -r
|
||||
make package
|
||||
mv zentaopms zentaoalm
|
||||
zip -rq -9 ZenTaoALM.$(VERSION).int.zip zentaoalm
|
||||
rm -fr zentaoalm
|
||||
#echo $(VERSION).int > VERSION
|
||||
#make endeb
|
||||
#make enrpm
|
||||
#echo $(VERSION) > VERSION
|
||||
endeb:
|
||||
mkdir buildroot
|
||||
cp -r build/debian/DEBIAN buildroot
|
||||
sed -i '/^Version/cVersion: ${VERSION}' buildroot/DEBIAN/control
|
||||
mkdir buildroot/opt
|
||||
mkdir buildroot/etc/apache2/sites-enabled/ -p
|
||||
cp build/debian/zentaopms.conf buildroot/etc/apache2/sites-enabled/
|
||||
cp ZenTaoALM.${VERSION}.zip buildroot/opt
|
||||
cd buildroot/opt; unzip ZenTaoALM.${VERSION}.zip; mv zentaoalm zentao; rm ZenTaoALM.${VERSION}.zip
|
||||
sed -i 's/index.php/\/zentao\/index.php/' buildroot/opt/zentao/www/.htaccess
|
||||
sudo dpkg -b buildroot/ ZenTaoALM_${VERSION}_1_all.deb
|
||||
rm -rf buildroot
|
||||
enrpm:
|
||||
mkdir ~/rpmbuild/SPECS -p
|
||||
cp build/rpm/zentaopms.spec ~/rpmbuild/SPECS
|
||||
sed -i '/^Version/cVersion:${VERSION}' ~/rpmbuild/SPECS/zentaopms.spec
|
||||
sed -i '/^Name:/cName:zentaoalm' ~/rpmbuild/SPECS/zentaopms.spec
|
||||
mkdir ~/rpmbuild/SOURCES
|
||||
cp ZenTaoALM.${VERSION}.zip ~/rpmbuild/SOURCES
|
||||
mkdir ~/rpmbuild/SOURCES/etc/httpd/conf.d/ -p
|
||||
cp build/debian/zentaopms.conf ~/rpmbuild/SOURCES/etc/httpd/conf.d/zentaoalm.conf
|
||||
mkdir ~/rpmbuild/SOURCES/opt/ -p
|
||||
cd ~/rpmbuild/SOURCES; unzip ZenTaoALM.${VERSION}.zip; mv zentaoalm opt/zentao;
|
||||
sed -i 's/index.php/\/zentao\/index.php/' ~/rpmbuild/SOURCES/opt/zentao/www/.htaccess
|
||||
cd ~/rpmbuild/SOURCES; tar -czvf zentaoalm-${VERSION}.tar.gz etc opt; rm -rf ZenTaoALM.${VERSION}.zip etc opt;
|
||||
rpmbuild -ba ~/rpmbuild/SPECS/zentaopms.spec
|
||||
cp ~/rpmbuild/RPMS/noarch/zentaoalm-${VERSION}-1.noarch.rpm ./
|
||||
rm -rf ~/rpmbuild
|
||||
cleanAssets:
|
||||
find zentaopms/ -type f \( -name "*.js.map" -o -name "*.gz" \) -delete
|
||||
ciCommon:
|
||||
make common
|
||||
|
||||
ifneq ($(XUANPATH), )
|
||||
make zentaoxx
|
||||
cp zentaoxx/* zentaopms/ -r
|
||||
rm -rf zentaoxx
|
||||
endif
|
||||
|
||||
make package
|
||||
make cleanAssets
|
||||
|
||||
ifeq ($(BUILD_KIND),release)
|
||||
find zentaopms -name "*.php" | xargs sed -i '/^declare(strict_types/d'
|
||||
endif
|
||||
|
||||
sed -i '/legacy/d' zentaopms/db/*.sql
|
||||
sed -i '/legacy/d' zentaopms/db/standard/*.sql
|
||||
sed -i '/uniqueIndex/d' zentaopms/db/*.sql
|
||||
sed -i '/uniqueIndex/d' zentaopms/db/standard/*.sql
|
||||
sed -i 's/KEY `mtype` (`type`),/KEY `mtype` (`type`)/g' zentaopms/db/xuanxuan.sql
|
||||
|
||||
# Merge xuanxuan sql to zentao.
|
||||
cat zentaopms/db/xuanxuan.sql >> zentaopms/db/zentao.sql
|
||||
|
||||
cp -a zentaopms zentaoalm
|
||||
sed -i '/^\s*$$config->langs\['"'"'de'"'"']/d' zentaopms/config/config.php
|
||||
sed -i '/^\s*$$config->langs\['"'"'fr'"'"']/d' zentaopms/config/config.php
|
||||
zip -rq -9 ZenTaoPMS.$(VERSION).zip zentaopms -x "*/de.php" "*/fr.php" "*/vi.php" "*/de/*" "*/fr/*" "*/vi/*"
|
||||
tar -cpJf ZenTaoPMS.$(VERSION).tar.xz --exclude="*/de.php" --exclude="*/fr.php" --exclude="*/vi.php" --exclude="*/de" --exclude="*/fr" --exclude="*/vi" zentaopms
|
||||
|
||||
# en
|
||||
cd zentaoalm/; grep -rl 'zentao.net'|xargs sed -i 's/zentao.net/zentao.pm/g';
|
||||
cd zentaoalm/; grep -rl 'http://www.zentao.pm'|xargs sed -i 's/http:\/\/www.zentao.pm/https:\/\/www.zentao.pm/g';
|
||||
cd zentaoalm/config/; echo >> config.php; echo '$$config->isINT = true;' >> config.php
|
||||
zip -rq -9 ZenTaoALM.$(VERSION).int.zip zentaoalm
|
||||
|
||||
rm -fr zentaoalm
|
||||
|
||||
# move pms zip to build and release path.
|
||||
rm -f $(BUILD_PATH)/ZenTao*.zip $(BUILD_PATH)/ZenTao*.tar.xz $(RELEASE_PATH)/ZenTaoPMS.$(VERSION).zip $(RELEASE_PATH)/ZenTaoALM.$(VERSION).int.zip $(RELEASE_PATH)/ZenTaoPMS.$(VERSION).tar.xz $(RELEASE_PATH)/ZenTaoALM.$(VERSION).int.tar.xz
|
||||
cp ZenTaoPMS.$(VERSION).zip $(BUILD_PATH)
|
||||
cp ZenTaoPMS.$(VERSION).zip ZenTaoALM.$(VERSION).int.zip $(RELEASE_PATH)
|
||||
cizip:
|
||||
make common
|
||||
|
||||
ifneq ($(XUANPATH), )
|
||||
make zentaoxx
|
||||
cp zentaoxx/* zentaopms/ -r
|
||||
rm -rf zentaoxx
|
||||
endif
|
||||
|
||||
make package
|
||||
zip -rq -9 ZenTaoPMS.$(VERSION).zip zentaopms
|
||||
# en
|
||||
cd zentaopms/; grep -rl 'zentao.net'|xargs sed -i 's/zentao.net/zentao.pm/g';
|
||||
cd zentaopms/; grep -rl 'http://www.zentao.pm'|xargs sed -i 's/http:\/\/www.zentao.pm/https:\/\/www.zentao.pm/g';
|
||||
cd zentaopms/config/; echo >> config.php; echo '$$config->isINT = true;' >> config.php
|
||||
mv zentaopms zentaoalm
|
||||
zip -r -9 ZenTaoALM.$(VERSION).int.zip zentaoalm
|
||||
rm -fr zentaoalm
|
||||
# move pms zip to build and release path.
|
||||
rm -f $(BUILD_PATH)/ZenTao*.zip $(RELEASE_PATH)/ZenTaoPMS.$(VERSION).zip $(RELEASE_PATH)/ZenTaoALM.$(VERSION).int.zip
|
||||
cp ZenTaoPMS.$(VERSION).zip $(BUILD_PATH)
|
||||
cp ZenTaoPMS.$(VERSION).zip ZenTaoALM.$(VERSION).int.zip $(RELEASE_PATH)
|
||||
# make zip packages.
|
||||
php misc/packZip.php $(VERSION)
|
||||
sh zip.sh
|
||||
rm -rf tmp/ *.sh zentaobiz* zentaomax* $(RELEASE_PATH)/ZenTaoALM.$(VERSION)*.zip $(RELEASE_PATH)/ZenTaoPMS.$(VERSION)*.zip $(RELEASE_PATH)/pmsPack/*.zip
|
||||
mv ZenTaoPMS.$(VERSION).zip ZenTaoALM.$(VERSION).int.zip $(RELEASE_PATH)
|
||||
mv ZenTaoALM.$(VERSION).int.php*.zip ZenTaoPMS.$(VERSION).php*.zip $(RELEASE_PATH)/pmsPack
|
||||
syspack:
|
||||
php misc/packDeb.php $(VERSION)
|
||||
sh deb.sh
|
||||
rm -rf tmp/ deb.sh
|
||||
php misc/packRpm.php $(VERSION)
|
||||
sh rpm.sh
|
||||
rm -rf tmp/ rpm.sh
|
||||
commitBuild:
|
||||
make ciCommon
|
||||
php misc/packZip.php $(VERSION)
|
||||
sh zip.sh
|
||||
rm -rf tmp/ zip.sh
|
||||
commitClear:
|
||||
rm -rf zentaobiz* zentaomax* $(RELEASE_PATH)/pmsPack/*.zip
|
||||
commitMove:
|
||||
mv ZenTaoALM.$(VERSION).int.php*.zip ZenTaoPMS.$(VERSION).php*.zip $(RELEASE_PATH)/pmsPack
|
||||
releaseBuild:
|
||||
make commitBuild
|
||||
make syspack
|
||||
releaseClear:
|
||||
make commitClear
|
||||
rm -rf $(RELEASE_PATH)/pmsPack/deb/* $(RELEASE_PATH)/pmsPack/rpm/*
|
||||
releaseMove:
|
||||
make commitMove
|
||||
mv *.deb $(RELEASE_PATH)/pmsPack/deb/
|
||||
mv *.rpm $(RELEASE_PATH)/pmsPack/rpm/
|
||||
commitCi:
|
||||
make commitBuild
|
||||
make commitClear
|
||||
make commitMove
|
||||
releaseCi:
|
||||
make releaseBuild
|
||||
make releaseClear
|
||||
make releaseMove
|
||||
ci:
|
||||
make commitBuild
|
||||
make syspack
|
||||
rm -rf zentaobiz* zentaomax* $(RELEASE_PATH)/ZenTaoALM.$(VERSION)*.zip $(RELEASE_PATH)/ZenTaoPMS.$(VERSION)*.zip $(RELEASE_PATH)/*.deb $(RELEASE_PATH)/*.rpm *.sh $(RELEASE_PATH)/pmsPack/*.zip $(RELEASE_PATH)/pmsPack/deb/* $(RELEASE_PATH)/pmsPack/rpm/*
|
||||
mv ZenTaoPMS.$(VERSION).zip ZenTaoALM.$(VERSION).int.zip $(RELEASE_PATH)
|
||||
mv ZenTaoALM.$(VERSION).int.php*.zip ZenTaoPMS.$(VERSION).php*.zip $(RELEASE_PATH)/pmsPack
|
||||
mv *.deb $(RELEASE_PATH)/pmsPack/deb/
|
||||
mv *.rpm $(RELEASE_PATH)/pmsPack/rpm/
|
||||
xhprof:
|
||||
wget https://pecl.php.net/get/xhprof-$(XHPROF_VERSION).tgz
|
||||
tar -zxvf xhprof-$(XHPROF_VERSION).tgz
|
||||
rm -rf www/xhprof/xhprof_html www/xhprof/xhprof_lib
|
||||
mkdir -p www/xhprof
|
||||
mv xhprof-$(XHPROF_VERSION)/xhprof_html xhprof-$(XHPROF_VERSION)/xhprof_lib www/xhprof/
|
||||
rm -rf xhprof-$(XHPROF_VERSION)* package.xml
|
||||
183
QWEN.md
Normal file
183
QWEN.md
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
# 禅道PMS项目上下文
|
||||
|
||||
## 交互
|
||||
始终用中文回复。
|
||||
|
||||
## 项目概述
|
||||
|
||||
禅道PMS(项目管理系统)是由禅道软件(青岛)有限公司开发的开源项目管理软件。它是中国第一个开源项目管理软件,旨在覆盖从产品和项目管理到质量管理、文档管理、组织管理和办公管理的主要项目管理流程。
|
||||
|
||||
### 主要特性
|
||||
|
||||
- 基于禅道PHP框架构建
|
||||
- 支持多种项目管理方法论:Scrum、瀑布和看板
|
||||
- 全面的功能包括产品管理、项目管理、质量管理、文档管理
|
||||
- 多语言支持(中文、英文、德语、法语等)
|
||||
- 丰富的模块包括数据可视化、度量、DevOps、文档资产管理、自动化测试
|
||||
- 版本21.7.5(根据VERSION文件)
|
||||
|
||||
### 架构
|
||||
|
||||
禅道采用模块化MVC架构:
|
||||
- **框架**:位于`/framework`的自定义PHP框架
|
||||
- **模块**:位于`/module`的功能模块(如产品、项目、执行、缺陷、任务等)
|
||||
- **数据库**:基于MySQL,模式在`/db/zentao.sql`中定义
|
||||
- **Web界面**:位于`/www`的基于PHP的Web应用程序
|
||||
- **配置**:位于`/config`的集中配置
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
zentaopms/
|
||||
├── api/ # API相关文件
|
||||
├── bin/ # 可执行二进制文件/脚本
|
||||
├── config/ # 配置文件
|
||||
├── db/ # 数据库模式文件
|
||||
├── doc/ # 文档
|
||||
├── extension/ # 扩展模块
|
||||
├── framework/ # 核心框架文件
|
||||
├── lib/ # 库文件
|
||||
├── misc/ # 杂项文件
|
||||
├── module/ # 应用模块
|
||||
├── sdk/ # 软件开发工具包
|
||||
├── tmp/ # 临时文件
|
||||
├── www/ # Web根目录
|
||||
└── README.md # 项目文档
|
||||
```
|
||||
|
||||
## 构建和运行
|
||||
|
||||
### 先决条件
|
||||
|
||||
- PHP 8.1或更高版本
|
||||
- MySQL数据库
|
||||
- Apache或Nginx Web服务器
|
||||
|
||||
### 构建过程
|
||||
|
||||
项目使用Makefile进行构建:
|
||||
|
||||
1. **清理构建环境**:`make clean`
|
||||
2. **构建应用程序**:`make`或`make all`
|
||||
3. **创建包**:`make package`
|
||||
4. **创建分发版**:`make pms`
|
||||
|
||||
构建过程:
|
||||
- 将必要文件复制到`zentaopms`目录
|
||||
- 处理和压缩JavaScript/CSS资源
|
||||
- 设置适当权限
|
||||
- 创建分发包(ZIP、tar.xz)
|
||||
|
||||
### 安装
|
||||
|
||||
1. 将分发包解压到Web服务器目录
|
||||
2. 在`config/my.php`中配置数据库设置(从`config/config.php`复制)
|
||||
3. 访问Web界面并按照安装向导操作
|
||||
4. 如果未安装,系统将自动重定向到`install.php`
|
||||
|
||||
### 开发环境运行
|
||||
|
||||
1. 将源代码放置在Web服务器的文档根目录中
|
||||
2. 配置Web服务器以服务PHP文件
|
||||
3. 确保以下目录可写:
|
||||
- `tmp/`
|
||||
- `www/data/`
|
||||
- `config/`
|
||||
- `extension/`
|
||||
|
||||
### 生产环境运行
|
||||
|
||||
1. 使用`make pms`构建分发包
|
||||
2. 解压到生产服务器
|
||||
3. 设置目录的适当权限
|
||||
4. 在`config/my.php`中配置数据库连接
|
||||
5. 通过Web浏览器访问以完成安装
|
||||
|
||||
## 配置
|
||||
|
||||
### 主配置
|
||||
|
||||
主配置在`config/config.php`中,重要设置包括:
|
||||
|
||||
- 数据库连接设置
|
||||
- 请求路由配置
|
||||
- 语言和主题设置
|
||||
- 安全设置
|
||||
- 文件上传限制
|
||||
|
||||
### 自定义配置
|
||||
|
||||
创建`config/my.php`来覆盖默认设置:
|
||||
- 从`config/config.php`复制
|
||||
- 修改数据库连接设置
|
||||
- 根据需要调整其他配置
|
||||
|
||||
### 数据库配置
|
||||
|
||||
数据库表在`config/zentaopms.php`中定义为常量:
|
||||
- 表前缀:默认为`zt_`
|
||||
- 超过100个表用于不同功能
|
||||
- 模式在`db/zentao.sql`中定义
|
||||
|
||||
## 开发规范
|
||||
|
||||
### 代码结构
|
||||
|
||||
- 遵循MVC模式,包含模型、视图和控制器
|
||||
- 模块组织在`/module/{module}/`目录中
|
||||
- 每个模块通常包含:
|
||||
- `model.php`:业务逻辑
|
||||
- `control.php`:控制器动作
|
||||
- `view/`:模板文件
|
||||
- `lang/`:语言文件
|
||||
- `js/`:模块特定的JavaScript
|
||||
- `css/`:模块特定的CSS
|
||||
|
||||
### 路由
|
||||
|
||||
- 默认路由:`index.php?m={module}&f={method}`
|
||||
- PATH_INFO路由:`index.php/{module}-{method}`
|
||||
- 可在`config/routes.php`中自定义API路由
|
||||
|
||||
### 数据库访问
|
||||
|
||||
- 使用自定义DAO(数据访问对象)模式
|
||||
- 定义在`lib/base/dao/`中
|
||||
- 示例:`$this->dao->select('*')->from(TABLE_USER)->where('id')->eq($id)->fetch()`
|
||||
|
||||
### 测试
|
||||
|
||||
- 测试位于模块目录下的`test/`中
|
||||
|
||||
## 主要模块
|
||||
|
||||
禅道具有广泛的模块结构:
|
||||
- **产品管理**:product、story、productplan、release
|
||||
- **项目管理**:project、execution、task、build
|
||||
- **质量管理**:bug、testcase、testtask、testsuite
|
||||
- **文档管理**:doc、doclib
|
||||
- **组织管理**:company、dept、user、group
|
||||
- **DevOps**:repo、job、compile、mr
|
||||
- **报表**:report、pivot、chart
|
||||
- **管理**:admin、custom、extension
|
||||
|
||||
## API和集成
|
||||
|
||||
- 通过`api.php`提供RESTful API
|
||||
- Webhooks支持集成
|
||||
- 支持GitLab、Gogs、Gitea、Jenkins、SonarQube
|
||||
- Xuanxuan集成用于消息传递
|
||||
|
||||
## 安全
|
||||
|
||||
- 输入验证和过滤
|
||||
- XSS防护
|
||||
- CSRF防护
|
||||
- 通过DAO防止SQL注入
|
||||
- 文件上传限制
|
||||
|
||||
## 国际化
|
||||
|
||||
- 多语言支持,语言文件在`/module/{module}/lang/`中
|
||||
- 支持的语言:简体中文、繁体中文、英文、德语、法语、越南语、日语、西班牙语、葡萄牙语
|
||||
- 语言选择可在用户偏好中配置
|
||||
81
README.md
Normal file
81
README.md
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
English | [中文](Readme_zh.md)
|
||||
|
||||
<p align="center"><a href="https://www.zentao.pm" target="_blank" rel="noopener noreferrer"><img src="doc/img/zentao-en.png" alt="ZenTao Logo"></a></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.php.net"><img src="https://img.shields.io/badge/php-%3E=5.6-brightgreen.svg?maxAge=2592000" alt="PHP Version"></a>
|
||||
<a href="https://github.com/easysoft/zentaopms/releases/latest"><img src="https://img.shields.io/github/release/easysoft/zentaopms.svg" alt="Latest Version"></a>
|
||||
<a href="mailto:chunsheng@easycorp.ltd"><img src="https://img.shields.io/badge/Email-chunsheng@easycorp.ltd-ea644a" alt="Email" /></a>
|
||||
<a href="https://github.com/easysoft/zentaopms/blob/master/COPYING"><img src="https://img.shields.io/badge/License-AGPL%20or%20ZPL-blue" alt="ZenTao License"></a>
|
||||
<a href="https://www.zentao.pm"><img src="https://img.shields.io/badge/Website-www.zentao.pm-blue" alt="ZenTao Website"></a>
|
||||
</p>
|
||||
|
||||
# Introduction
|
||||
|
||||
ZenTao is the first opensource project management software in China. It’s a comprehensive, all-in-one platform that covers the main PM process, from product and project management to quality management, documentation management, organization management, and office management.
|
||||
|
||||
Since its establishment in 2009, ZenTao has helped tens of thousands of teams and organizations improve their project management structures. Currently, ZenTao is being used by some of the largest companies in the world, ranging from those in the sectors of finance and telecoms to manufacturing and software development. They trust ZenTao for streamlining their processes, simplifying communication between clients and employees, increasing transparency, and improving productivity and efficiency.
|
||||
|
||||
# Design Philosophy
|
||||
|
||||
The name ZenTao came from combining two Chinese characters, Zen(禅) and Tao(道), which have rich inspirations pertaining to culture and history. With its name referring to highly respected aspects of life, it’s only logical to convey their meaning in management by providing transparency, orderliness, and accessibility.
|
||||
|
||||
ZenTao management concept is built on the 3 popular management methodologies: Scrum, Waterfall, and Kanban:
|
||||
|
||||
- The Scrum model built-in ZenTao is adaptable and flexible, which perfectly matches the rapid iterations of software development projects.
|
||||
- The Waterfall model built-in ZenTao lays emphasis on stages division and strict process control, which is ideal for projects that are well defined in advance and with fewer changes.
|
||||
- The Kanban model built-in ZenTao pays more attention to value flow and visualization, which is suitable for the team with a transparent process and efficient transmission of information.
|
||||
|
||||
ZenTao clearly defines the concepts of product, project, and QA to help the product owners, developers, and testers coordinate with each other while maintaining separate functionalities. Through stories, tasks, and bugs, the whole teams interact and track issues and improvements to ensure the delivery of quality products.
|
||||
|
||||
Besides, with ZenTao's feature-rich modules including data visualization, measurement, DevOps, Doc asset management, and automated testing, ZenTao offers flexible solutions to cover the entire process of software development, allows organizations to work efficiently and productivity, and helps them better control time, cost, and quality.
|
||||
|
||||
# Official Website
|
||||
|
||||
- [Website](https://www.zentao.pm/)
|
||||
- [Manual](https://www.zentao.pm/book/)
|
||||
- [FAQ](https://www.zentao.pm/page/faq.html)
|
||||
- [Extension](https://www.zentao.pm/extension-browse.html)
|
||||
|
||||
# Demo
|
||||
|
||||
- [ZenTao Opensource](https://demo15.zentao.pm)
|
||||
- [ZenTao Biz](https://biz.demo15.zentao.pm)
|
||||
- [ZenTao Max](https://max.demo15.zentao.pm)
|
||||
|
||||
# Security Vulnerabilities
|
||||
|
||||
If you find any vulnerability in ZenTao system please feel free to contact us at chunsheng@easycorp.ltd. We do appreciate your time and effort.
|
||||
|
||||
# License
|
||||
|
||||
ZenTao is an opensource project management software licensed on [AGPL](https://www.gnu.org/licenses/agpl-3.0.en.html) and [ZPL](http://zpl.pub/page/zplv12.html).
|
||||
|
||||
<details>
|
||||
<summary><h1>Enhanced version<h1/></summary>
|
||||
|
||||
ZenTao Biz, ZenTao Max, and ZenTao Cloud are available for you if ZenTao Opensource can not meet your feature requirement.
|
||||
|
||||
> [Learn more about the comparison between ZenTao Opensource, ZenTao Biz, and ZenTao Max](https://www.zentao.pm/page/vs.html).
|
||||
|
||||
## ZenTao Biz
|
||||
|
||||
ZenTao Biz has more powerful functions based on the ZenTao Open Source. It also expands horizontally based on the project management process and covers more roles.
|
||||
|
||||
On the one hand, ZenTao Biz provides more complete services for enterprises and its enhanced functions are more suitable for the internal process management of the companies.
|
||||
|
||||
On the other hand, ZenTao Biz has more added functions such as operation and maintenance management, OA office management, feedback management, as well as document version management, and online preview. It can support the customer's related work more effectively outside the development process, and provide more comprehensive support for the project management process.
|
||||
|
||||
## ZenTao Max
|
||||
|
||||
ZenTao Max, the most advanced ZenTao version, allows users to easily monitor and track the entire process of project management. It also helps improve the robustness and maturity of enterprises to greatly increase the probability of project success.
|
||||
|
||||
The features such as process control, process definition, project measurement, issue management, risk management, quality assurance, and project reporting are strong enhanced in ZenTao Max. It's also supported the implementation of CMMI standards, help enterprises pass CMMI assessment.
|
||||
|
||||
## ZenTao Cloud
|
||||
|
||||
> Learn more about [ZenTao Cloud](https://www.zentao.pm/page/saas-pricing.html).
|
||||
|
||||
ZenTao Cloud provides a flexible solution for users who prefer the SaaS service and running businesses anywhere and anytime. It's easy to use and super convenient in that it only needs one click to activate an account. Besides, ZenTao Cloud requires no maintenance and will keep updating automatically. With HTTPS agreement, your data will keep safe and no worry about information disclosure. Even better, data on ZenTao Cloud will backup automatically and users can download the backup file at any time.
|
||||
|
||||
</details>
|
||||
89
Readme_zh.md
Normal file
89
Readme_zh.md
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
[English](README.md) | 中文
|
||||
|
||||
<p align="center"><a href="https://www.zentao.net" target="_blank" rel="noopener noreferrer"><img src="doc/img/zentao-cn.svg" width="300" alt="ZenTao Logo"></a></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.php.net"><img src="https://img.shields.io/badge/php-%3E=5.6-brightgreen.svg?maxAge=2592000" alt="PHP Version"></a>
|
||||
<a href="https://github.com/easysoft/zentaopms/releases/latest"><img src="https://img.shields.io/github/release/easysoft/zentaopms.svg" alt="Latest Version"></a>
|
||||
<a href="mailto:chunsheng@easycorp.ltd"><img src="https://img.shields.io/badge/Email-chunsheng@easycorp.ltd-ea644a" alt="Email" /></a>
|
||||
<a href="https://github.com/easysoft/zentaopms/blob/master/COPYING"><img src="https://img.shields.io/badge/License-AGPL%20or%20ZPL-blue" alt="ZenTao License"></a>
|
||||
<a href="https://www.zentao.net"><img src="https://img.shields.io/badge/Website-www.zentao.net-blue" alt="ZenTao Website"></a>
|
||||
</p>
|
||||
|
||||
# 介绍
|
||||
|
||||
禅道是第一款国产的开源项目管理软件。它集产品管理、项目管理、质量管理、文档管理、 组织管理和事务管理于一体,是一款专业的研发项目管理软件,完整地覆盖了项目管理的核心流程。
|
||||
|
||||
禅道管理思想注重实效,功能完备丰富,操作简洁高效,界面美观大方,搜索功能强大,统计报表丰富多样,软件架构合理,扩展灵活,有完善的 API 可以调用。
|
||||
|
||||
# 设计理念
|
||||
|
||||
禅和道是中国文化中极具代表意义的两个字,是中国传统文化的结晶。我们之所以选用“禅道”作为我们软件的名字,是希望通过这两个字来传达我们对管理的理解和思考。我们希望通过禅道来进行的管理,可以摒弃繁文缛节,还原管理的本质!
|
||||
|
||||
禅道项目管理软件的主要管理思想基于国际流行的`Scrum`模型、瀑布模型和看板模型三种项目管理方法:
|
||||
|
||||
- `Scrum`模型方法注重实效,操作性强,非常适合软件研发项目的快速迭代开发。
|
||||
|
||||
- 瀑布模型方法注重阶段清晰、流程严谨、范围可控,非常适合预先有明确定义且变动不大的产品研发管理。
|
||||
|
||||
- 看板模型方式注重价值流转和可视化,非常适合流程公开透明和信息高效传递的团队。
|
||||
|
||||
禅道首次创造性的将产品、项目、测试这三者的概念明确分开,产品人员、开发团队、测试人员,三者分立,互相配合,又互相制约,通过需求、任务、`BUG` 来进行交相互动,终通过项目拿到合格的产品。
|
||||
|
||||
在数据可视化、度量、`DevOps`、文档资产管理和自动化测试等模块的加持下,禅道软件形成了项目流程管理、`DevOps` 一体化、自动化测试等三大解决方案,完整的覆盖了产品研发的全生命周期管理,助力广大企业高效协作、降本提效。
|
||||
|
||||
# 官方网站
|
||||
|
||||
- [官网](https://www.zentao.net)
|
||||
- [文档](https://www.zentao.net/book/zentaopms.html)
|
||||
- [常见问题](https://www.zentao.net/faq.html)
|
||||
- [插件库](https://www.zentao.net/extension-browse.html)
|
||||
|
||||
## Demo
|
||||
|
||||
- [开源版](https://www.zentao.net/demo/zentao.html)
|
||||
- [企业版](https://www.zentao.net/demo/zentaobiz.html)
|
||||
- [旗舰版](https://www.zentao.net/demo/zentaomax.html)
|
||||
|
||||
# 安全漏洞
|
||||
|
||||
如果您发现禅道项目管理软件中存在安全漏洞,请发送电子邮件至禅道官方团队,电子邮件地址为 chunsheng@easycorp.ltd ,所有安全漏洞都会被及时的解决。
|
||||
|
||||
# 开源协议
|
||||
|
||||
禅道是一个基于 [AGPL](https://www.gnu.org/licenses/agpl-3.0.en.html) 和 [ZPL](http://zpl.pub/page/zplv12.html) 双协议的开源项目管理软件。
|
||||
|
||||
---
|
||||
|
||||
也许您已经"众里寻她千百度",那么让禅道带给您"蓦然回首,那人却在灯火阑珊处"的惊喜吧!
|
||||
|
||||
<details>
|
||||
<summary><h1>增强版本<h1/></summary>
|
||||
|
||||
如果开源版的功能不能满足您的需要,可以考虑禅道[企业版](https://www.zentao.net/page/enterprise.html)、[旗舰版](https://www.zentao.net/page/max.html)或[云禅道](https://www.chandao.net)。
|
||||
|
||||
## 企业版
|
||||
|
||||
> 前往查看[企业版和开源版的对比](https://www.zentao.net/page/enterprise.html#diff)。
|
||||
|
||||
禅道企业版是在禅道开源版的基础上增加增强功能的版本,该版本也基于项目管理的流程做了横向拓展,覆盖了更多的角色。
|
||||
|
||||
一方面,企业版可以企业提供更完善的服务;增强功能更加适合企业的内部流程化管理。
|
||||
|
||||
另一方面,企业版还增加了运维管理、OA 办公管理、反馈管理,以及文档的版本管理及在线预览等功能,可以更有效地支持客户在研发管理流程之外的相关工作,为企业项目管理流程提供更全面的支撑。
|
||||
|
||||
## 旗舰版
|
||||
|
||||
> 前往查看[旗舰版功能对比](https://www.zentao.net/page/max.html#diff)。
|
||||
|
||||
旗舰版作为禅道最高的版本系列,可以完整覆盖项目管理的各个过程,帮助企业建立研发管理体系,提高企业管理流程的稳健性和项目管理成熟度,大大增加项目成功的概率。
|
||||
|
||||
旗舰版增强了流程控制、过程定义、项目度量、问题管理、风险管控、质量保证、项目报告等方面的功能,同时可以支持 CMMI 标准的落地实施,帮助企业通过 CMMI 评估,提升研发管理能力。
|
||||
|
||||
## 云禅道
|
||||
|
||||
> 前往了解和体验[云禅道](https://www.chandao.net)。
|
||||
|
||||
云禅道是禅道企业版和旗舰版的 SaaS 服务,使用便捷,一键即可开通,无需维护,禅道版本自动升级;资源与服务支持灵活扩容,资源按需购买;提供覆盖全国的 CDN 服务,访问更快;HTTPS 协议加密,更加安全;数据自动备份,随时下载备份至本地。
|
||||
|
||||
</details>
|
||||
35
api/v1/config/zdisk.php
Normal file
35
api/v1/config/zdisk.php
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
global $lang;
|
||||
|
||||
$config->zdisk = new stdclass();
|
||||
|
||||
$config->zdisk->root = array();
|
||||
$config->zdisk->root['my'] = array('name' => $lang->my->common, 'type' => 'folder');
|
||||
$config->zdisk->root['program'] = array('name' => $lang->program->common, 'type' => 'folder');
|
||||
$config->zdisk->root['product'] = array('name' => $lang->product->common, 'type' => 'folder');
|
||||
$config->zdisk->root['project'] = array('name' => $lang->project->common, 'type' => 'folder');
|
||||
$config->zdisk->root['qa'] = array('name' => $lang->qa->common, 'type' => 'folder');
|
||||
|
||||
$config->zdisk->my = array();
|
||||
$config->zdisk->my['todo'] = array('name' => $lang->user->todo, 'type' => 'file');
|
||||
$config->zdisk->my['work'] = array('name' => $lang->my->work, 'type' => 'folder');
|
||||
$config->zdisk->my['myproject'] = array('name' => $lang->projectCommon, 'type' => 'folder');
|
||||
$config->zdisk->my['myexecution'] = array('name' => $lang->executionCommon, 'type' => 'folder');
|
||||
|
||||
$config->zdisk->work = array();
|
||||
$config->zdisk->work['task'] = array('name' => $lang->user->task, 'type' => 'file');
|
||||
$config->zdisk->work['story'] = array('name' => $lang->user->story, 'type' => 'file');
|
||||
$config->zdisk->work['bug'] = array('name' => $lang->user->bug, 'type' => 'file');
|
||||
$config->zdisk->work['case'] = array('name' => $lang->user->testCase, 'type' => 'file');
|
||||
$config->zdisk->work['testtask'] = array('name' => $lang->user->testTask, 'type' => 'file');
|
||||
|
||||
$config->zdisk->myproject = array();
|
||||
$config->zdisk->myproject['doing'] = array('name' => $lang->zdisk->doing, 'type' => 'file');
|
||||
$config->zdisk->myproject['wait'] = array('name' => $lang->zdisk->wait, 'type' => 'file');
|
||||
$config->zdisk->myproject['suspend'] = array('name' => $lang->zdisk->suspend, 'type' => 'file');
|
||||
$config->zdisk->myproject['closed'] = array('name' => $lang->zdisk->closed, 'type' => 'file');
|
||||
$config->zdisk->myproject['openedbyme'] = array('name' => $lang->zdisk->openedByMe, 'type' => 'file');
|
||||
|
||||
$config->zdisk->myexecution = array();
|
||||
$config->zdisk->myexecution['undone'] = array('name' => $lang->zdisk->undone, 'type' => 'file');
|
||||
$config->zdisk->myexecution['done'] = array('name' => $lang->zdisk->done, 'type' => 'file');
|
||||
135
api/v1/entries/bug.php
Normal file
135
api/v1/entries/bug.php
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
<?php
|
||||
/**
|
||||
* The bug entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class bugEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $bugID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($bugID)
|
||||
{
|
||||
$this->resetOpenApp($this->param('tab', 'product'));
|
||||
|
||||
$control = $this->loadController('bug', 'view');
|
||||
$control->view($bugID);
|
||||
|
||||
$data = $this->getData();
|
||||
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$bug = $data->data->bug;
|
||||
|
||||
/* Set product name and status */
|
||||
$bug->productName = $data->data->product->name;
|
||||
$bug->productStatus = $data->data->product->status;
|
||||
|
||||
/* Set module title */
|
||||
$moduleTitle = '';
|
||||
if(empty($bug->module)) $moduleTitle = '/';
|
||||
if($bug->module)
|
||||
{
|
||||
$modulePath = $data->data->modulePath;
|
||||
foreach($modulePath as $key => $module)
|
||||
{
|
||||
$moduleTitle .= $module->name;
|
||||
if(isset($modulePath[$key + 1])) $moduleTitle .= '/';
|
||||
}
|
||||
}
|
||||
$bug->moduleTitle = $moduleTitle;
|
||||
|
||||
$openedBuilds = array();
|
||||
foreach(explode(',', $bug->openedBuild) as $buildID)
|
||||
{
|
||||
if(empty($buildID)) continue;
|
||||
|
||||
$openedBuild = new stdclass();
|
||||
$openedBuild->id = $buildID;
|
||||
$openedBuild->title = zget($data->data->builds, $buildID, '');
|
||||
|
||||
$openedBuilds[] = $openedBuild;
|
||||
}
|
||||
$bug->openedBuild = $openedBuilds;
|
||||
|
||||
if($bug->resolvedBuild)
|
||||
{
|
||||
$resolvedBuild = new stdclass();
|
||||
$resolvedBuild->id = $bug->resolvedBuild;
|
||||
$resolvedBuild->title = zget($data->data->builds, $bug->resolvedBuild, '');
|
||||
$bug->resolvedBuild = $resolvedBuild;
|
||||
}
|
||||
|
||||
$bug->actions = $this->loadModel('action')->processActionForAPI($data->data->actions, $data->data->users, $this->lang->bug);
|
||||
|
||||
$preAndNext = $data->data->preAndNext;
|
||||
$bug->preAndNext = array();
|
||||
$bug->preAndNext['pre'] = $preAndNext->pre ? $preAndNext->pre->id : '';
|
||||
$bug->preAndNext['next'] = $preAndNext->next ? $preAndNext->next->id : '';
|
||||
|
||||
return $this->send(200, $this->format($bug, 'activatedDate:time,openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,mailto:userList,resolvedBy:user,resolvedDate:time,closedBy:user,closedDate:time,lastEditedBy:user,lastEditedDate:time,deadline:date,deleted:bool'));
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT method.
|
||||
*
|
||||
* @param int $bugID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function put($bugID)
|
||||
{
|
||||
$control = $this->loadController('bug', 'edit');
|
||||
|
||||
$oldBug = $this->loadModel('bug')->getByID($bugID);
|
||||
|
||||
/* Set $_POST variables. */
|
||||
$fields = 'uid,title,project,execution,openedBuild,assignedTo,pri,severity,type,story,resolvedBy,resolvedBuild,resolvedDate,closedBy,resolution,product,plan,task,module,steps,mailto,keywords,deadline,os,browser,feedbackBy';
|
||||
$this->batchSetPost($fields, $oldBug);
|
||||
$this->setPost('notifyEmail', implode(',', $this->request('notifyEmail', array())));
|
||||
|
||||
$control->edit($bugID);
|
||||
|
||||
$data = $this->getData();
|
||||
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
|
||||
if(!isset($data->status)) return $this->sendError(400, 'error');
|
||||
|
||||
$bug = $this->bug->getByID($bugID);
|
||||
return $this->send(200, $this->format($bug, 'activatedDate:time,openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,mailto:userList,resolvedBy:user,resolvedDate:time,closedBy:user,closedDate:time,lastEditedBy:user,lastEditedDate:time,deadline:date,deleted:bool'));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE method.
|
||||
*
|
||||
* @param int $bugID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function delete($bugID)
|
||||
{
|
||||
$control = $this->loadController('bug', 'delete');
|
||||
if(!$this->app->user->admin)
|
||||
{
|
||||
$bug = $this->loadModel('bug')->getByID($bugID);
|
||||
$projects = explode(',', "0,{$this->app->user->view->projects}");
|
||||
if(!in_array($bug->project, $projects)) return $this->sendError(400, 'No access to the project that the bug belongs to');
|
||||
}
|
||||
|
||||
$control->delete($bugID, 'yes');
|
||||
|
||||
$this->getData();
|
||||
return $this->sendSuccess(200, 'success');
|
||||
}
|
||||
}
|
||||
39
api/v1/entries/bugactive.php
Normal file
39
api/v1/entries/bugactive.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
/**
|
||||
* The bug active entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
**/
|
||||
class bugActiveEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $bugID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($bugID)
|
||||
{
|
||||
$control = $this->loadController('bug', 'activate');
|
||||
|
||||
$fields = 'assignedTo,uid,openedBuild,comment';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$control->activate($bugID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$bug = $this->loadModel('bug')->getByID($bugID);
|
||||
|
||||
return $this->send(200, $this->format($bug, 'openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList'));
|
||||
}
|
||||
}
|
||||
|
||||
39
api/v1/entries/bugassign.php
Normal file
39
api/v1/entries/bugassign.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
/**
|
||||
* The bug assign entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
**/
|
||||
class bugAssignEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $bugID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($bugID)
|
||||
{
|
||||
$control = $this->loadController('bug', 'assignTo');
|
||||
|
||||
$fields = 'assignedTo,mailto,comment';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$control->assignTo($bugID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$bug = $this->loadModel('bug')->getByID($bugID);
|
||||
|
||||
return $this->send(200, $this->format($bug, 'openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList'));
|
||||
}
|
||||
}
|
||||
|
||||
38
api/v1/entries/bugclose.php
Normal file
38
api/v1/entries/bugclose.php
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
/**
|
||||
* The bug close entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
**/
|
||||
class bugCloseEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $bugID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($bugID)
|
||||
{
|
||||
$control = $this->loadController('bug', 'close');
|
||||
|
||||
$fields = 'comment';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$control->close($bugID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
$bug = $this->loadModel('bug')->getByID($bugID);
|
||||
|
||||
return $this->send(200, $this->format($bug, 'openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList'));
|
||||
}
|
||||
}
|
||||
|
||||
40
api/v1/entries/bugconfirm.php
Normal file
40
api/v1/entries/bugconfirm.php
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
/**
|
||||
* The bug confirm entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class bugConfirmEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $bugID
|
||||
* @access public
|
||||
* @return string
|
||||
**/
|
||||
public function post($bugID)
|
||||
{
|
||||
$control = $this->loadController('bug', 'confirm');
|
||||
|
||||
$fields = 'assignedTo,mailto,comment,pri,type,status,deadline';
|
||||
$bug = $this->loadModel('bug')->getByID($bugID);
|
||||
$this->batchSetPost($fields, $bug);
|
||||
|
||||
$control->confirm($bugID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$bug = $this->loadModel('bug')->getById($bugID);
|
||||
|
||||
return $this->send(200, $this->format($bug, 'openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList'));
|
||||
}
|
||||
}
|
||||
|
||||
62
api/v1/entries/bugrecordestimate.php
Normal file
62
api/v1/entries/bugrecordestimate.php
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
/**
|
||||
* The bug recordWorkhour entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class bugRecordEstimateEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $bugID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($bugID)
|
||||
{
|
||||
if($this->config->edition == 'open') return $this->send400('ZenTaoPMS does not have bug effort function.');
|
||||
|
||||
$control = $this->loadController('effort', 'createForObject');
|
||||
$control->createForObject('bug', $bugID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data) return $this->error('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$effort = $data->data->efforts;
|
||||
|
||||
return $this->send(200, array('effort' => $effort));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $bugID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($bugID)
|
||||
{
|
||||
if($this->config->edition == 'open') return $this->send400('ZenTaoPMS does not have bug effort function.');
|
||||
|
||||
$control = $this->loadController('effort', 'createForObject');
|
||||
|
||||
$fields = 'id,dates,consumed,objectType,objectID,work';
|
||||
$this->batchSetPost($fields);
|
||||
$control->createForObject('bug', $bugID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$bug = $this->loadModel('bug')->getByID($bugID);
|
||||
|
||||
return $this->send(200, $this->format($bug, 'openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList'));
|
||||
}
|
||||
}
|
||||
39
api/v1/entries/bugresolve.php
Normal file
39
api/v1/entries/bugresolve.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
/**
|
||||
* The bug resolve entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
**/
|
||||
class bugResolveEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $bugID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($bugID)
|
||||
{
|
||||
$control = $this->loadController('bug', 'resolve');
|
||||
|
||||
$fields = 'resolution,resolvedBuild,resolvedDate,duplicateBug,assignedTo,uid,comment';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$control->resolve($bugID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data) return $this->send400('error');
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$bug = $this->loadModel('bug')->getByID($bugID);
|
||||
|
||||
return $this->send(200, $this->format($bug, 'openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,resolvedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList'));
|
||||
}
|
||||
}
|
||||
|
||||
99
api/v1/entries/bugs.php
Normal file
99
api/v1/entries/bugs.php
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
/**
|
||||
* The bugs entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class bugsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $productID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($productID = 0)
|
||||
{
|
||||
if(empty($productID)) $productID = $this->param('product', 0);
|
||||
if(empty($productID)) return $this->sendError(400, 'Need product id.');
|
||||
|
||||
$control = $this->loadController('bug', 'browse');
|
||||
$control->browse($productID, $this->param('branch', 'all'), $this->param('status', ''), 0, $this->param('order', 'id_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
|
||||
$data = $this->getData();
|
||||
|
||||
if(isset($data->status) and $data->status == 'success')
|
||||
{
|
||||
$bugs = $data->data->bugs;
|
||||
$pager = $data->data->pager;
|
||||
$result = array();
|
||||
$this->loadModel('product');
|
||||
foreach($bugs as $bug)
|
||||
{
|
||||
$product = $this->product->getById($bug->product);
|
||||
$bug->statusName = $this->lang->bug->statusList[$bug->status];
|
||||
$bug->productStatus = $product->status;
|
||||
|
||||
$result[$bug->id] = $this->format($bug, 'activatedDate:time,openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,mailto:userList,resolvedBy:user,resolvedDate:time,closedBy:user,closedDate:time,lastEditedBy:user,lastEditedDate:time,deadline:date,deleted:bool');
|
||||
}
|
||||
|
||||
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'bugs' => array_values($result)));
|
||||
}
|
||||
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
return $this->sendError(400, 'error');
|
||||
}
|
||||
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $productID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($productID = 0)
|
||||
{
|
||||
if(!$productID) $productID = $this->param('product');
|
||||
if(!$productID and isset($this->requestBody->product)) $productID = $this->requestBody->product;
|
||||
if(!$productID) return $this->sendError(400, 'Need product id.');
|
||||
|
||||
$control = $this->loadController('bug', 'create');
|
||||
|
||||
$fields = 'title,project,execution,browser,branch,os,assignedTo,pri,module,severity,type,story,task,mailto,keywords,steps,uid,deadline,plan,feedbackBy';
|
||||
$this->batchSetPost($fields);
|
||||
$this->setPost('openedBuild', $this->request('openedBuild', ["trunk"]));
|
||||
|
||||
$caseID = $this->request('case', 0);
|
||||
if($caseID)
|
||||
{
|
||||
$case = $this->loadModel('testcase')->getById($caseID);
|
||||
if($case)
|
||||
{
|
||||
$this->setPost('case', $case->id);
|
||||
$this->setPost('caseVersion', $case->version);
|
||||
}
|
||||
}
|
||||
|
||||
$this->setPost('product', $productID);
|
||||
$this->setPost('notifyEmail', implode(',', $this->request('notifyEmail', array())));
|
||||
|
||||
$this->requireFields('title,pri,severity,type,openedBuild');
|
||||
|
||||
$control->create($productID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
if(isset($data->result) and !isset($data->id)) return $this->sendError(400, $data->message);
|
||||
|
||||
$bug = $this->loadModel('bug')->getByID($data->id);
|
||||
|
||||
return $this->send(201, $this->format($bug, 'activatedDate:time,openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,mailto:userList,resolvedBy:user,resolvedDate:time,closedBy:user,closedDate:time,lastEditedBy:user,lastEditedDate:time,deadline:date,deleted:bool'));
|
||||
}
|
||||
}
|
||||
76
api/v1/entries/build.php
Normal file
76
api/v1/entries/build.php
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
/**
|
||||
* The build entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class buildEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $buildID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($buildID)
|
||||
{
|
||||
$control = $this->loadController('build', 'view');
|
||||
$control->view($buildID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->status) and $data->status == 'success') return $this->send(200, $this->format($data->data->build, 'builder:user,stories:idList,bugs:idList,deleted:bool'));
|
||||
|
||||
/* Exception handling. */
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
return $this->sendError(400, 'error');
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT method.
|
||||
*
|
||||
* @param int $buildID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function put($buildID)
|
||||
{
|
||||
$control = $this->loadController('build', 'edit');
|
||||
$oldBuild = $this->loadModel('build')->getByID($buildID);
|
||||
|
||||
/* Set $_POST variables. */
|
||||
$fields = 'execution,product,branch,name,builder,date,scmPath,filePath,desc';
|
||||
$this->batchSetPost($fields, $oldBuild);
|
||||
|
||||
$control->edit($buildID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data or (isset($data->message) and $data->message == '404 Not found')) return $this->send404();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
|
||||
$build = $this->build->getByID($buildID);
|
||||
return $this->send(200, $this->format($build, 'builder:user,stories:idList,bugs:idList,deleted:bool'));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE method.
|
||||
*
|
||||
* @param int $buildID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function delete($buildID)
|
||||
{
|
||||
$control = $this->loadController('build', 'delete');
|
||||
$control->delete($buildID, 'true');
|
||||
|
||||
$this->getData();
|
||||
return $this->sendSuccess(200, 'success');
|
||||
}
|
||||
}
|
||||
74
api/v1/entries/builds.php
Normal file
74
api/v1/entries/builds.php
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
/**
|
||||
* The builds entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class buildsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($projectID = 0)
|
||||
{
|
||||
if(empty($projectID)) $projectID = $this->param('project', 0);
|
||||
if(empty($projectID)) return $this->sendError(400, "Need project id.");
|
||||
|
||||
$control = $this->loadController('projectbuild', 'browse');
|
||||
$control->browse($projectID, $this->param('type', 'all'), $this->param('param', 0), $this->param('order', 't1.date_desc,t1.id_desc'));
|
||||
$data = $this->getData();
|
||||
|
||||
if(!isset($data->status)) return $this->sendError(400, 'error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$result = array();
|
||||
foreach($data->data->builds as $build)
|
||||
{
|
||||
$result[] = $this->format($build, 'bugs:idList,stories:idList,builder:user,deleted:bool');
|
||||
}
|
||||
|
||||
return $this->send(200, array('total' => count($result), 'builds' => $result));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($projectID = 0)
|
||||
{
|
||||
$control = $this->loadController('build', 'create');
|
||||
if(!$projectID) $projectID = $this->param('project', 0);
|
||||
|
||||
$project = $this->loadModel('project')->getByID($projectID);
|
||||
if(!$project) return $this->sendError(404, 'Error project id');
|
||||
$this->setPost('project', $projectID);
|
||||
|
||||
$fields = 'execution,product,name,builder,date,scmPath,filePath,desc,branch';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$this->requireFields('execution,product,name,builder,date');
|
||||
|
||||
$executionID = isset($_POST['execution']) ? $_POST['execution'] : 0;
|
||||
$control->create($executionID, 0, $projectID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
if(isset($data->result) and !isset($data->id)) return $this->sendError(400, $data->message);
|
||||
|
||||
$build = $this->loadModel('build')->getByID($data->id);
|
||||
|
||||
return $this->send(201, $build);
|
||||
}
|
||||
}
|
||||
30
api/v1/entries/ciresults.php
Normal file
30
api/v1/entries/ciresults.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
/**
|
||||
* The ciresults entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class ciresultsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post()
|
||||
{
|
||||
$control = $this->loadController('ci', 'commitResult');
|
||||
$control->commitResult();
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
|
||||
return $this->sendSuccess(200, 'success');
|
||||
}
|
||||
}
|
||||
48
api/v1/entries/config.php
Normal file
48
api/v1/entries/config.php
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
/**
|
||||
* The config entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class configEntry extends baseEntry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $name language,version,timezone etc.
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
$config = array('name' => $name);
|
||||
|
||||
switch($name)
|
||||
{
|
||||
case 'language':
|
||||
$config['value'] = $this->config->default->lang;
|
||||
break;
|
||||
case 'version':
|
||||
$config['value'] = $this->config->version;
|
||||
break;
|
||||
case 'charset':
|
||||
$config['value'] = $this->config->charset;
|
||||
break;
|
||||
case 'timezone':
|
||||
$config['value'] = $this->config->timezone;
|
||||
break;
|
||||
case 'systemMode':
|
||||
$config['value'] = $this->config->systemMode;
|
||||
break;
|
||||
default:
|
||||
return $this->sendError(400, 'No configuration.');
|
||||
}
|
||||
|
||||
return $this->send(200, $config);
|
||||
}
|
||||
}
|
||||
42
api/v1/entries/configs.php
Normal file
42
api/v1/entries/configs.php
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* The configs entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class configsEntry extends baseEntry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
$configs = array();
|
||||
|
||||
$this->app->loadConfig('story');
|
||||
|
||||
/* System basic configs. */
|
||||
$configs[] = array('key' => 'language', 'value' => $this->config->default->lang);
|
||||
$configs[] = array('key' => 'version', 'value' => $this->config->version);
|
||||
$configs[] = array('key' => 'charset', 'value' => $this->config->charset);
|
||||
$configs[] = array('key' => 'timezone', 'value' => $this->config->timezone);
|
||||
$configs[] = array('key' => 'systemMode', 'value' => $this->config->systemMode);
|
||||
$configs[] = array('key' => 'hourUnit', 'value' => $this->config->hourUnit);
|
||||
$configs[] = array('key' => 'CRProduct', 'value' => $this->config->CRProduct);
|
||||
$configs[] = array('key' => 'CRExecution', 'value' => $this->config->CRExecution);
|
||||
$configs[] = array('key' => 'CRTask', 'value' => $this->config->CRTask);
|
||||
$configs[] = array('key' => 'edition', 'value' => $this->config->edition);
|
||||
$configs[] = array('key' => 'vision', 'value' => $this->config->vision);
|
||||
$configs[] = array('key' => 'storyNeedReview', 'value' => !!$this->config->story->needReview);
|
||||
|
||||
return $this->send(200, $configs);
|
||||
}
|
||||
}
|
||||
70
api/v1/entries/department.php
Normal file
70
api/v1/entries/department.php
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
/**
|
||||
* The department entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class departmentEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $departmentID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($departmentID)
|
||||
{
|
||||
$dept = $this->loadModel('dept')->getByID($departmentID);
|
||||
|
||||
if(!$dept) return $this->send404();
|
||||
return $this->send(200, $dept);
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT method.
|
||||
*
|
||||
* @param int $departmentID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function put($departmentID)
|
||||
{
|
||||
$control = $this->loadController('dept', 'edit');
|
||||
$oldDept = $this->loadModel('dept')->getByID($departmentID);
|
||||
|
||||
/* Set $_POST variables. */
|
||||
$fields = 'parent,name,manager';
|
||||
$this->batchSetPost($fields, $oldDept);
|
||||
|
||||
$this->requireFields('name');
|
||||
$control->edit($departmentID);
|
||||
|
||||
$this->getData();
|
||||
$department = $this->dept->getByID($departmentID);
|
||||
return $this->send(200, $department);
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE method.
|
||||
*
|
||||
* @param int $departmentID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function delete($departmentID)
|
||||
{
|
||||
$control = $this->loadController('dept', 'delete');
|
||||
$control->delete($departmentID, 'true');
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
|
||||
|
||||
return $this->sendSuccess(200, 'success');
|
||||
}
|
||||
}
|
||||
20
api/v1/entries/departments.php
Normal file
20
api/v1/entries/departments.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
/**
|
||||
* The departments entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class departmentsEntry extends entry
|
||||
{
|
||||
public function get()
|
||||
{
|
||||
$depts = $this->loadModel('dept')->getDataStructure();
|
||||
|
||||
return $this->send(200, $depts);
|
||||
}
|
||||
}
|
||||
83
api/v1/entries/doc.php
Normal file
83
api/v1/entries/doc.php
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
/**
|
||||
* The doc entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class docEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $docID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($docID)
|
||||
{
|
||||
$this->resetOpenApp($this->param('tab', 'doc'));
|
||||
|
||||
$control = $this->loadController('doc', 'view');
|
||||
|
||||
$doc = $this->loadModel('doc')->getByID($docID, 0, true);
|
||||
if(!$doc) return $this->send400('error');
|
||||
|
||||
unset($doc->draft);
|
||||
if(!empty($doc->files)) $doc->files = array_values((array)$doc->files);
|
||||
|
||||
$lib = null;
|
||||
if($doc->lib) $lib = $this->doc->getLibByID((int)$doc->lib);
|
||||
$doc->libName = $lib ? $lib->name : '';
|
||||
|
||||
$doc->preAndNext = array();
|
||||
$doc->preAndNext['pre'] = '';
|
||||
$doc->preAndNext['next'] = '';
|
||||
|
||||
return $this->send(200, $this->format($doc, 'addedBy:user,addedDate:time,assignedTo:user,assignedDate:date,editedBy:user,editedDate:time,mailto:userList'));
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT method.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function put($storyID)
|
||||
{
|
||||
$control = $this->loadController('story', 'edit');
|
||||
$oldStory = $this->loadModel('story')->getByID($storyID);
|
||||
|
||||
/* Set $_POST variables. */
|
||||
$fields = 'type';
|
||||
$this->batchSetPost($fields, $oldStory);
|
||||
$this->setPost('parent', 0);
|
||||
|
||||
$control->edit($storyID);
|
||||
|
||||
$this->getData();
|
||||
$story = $this->story->getByID($storyID);
|
||||
return $this->sendSuccess(200, $this->format($story, 'openedDate:time,assignedDate:time,reviewedDate:time,lastEditedDate:time,closedDate:time,deleted:bool'));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE method.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function delete($storyID)
|
||||
{
|
||||
$control = $this->loadController('story', 'delete');
|
||||
$control->delete($storyID, 'yes');
|
||||
|
||||
$this->getData();
|
||||
return $this->sendSuccess(200, 'success');
|
||||
}
|
||||
}
|
||||
38
api/v1/entries/doclibs.php
Normal file
38
api/v1/entries/doclibs.php
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
/**
|
||||
* The doclibs entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class doclibsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
$type = $this->param('type', 0);
|
||||
$objectID = $this->param('objectID', 0);
|
||||
|
||||
$libs = $this->loadModel('doc')->getLibs($type, $this->param('extra', ''), $this->param('appendLibs', ''), $objectID);
|
||||
$result = array();
|
||||
foreach($libs as $libID => $libName)
|
||||
{
|
||||
$lib = new stdclass();
|
||||
$lib->id = $libID;
|
||||
$lib->name = $libName;
|
||||
$result[] = $lib;
|
||||
}
|
||||
krsort($result);
|
||||
|
||||
return $this->send(200, array('libs' => array_values($result)));
|
||||
}
|
||||
}
|
||||
38
api/v1/entries/docs.php
Normal file
38
api/v1/entries/docs.php
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
/**
|
||||
* The docs entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class docsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($libID = 0)
|
||||
{
|
||||
if(empty($libID)) $libID = $this->param('lib', 0);
|
||||
if(empty($libID)) return $this->sendError(400, 'Need lib id.');
|
||||
|
||||
$docTree = $this->loadModel('doc')->getDocTree($libID);
|
||||
|
||||
foreach($docTree as $i => $module)
|
||||
{
|
||||
if(empty($module->id))
|
||||
{
|
||||
unset($docTree[$i]);
|
||||
foreach($module->children as $doc) $docTree[] = $doc;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->send(200, array('docs' => array_values($docTree)));
|
||||
}
|
||||
}
|
||||
24
api/v1/entries/error.php
Normal file
24
api/v1/entries/error.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
/**
|
||||
* The error entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class errorEntry extends entry
|
||||
{
|
||||
/**
|
||||
* 404 Not Found.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function notFound()
|
||||
{
|
||||
return $this->send(404, array('error' => 'not found'));
|
||||
}
|
||||
}
|
||||
159
api/v1/entries/execution.php
Normal file
159
api/v1/entries/execution.php
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
<?php
|
||||
/**
|
||||
* The execution entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class executionEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $executionID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($executionID)
|
||||
{
|
||||
$fields = $this->param('fields');
|
||||
$status = $this->param('status', 'all');
|
||||
|
||||
$control = $this->loadController('execution', 'view');
|
||||
$control->view($executionID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$execution = $this->format($data->data->execution, 'openedBy:user,openedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,PM:user,PO:user,RD:user,QD:user,whitelist:userList,begin:date,end:date,realBegan:date,realEnd:date,deleted:bool');
|
||||
|
||||
$execution->progress = ($execution->totalConsumed + $execution->totalLeft) ? round($execution->totalConsumed / ($execution->totalConsumed + $execution->totalLeft) * 100, 1) : 0;
|
||||
$execution->teamMembers = array_values((array)$data->data->teamMembers);
|
||||
$execution->products = array();
|
||||
foreach($data->data->products as $productID => $executionProduct)
|
||||
{
|
||||
if($status == 'noclosed' and $executionProduct->status == 'closed') continue;
|
||||
|
||||
$product = new stdclass();
|
||||
$product->id = $executionProduct->id;
|
||||
$product->name = $executionProduct->name;
|
||||
$product->plans = array();
|
||||
foreach($executionProduct->plans as $planID)
|
||||
{
|
||||
$plan = new stdclass();
|
||||
$plan->id = trim($planID, ',');
|
||||
$plan->name = $data->data->planGroups->{$productID}->{$plan->id};
|
||||
$product->plans[] = $plan;
|
||||
}
|
||||
$execution->products[] = $product;
|
||||
}
|
||||
|
||||
$this->loadModel('testcase');
|
||||
$execution->caseReview = ($this->config->testcase->needReview or !empty($this->config->testcase->forceReview));
|
||||
|
||||
if(!$fields) $this->send(200, $execution);
|
||||
|
||||
$users = $data->data->users;
|
||||
|
||||
/* Set other fields. */
|
||||
$fields = explode(',', strtolower($fields));
|
||||
foreach($fields as $field)
|
||||
{
|
||||
switch($field)
|
||||
{
|
||||
case 'modules':
|
||||
$control = $this->loadController('tree', 'browsetask');
|
||||
$control->browsetask($executionID);
|
||||
$data = $this->getData();
|
||||
if(isset($data->status) and $data->status == 'success')
|
||||
{
|
||||
$execution->modules = $data->data->tree;
|
||||
}
|
||||
case 'builds':
|
||||
$execution->builds = $this->loadModel('build')->getBuildPairs(array($productID), 'all', 'noempty,noterminate,nodone', $executionID, 'execution');
|
||||
break;
|
||||
case 'moduleoptionmenu':
|
||||
$execution->moduleOptionMenu = $this->loadModel('tree')->getTaskOptionMenu($executionID, 0, 'allModule');
|
||||
break;
|
||||
case 'members':
|
||||
$execution->members = $this->loadModel('user')->getTeamMemberPairs($executionID, 'execution', 'nodeleted');;
|
||||
unset($execution->members['']);
|
||||
break;
|
||||
case 'stories':
|
||||
$stories = $this->loadModel('story')->getExecutionStories($executionID);
|
||||
foreach($stories as $storyID => $story) $stories[$storyID] = $this->filterFields($story, 'id,title,module,pri,status,stage,estimate');
|
||||
|
||||
$execution->stories = array_values($stories);
|
||||
break;
|
||||
case 'actions':
|
||||
$actions = $data->data->actions;
|
||||
$execution->actions = $this->loadModel('action')->processActionForAPI($actions, $users, $this->lang->execution);
|
||||
break;
|
||||
case "dynamics":
|
||||
$dynamics = $data->data->dynamics ?? array();
|
||||
$execution->dynamics = $this->loadModel('action')->processDynamicForAPI($dynamics);
|
||||
break;
|
||||
case 'chartdata':
|
||||
list($dateList, $interval) = $this->loadModel('execution')->getDateList($execution->begin, $execution->end, 'noweekend', 0, 'Y-m-d');
|
||||
$execution->chartData = $this->execution->buildBurnData($executionID, $dateList, 'left');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->send(200, $execution);
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT method.
|
||||
*
|
||||
* @param int $executionID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function put($executionID)
|
||||
{
|
||||
$control = $this->loadController('execution', 'edit');
|
||||
$oldExecution = $this->loadModel('execution')->getByID($executionID);
|
||||
|
||||
$useCode = $this->checkCodeUsed();
|
||||
/* Set $_POST variables. */
|
||||
$fields = 'project,name,begin,end,lifetime,desc,days,acl,status,PO,PM,QD,RD';
|
||||
if($useCode) $fields .= ',code';
|
||||
$this->batchSetPost($fields, $oldExecution);
|
||||
|
||||
$this->setPost('whitelist', $this->request('whitelist', explode(',', $oldExecution->whitelist)));
|
||||
|
||||
$products = $this->loadModel('product')->getProducts($executionID);
|
||||
$this->setPost('products', $this->request('products', array_keys($products)));
|
||||
|
||||
$control->edit($executionID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
if(!isset($data->result)) return $this->sendError(400, 'error');
|
||||
|
||||
$execution = $this->execution->getByID($executionID);
|
||||
return $this->send(200, $this->format($execution, 'openedBy:user,openedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,PM:user,PO:user,RD:user,QD:user,whitelist:userList,begin:date,end:date,realBegan:date,realEnd:date,deleted:bool'));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE method.
|
||||
*
|
||||
* @param int $executionID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function delete($executionID)
|
||||
{
|
||||
$control = $this->loadController('execution', 'delete');
|
||||
$control->delete($executionID, 'true');
|
||||
|
||||
$this->getData();
|
||||
return $this->sendSuccess(200, 'success');
|
||||
}
|
||||
}
|
||||
72
api/v1/entries/executionbugs.php
Normal file
72
api/v1/entries/executionbugs.php
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
/**
|
||||
* The execution bugs entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class executionBugsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $executionID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($executionID = 0)
|
||||
{
|
||||
if(!$executionID) $executionID = $this->param('execution', 0);
|
||||
if(empty($executionID)) return $this->sendError(400, 'Need execution id.');
|
||||
|
||||
$control = $this->loadController('execution', 'bug');
|
||||
$control->bug($executionID, $this->param('product', 0), $this->param('branch', 0), $this->param('order', 'status,id_desc'), $this->param('build', 0), $this->param('status', 'all'), 0, 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
|
||||
$data = $this->getData();
|
||||
|
||||
if(isset($data->status) and $data->status == 'success')
|
||||
{
|
||||
$bugs = $data->data->bugs;
|
||||
$pager = $data->data->pager;
|
||||
$result = array();
|
||||
$this->loadModel('product');
|
||||
foreach($bugs as $bug)
|
||||
{
|
||||
$status = array('code' => $bug->status, 'name' => $this->lang->bug->statusList[$bug->status]);
|
||||
if($bug->status == 'active' and $bug->confirmed) $status = array('code' => 'confirmed', 'name' => $this->lang->bug->labelConfirmed);
|
||||
if($bug->resolution == 'postponed') $status = array('code' => 'postponed', 'name' => $this->lang->bug->labelPostponed);
|
||||
if(!empty($bug->delay)) $status = array('code' => 'delay', 'name' => $this->lang->bug->overdueBugs);
|
||||
$bug->status = $status['code'];
|
||||
$bug->statusName = $status['name'];
|
||||
|
||||
$product = $this->product->getById($bug->product);
|
||||
$bug->productStatus = $product->status;
|
||||
|
||||
$result[$bug->id] = $this->format($bug, 'activatedDate:time,openedDate:time,assignedDate:time,resolvedDate:time,closedDate:time,lastEditedDate:time,deadline:date,deleted:bool');
|
||||
}
|
||||
|
||||
$storyChangeds = $this->dao->select('t1.id')->from(TABLE_BUG)->alias('t1')
|
||||
->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story=t2.id')
|
||||
->where('t1.id')->in(array_keys($result))
|
||||
->andWhere('t1.story')->ne('0')
|
||||
->andWhere('t1.storyVersion != t2.version')
|
||||
->fetchPairs('id', 'id');
|
||||
foreach($storyChangeds as $bugID)
|
||||
{
|
||||
$status = array('code' => 'storyChanged', 'name' => $this->lang->bug->changed);
|
||||
$result[$bugID]->status = $status['code'];
|
||||
$result[$bugID]->statusName = $status['name'];
|
||||
}
|
||||
|
||||
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'bugs' => array_values($result)));
|
||||
}
|
||||
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
return $this->sendError(400, 'error');
|
||||
}
|
||||
}
|
||||
41
api/v1/entries/executionbuilds.php
Normal file
41
api/v1/entries/executionbuilds.php
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
/**
|
||||
* The execution builds entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class executionBuildsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $executionID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($executionID = 0)
|
||||
{
|
||||
if(empty($executionID)) $executionID = $this->param('execution', 0);
|
||||
if(empty($executionID)) return $this->sendError(400, "Need execution id.");
|
||||
|
||||
$control = $this->loadController('execution', 'build');
|
||||
$control->build($executionID, $this->param('status', 'all'), $this->param('param', 0), $this->param('order', 't1.date_desc,t1.id_desc'));
|
||||
$data = $this->getData();
|
||||
|
||||
if(!isset($data->status)) return $this->sendError(400, 'error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$result = array();
|
||||
foreach($data->data->builds as $build)
|
||||
{
|
||||
$result[] = $this->format($build, 'builder:user,bugs:idList,stories:idList,deleted:bool');
|
||||
}
|
||||
|
||||
return $this->send(200, array('total' => count($result), 'builds' => $result));
|
||||
}
|
||||
}
|
||||
49
api/v1/entries/executioncases.php
Normal file
49
api/v1/entries/executioncases.php
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
/**
|
||||
* The execution cases entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class executionCasesEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $executionID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($executionID = 0)
|
||||
{
|
||||
if(!$executionID) $executionID = $this->param('execution', 0);
|
||||
if(empty($executionID)) return $this->sendError(400, 'Need execution id.');
|
||||
|
||||
$control = $this->loadController('execution', 'testcase');
|
||||
$control->testcase($executionID, (int)$this->param('product', 0), $this->param('branch', 'all'), $this->param('status', 'all'), 0, (int)$this->param('module', 0), $this->param('order', 'id_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
|
||||
$data = $this->getData();
|
||||
|
||||
if(isset($data->status) and $data->status == 'success')
|
||||
{
|
||||
$cases = $data->data->cases;
|
||||
$pager = $data->data->pager;
|
||||
$result = array();
|
||||
foreach($cases as $case)
|
||||
{
|
||||
$case->statusName = $this->lang->testcase->statusList[$case->status];
|
||||
$result[] = $this->format($case, 'openedDate:time,reviewedDate:date,lastEditedDate:time,lastRunDate:time');
|
||||
}
|
||||
|
||||
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'cases' => $result));
|
||||
}
|
||||
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
return $this->sendError(400, 'error');
|
||||
}
|
||||
}
|
||||
194
api/v1/entries/executions.php
Normal file
194
api/v1/entries/executions.php
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
<?php
|
||||
/**
|
||||
* The executions entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class executionsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($projectID = 0)
|
||||
{
|
||||
$appendFields = $this->param('fields', '');
|
||||
$withProject = $this->param('withProject', '');
|
||||
$mergeChildren = $this->param('mergeChildren', 0);
|
||||
if(strpos(strtolower(",{$appendFields},"), ',dropmenu,') !== false) return $this->getDropMenu();
|
||||
|
||||
if($projectID)
|
||||
{
|
||||
$control = $this->loadController('project', 'execution');
|
||||
$control->execution($this->param('status', 'undone'), $projectID, $this->param('order', 'id_desc'), $this->param('product', 0), 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
|
||||
/* Response */
|
||||
$data = $this->getData();
|
||||
if(!$data or !isset($data->status)) return $this->sendError(400, 'error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$executions = $data->data->executionStats;
|
||||
$pager = $data->data->pager;
|
||||
$projects = $data->data->projects;
|
||||
}
|
||||
else
|
||||
{
|
||||
$control = $this->loadController('execution', 'all');
|
||||
$control->all($this->param('status', 'all'), $this->param('order', 'id_desc'), 0, '', 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
$data = $this->getData();
|
||||
|
||||
if(!$data or !isset($data->status)) return $this->sendError(400, 'error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
|
||||
|
||||
$executions = $data->data->executionStats;
|
||||
$pager = $data->data->pager;
|
||||
$projects = $data->data->projects;
|
||||
}
|
||||
|
||||
$result = array();
|
||||
$executionsMap = array();
|
||||
foreach($data->data->executionStats as $execution)
|
||||
{
|
||||
$execution = $this->filterFields($execution, 'id,name,project,code,type,parent,begin,end,status,openedBy,openedDate,delay,progress,children,isParent,' . $appendFields);
|
||||
$execution = $this->format($execution, 'openedBy:user,openedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,PM:user,PO:user,RD:user,QD:user,whitelist:userList,begin:date,end:date,realBegan:date,realEnd:date,deleted:bool');
|
||||
|
||||
if($mergeChildren)
|
||||
{
|
||||
$executionsMap[$execution->id] = $execution;
|
||||
}
|
||||
else
|
||||
{
|
||||
$result[] = $execution;
|
||||
}
|
||||
}
|
||||
|
||||
if($mergeChildren)
|
||||
{
|
||||
foreach($executionsMap as $execution)
|
||||
{
|
||||
if(empty($execution->parent))
|
||||
{
|
||||
$result[$execution->id] = $execution;
|
||||
}
|
||||
elseif((!empty($execution->parent) and $execution->parent != 0 and $execution->parent != '0') and isset($executionsMap[$execution->parent]))
|
||||
{
|
||||
$parentExecution = $executionsMap[$execution->parent];
|
||||
if(!isset($parentExecution->children)) $parentExecution->children = array();
|
||||
$parentExecution->children[] = $execution;
|
||||
}
|
||||
else
|
||||
{
|
||||
$result[$execution->id] = $execution;
|
||||
}
|
||||
}
|
||||
$result = array_values($result);
|
||||
}
|
||||
|
||||
$data = array();
|
||||
$data['page'] = $pager->pageID;
|
||||
$data['total'] = $pager->recTotal;
|
||||
$data['limit'] = $pager->recPerPage;
|
||||
$data['executions'] = $result;
|
||||
if(!empty($withProject)) $data['projects'] = $projects;
|
||||
|
||||
return $this->send(200, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($projectID = 0)
|
||||
{
|
||||
$useCode = $this->checkCodeUsed();
|
||||
|
||||
$control = $this->loadController('execution', 'create');
|
||||
|
||||
$fields = 'project,name,begin,end,lifetime,desc,days,percent,parent';
|
||||
if($useCode) $fields .= ',code';
|
||||
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$projectID = $this->param('project', $projectID);
|
||||
$this->setPost('project', $projectID);
|
||||
$this->setPost('acl', $this->request('acl', 'private'));
|
||||
$this->setPost('PO', $this->request('PO', ''));
|
||||
$this->setPost('PM', $this->request('PM', ''));
|
||||
$this->setPost('QD', $this->request('QD', ''));
|
||||
$this->setPost('RD', $this->request('RD', ''));
|
||||
$this->setPost('whitelist', $this->request('whitelist', array()));
|
||||
$this->setPost('products', $this->request('products', array()));
|
||||
$this->setPost('plans', $this->request('plans', array()));
|
||||
$this->setPost('teamMembers', $this->request('teamMembers', array()));
|
||||
|
||||
$requireFields = 'name,begin,end';
|
||||
if($useCode) $requireFields .= ',code';
|
||||
$this->requireFields($requireFields);
|
||||
|
||||
$control->create($projectID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
|
||||
$execution = $this->loadModel('execution')->getByID($data->id);
|
||||
|
||||
return $this->send(201, $this->format($execution, 'openedBy:user,openedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,PM:user,PO:user,RD:user,QD:user,whitelist:userList,begin:date,end:date,realBegan:date,realEnd:date,deleted:bool'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get drop menu.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getDropMenu()
|
||||
{
|
||||
$control = $this->loadController('execution', 'ajaxGetDropMenu');
|
||||
$control->ajaxGetDropMenu($this->request('executionID', 0), $this->request('module', 'execution'), $this->request('method', 'task'), $this->request('extra', ''));
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
|
||||
$account = $this->app->user->account;
|
||||
$dropMenu = array('involved' => array(), 'other' => array(), 'closed' => array());
|
||||
foreach($data->data->projects as $projectID => $projectName)
|
||||
{
|
||||
if(!isset($data->data->projectExecutions->$projectID)) continue;
|
||||
|
||||
foreach($data->data->projectExecutions->$projectID as $execution)
|
||||
{
|
||||
if(helper::diffDate(date('Y-m-d'), $execution->end) > 0) $execution->delay = true;
|
||||
$teams = $execution->teams;
|
||||
$execution = $this->filterFields($execution, 'id,project,model,type,name,code,status,PM,delay');
|
||||
|
||||
$execution->name = $projectName . '/' . $execution->name;
|
||||
|
||||
if($execution->status == 'closed')
|
||||
{
|
||||
$dropMenu['closed'][] = $execution;
|
||||
}
|
||||
elseif($execution->status != 'done' and $execution->status != 'closed' and ($execution->PM == $account or isset($teams->$account)))
|
||||
{
|
||||
$dropMenu['involved'][] = $execution;
|
||||
}
|
||||
else
|
||||
{
|
||||
$dropMenu['other'][] = $execution;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->send(200, $dropMenu);
|
||||
}
|
||||
}
|
||||
50
api/v1/entries/executionstories.php
Normal file
50
api/v1/entries/executionstories.php
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
/**
|
||||
* The execution entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package execution
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class executionStoriesEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $executionID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($executionID)
|
||||
{
|
||||
if(empty($executionID)) $this->param('execution', 0);
|
||||
if(empty($executionID)) return $this->sendError(400, 'Need execution id.');
|
||||
|
||||
$control = $this->loadController('execution', 'story');
|
||||
$control->story($executionID, $this->param('storyType', 'story'), $this->param('order', 'id_desc'), $this->param('status', 'all'), 0, 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
$data = $this->getData();
|
||||
|
||||
if(isset($data->status) and $data->status == 'success')
|
||||
{
|
||||
$stories = $data->data->stories;
|
||||
$pager = $data->data->pager;
|
||||
$result = array();
|
||||
$this->loadModel('product');
|
||||
foreach($stories as $story)
|
||||
{
|
||||
$product = $this->product->getById($story->product);
|
||||
$story->productStatus = $product->status;
|
||||
|
||||
$result[] = $this->format($story, 'openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList');
|
||||
}
|
||||
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'stories' => $result));
|
||||
}
|
||||
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
return $this->sendError(400, 'error');
|
||||
}
|
||||
}
|
||||
86
api/v1/entries/feedback.php
Normal file
86
api/v1/entries/feedback.php
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
/**
|
||||
* The product entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class feedbackEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $feedbackID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($feedbackID)
|
||||
{
|
||||
$control = $this->loadController('feedback', 'adminView');
|
||||
$control->adminView($feedbackID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$feedback = $data->data->feedback;
|
||||
|
||||
$feedback->publicStatus = $feedback->public;
|
||||
$feedback->productName = $data->data->product;
|
||||
$feedback->moduleName = isset($data->data->modulePath[0]->name) ? $data->data->modulePath[0]->name : '/';
|
||||
if(isset($data->data->type)) $feedback->resultType = $data->data->type;
|
||||
if(isset($feedback->resultInfo) and $feedback->resultInfo->deleted == 0) $feedback->resultStatus = $this->loadModel('feedback')->processStatus($feedback->resultType, $feedback->resultInfo);
|
||||
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$feedback->actions = $this->loadModel('action')->processActionForAPI($data->data->actions, $data->data->users, $this->lang->feedback);
|
||||
return $this->send(200, $this->format($feedback, 'activatedDate:time,openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,mailto:userList,resolvedBy:user,resolvedDate:time,closedBy:user,closedDate:time,lastEditedBy:user,lastEditedDate:time,deadline:date,deleted:bool'));
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT method.
|
||||
*
|
||||
* @param int $feedbackID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function put($feedbackID)
|
||||
{
|
||||
$control = $this->loadController('feedback', 'edit');
|
||||
$oldFeedback = $this->loadModel('feedback')->getById($feedbackID);
|
||||
|
||||
$fields = 'module,product,type,title,public,desc,status,feedbackBy,notifyEmail,notify,uid,pri';
|
||||
$this->batchSetPost($fields, $oldFeedback);
|
||||
|
||||
$control->edit($feedbackID, '');
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
if(!isset($data->result)) return $this->sendError(400, 'error');
|
||||
|
||||
$feedback = $this->feedback->getByID($feedbackID);
|
||||
|
||||
return $this->send(200, $this->format($feedback, 'openedBy:user,openedDate:time,reviewedBy:user,reviewedDate:time,processedBy:user,processedDate:time,closedBy:user,closedDate:time,editedBy:user,editedDate:time,mailto:userList,deleted:bool'));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE method.
|
||||
*
|
||||
* @param int $feedbackID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function delete($feedbackID)
|
||||
{
|
||||
$control = $this->loadController('feedback', 'delete');
|
||||
$control->delete($feedbackID, 'yes');
|
||||
|
||||
$this->getData();
|
||||
return $this->sendSuccess(200, 'success');
|
||||
}
|
||||
}
|
||||
|
||||
58
api/v1/entries/feedbackassignto.php
Normal file
58
api/v1/entries/feedbackassignto.php
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
/**
|
||||
* The feedback assignto entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class feedbackAssignToEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $feedbackID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($feedbackID)
|
||||
{
|
||||
$control = $this->loadController('feedback', 'assignTo');
|
||||
$control->assignTo($feedbackID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
return $this->send(200, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $feedbackID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($feedbackID)
|
||||
{
|
||||
$control = $this->loadController('feedback', 'assignTo');
|
||||
$feedback = $this->loadModel('feedback')->getById($feedbackID);
|
||||
|
||||
$fields = 'assignedTo,comment,mailto';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$control->assignTo($feedbackID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$feedback = $this->loadModel('feedback')->getById($feedbackID);
|
||||
|
||||
return $this->send(200, $this->format($feedback, 'activatedDate:time,openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,mailto:userList,resolvedBy:user,resolvedDate:time,closedBy:user,closedDate:time,lastEditedBy:user,lastEditedDate:time,deadline:date,deleted:bool'));
|
||||
}
|
||||
}
|
||||
41
api/v1/entries/feedbackclose.php
Normal file
41
api/v1/entries/feedbackclose.php
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
/**
|
||||
* The feedback close entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class feedbackCloseEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $feedbackID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($feedbackID)
|
||||
{
|
||||
$control = $this->loadController('feedback', 'close');
|
||||
$feedback = $this->loadModel('feedback')->getById($feedbackID);
|
||||
|
||||
$fields = 'closedReason,comment';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
if(empty($_POST)) $this->setPost('status', 'closed');
|
||||
|
||||
$control->close($feedbackID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$feedback = $this->loadModel('feedback')->getById($feedbackID);
|
||||
|
||||
return $this->send(200, $feedback);
|
||||
}
|
||||
}
|
||||
99
api/v1/entries/feedbacks.php
Normal file
99
api/v1/entries/feedbacks.php
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
/**
|
||||
* The executions entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class feedbacksEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
if(strpos(strtolower($this->param('fields')), 'moduleandproduct') !== false) return $this->getModuleAndProduct();
|
||||
|
||||
$control = $this->loadController('feedback', 'admin');
|
||||
$control->session->set('feedbackProduct', 0);
|
||||
$control->admin($this->param('status', 'unclosed'), 0, $this->param('orderBy', 'id_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
$data = $this->getData();
|
||||
|
||||
if(!$data or !isset($data->status)) return $this->sendError(400, 'error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
|
||||
|
||||
$feedbacks = $data->data->feedbacks;
|
||||
$pager = $data->data->pager;
|
||||
|
||||
$result = array();
|
||||
foreach($feedbacks as $feedback)
|
||||
{
|
||||
$result[] = $this->format($feedback, 'openedBy:user,openedDate:time,reviewedBy:user,reviewedDate:time,processedBy:user,processedDate:time,closedBy:user,closedDate:time,editedBy:user,editedDate:time,assignedTo:user,mailto:userList,deleted:bool');
|
||||
}
|
||||
|
||||
$data = array();
|
||||
$data['page'] = $pager->pageID;
|
||||
$data['total'] = $pager->recTotal;
|
||||
$data['limit'] = $pager->recPerPage;
|
||||
$data['feedbacks'] = $result;
|
||||
|
||||
return $this->send(200, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post()
|
||||
{
|
||||
$control = $this->loadController('feedback', 'create');
|
||||
|
||||
$fields = 'module,product,type,title,public,desc,status,feedbackBy,notify,uid,pri';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$this->setPost('notifyEmail', $this->request('notifyEmail', ''));
|
||||
|
||||
$this->requireFields('title,product');
|
||||
$control->create();
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
|
||||
$feedback = $this->loadModel('feedback')->getById($data->id);
|
||||
|
||||
return $this->send(201, $this->format($feedback, 'openedBy:user,openedDate:time,reviewedBy:user,reviewedDate:time,processedBy:user,processedDate:time,closedBy:user,closedDate:time,editedBy:user,editedDate:time,assignedTo:user,assignedDate:time,feedbackBy:user,mailto:userList,deleted:bool'));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getModuleAndProduct()
|
||||
{
|
||||
$control = $this->loadController('feedback', 'create');
|
||||
$control->create();
|
||||
|
||||
$data = $this->getData();
|
||||
|
||||
$modules = $data->data->modules;
|
||||
$products = $data->data->products;
|
||||
|
||||
$data = array();
|
||||
$data['modules'] = $modules;
|
||||
$data['products'] = $products;
|
||||
|
||||
return $this->send(200, $data);
|
||||
}
|
||||
|
||||
}
|
||||
46
api/v1/entries/file.php
Normal file
46
api/v1/entries/file.php
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
/**
|
||||
* The file entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class fileEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($fileID)
|
||||
{
|
||||
$control = $this->loadController('file', 'download');
|
||||
$control->download($fileID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
return $this->send(200, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function put($fileID)
|
||||
{
|
||||
$uid = $this->param('uid', '');
|
||||
$action = $this->param('action', '');
|
||||
if($action == 'remove') unset($_SESSION['album']['used'][$uid][$fileID]);
|
||||
|
||||
return $this->send(200, array('id' => $fileID));
|
||||
}
|
||||
}
|
||||
34
api/v1/entries/files.php
Normal file
34
api/v1/entries/files.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
/**
|
||||
* The files entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class filesEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post()
|
||||
{
|
||||
$uid = $this->param('uid', '');
|
||||
|
||||
$control = $this->loadController('file', 'ajaxUpload');
|
||||
$control->ajaxUpload($uid);
|
||||
|
||||
$data = $this->getData();
|
||||
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
return $this->send(200, array('id' => $data->id, 'url' => $data->url));
|
||||
}
|
||||
}
|
||||
42
api/v1/entries/gitlabwebhook.php
Normal file
42
api/v1/entries/gitlabwebhook.php
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* The repo entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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 xiawenlong <xiawenlong@cnezsoft.com>
|
||||
* @package repo
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class gitlabWebhookEntry extends baseEntry
|
||||
{
|
||||
|
||||
/**
|
||||
* Repo webhook.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post()
|
||||
{
|
||||
$headers = getallheaders(); /* Fetch all HTTP request headers. */
|
||||
$event = isset($headers['X-Gitlab-Event']) ? $headers['X-Gitlab-Event'] : '';
|
||||
if(empty($event)) return;
|
||||
|
||||
$repoID = $this->param('repoID');
|
||||
if(empty($repoID)) return;
|
||||
|
||||
$this->app->user = new stdclass();
|
||||
$this->app->user->account = '';
|
||||
$this->app->user->admin = false;
|
||||
$this->app->user->rights['rights'] = array();
|
||||
$this->app->user->rights['acls'] = array();
|
||||
|
||||
$repo = $this->loadModel('repo')->getByID($repoID);
|
||||
if(empty($repo)) return;
|
||||
|
||||
$this->loadController('user', 'login');
|
||||
$this->repo->handleWebhook($event, $this->requestBody, $repo);
|
||||
}
|
||||
}
|
||||
49
api/v1/entries/groups.php
Normal file
49
api/v1/entries/groups.php
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
/**
|
||||
* The groups entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class groupsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
$groups = $this->loadModel('group')->getList();
|
||||
$privsGroup = $this->dao->select('`group`,module, method')->from(TABLE_GROUPPRIV)->orderBy('module')->fetchGroup('group');
|
||||
$usersGroup = $this->dao->select('t1.`group`,t1.account,t2.realname')->from(TABLE_USERGROUP)->alias('t1')
|
||||
->leftJoin(TABLE_USER)->alias('t2')->on('t1.account=t2.account')
|
||||
->fetchGroup('group');
|
||||
|
||||
foreach($groups as $i => $group)
|
||||
{
|
||||
if($group->acl)
|
||||
{
|
||||
$acl = json_decode($group->acl, true);
|
||||
$group->acl = array();
|
||||
$group->acl['views'] = $acl['views'];
|
||||
}
|
||||
$privs = zget($privsGroup, $group->id, array());
|
||||
$group->privs = array();
|
||||
foreach($privs as $priv) $group->privs[$priv->module][$priv->method] = true;
|
||||
|
||||
$accounts = zget($usersGroup, $group->id, array());
|
||||
$group->accounts = array();
|
||||
foreach($accounts as $account) $group->accounts[$account->account] = $account->realname;
|
||||
|
||||
$groups[$i] = $group;
|
||||
}
|
||||
|
||||
return $this->send(200, $groups);
|
||||
}
|
||||
}
|
||||
122
api/v1/entries/hostheartbeat.php
Normal file
122
api/v1/entries/hostheartbeat.php
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
/**
|
||||
* The host entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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 Yuchun Li <liyuchun@easycorp.ltd>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class hostHeartbeatEntry extends baseEntry
|
||||
{
|
||||
/**
|
||||
* Listen host heartbeat.
|
||||
*
|
||||
* @param int|string $userID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function post()
|
||||
{
|
||||
/* Check authorize. */
|
||||
$header = getallheaders();
|
||||
$token = isset($header['Authorization']) ? substr($header['Authorization'], 7) : '';
|
||||
$secret = isset($this->requestBody->secret) ? $this->requestBody->secret : '';
|
||||
if(!$secret and !$token) return $this->sendError(401, 'Unauthorized');
|
||||
|
||||
/* Check param. */
|
||||
$status = $this->requestBody->status;
|
||||
$vms = !empty($this->requestBody->Vms) ? $this->requestBody->Vms : array();
|
||||
$zap = !empty($this->requestBody->port) ? $this->requestBody->port : 0;
|
||||
$now = helper::now();
|
||||
if(!$status) return $this->sendError(400, 'Params error.');
|
||||
|
||||
$conditionField = $secret ? 'secret' : 'tokenSN';
|
||||
$conditionValue = $secret ? $secret : $token;
|
||||
|
||||
$this->dao = $this->loadModel('common')->dao;
|
||||
$hostInfo = $this->dao->select('id,tokenSN,hostType,type')->from(TABLE_ZAHOST)
|
||||
->beginIF($secret)->where('secret')->eq($secret)->fi()
|
||||
->beginIF(!$secret)->where('tokenSN')->eq($token)
|
||||
->andWhere('tokenTime')->gt($now)->fi()
|
||||
->fetch();
|
||||
if(empty($hostInfo->id))
|
||||
{
|
||||
if(empty($token)) return $this->sendError(400, 'Secret error.');
|
||||
$hostInfo = $this->dao->select('id,tokenSN,hostType,type')->from(TABLE_ZAHOST)
|
||||
->where('oldTokenSN')->eq($token)
|
||||
->andWhere('tokenTime')->gt(date(DT_DATETIME1, strtotime($now) - 30))->fi()
|
||||
->fetch();
|
||||
if(empty($hostInfo->id)) return $this->sendError(400, 'Secret error.');
|
||||
}
|
||||
|
||||
$isPhysicsNode = $hostInfo->type == 'node' && $hostInfo->hostType == 'physics' ? true : false;
|
||||
|
||||
$host = new stdclass();
|
||||
$host->status = $status;
|
||||
if($secret)
|
||||
{
|
||||
$host->tokenSN = md5($secret . $now);
|
||||
$host->tokenTime = date('Y-m-d H:i:s', time() + 7200);
|
||||
$host->oldTokenSN = $hostInfo->tokenSN;
|
||||
}
|
||||
$host->heartbeat = $now;
|
||||
$host->zap = $zap;
|
||||
$this->dao->update(TABLE_ZAHOST)->data($host)->where($conditionField)->eq($conditionValue)->exec();
|
||||
|
||||
if($vms)
|
||||
{
|
||||
foreach($vms as $vm)
|
||||
{
|
||||
$vmData = array(
|
||||
'vnc' => $vm->vncPortOnHost,
|
||||
'zap' => $vm->agentPortOnHost,
|
||||
'ztf' => $vm->ztfPortOnHost,
|
||||
'zd' => $vm->zdPortOnHost,
|
||||
'ssh' => $vm->sshPortOnHost,
|
||||
'status' => $vm->status,
|
||||
'extranet' => $vm->ip,
|
||||
'heartbeat' => helper::now()
|
||||
);
|
||||
|
||||
if(!$vm->sshPortOnHost) unset($vmData['ssh']);
|
||||
if($isPhysicsNode)
|
||||
{
|
||||
unset($vmData['extranet']);
|
||||
$this->dao->update(TABLE_ZAHOST)->data($vmData)->where('id')->eq($hostInfo->id)->exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
$node = $this->loadModel('zanode')->getNodeByMac($vm->macAddress);
|
||||
if(empty($node)) continue;
|
||||
|
||||
if(in_array($node->status, array('restoring', 'creating_img', 'creating_snap')))
|
||||
$vmData['status'] = $vm->status = $node->status;
|
||||
$this->dao->update(TABLE_ZAHOST)->data($vmData)->where('mac')->eq($vm->macAddress)->exec();
|
||||
}
|
||||
|
||||
if($vm->status == 'running' && !$isPhysicsNode)
|
||||
{
|
||||
if(!empty($node))
|
||||
{
|
||||
$snaps = $this->loadModel('zanode')->getSnapshotList($node->id);
|
||||
if(empty($snaps))
|
||||
{
|
||||
if($vm->status == 'running') $this->loadModel('zanode')->createDefaultSnapshot($node->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!$secret) return $this->sendSuccess(200, 'success');
|
||||
|
||||
$host->tokenTimeUnix = strtotime($host->tokenTime);
|
||||
unset($host->status);
|
||||
unset($host->tokenTime);
|
||||
unset($host->oldTokenSN);
|
||||
return $this->send(200, $host);
|
||||
}
|
||||
}
|
||||
72
api/v1/entries/hostsubmit.php
Normal file
72
api/v1/entries/hostsubmit.php
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
/**
|
||||
* The host entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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 Ke Zhao <zhaoke@easycorp.ltd>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class hostSubmitEntry extends baseEntry
|
||||
{
|
||||
/**
|
||||
* Listen host task finish submit.
|
||||
*
|
||||
* @param int|string $userID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function post()
|
||||
{
|
||||
/* Check authorize. */
|
||||
$header = getallheaders();
|
||||
$token = isset($header['Authorization']) ? substr($header['Authorization'], 7) : '';
|
||||
if(!$token) return $this->sendError(401, 'Unauthorized');
|
||||
|
||||
$now = helper::now();
|
||||
|
||||
/* Check param. */
|
||||
$image = new stdclass();
|
||||
$task = $this->requestBody->task;
|
||||
$image->status = $this->requestBody->status;
|
||||
$image->status == 'complete' && $image->status = "completed";
|
||||
|
||||
$this->dao = $this->loadModel('common')->dao;
|
||||
$id = $this->dao->select('id')->from(TABLE_ZAHOST)
|
||||
->where('tokenSN')->eq($token)
|
||||
->andWhere('tokenTime')->gt($now)->fi()
|
||||
->fetch('id');
|
||||
|
||||
if(!$id) return $this->sendError(400, 'Secret error.');
|
||||
|
||||
$imageInfo = $this->dao->select('`status`,`from`,name,host')->from(TABLE_IMAGE)
|
||||
->where('id')->eq($task)
|
||||
->fetch();
|
||||
if(empty($imageInfo)) return $this->sendSuccess(200, 'success');
|
||||
|
||||
if($imageInfo->from == 'snapshot' && $imageInfo->status == 'restoring')
|
||||
{
|
||||
if(in_array($image->status, array('failed', 'completed'))) $image->status = $image->status == 'completed' ? 'restore_completed' : 'restore_failed';
|
||||
}
|
||||
else if($imageInfo->from == 'snapshot')
|
||||
{
|
||||
if($image->status == 'failed')
|
||||
{
|
||||
$this->dao->delete()->from(TABLE_IMAGE)->where("id")->eq($task)->exec();
|
||||
return $this->sendSuccess(200, 'success');
|
||||
}
|
||||
}
|
||||
|
||||
$this->dao->update(TABLE_IMAGE)->data($image)->where("id")->eq($task)->exec();
|
||||
|
||||
if($imageInfo->from != 'zentao' && in_array($imageInfo->status, array('creating', 'restoring')))
|
||||
{
|
||||
$hostID = is_numeric($imageInfo->from) ? $imageInfo->from : $imageInfo->host;
|
||||
$this->dao->update(TABLE_ZAHOST)->data(array("status" => "wait"))->where("id")->eq($hostID)->exec();
|
||||
}
|
||||
|
||||
return $this->sendSuccess(200, 'success');
|
||||
}
|
||||
}
|
||||
79
api/v1/entries/issue.php
Normal file
79
api/v1/entries/issue.php
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
/**
|
||||
* The issue entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class issueEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int|string $issueID. Issues id for Gitlab has '-', such as task-1, bug-1.
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($issueID)
|
||||
{
|
||||
/* If $issueID has '-', go to productIssue entry point for Gitlab. */
|
||||
if(strpos($issueID, '-') !== FALSE) return $this->fetch('productIssue', 'get', array('issueID' => $issueID));
|
||||
|
||||
/* Otherwise, get issue of project. */
|
||||
$control = $this->loadController('issue', 'view');
|
||||
$control->view($issueID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data or (isset($data->message) and $data->message == '404 Not found')) return $this->send404();
|
||||
if(isset($data->status) and $data->status == 'success') return $this->send(200, $this->format($data->data->issue, 'createdDate:time,editedDate:time,assignedDate:time'));
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$this->sendError(400, 'error');
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT method.
|
||||
*
|
||||
* @param int $issueID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function put($issueID)
|
||||
{
|
||||
$control = $this->loadController('issue', 'edit');
|
||||
$oldIssue = $this->loadModel('issue')->getByID($issueID);
|
||||
|
||||
/* Set $_POST variables. */
|
||||
$fields = 'type,title,severity,pri,assignedTo,deadline,desc';
|
||||
$this->batchSetPost($fields, $oldIssue);
|
||||
|
||||
$control->edit($issueID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data or (isset($data->message) and $data->message == '404 Not found')) return $this->send404();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
|
||||
$issue = $this->issue->getByID($issueID);
|
||||
return $this->send(200, $this->format($issue, 'createdDate:time,editedDate:time,assignedDate:time'));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE method.
|
||||
*
|
||||
* @param int $issueID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function delete($issueID)
|
||||
{
|
||||
$control = $this->loadController('issue', 'delete');
|
||||
$control->delete($issueID, 'true');
|
||||
|
||||
$this->getData();
|
||||
return $this->sendSuccess(200, 'success');
|
||||
}
|
||||
}
|
||||
100
api/v1/entries/issues.php
Normal file
100
api/v1/entries/issues.php
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
/**
|
||||
* The issues entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class issuesEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($projectID = 0)
|
||||
{
|
||||
if($projectID) return $this->getProjectIssues($projectID);
|
||||
|
||||
/* Get my issues defaultly. */
|
||||
$control = $this->loadController('my', 'issue');
|
||||
$control->issue($this->param('type', 'assignedTo'), $this->param('order', 'id_desc'), $this->param('total', 0), $this->param('limit', 20), $this->param('page', 1));
|
||||
$data = $this->getData();
|
||||
|
||||
if(!isset($data->status)) return $this->sendError(400, 'error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$pager = $data->data->pager;
|
||||
$result = array();
|
||||
foreach($data->data->issues as $issue)
|
||||
{
|
||||
$result[] = $this->format($issue, 'createdDate:time,editedDate:time,assignedDate:time');
|
||||
}
|
||||
|
||||
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'issues' => $result));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get issues of project.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
private function getProjectIssues($projectID)
|
||||
{
|
||||
$control = $this->loadController('issue', 'browse');
|
||||
$project = $this->loadModel('project')->getByID($projectID);
|
||||
if(!$project) return $this->send404();
|
||||
|
||||
$control->browse($projectID, $this->param('type', 'all'), 0, $this->param('order', ''), $this->param('total', 0), $this->param('limit', 20), $this->param('page', 1));
|
||||
$data = $this->getData();
|
||||
|
||||
if(!isset($data->status)) return $this->sendError(400, 'error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
|
||||
|
||||
$pager = $data->data->pager;
|
||||
$result = array();
|
||||
foreach($data->data->issueList as $issue)
|
||||
{
|
||||
$result[] = $this->format($issue, 'createdDate:time,editedDate:time,assignedDate:time');
|
||||
}
|
||||
|
||||
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'issues' => $result));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($projectID = 0)
|
||||
{
|
||||
$control = $this->loadController('issue', 'create');
|
||||
$project = $this->loadModel('project')->getByID($projectID);
|
||||
if(!$project) return $this->send404();
|
||||
|
||||
$fields = 'type,title,severity,pri,assignedTo,deadline,desc';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$this->requireFields('type,title,severity');
|
||||
|
||||
$control->create($projectID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
if(isset($data->result) and!isset($data->id)) return $this->sendError(400, $data->message);
|
||||
|
||||
$issue = $this->loadModel('issue')->getByID($data->id);
|
||||
|
||||
return $this->send(201, $this->format($issue, 'createdDate:time,editedDate:time,assignedDate:time'));
|
||||
}
|
||||
}
|
||||
52
api/v1/entries/jobs.php
Normal file
52
api/v1/entries/jobs.php
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
/**
|
||||
* The jobs entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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 Yanyi Cao <caoyanyi@easycorp.ltd>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class jobsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
$control = $this->loadController('job', 'browse');
|
||||
$pipeline = $this->param('pipeline', '');
|
||||
$orderBy = $this->param('order', 'id_desc');
|
||||
|
||||
if(empty($pipeline))
|
||||
{
|
||||
$control->browse($orderBy, 0, $this->param('limit', 100), $this->param('page', 1));
|
||||
|
||||
/* Response */
|
||||
$data = $this->getData();
|
||||
if(isset($data->status) and $data->status == 'success')
|
||||
{
|
||||
$result = array();
|
||||
$pager = $data->data->pager;
|
||||
$jobs = $data->data->jobList;
|
||||
foreach($jobs as $job) $result[] = $this->format($job, 'deleted:bool,lastSync:datetime,synced:bool,product:idList');
|
||||
|
||||
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'jobs' => $result));
|
||||
}
|
||||
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
}
|
||||
else
|
||||
{
|
||||
$jobs = $this->loadModel('job')->getList(0, '', $orderBy, null, $this->param('engine', 'jenkins'), $pipeline);
|
||||
return $this->send(200, array('jobs' => array_values($jobs)));
|
||||
}
|
||||
|
||||
return $this->sendError(400, 'error');
|
||||
}
|
||||
}
|
||||
83
api/v1/entries/langs.php
Normal file
83
api/v1/entries/langs.php
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
/**
|
||||
* The langs entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class langsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
$modules = $this->param('modules', '');
|
||||
$language = $this->param('lang', '');
|
||||
|
||||
if($language and !isset($this->config->langs[$language])) return $this->sendError(400, 'Error lang parameter');
|
||||
if(empty($modules)) return $this->sendError(400, 'Need modules');
|
||||
|
||||
if(empty($language)) $language = 'zh-cn';
|
||||
$this->app->setClientLang($language);
|
||||
|
||||
global $filter;
|
||||
$rule = $filter->default->moduleName;
|
||||
$modules = explode(',', $modules);
|
||||
foreach($modules as $module)
|
||||
{
|
||||
if($module == 'all')
|
||||
{
|
||||
$loadedModule = array();
|
||||
foreach(glob($this->app->getModuleRoot() . '*') as $modulePath)
|
||||
{
|
||||
if(!is_dir($modulePath)) continue;
|
||||
|
||||
$moduleName = basename($modulePath);
|
||||
if(!validater::checkByRule($moduleName, $rule)) continue;
|
||||
$this->app->loadLang($moduleName);
|
||||
|
||||
$loadedModule[$moduleName] = $moduleName;
|
||||
}
|
||||
|
||||
foreach(glob($this->app->getExtensionRoot() . '*') as $extensionPath)
|
||||
{
|
||||
if(!is_dir($extensionPath)) continue;
|
||||
|
||||
$edition = basename($extensionPath);
|
||||
if($edition == 'lite') continue;
|
||||
if($edition == 'biz' or $edition == 'max')
|
||||
{
|
||||
if($this->config->edition == 'open') continue;
|
||||
if($this->config->edition != 'open' and $this->config->edition != $edition) continue;
|
||||
}
|
||||
|
||||
foreach(glob($extensionPath . '/*') as $modulePath)
|
||||
{
|
||||
if(!is_dir($modulePath)) continue;
|
||||
|
||||
$moduleName = basename($modulePath);
|
||||
if(!validater::checkByRule($moduleName, $rule)) continue;
|
||||
if(isset($loadedModule[$moduleName])) continue;
|
||||
|
||||
$this->app->loadLang($moduleName);
|
||||
|
||||
$loadedModule[$moduleName] = $moduleName;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(validater::checkByRule($module, $rule)) $this->app->loadLang($module);
|
||||
}
|
||||
|
||||
return $this->send(200, $this->lang);
|
||||
}
|
||||
}
|
||||
80
api/v1/entries/meetings.php
Normal file
80
api/v1/entries/meetings.php
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
/**
|
||||
* The meetings entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class meetingsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($projectID = 0)
|
||||
{
|
||||
if(empty($projectID)) $projectID = $this->param('project', 0);
|
||||
if(empty($projectID)) return $this->sendError(400, 'Need project id.');
|
||||
|
||||
$control = $this->loadController('meeting', 'browse');
|
||||
$project = $this->loadModel('project')->getByID($projectID);
|
||||
if(!$project) return $this->send404();
|
||||
|
||||
/* Get meetings by project. */
|
||||
$control->browse($projectID, $this->param('status', 'all'), '', $this->param('order', 'id_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
$data = $this->getData();
|
||||
|
||||
if(!isset($data->status)) return $this->sendError(400, 'error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$pager = $data->data->pager;
|
||||
$result = array();
|
||||
foreach($data->data->meetings as $risk)
|
||||
{
|
||||
$result[] = $this->format($risk, 'createdDate:time,editedDate:time');
|
||||
}
|
||||
|
||||
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'meetings' => $result));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($projectID = 0)
|
||||
{
|
||||
$control = $this->loadController('risk', 'create');
|
||||
$project = $this->loadModel('project')->getByID($projectID);
|
||||
if(!$project) return $this->send404();
|
||||
|
||||
$fields = 'source,name,category,strategy,status,impact,probability,rate,identifiedDate,plannedClosedDate,actualClosedDate,resolvedBy,assignedTo,prevention,remedy,resolution';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$this->setPost('impact', $this->request('impact', 3));
|
||||
$this->setPost('probability', $this->request('probability', 3));
|
||||
$this->setPost('rate', $this->request('rate', 9));
|
||||
$this->setPost('pri', 'middle');
|
||||
|
||||
$this->requireFields('name');
|
||||
|
||||
$control->create($projectID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
if(isset($data->result) and !isset($data->id)) return $this->sendError(400, $data->message);
|
||||
|
||||
$risk = $this->loadModel('risk')->getByID($data->id);
|
||||
|
||||
return $this->send(201, $this->format($risk, 'createdDate:time,editedDate:time'));
|
||||
}
|
||||
}
|
||||
43
api/v1/entries/modules.php
Normal file
43
api/v1/entries/modules.php
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* The modules entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class modulesEntry extends entry
|
||||
{
|
||||
/**
|
||||
* Get method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
$objectType = $this->param('type', '');
|
||||
$objectID = $this->param('id', '');
|
||||
|
||||
if(!$objectType or !$objectID) return $this->sendError(400, 'Need id and type.');
|
||||
if(!in_array($objectType, array('story', 'task', 'bug', 'case', 'feedback', 'product'))) return $this->sendError(400, 'Type is not allowed');
|
||||
|
||||
if($objectType == 'task')
|
||||
{
|
||||
$control = $this->loadController('tree', 'browsetask');
|
||||
$control->browseTask($objectID);
|
||||
}
|
||||
else
|
||||
{
|
||||
$control = $this->loadController('tree', 'browse');
|
||||
$control->browse($objectID, $objectType);
|
||||
}
|
||||
$data = $this->getData();
|
||||
if(isset($data->status) and $data->status == 'success') return $this->send(200, array('modules' => $data->data->tree));
|
||||
|
||||
return $this->send400(isset($data->message) ? $data->message: 'error');
|
||||
}
|
||||
}
|
||||
33
api/v1/entries/mr.php
Normal file
33
api/v1/entries/mr.php
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
/**
|
||||
* The mr entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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 liyuchun <liyuchun@easysoft.ltd>
|
||||
* @package repo
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class mrEntry extends baseEntry
|
||||
{
|
||||
/**
|
||||
* Create mr.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post()
|
||||
{
|
||||
$this->loadController('mr', 'create');
|
||||
|
||||
$fields = 'repoID,jobID,sourceBranch,targetBranch,diffs,mergeStatus';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$MRID = $this->loadModel('mr')->apiCreate();
|
||||
if(dao::isError()) $this->sendError(400, dao::getError());
|
||||
|
||||
$MR = $this->mr->fetchByID($MRID);
|
||||
return $this->send(201, $MR);
|
||||
}
|
||||
}
|
||||
46
api/v1/entries/options.php
Normal file
46
api/v1/entries/options.php
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
/**
|
||||
* The options entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class optionsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param string $type
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($type = '')
|
||||
{
|
||||
if(!$type) return $this->sendError(400, 'error');
|
||||
|
||||
$options = array();
|
||||
switch($type)
|
||||
{
|
||||
case 'bug':
|
||||
$this->app->loadLang('bug');
|
||||
$options['type'] = $this->lang->bug->typeList;
|
||||
$options['pri'] = $this->lang->bug->priList;
|
||||
$options['severity'] = $this->lang->bug->severityList;
|
||||
|
||||
$options['modules'] = new stdclass();
|
||||
$product = $this->param('product', 0);
|
||||
if($product) $options['modules'] = $this->loadModel('tree')->getOptionMenu($product, 'bug');
|
||||
|
||||
$execution = $this->param('execution', 0);
|
||||
$options['build'] = $this->loadModel('build')->getBuildPairs(array($product), 'all', '', $execution, 'execution');
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return $this->send(200, array('options' => $options));
|
||||
}
|
||||
}
|
||||
24
api/v1/entries/ping.php
Normal file
24
api/v1/entries/ping.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
/**
|
||||
* The ping entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class pingEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
return $this->send(200, array('token' => session_id(), 'tokenLife' => ini_get('session.gc_maxlifetime')));
|
||||
}
|
||||
}
|
||||
32
api/v1/entries/pipelines.php
Normal file
32
api/v1/entries/pipelines.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
/**
|
||||
* The pipeline entry point of ZenTaoPMS.
|
||||
* It is only used by Zcli.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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 Yanyi Cao <caoyanyi@easycorp.ltd>
|
||||
* @package pipeline
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class pipelinesEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
$pipeline = $this->param('pipeline', '');
|
||||
$repoUrl = $this->param('repoUrl', '');
|
||||
if(empty($pipeline) and empty($repoUrl)) return $this->sendError(400, 'The parameter is incorrect!');
|
||||
|
||||
$repo = $this->loadModel('repo')->getRepoByUrl($repoUrl, $pipeline);
|
||||
if(empty($repo['data'])) return $this->sendError(400, $repo['message']);
|
||||
|
||||
return $this->send(200, array('status' => 'success', 'repo' => $repo['data']));
|
||||
}
|
||||
}
|
||||
138
api/v1/entries/product.php
Normal file
138
api/v1/entries/product.php
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
<?php
|
||||
/**
|
||||
* The product entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class productEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $productID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($productID)
|
||||
{
|
||||
$fields = $this->param('fields');
|
||||
|
||||
$control = $this->loadController('product', 'view');
|
||||
$control->view($productID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$product = $this->format($data->data->product, 'createdDate:time,whitelist:userList,createdBy:user,PO:user,RD:user,QD:user,feedback:user');
|
||||
|
||||
$this->loadModel('testcase');
|
||||
$product->caseReview = ($this->config->testcase->needReview or !empty($this->config->testcase->forceReview));
|
||||
|
||||
if(!$fields) return $this->send(200, $product);
|
||||
|
||||
/* Set other fields. */
|
||||
$fields = explode(',', strtolower($fields));
|
||||
foreach($fields as $field)
|
||||
{
|
||||
switch($field)
|
||||
{
|
||||
case 'modules':
|
||||
$control = $this->loadController('tree', 'browse');
|
||||
$control->browse($productID, 'story');
|
||||
$data = $this->getData();
|
||||
if(isset($data->status) and $data->status == 'success')
|
||||
{
|
||||
$product->modules = $data->data->tree;
|
||||
}
|
||||
break;
|
||||
case 'execution':
|
||||
$product->execution = $this->loadModel('product')->getExecutionPairsByProduct($productID);
|
||||
break;
|
||||
case 'bugstatistic':
|
||||
$product->bugStatistic = $this->loadModel('bug')->getStatistic($productID);
|
||||
break;
|
||||
case 'moduleoptionmenu':
|
||||
$modules = $this->loadModel('tree')->getOptionMenu($productID, $this->param('moduleType', 'story'));
|
||||
$product->moduleOptionMenu = array();
|
||||
foreach($modules as $id => $name) $product->moduleOptionMenu[] = array('id' => $id, 'name' => $name);
|
||||
break;
|
||||
case 'parentstories':
|
||||
$product->parentstories= $this->loadModel('story')->getParentStoryPairs($productID);
|
||||
break;
|
||||
case 'builds':
|
||||
$product->builds = $this->loadModel('build')->getBuildPairs(array($productID), 'all', 'noempty,noterminate,nodone,withbranch', $this->param('object', 0), $this->param('objectType', 'execution'));
|
||||
break;
|
||||
case 'actions':
|
||||
$product->addComment = common::hasPriv('action', 'comment') ? true : false;
|
||||
|
||||
$users = $this->loadModel('user')->getPairs();
|
||||
$actions = $data->data->actions;
|
||||
$product->actions = $this->loadModel('action')->processActionForAPI($actions, $users, $this->lang->product);
|
||||
break;
|
||||
case 'lastexecution':
|
||||
$execution = $this->dao->select('t2.id,t2.name,t2.type,t2.progress')->from(TABLE_PROJECTPRODUCT)->alias('t1')
|
||||
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
|
||||
->where('t2.deleted')->eq(0)
|
||||
->andWhere('t1.product')->eq($productID)
|
||||
->andWhere('t2.type')->in('sprint,stage')
|
||||
->orderBy('t2.id desc')
|
||||
->limit(1)
|
||||
->fetch();
|
||||
|
||||
$product->lastExecution = $execution;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->send(200, $product);
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT method.
|
||||
*
|
||||
* @param int $productID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function put($productID)
|
||||
{
|
||||
$control = $this->loadController('product', 'edit');
|
||||
$useCode = $this->checkCodeUsed();
|
||||
$oldProduct = $this->loadModel('product')->getByID($productID);
|
||||
|
||||
/* Set $_POST variables. */
|
||||
$fields = 'program,line,name,PO,QD,RD,type,desc,whitelist,status,acl';
|
||||
if($useCode) $fields .= ',code';
|
||||
$this->batchSetPost($fields, $oldProduct);
|
||||
|
||||
$control->edit($productID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
|
||||
$product = $this->product->getByID($productID);
|
||||
return $this->send(200, $this->format($product, 'createdDate:time,whitelist:userList,createdBy:user,PO:user,RD:user,QD:user'));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE method.
|
||||
*
|
||||
* @param int $productID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function delete($productID)
|
||||
{
|
||||
$control = $this->loadController('product', 'delete');
|
||||
$control->delete($productID, 'yes');
|
||||
|
||||
$this->getData();
|
||||
return $this->sendSuccess(200, 'success');
|
||||
}
|
||||
}
|
||||
205
api/v1/entries/productissue.php
Normal file
205
api/v1/entries/productissue.php
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
<?php
|
||||
/**
|
||||
* The productissue entry point of ZenTaoPMS.
|
||||
* It is only used by Gitlab.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class productIssueEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param string $issueID, such as task-1, story-1, bug-1
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($issueID)
|
||||
{
|
||||
$this->loadModel('entry');
|
||||
|
||||
$idParams = explode('-', $issueID);
|
||||
if(count($idParams) < 2) $this->sendError(400, 'The id of issue is wrong.');
|
||||
|
||||
$type = $idParams[0];
|
||||
$id = intval($idParams[1]);
|
||||
|
||||
$issue = new stdclass();
|
||||
switch($type)
|
||||
{
|
||||
case 'story':
|
||||
$this->app->loadLang('story');
|
||||
$storyStatus = array('' => '', 'draft' => 'opened', 'reviewing' => 'opened', 'active' => 'opened', 'changing' => 'opened', 'closed' => 'closed');
|
||||
|
||||
$story = $this->dao->select('*')->from(TABLE_STORY)->where('id')->eq($id)->fetch();
|
||||
if(!$story) $this->send404();
|
||||
|
||||
$issue->id = $issueID;
|
||||
$issue->title = $story->title;
|
||||
$issue->labels = array($this->app->lang->story->common, zget($this->app->lang->story->categoryList, $story->category));
|
||||
$issue->pri = $story->pri;
|
||||
$issue->openedDate = $story->openedDate;
|
||||
$issue->openedBy = $story->openedBy;
|
||||
$issue->lastEditedDate = $story->lastEditedDate < '1970-01-01 01:01:01' ? $story->openedDate : $story->lastEditedDate;
|
||||
$issue->lastEditedBy = $story->lastEditedDate < '1970-01-01 01:01:01' ? $story->openedBy : $story->lastEditedBy;
|
||||
$issue->status = $storyStatus[$story->status];
|
||||
$issue->url = helper::createLink('story', 'view', "storyID=$id");
|
||||
|
||||
$storySpec = $this->dao->select('*')->from(TABLE_STORYSPEC)->where('story')->eq($id)->andWhere('version')->eq($story->version)->fetch();
|
||||
$issue->desc = $storySpec->spec;
|
||||
|
||||
$issue->assignedTo = $story->assignedTo == "" ? array() : array($story->assignedTo);
|
||||
|
||||
break;
|
||||
|
||||
case 'bug':
|
||||
$this->app->loadLang('bug');
|
||||
$bugStatus = array('' => '', 'active' => 'opened', 'resolved' => 'opened', 'closed' => 'closed');
|
||||
|
||||
$bug = $this->dao->select('*')->from(TABLE_BUG)->where('id')->eq($id)->fetch();
|
||||
if(!$bug) $this->send404();
|
||||
|
||||
$issue->id = $issueID;
|
||||
$issue->title = $bug->title;
|
||||
$issue->labels = array($this->app->lang->bug->common, zget($this->app->lang->bug->typeList, $bug->type));
|
||||
$issue->pri = $bug->pri;
|
||||
$issue->openedDate = $bug->openedDate;
|
||||
$issue->openedBy = $bug->openedBy;
|
||||
$issue->lastEditedDate = helper::isZeroDate($bug->lastEditedDate) ? $bug->openedDate : $bug->lastEditedDate;
|
||||
$issue->lastEditedBy = helper::isZeroDate($bug->lastEditedDate) ? $bug->openedBy : $bug->lastEditedBy;
|
||||
$issue->status = $bugStatus[$bug->status];
|
||||
$issue->url = helper::createLink('bug', 'view', "bugID=$id");
|
||||
$issue->desc = $bug->steps;
|
||||
|
||||
$issue->assignedTo = $bug->assignedTo == "" ? array() : array($bug->assignedTo);
|
||||
break;
|
||||
|
||||
case 'task':
|
||||
$this->app->loadLang('task');
|
||||
$taskStatus = array('' => '', 'wait' => 'opened', 'doing' => 'opened', 'done' => 'opened', 'pause' => 'opened', 'cancel' => 'opened', 'closed' => 'closed');
|
||||
|
||||
$task = $this->dao->select('*')->from(TABLE_TASK)->where('id')->eq($id)->fetch();
|
||||
if(!$task) $this->send404();
|
||||
|
||||
$issue->id = $issueID;
|
||||
$issue->title = $task->name;
|
||||
$issue->labels = array($this->app->lang->task->common, zget($this->app->lang->task->typeList, $task->type));
|
||||
$issue->pri = $task->pri;
|
||||
$issue->openedDate = $task->openedDate;
|
||||
$issue->openedBy = $task->openedBy;
|
||||
$issue->lastEditedDate = $task->lastEditedDate < '1970-01-01 01:01:01' ? $task->openedDate : $task->lastEditedDate;
|
||||
$issue->lastEditedBy = $task->lastEditedDate < '1970-01-01 01:01:01' ? $task->openedBy : $task->lastEditedBy;
|
||||
$issue->status = $taskStatus[$task->status];
|
||||
$issue->url = helper::createLink('task', 'view', "taskID=$id");
|
||||
$issue->desc = $task->desc;
|
||||
|
||||
/* Get assignees for task, the task object has the type of multiple assign only so far. */
|
||||
$users = $this->dao->select('account')->from(TABLE_TEAM)
|
||||
->where('type')->eq('task')
|
||||
->andWhere('root')->eq($task->id)
|
||||
->fetchAll();
|
||||
if($users)
|
||||
{
|
||||
foreach($users as $user) $issue->assignedTo[] = $user->account;
|
||||
}
|
||||
else
|
||||
{
|
||||
$issue->assignedTo = $task->assignedTo == "" ? array() : array($task->assignedTo);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->send404();
|
||||
}
|
||||
|
||||
$actions = $this->loadModel('action')->getList($type, $id);
|
||||
|
||||
$issue->comments = array_values($this->processActions($type, $actions));
|
||||
|
||||
/* Get all users in issues so that we can get user detail later in batch. */
|
||||
$accountList = array();
|
||||
foreach($issue->assignedTo as $account) $accountList[] = $account;
|
||||
$accountList[] = $issue->openedBy;
|
||||
$accountList = array_unique($accountList);
|
||||
$profileList = $this->loadModel('user')->getListForGitLabAPI($accountList);
|
||||
|
||||
/* Set the user detail to assignedTo and openedBy. */
|
||||
foreach($issue->assignedTo as $key => $account)
|
||||
{
|
||||
if($account == 'closed')
|
||||
{
|
||||
$issue->assignedTo = array();
|
||||
break;
|
||||
}
|
||||
|
||||
$issue->assignedTo[$key] = $profileList[$account];
|
||||
}
|
||||
$issue->openedBy = $profileList[$issue->openedBy];
|
||||
|
||||
return $this->send(200, array('issue' => $this->format($issue, 'openedDate:time,lastEditedDate:time')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Process actions of one issue.
|
||||
*
|
||||
* @param string $type bug|task|story
|
||||
* @param array $actions
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function processActions($type, $actions)
|
||||
{
|
||||
$accountList = array();
|
||||
foreach($actions as $action)
|
||||
{
|
||||
$accountList[] = $action->actor;
|
||||
ob_start();
|
||||
if(method_exists($this->action, "printActionForGitLab"))
|
||||
{
|
||||
$this->action->printActionForGitLab($action);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->action->printAction($action);
|
||||
}
|
||||
$action->title = ob_get_contents();
|
||||
ob_clean();
|
||||
|
||||
$action->body_html = '';
|
||||
|
||||
if(!empty($action->history))
|
||||
{
|
||||
ob_start();
|
||||
$this->action->printChanges($action->objectType, $action->history);
|
||||
$action->body_html = ob_get_contents();
|
||||
ob_clean();
|
||||
}
|
||||
|
||||
if(!empty($action->comment))
|
||||
{
|
||||
$comment = strip_tags($action->comment) == $action->comment ? nl2br($action->comment) : $action->comment;
|
||||
$action->body_html = "{$comment}";
|
||||
}
|
||||
}
|
||||
|
||||
/* Format user detail and date. */
|
||||
$accountList = array_unique($accountList);
|
||||
$profileList = $this->loadModel('user')->getListForGitLabAPI($accountList);
|
||||
foreach($actions as $key => $action)
|
||||
{
|
||||
$action->actor = isset($profileList[$action->actor]) ? $profileList[$action->actor] : array();
|
||||
$action->date = gmdate("Y-m-d\TH:i:s\Z", strtotime($action->date));
|
||||
|
||||
/* Unset this action when actor is System. */
|
||||
if(empty($action->actor)) unset($actions[$key]);
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
}
|
||||
353
api/v1/entries/productissues.php
Normal file
353
api/v1/entries/productissues.php
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
<?php
|
||||
/**
|
||||
* The productissue entry point of ZenTaoPMS.
|
||||
* It is only used by Gitlab.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class productIssuesEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $productID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($productID)
|
||||
{
|
||||
if(!is_numeric($productID)) $this->sendError(400, 'The product_id is not supported');
|
||||
|
||||
$taskFields = 'id,status';
|
||||
$taskStatus = array();
|
||||
$taskStatus['opened'] = 'wait,doing,done,pause';
|
||||
$taskStatus['closed'] = 'closed';
|
||||
|
||||
$storyFields = 'id,status';
|
||||
$storyStatus = array();
|
||||
$storyStatus['opened'] = 'draft,reviewing,active,changing';
|
||||
$storyStatus['closed'] = 'closed';
|
||||
|
||||
$bugFields = 'id,status';
|
||||
$bugStatus = array();
|
||||
$bugStatus['opened'] = 'active,resolved';
|
||||
$bugStatus['closed'] = 'closed';
|
||||
|
||||
$productID = (int)$productID;
|
||||
$status = $this->param('status', '');
|
||||
$search = $this->param('search', '');
|
||||
$page = intval($this->param('page', 1));
|
||||
$limit = intval($this->param('limit', 20));
|
||||
$order = $this->param('order', 'openedDate_desc');
|
||||
|
||||
$labels = $this->param('labels', '');
|
||||
$labels = $labels ? explode(',', $labels) : array();
|
||||
|
||||
$orderParams = explode('_', $order);
|
||||
$order = $orderParams[0];
|
||||
$sort = (isset($orderParams[1]) and strtolower($orderParams[1]) == 'asc') ? 'asc' : 'desc';
|
||||
|
||||
if($status == 'all') $status = '';
|
||||
if(!in_array($status, array('opened', 'closed', ''))) $this->sendError(400, 'The status is not supported');
|
||||
|
||||
switch($order)
|
||||
{
|
||||
case 'openedDate':
|
||||
$taskFields .= ',openedDate';
|
||||
$storyFields .= ',openedDate';
|
||||
$bugFields .= ',openedDate';
|
||||
break;
|
||||
case 'title':
|
||||
$taskFields .= ',name as title';
|
||||
$storyFields .= ',title';
|
||||
$bugFields .= ',title';
|
||||
break;
|
||||
case 'lastEditedDate':
|
||||
$taskFields .= ",if(lastEditedDate < '1970-01-01 01-01-01', openedDate, lastEditedDate) as lastEditedDate";
|
||||
$storyFields .= ",if(lastEditedDate < '1970-01-01 01-01-01', openedDate, lastEditedDate) as lastEditedDate";
|
||||
$bugFields .= ",if(lastEditedDate < '1970-01-01 01-01-01', openedDate, lastEditedDate) as lastEditedDate";
|
||||
break;
|
||||
default:
|
||||
$this->sendError(400, 'The order is not supported');
|
||||
}
|
||||
|
||||
$issues = array();
|
||||
$storyFilter = array();
|
||||
$bugFilter = array();
|
||||
$taskFilter = array();
|
||||
$labelTypes = array();
|
||||
|
||||
if(!empty($labels))
|
||||
{
|
||||
$this->app->loadLang('story');
|
||||
$this->app->loadLang('task');
|
||||
$this->app->loadLang('bug');
|
||||
|
||||
$storyTypeMap = array_flip($this->app->lang->story->categoryList);
|
||||
$taskTypeMap = array_flip($this->app->lang->task->typeList);
|
||||
$bugTypeMap = array_flip($this->app->lang->bug->typeList);
|
||||
|
||||
$allValidLabels = array_merge(array_keys(array_merge($storyTypeMap, $taskTypeMap, $bugTypeMap)), array($this->app->lang->story->common, $this->app->lang->task->common, $this->app->lang->bug->common));
|
||||
foreach($labels as $label)
|
||||
{
|
||||
/* Return empty result if label is not exists.*/
|
||||
if(!in_array($label, $allValidLabels)) $this->send(200, array('page' => $page, 'total' => 0, 'limit' => $limit, 'issues' => array()));
|
||||
|
||||
if($label == $this->app->lang->story->common) $storyFilter[] = 'all';
|
||||
if(isset($storyTypeMap[$label])) $storyFilter[] = $storyTypeMap[$label];
|
||||
|
||||
if($label == $this->app->lang->task->common) $taskFilter[] = 'all';
|
||||
if(isset($taskTypeMap[$label])) $taskFilter[] = $taskTypeMap[$label];
|
||||
|
||||
if($label == $this->app->lang->bug->common) $bugFilter[] = 'all';
|
||||
if(isset($bugTypeMap[$label])) $bugFilter[] = $bugTypeMap[$label];
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($storyFilter)) $labelTypes[] = 'story';
|
||||
if(!empty($taskFilter)) $labelTypes[] = 'task';
|
||||
if(!empty($bugFilter)) $labelTypes[] = 'bug';
|
||||
|
||||
/* If posted labels are not conflictive. */
|
||||
if(count($labelTypes) < 2)
|
||||
{
|
||||
$storyFilter = array_unique($storyFilter);
|
||||
$taskFilter = array_unique($taskFilter);
|
||||
$bugFilter = array_unique($bugFilter);
|
||||
|
||||
$executions = $this->dao->select('project')->from(TABLE_PROJECTPRODUCT)->where('product')->eq($productID)->fetchPairs();
|
||||
|
||||
/* Get tasks. */
|
||||
if(empty($labelTypes) or in_array('task', $labelTypes))
|
||||
{
|
||||
$query = $this->dao->select($taskFields)->from(TABLE_TASK)->where('execution')->in(array_values($executions))
|
||||
->beginIF($search)->andWhere('name')->like("%$search%")->fi()
|
||||
->beginIF($status)->andWhere('status')->in($taskStatus[$status])->fi()
|
||||
->andWhere('deleted')->eq(0);
|
||||
foreach($taskFilter as $filter) if($filter != 'all') $query->andWhere('type')->eq($filter);
|
||||
$tasks = $query->fetchAll();
|
||||
foreach($tasks as $task) $issues[] = array('id' => $task->id, 'type' => 'task', 'order' => $task->$order, 'status' => $this->getKey($task->status, $taskStatus));
|
||||
}
|
||||
|
||||
/* Get stories. */
|
||||
if(empty($labelTypes) or in_array('story', $labelTypes))
|
||||
{
|
||||
$query = $this->dao->select($storyFields)->from(TABLE_STORY)
|
||||
->where('product')->eq($productID)
|
||||
->beginIF($search)->andWhere('title')->like("%$search%")->fi()
|
||||
->beginIF($status)->andWhere('status')->in($storyStatus[$status])->fi()
|
||||
->andWhere('deleted')->eq(0);
|
||||
foreach($storyFilter as $filter) if($filter != 'all') $query->andWhere('category')->eq($filter);
|
||||
$stories = $query->fetchAll();
|
||||
foreach($stories as $story) $issues[] = array('id' => $story->id, 'type' => 'story', 'order' => $story->$order, 'status' => $this->getKey($story->status, $storyStatus));
|
||||
}
|
||||
|
||||
/* Get bugs. */
|
||||
if(empty($labelTypes) or in_array('bug', $labelTypes))
|
||||
{
|
||||
$query = $this->dao->select($bugFields)->from(TABLE_BUG)
|
||||
->where('product')->eq($productID)
|
||||
->beginIF($search)->andWhere('title')->like("%$search%")->fi()
|
||||
->beginIF($status)->andWhere('status')->in($bugStatus[$status])->fi()
|
||||
->andWhere('deleted')->eq(0);
|
||||
foreach($bugFilter as $filter) if($filter != 'all') $query->andWhere('type')->eq($filter);
|
||||
$bugs = $query->fetchAll();
|
||||
foreach($bugs as $bug) $issues[] = array('id' => $bug->id, 'type' => 'bug', 'order' => $bug->$order, 'status' => $this->getKey($bug->status, $bugStatus));
|
||||
}
|
||||
}
|
||||
|
||||
array_multisort(array_column($issues, 'order'), $sort == 'asc' ? SORT_ASC : SORT_DESC, $issues);
|
||||
$total = count($issues);
|
||||
$issues = $page < 1 ? array() : array_slice($issues, ($page-1) * $limit, $limit);
|
||||
|
||||
$result = $this->processIssues($issues);
|
||||
return $this->send(200, array('page' => $page, 'total' => $total, 'limit' => $limit, 'issues' => $result));
|
||||
}
|
||||
|
||||
/**
|
||||
* Process issues, format fields.
|
||||
*
|
||||
* @param array $issues
|
||||
* @param int $page
|
||||
* @param int $limit
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function processIssues($issues)
|
||||
{
|
||||
$this->app->loadLang('story');
|
||||
$this->app->loadLang('task');
|
||||
$this->app->loadLang('bug');
|
||||
|
||||
$this->loadModel('entry');
|
||||
|
||||
$tasks = array();
|
||||
$stories = array();
|
||||
$bugs = array();
|
||||
foreach($issues as $issue)
|
||||
{
|
||||
if($issue['type'] == 'story') $stories[] = $issue['id'];
|
||||
if($issue['type'] == 'task') $tasks[] = $issue['id'];
|
||||
if($issue['type'] == 'bug') $bugs[] = $issue['id'];
|
||||
}
|
||||
|
||||
if(!empty($tasks)) $tasks = $this->dao->select('*')->from(TABLE_TASK)->where('id')->in($tasks)->fetchAll('id');
|
||||
if(!empty($stories)) $stories = $this->dao->select('*')->from(TABLE_STORY)->where('id')->in($stories)->fetchAll('id');
|
||||
if(!empty($bugs)) $bugs = $this->dao->select('*')->from(TABLE_BUG)->where('id')->in($bugs)->fetchAll('id');
|
||||
|
||||
$result = array();
|
||||
foreach($issues as $issue)
|
||||
{
|
||||
$r = new stdclass();
|
||||
if($issue['type'] == 'task')
|
||||
{
|
||||
$task = $tasks[$issue['id']];
|
||||
|
||||
$r->id = 'task-' . $task->id;
|
||||
$r->title = $task->name;
|
||||
$r->labels = array($this->app->lang->task->common, zget($this->app->lang->task->typeList, $task->type));
|
||||
$r->pri = $task->pri;
|
||||
$r->openedDate = $task->openedDate;
|
||||
$r->openedBy = $task->openedBy;
|
||||
$r->lastEditedDate = $task->lastEditedDate < '1970-01-01 01:01:01' ? $task->openedDate : $task->lastEditedDate;
|
||||
$r->lastEditedBy = $task->lastEditedDate < '1970-01-01 01:01:01' ? $task->openedBy : $task->lastEditedBy;
|
||||
$r->status = $issue['status'];
|
||||
$r->url = helper::createLink('task', 'view', "taskID=$task->id");
|
||||
$r->assignedTo = array();
|
||||
|
||||
/* Get assignees for task, the task object has the type of multiple assign only so far. */
|
||||
$users = $this->dao->select('account')->from(TABLE_TEAM)
|
||||
->where('type')->eq('task')
|
||||
->andWhere('root')->eq($task->id)
|
||||
->fetchAll();
|
||||
if($users)
|
||||
{
|
||||
foreach($users as $user)
|
||||
{
|
||||
$r->assignedTo[] = $user->account;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if($task->assignedTo == "")
|
||||
{
|
||||
$r->assignedTo = array();
|
||||
}
|
||||
else
|
||||
{
|
||||
$r->assignedTo = array($task->assignedTo);
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif($issue['type'] == 'story')
|
||||
{
|
||||
$story = $stories[$issue['id']];
|
||||
|
||||
$r->id = 'story-' . $story->id;
|
||||
$r->title = $story->title;
|
||||
$r->labels = array($this->app->lang->story->common, zget($this->app->lang->story->categoryList, $story->category));
|
||||
$r->pri = $story->pri;
|
||||
$r->openedDate = $story->openedDate;
|
||||
$r->openedBy = $story->openedBy;
|
||||
$r->lastEditedDate = $story->lastEditedDate < '1970-01-01 01:01:01' ? $story->openedDate : $story->lastEditedDate;
|
||||
$r->lastEditedBy = $story->lastEditedDate < '1970-01-01 01:01:01' ? $story->openedBy : $story->lastEditedBy;
|
||||
$r->status = $issue['status'];
|
||||
$r->url = helper::createLink('story', 'view', "storyID=$story->id");
|
||||
|
||||
if($story->assignedTo == "")
|
||||
{
|
||||
$r->assignedTo = array();
|
||||
}
|
||||
else
|
||||
{
|
||||
$r->assignedTo = array($story->assignedTo);
|
||||
}
|
||||
}
|
||||
elseif($issue['type'] == 'bug')
|
||||
{
|
||||
$bug = $bugs[$issue['id']];
|
||||
|
||||
$r->id = 'bug-' . $bug->id;
|
||||
$r->title = $bug->title;
|
||||
$r->labels = array($this->app->lang->bug->common, zget($this->app->lang->bug->typeList, $bug->type));
|
||||
$r->pri = $bug->pri;
|
||||
$r->openedDate = $bug->openedDate;
|
||||
$r->openedBy = $bug->openedBy;
|
||||
$r->lastEditedDate = $bug->lastEditedDate < '1970-01-01 01:01:01' ? $bug->openedDate : $bug->lastEditedDate;
|
||||
$r->lastEditedBy = $bug->lastEditedDate < '1970-01-01 01:01:01' ? $bug->openedBy : $bug->lastEditedBy;
|
||||
$r->status = $issue['status'];
|
||||
$r->url = helper::createLink('bug', 'view', "bugID=$bug->id");
|
||||
|
||||
if($bug->assignedTo == "")
|
||||
{
|
||||
$r->assignedTo = array();
|
||||
}
|
||||
else
|
||||
{
|
||||
$r->assignedTo = array($bug->assignedTo);
|
||||
}
|
||||
}
|
||||
|
||||
$result[] = $this->format($r, 'openedDate:time,lastEditedDate:time');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all users in issues so that we can bulk get user detail later.
|
||||
*
|
||||
*/
|
||||
$userList = array();
|
||||
foreach($result as $issue)
|
||||
{
|
||||
foreach($issue->assignedTo as $account)
|
||||
{
|
||||
$userList[] = $account;
|
||||
}
|
||||
$userList[] = $issue->openedBy;
|
||||
}
|
||||
$userList = array_unique($userList);
|
||||
$userDetails = $this->loadModel('user')->getListForGitLabAPI($userList);
|
||||
|
||||
/**
|
||||
* Set the user detail to assignedTo and openedBy.
|
||||
*
|
||||
*/
|
||||
foreach($result as $issue)
|
||||
{
|
||||
foreach($issue->assignedTo as $key => $account)
|
||||
{
|
||||
if($account == 'closed')
|
||||
{
|
||||
$issue->assignedTo = array();
|
||||
break;
|
||||
}
|
||||
$issue->assignedTo[$key] = $userDetails[$account];
|
||||
}
|
||||
$issue->openedBy = $userDetails[$issue->openedBy];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get key in array by value.
|
||||
*
|
||||
* @param string $value
|
||||
* @param array $array
|
||||
* @access private
|
||||
* @return string
|
||||
*/
|
||||
private function getKey($value, $array)
|
||||
{
|
||||
foreach($array as $key => $values)
|
||||
{
|
||||
if($values and strpos($values, $value) !== FALSE) return $key;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
91
api/v1/entries/productplan.php
Normal file
91
api/v1/entries/productplan.php
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
/**
|
||||
* The productplan entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class productplanEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $planID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($planID)
|
||||
{
|
||||
$fields = $this->param('fields');
|
||||
|
||||
$control = $this->loadController('productplan', 'view');
|
||||
$control->view($planID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$plan = $data->data->plan;
|
||||
$plan->stories = $data->data->planStories;
|
||||
$plan->bugs = $data->data->planBugs;
|
||||
|
||||
$plan = $this->format($plan, 'begin:date,end:date,deleted:bool,stories:array,bugs:array');
|
||||
|
||||
return $this->send(200, $plan);
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT method.
|
||||
*
|
||||
* @param int $planID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function put($planID)
|
||||
{
|
||||
$control = $this->loadController('productplan', 'edit');
|
||||
$oldPlan = $this->loadModel('productplan')->getByID($planID);
|
||||
|
||||
/* Set $_POST variables. */
|
||||
$fields = 'title,begin,end,desc';
|
||||
$this->batchSetPost($fields, $oldPlan);
|
||||
$this->setPost('product', $oldPlan->product);
|
||||
$this->setPost('status', $oldPlan->status);
|
||||
|
||||
$control->edit($planID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
|
||||
/* Get plan info. */
|
||||
$control = $this->loadController('productplan', 'view');
|
||||
$control->view($planID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$plan = $this->productplan->getByID($planID);
|
||||
return $this->send(200, $this->format($plan, 'begin:date,end:date,deleted:bool,stories:array,bugs:array'));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE method.
|
||||
*
|
||||
* @param int $productID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function delete($planID)
|
||||
{
|
||||
$control = $this->loadController('productplan', 'delete');
|
||||
$control->delete($planID, 'yes');
|
||||
|
||||
$this->getData();
|
||||
return $this->sendSuccess(200, 'success');
|
||||
}
|
||||
}
|
||||
51
api/v1/entries/productplanlinkbugs.php
Normal file
51
api/v1/entries/productplanlinkbugs.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
/**
|
||||
* The productplanlinkbugs entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class productplanLinkBugsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $planID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($planID)
|
||||
{
|
||||
$control = $this->loadController('productplan', 'linkBug');
|
||||
|
||||
$fields = 'bugs';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$control->linkBug($planID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'success')
|
||||
{
|
||||
$control = $this->loadController('productplan', 'view');
|
||||
$control->view($planID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$plan = $data->data->plan;
|
||||
$plan->stories = $data->data->planStories;
|
||||
$plan->bugs = $data->data->planBugs;
|
||||
|
||||
$plan = $this->format($plan, 'begin:date,end:date,deleted:bool,stories:array,bugs:array');
|
||||
|
||||
return $this->send(200, $plan);
|
||||
}
|
||||
|
||||
$this->sendError(400, array('message' => isset($data->message) ? $data->message : 'error'));
|
||||
}
|
||||
}
|
||||
51
api/v1/entries/productplanlinkstories.php
Normal file
51
api/v1/entries/productplanlinkstories.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
/**
|
||||
* The productplanlinkstories entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class productplanLinkStoriesEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $planID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($planID)
|
||||
{
|
||||
$control = $this->loadController('productplan', 'linkStory');
|
||||
|
||||
$fields = 'stories';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$control->linkStory($planID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'success')
|
||||
{
|
||||
$control = $this->loadController('productplan', 'view');
|
||||
$control->view($planID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$plan = $data->data->plan;
|
||||
$plan->stories = $data->data->planStories;
|
||||
$plan->bugs = $data->data->planBugs;
|
||||
|
||||
$plan = $this->format($plan, 'begin:date,end:date,deleted:bool,stories:array,bugs:array');
|
||||
|
||||
return $this->send(200, $plan);
|
||||
}
|
||||
|
||||
$this->sendError(400, array('message' => isset($data->message) ? $data->message : 'error'));
|
||||
}
|
||||
}
|
||||
94
api/v1/entries/productplans.php
Normal file
94
api/v1/entries/productplans.php
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
/**
|
||||
* The productplans entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class productplansEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $productID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($productID = 0)
|
||||
{
|
||||
if(!$productID) $productID = $this->param('product', 0);
|
||||
if(!$productID) return $this->sendError(400, 'No product id.');
|
||||
|
||||
$control = $this->loadController('productplan', 'browse');
|
||||
$control->browse($productID, $this->param('branch', 0), $this->param('status', 'all'), $this->param('query', 0), $this->param('order', 'begin_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
|
||||
/* Response */
|
||||
$data = $this->getData();
|
||||
if(isset($data->status) and $data->status == 'success')
|
||||
{
|
||||
$result = array();
|
||||
$plans = $data->data->plans;
|
||||
$pager = $data->data->pager;
|
||||
|
||||
foreach($plans as $plan)
|
||||
{
|
||||
if($plan->parent > 0 and isset($result[$plan->parent]))
|
||||
{
|
||||
$parentPlan = $result[$plan->parent];
|
||||
|
||||
if(!isset($parentPlan->children) or !is_array($parentPlan->children)) $parentPlan->children = array();
|
||||
$parentPlan->children[] = $plan;
|
||||
$result[$plan->parent] = $parentPlan;
|
||||
}
|
||||
else
|
||||
{
|
||||
$result[$plan->id] = $this->format($plan, 'begin:date,end:date,deleted:bool,project:int');
|
||||
}
|
||||
}
|
||||
|
||||
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'plans' => array_values($result)));
|
||||
}
|
||||
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
return $this->sendError(400, 'error');
|
||||
}
|
||||
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $productID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($productID = 0)
|
||||
{
|
||||
if(!$productID) $productID = $this->param('product', 0);
|
||||
if(!$productID) return $this->sendError(400, 'No product id.');
|
||||
|
||||
$control = $this->loadController('productplan', 'create');
|
||||
|
||||
$fields = 'branch,begin,end,title,desc';
|
||||
$this->batchSetPost($fields);
|
||||
$this->setPost('product', $productID);
|
||||
$this->setPost('parent', $this->request('parent', 0));
|
||||
$this->setPost('branch', $this->request('branch', 0));
|
||||
|
||||
$control->create($productID, $this->param('branch', 0), $this->param('parent', 0));
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'success')
|
||||
{
|
||||
$plan = $this->loadModel('productplan')->getByID($data->id);
|
||||
$plan->stories = array();
|
||||
$plan->bugs = array();
|
||||
return $this->send(201, $this->format($plan, 'begin:date,end:date,deleted:bool,project:int'));
|
||||
}
|
||||
|
||||
$this->sendError(400, array('message' => isset($data->message) ? $data->message : 'error'));
|
||||
}
|
||||
}
|
||||
45
api/v1/entries/productplanunlinkbugs.php
Normal file
45
api/v1/entries/productplanunlinkbugs.php
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
/**
|
||||
* The productplanunlinkbugs entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class productplanUnlinkBugsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $planID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($planID)
|
||||
{
|
||||
$control = $this->loadController('productplan', 'view');
|
||||
$productplan = $this->loadModel('productplan');
|
||||
foreach($this->request('bugs', array()) as $bugID)
|
||||
{
|
||||
$productplan->unlinkBug($bugID, $planID);
|
||||
if(dao::isError()) return $this->sendError('error');
|
||||
}
|
||||
|
||||
$control->view($planID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$plan = $data->data->plan;
|
||||
$plan->stories = $data->data->planStories;
|
||||
$plan->bugs = $data->data->planBugs;
|
||||
|
||||
$plan = $this->format($plan, 'begin:date,end:date,deleted:bool,stories:array,bugs:array');
|
||||
|
||||
return $this->send(200, $plan);
|
||||
}
|
||||
}
|
||||
45
api/v1/entries/productplanunlinkstories.php
Normal file
45
api/v1/entries/productplanunlinkstories.php
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
/**
|
||||
* The productplanunlinkstories entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class productplanUnlinkStoriesEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $planID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($planID)
|
||||
{
|
||||
$control = $this->loadController('productplan', 'view');
|
||||
$productplan = $this->loadModel('productplan');
|
||||
foreach($this->request('stories', array()) as $storyID)
|
||||
{
|
||||
$productplan->unlinkStory($storyID, $planID);
|
||||
if(dao::isError()) return $this->sendError('error');
|
||||
}
|
||||
|
||||
$control->view($planID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$plan = $data->data->plan;
|
||||
$plan->stories = $data->data->planStories;
|
||||
$plan->bugs = $data->data->planBugs;
|
||||
|
||||
$plan = $this->format($plan, 'begin:date,end:date,deleted:bool,stories:array,bugs:array');
|
||||
|
||||
return $this->send(200, $plan);
|
||||
}
|
||||
}
|
||||
129
api/v1/entries/productprojects.php
Normal file
129
api/v1/entries/productprojects.php
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
<?php
|
||||
/**
|
||||
* The product projects entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class productProjectsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $productID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($productID = 0)
|
||||
{
|
||||
if(empty($productID)) $productID = $this->param('product', 0);
|
||||
if(empty($productID)) return $this->sendError('400', "Need product id");
|
||||
$appendFields = $this->param('fields', '');
|
||||
|
||||
$control = $this->loadController('product', 'project');
|
||||
$control->project($this->param('status', 'all'), $productID, $this->param('branch', 0), $this->param('involved', 0), $this->param('order', 'order_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
$data = $this->getData();
|
||||
|
||||
if(isset($data->status) and $data->status == 'success')
|
||||
{
|
||||
$result = array();
|
||||
foreach($data->data->projectStats as $project)
|
||||
{
|
||||
foreach($project->hours as $field => $value) $project->$field = $value;
|
||||
|
||||
$project = $this->filterFields($project, 'id,name,code,model,type,budget,budgetUnit,parent,begin,end,status,openedBy,openedDate,PM,delay,progress,' . $appendFields);
|
||||
$result[] = $this->format($project, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time');
|
||||
}
|
||||
|
||||
$data = array();
|
||||
$data['total'] = count($result);
|
||||
$data['projects'] = $result;
|
||||
|
||||
$withUser = $this->param('withUser', '');
|
||||
if(!empty($withUser)) $data['users'] = $users;
|
||||
|
||||
return $this->send(200, $data);
|
||||
}
|
||||
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
// TODO There is no handle for 401.
|
||||
return $this->sendError(400, 'error');
|
||||
}
|
||||
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post()
|
||||
{
|
||||
$control = $this->loadController('project', 'create');
|
||||
|
||||
$fields = 'name,begin,end,products';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$this->setPost('code', $this->request('code', ''));
|
||||
$this->setPost('acl', $this->request('acl', 'private'));
|
||||
$this->setPost('parent', $this->request('program', 0));
|
||||
$this->setPost('whitelist', $this->request('whitelist', array()));
|
||||
$this->setPost('PM', $this->request('PM', ''));
|
||||
$this->setPost('model', $this->request('model', 'scrum'));
|
||||
|
||||
$this->requireFields('name,code,begin,end,products');
|
||||
|
||||
$control->create($this->request('model', 'scrum'));
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
if(!isset($data->result)) return $this->sendError(400, 'error');
|
||||
|
||||
$project = $this->loadModel('project')->getByID($data->id);
|
||||
|
||||
return $this->send(201, $this->format($project, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get drop menu.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getDropMenu()
|
||||
{
|
||||
$control = $this->loadController('project', 'ajaxGetDropMenu');
|
||||
$control->ajaxGetDropMenu($this->request('projectID', 0), $this->request('module', 'project'), $this->request('method', 'browse'));
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
|
||||
$dropMenu = array('owner' => array(), 'other' => array(), 'closed' => array());
|
||||
foreach($data->data->projects as $programID => $projects)
|
||||
{
|
||||
foreach($projects as $project)
|
||||
{
|
||||
if(helper::diffDate(date('Y-m-d'), $project->end) > 0) $project->delay = true;
|
||||
$project = $this->filterFields($project, 'id,model,type,name,code,parent,status,PM,delay');
|
||||
|
||||
if($project->status == 'closed')
|
||||
{
|
||||
$dropMenu['closed'][] = $project;
|
||||
}
|
||||
elseif($project->PM == $this->app->user->account)
|
||||
{
|
||||
$dropMenu['owner'][] = $project;
|
||||
}
|
||||
else
|
||||
{
|
||||
$dropMenu['other'][] = $project;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->send(200, $dropMenu);
|
||||
}
|
||||
}
|
||||
252
api/v1/entries/products.php
Normal file
252
api/v1/entries/products.php
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
<?php
|
||||
/**
|
||||
* The products entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class productsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($programID = 0)
|
||||
{
|
||||
$fields = $this->param('fields', '');
|
||||
if(strpos(strtolower(",{$fields},"), ',dropmenu,') !== false) return $this->getDropMenu();
|
||||
|
||||
if(!$programID) $programID = $this->param('program', 0);
|
||||
$projectID = $this->param('project', 0);
|
||||
$mergeChildren = $this->param('mergeChildren', '');
|
||||
|
||||
if($programID)
|
||||
{
|
||||
$control = $this->loadController('program', 'product');
|
||||
$control->product($programID, $this->param('status', 'all'), $this->param('order', 'order_asc'), 0, $this->param('limit', '20'), $this->param('page', '1'));
|
||||
|
||||
/* Response */
|
||||
$data = $this->getData();
|
||||
if(!$data or !isset($data->status)) return $this->sendError(400, 'error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$products = $data->data->products;
|
||||
|
||||
}
|
||||
elseif($projectID)
|
||||
{
|
||||
$control = $this->loadController('project', 'manageProducts');
|
||||
$control->manageProducts($projectID);
|
||||
|
||||
/* Response */
|
||||
$data = $this->getData();
|
||||
if(!$data or !isset($data->status)) return $this->sendError(400, 'error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$products = $data->data->linkedProducts;
|
||||
}
|
||||
else
|
||||
{
|
||||
$control = $this->loadController('product', 'all');
|
||||
$control->all($this->param('status', 'all'), $this->param('order', 'program_asc'), 0, 0, $this->param('limit', 100), $this->param('page', 1));
|
||||
|
||||
/* Response */
|
||||
$data = $this->getData();
|
||||
if(!$data or !isset($data->status)) return $this->sendError(400, 'error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
|
||||
|
||||
$products = $data->data->productStats;
|
||||
if($mergeChildren) $products = $data->data->productStructure;
|
||||
}
|
||||
$pager = $data->data->pager;
|
||||
|
||||
$result = array();
|
||||
if($mergeChildren)
|
||||
{
|
||||
$programs = $this->mergeChildren($products);
|
||||
return $this->send(200, $programs);
|
||||
}
|
||||
else
|
||||
{
|
||||
$accounts = array();
|
||||
foreach($products as $product)
|
||||
{
|
||||
$accounts[$product->PO] = $product->PO;
|
||||
$accounts[$product->QD] = $product->QD;
|
||||
$accounts[$product->RD] = $product->RD;
|
||||
$accounts[$product->createdBy] = $product->createdBy;
|
||||
if(isset($product->feedback)) $accounts[$product->feedback] = $product->feedback;
|
||||
if(!empty($product->mailto))
|
||||
{
|
||||
foreach(explode(',', $product->mailto) as $account)
|
||||
{
|
||||
$account = trim($account);
|
||||
if(empty($account)) continue;
|
||||
$accounts[$account] = $account;
|
||||
}
|
||||
}
|
||||
|
||||
$result[] = $this->format($product, 'createdDate:time,whitelist:userList,createdBy:user,PO:user,RD:user,QD:user');
|
||||
}
|
||||
|
||||
$data = array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'products' => $result);
|
||||
$withUser = $this->param('withUser', '');
|
||||
if(!empty($withUser)) $data['users'] = $this->loadModel('user')->getListByAccounts($accounts, 'account');
|
||||
|
||||
return $this->send(200, $data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post()
|
||||
{
|
||||
$control = $this->loadController('product', 'create');
|
||||
|
||||
$useCode = $this->checkCodeUsed();
|
||||
|
||||
$fields = 'program,line,name,PO,QD,RD,type,desc,whitelist';
|
||||
if($useCode) $fields .= ',code';
|
||||
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$this->setPost('acl', $this->request('acl', 'private'));
|
||||
$this->setPost('whitelist', $this->request('whitelist', array()));
|
||||
|
||||
$requireFields = 'name';
|
||||
if($useCode) $requireFields .= ',code';
|
||||
$this->requireFields($requireFields);
|
||||
|
||||
$control->create($this->request('program', 0));
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
/* Response */
|
||||
$product = $this->loadModel('product')->getByID($data->id);
|
||||
$product = $this->format($product, 'createdDate:time,whitelist:userList,createdBy:user,PO:user,RD:user,QD:user');
|
||||
|
||||
return $this->send(201, $product);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get dropmenu.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getDropMenu()
|
||||
{
|
||||
$control = $this->loadController('product', 'ajaxGetDropMenu');
|
||||
$control->ajaxGetDropMenu($this->request('productID', 0), $this->request('module', 'product'), $this->request('method', 'browse'), $this->request('extra', ''), $this->request('from', ''));
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$dropMenu = array('owner' => array(), 'other' => array(), 'closed' => array());
|
||||
foreach($data->data->products as $programID => $products)
|
||||
{
|
||||
foreach($products as $product)
|
||||
{
|
||||
$product = $this->filterFields($product, 'id,program,name,code,status,PO');
|
||||
|
||||
if($product->status == 'closed')
|
||||
{
|
||||
$dropMenu['closed'][] = $product;
|
||||
}
|
||||
elseif($product->PO == $this->app->user->account)
|
||||
{
|
||||
$dropMenu['owner'][] = $product;
|
||||
}
|
||||
else
|
||||
{
|
||||
$dropMenu['other'][] = $product;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->send(200, $dropMenu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge children products.
|
||||
*
|
||||
* @param array $products
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function mergeChildren($products)
|
||||
{
|
||||
$programs = array();
|
||||
foreach($products as $programID => $program)
|
||||
{
|
||||
$programs[$programID] = new stdclass();
|
||||
if(!empty($programID))
|
||||
{
|
||||
$programs[$programID]->id = $programID;
|
||||
$programs[$programID]->name = $program->programName;
|
||||
$programs[$programID]->type = 'program';
|
||||
}
|
||||
|
||||
$unclosedTotal = 0;
|
||||
foreach($program as $lineID => $value)
|
||||
{
|
||||
if(!isset($programs[$programID]->children)) $programs[$programID]->children = array();
|
||||
if(isset($value->products))
|
||||
{
|
||||
if(empty($lineID))
|
||||
{
|
||||
foreach($value->products as $product)
|
||||
{
|
||||
unset($product->desc);
|
||||
$programs[$programID]->children[$product->id] = $product;
|
||||
if($product->status != 'closed') $unclosedTotal += 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$line = new stdclass();
|
||||
$line->id = $lineID;
|
||||
$line->name = $value->lineName;
|
||||
$line->type = 'line';
|
||||
|
||||
$line->children = array();
|
||||
foreach($value->products as $product)
|
||||
{
|
||||
unset($product->desc);
|
||||
$line->children[$product->id] = $product;
|
||||
if($product->status != 'closed') $unclosedTotal += 1;
|
||||
}
|
||||
if(isset($line->children)) $line->children = array_values($line->children);
|
||||
|
||||
$programs[$programID]->children[$lineID] = $line;
|
||||
}
|
||||
if(isset($programs[$programID]->children)) $programs[$programID]->children = array_values($programs[$programID]->children);
|
||||
$programs[$programID]->unclosedTotal = $unclosedTotal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$topProducts = array();
|
||||
if(isset($programs[0]))
|
||||
{
|
||||
$topProducts = $programs[0]->children;
|
||||
unset($programs[0]);
|
||||
}
|
||||
|
||||
$programs = array_values($programs);
|
||||
foreach($topProducts as $product) $programs[] = $product;
|
||||
|
||||
return $programs;
|
||||
}
|
||||
}
|
||||
72
api/v1/entries/program.php
Normal file
72
api/v1/entries/program.php
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
/**
|
||||
* The program entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class programEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $programID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($programID)
|
||||
{
|
||||
$program = $this->loadModel('program')->getByID($programID);
|
||||
if(!$program) return $this->send404();
|
||||
|
||||
return $this->send(200, $this->format($program, 'begin:date,end:date,PO:user,PM:user,QD:user,RD:user,realBegan:date,realEnd:date,openedBy:user,openedDate:time,lastEditedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,deleted:bool,whitelist:userList'));
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT method.
|
||||
*
|
||||
* @param int $programID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function put($programID)
|
||||
{
|
||||
$control = $this->loadController('program', 'edit');
|
||||
$oldProgram = $this->loadModel('program')->getByID($programID);
|
||||
|
||||
/* Set $_POST variables. */
|
||||
$fields = 'name,PM,budget,budgetUnit,desc,parent,begin,end,realBegan,realEnd,acl,whitelist';
|
||||
$this->batchSetPost($fields, $oldProgram);
|
||||
$this->setPost('parent', $this->request('parent', 0));
|
||||
|
||||
$control->edit($programID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
|
||||
$program = $this->program->getByID($programID);
|
||||
return $this->send(200, $this->format($program, 'begin:date,end:date,PO:user,PM:user,QD:user,RD:user,realBegan:date,realEnd:date,openedBy:user,openedDate:time,lastEditedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,deleted:bool,whitelist:userList'));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE method.
|
||||
*
|
||||
* @param int $programID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function delete($programID)
|
||||
{
|
||||
$control = $this->loadController('program', 'delete');
|
||||
$control->delete($programID, 'true');
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
|
||||
return $this->sendSuccess(200, 'success');
|
||||
}
|
||||
}
|
||||
125
api/v1/entries/programs.php
Normal file
125
api/v1/entries/programs.php
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
/**
|
||||
* The programs entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class programsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
$_COOKIE['showClosed'] = $this->param('showClosed', 0);
|
||||
$mergeChildren = $this->param('mergeChildren', 0);
|
||||
|
||||
$this->config->systemMode = 'ALM';
|
||||
|
||||
$fields = $this->param('fields', '');
|
||||
if(stripos(strtolower(",{$fields},"), ",dropmenu,") !== false) return $this->getDropMenu();
|
||||
|
||||
$program = $this->loadController('program', 'browse');
|
||||
$program->browse($this->param('status', 'all'), $this->param('order', 'order_asc'));
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data or !isset($data->status)) return $this->sendError(400, 'error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$programs = $data->data->programs;
|
||||
$result = array();
|
||||
foreach($programs as $program)
|
||||
{
|
||||
$program = $this->format($program, 'begin:date,end:date,PO:user,PM:user,QD:user,RD:user,realBegan:date,realEnd:date,openedBy:user,openedDate:time,lastEditedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,deleted:bool,whitelist:userList');
|
||||
|
||||
if($mergeChildren)
|
||||
{
|
||||
unset($program->desc);
|
||||
$program->end = $program->end == LONG_TIME ? $this->lang->program->longTime : $program->end;
|
||||
|
||||
$programBudget = $this->loadModel('project')->getBudgetWithUnit($program->budget);
|
||||
$program->labelBudget = $program->budget != 0 ? zget($this->lang->project->currencySymbol, $program->budgetUnit) . ' ' . $programBudget : $this->lang->project->future;
|
||||
|
||||
if(empty($program->parent)) $result[$program->id] = $program;
|
||||
if(isset($programs->{$program->parent}))
|
||||
{
|
||||
$parentProgram = $programs->{$program->parent};
|
||||
if(!isset($parentProgram->children)) $parentProgram->children = array();
|
||||
$parentProgram->children[] = $program;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$result[] = $program;
|
||||
}
|
||||
}
|
||||
return $this->send(200, array('programs' => array_values($result)));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post()
|
||||
{
|
||||
$control = $this->loadController('program', 'create');
|
||||
|
||||
$fields = 'name,PM,budget,budgetUnit,desc,begin,end';
|
||||
$this->batchSetPost($fields);
|
||||
$this->setPost('acl', $this->request('acl', 'open'));
|
||||
$this->setPost('whitelist', $this->request('whitelist', array()));
|
||||
|
||||
$this->requireFields('name,begin,end');
|
||||
|
||||
$control->create($this->request('parent', 0));
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
|
||||
$program = $this->loadModel('program')->getByID($data->id);
|
||||
return $this->send(201, $this->format($program, 'begin:date,end:date,PO:user,PM:user,QD:user,RD:user,realBegan:date,realEnd:date,openedBy:user,openedDate:time,lastEditedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,deleted:bool,whitelist:userList'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get drop menu.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getDropMenu()
|
||||
{
|
||||
$programs = $this->dao->select('id,name,parent,path,grade,`order`')->from(TABLE_PROJECT)
|
||||
->where('deleted')->eq('0')
|
||||
->andWhere('type')->eq('program')
|
||||
->andWhere('id')->in($this->app->user->view->programs)
|
||||
->beginIF(empty($_COOKIE['showClosed']))->andWhere('status')->ne('closed')->fi()
|
||||
->orderBy('grade desc, `order`')
|
||||
->fetchAll('id');
|
||||
|
||||
$dropMenu = array();
|
||||
foreach($programs as $programID => $program)
|
||||
{
|
||||
if(empty($program->parent))
|
||||
{
|
||||
$dropMenu[] = $program;
|
||||
}
|
||||
elseif(isset($programs[$program->parent]))
|
||||
{
|
||||
if(!isset($programs[$program->parent]->children)) $programs[$program->parent]->children = array();
|
||||
$programs[$program->parent]->children[] = $program;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->send(200, $dropMenu);
|
||||
}
|
||||
}
|
||||
148
api/v1/entries/project.php
Normal file
148
api/v1/entries/project.php
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
<?php
|
||||
/**
|
||||
* The project entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class projectEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($projectID)
|
||||
{
|
||||
$fields = strtolower($this->param('fields'));
|
||||
|
||||
$control = $this->loadController('project', 'view');
|
||||
$control->view($projectID);
|
||||
|
||||
$data = $this->getData();
|
||||
|
||||
if(!$data or !isset($data->status)) return $this->sendError(400, 'error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$project = $this->format($data->data->project, 'openedBy:user,openedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,realBegan:date,realEnd:date,PM:user,whitelist:userList,deleted:bool');
|
||||
if(!$project->multiple) $project->executionID = $this->loadModel('execution')->getNoMultipleID($projectID);
|
||||
|
||||
$this->loadModel('testcase');
|
||||
$project->caseReview = ($this->config->testcase->needReview or !empty($this->config->testcase->forceReview));
|
||||
|
||||
if(empty($fields)) return $this->send(200, $project);
|
||||
|
||||
/* Set other fields. */
|
||||
$fields = explode(',', $fields);
|
||||
foreach($fields as $field)
|
||||
{
|
||||
switch($field)
|
||||
{
|
||||
case 'team':
|
||||
$teams = array();
|
||||
$accounts = array();
|
||||
foreach($data->data->teamMembers as $account => $team)
|
||||
{
|
||||
$team = $this->filterFields($team, "account,role,join,realname");
|
||||
|
||||
$teams[$account] = $team;
|
||||
$accounts[$account] = $account;
|
||||
}
|
||||
$users = $this->loadModel('user')->getListByAccounts($accounts, 'account');
|
||||
foreach($teams as $account => $team)
|
||||
{
|
||||
$user = zget($users, $account, '');
|
||||
$team->avatar = $user->avatar;
|
||||
}
|
||||
|
||||
$project->teams = $teams;
|
||||
break;
|
||||
case "products":
|
||||
$project->products = array();
|
||||
$productList = $this->loadModel('product')->getProducts($projectID, $this->param('status', 'all'));
|
||||
foreach($productList as $product) $project->products[] = $product;
|
||||
break;
|
||||
case "stat":
|
||||
$project->stat = $data->data->statData;
|
||||
break;
|
||||
case "workhour":
|
||||
$workhour = $data->data->workhour;
|
||||
$workhour->progress = ($workhour->totalConsumed + $workhour->totalLeft) ? floor($workhour->totalConsumed / ($workhour->totalConsumed + $workhour->totalLeft) * 1000) / 1000 * 100 : 0;
|
||||
$project->workhour = $workhour;
|
||||
break;
|
||||
case "actions":
|
||||
$actions = $data->data->actions;
|
||||
$project->actions = $this->loadModel('action')->processActionForAPI($actions, (array)$data->data->users, $this->lang->project);
|
||||
break;
|
||||
case "dynamics":
|
||||
$dynamics = $data->data->dynamics;
|
||||
$project->dynamics = $this->loadModel('action')->processDynamicForAPI($dynamics);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->send(200, $project);
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT method.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function put($projectID)
|
||||
{
|
||||
$control = $this->loadController('project', 'edit');
|
||||
|
||||
$oldProject = $this->loadModel('project')->getByID($projectID);
|
||||
$linkedProducts = $this->loadModel('product')->getProducts($projectID);
|
||||
|
||||
$useCode = $this->checkCodeUsed();
|
||||
/* Set $_POST variables. */
|
||||
$fields = 'name,begin,end,acl,parent,desc,PM,whitelist,model';
|
||||
if($useCode) $fields .= ',code';
|
||||
$this->batchSetPost($fields, $oldProject);
|
||||
|
||||
$products = array();
|
||||
$plans = array();
|
||||
foreach($linkedProducts as $product)
|
||||
{
|
||||
$products[] = $product->id;
|
||||
foreach($product->plans as $planID) $plans[] = $planID;
|
||||
}
|
||||
$this->setPost('products', $products);
|
||||
$this->setPost('plans', $plans);
|
||||
|
||||
$control->edit($projectID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
if(!isset($data->result)) return $this->sendError(400, 'error');
|
||||
|
||||
$project = $this->project->getByID($projectID);
|
||||
return $this->send(200, $this->format($project, 'openedBy:user,openedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,realBegan:date,realEnd:date,PM:user,whitelist:userList,deleted:bool'));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE method.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function delete($projectID)
|
||||
{
|
||||
$control = $this->loadController('project', 'delete');
|
||||
$control->delete($projectID, 'yes');
|
||||
|
||||
$this->getData();
|
||||
return $this->sendSuccess(200, 'success');
|
||||
}
|
||||
}
|
||||
72
api/v1/entries/projectbugs.php
Normal file
72
api/v1/entries/projectbugs.php
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
/**
|
||||
* The project bugs entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class projectBugsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($projectID = 0)
|
||||
{
|
||||
if(empty($projectID)) $projectID = $this->param('project', 0);
|
||||
if(empty($projectID)) return $this->sendError(400, 'Need project id.');
|
||||
|
||||
$control = $this->loadController('project', 'bug');
|
||||
$control->bug($projectID, $this->param('product', 0), $this->param('branch', 0), $this->param('order', 'status,id_desc'), $this->param('build', 0), $this->param('status', 'all'), 0, 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
|
||||
$data = $this->getData();
|
||||
|
||||
if(isset($data->status) and $data->status == 'success')
|
||||
{
|
||||
$bugs = $data->data->bugs;
|
||||
$pager = $data->data->pager;
|
||||
$result = array();
|
||||
$this->loadModel('product');
|
||||
foreach($bugs as $bug)
|
||||
{
|
||||
$status = array('code' => $bug->status, 'name' => $this->lang->bug->statusList[$bug->status]);
|
||||
if($bug->status == 'active' and $bug->confirmed) $status = array('code' => 'confirmed', 'name' => $this->lang->bug->labelConfirmed);
|
||||
if($bug->resolution == 'postponed') $status = array('code' => 'postponed', 'name' => $this->lang->bug->labelPostponed);
|
||||
if(!empty($bug->delay)) $status = array('code' => 'delay', 'name' => $this->lang->bug->overdueBugs);
|
||||
$bug->status = $status['code'];
|
||||
$bug->statusName = $status['name'];
|
||||
|
||||
$product = $this->product->getById($bug->product);
|
||||
$bug->productStatus = $product->status;
|
||||
|
||||
$result[$bug->id] = $this->format($bug, 'activatedDate:time,openedDate:time,assignedDate:time,resolvedDate:time,closedDate:time,lastEditedDate:time,deadline:date,deleted:bool');
|
||||
}
|
||||
|
||||
$storyChangeds = $this->dao->select('t1.id')->from(TABLE_BUG)->alias('t1')
|
||||
->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story=t2.id')
|
||||
->where('t1.id')->in(array_keys($result))
|
||||
->andWhere('t1.story')->ne('0')
|
||||
->andWhere('t1.storyVersion != t2.version')
|
||||
->fetchPairs('id', 'id');
|
||||
foreach($storyChangeds as $bugID)
|
||||
{
|
||||
$status = array('code' => 'storyChanged', 'name' => $this->lang->bug->changed);
|
||||
$result[$bugID]->status = $status['code'];
|
||||
$result[$bugID]->statusName = $status['name'];
|
||||
}
|
||||
|
||||
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'bugs' => array_values($result)));
|
||||
}
|
||||
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
return $this->sendError(400, 'error');
|
||||
}
|
||||
}
|
||||
51
api/v1/entries/projectcases.php
Normal file
51
api/v1/entries/projectcases.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
/**
|
||||
* The project cases entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class projectCasesEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($projectID = 0)
|
||||
{
|
||||
if(!$projectID) $projectID = $this->param('project', 0);
|
||||
if(empty($projectID)) return $this->sendError(400, 'Need project id.');
|
||||
|
||||
$this->resetOpenApp('project');
|
||||
$this->app->session->set('project', $projectID, $this->app->tab);
|
||||
|
||||
$control = $this->loadController('project', 'testcase');
|
||||
$control->testcase($projectID, $this->param('product', 0), $this->param('branch', 'all'), $this->param('status', 'all'), 0, $this->param('caseType', ''), $this->param('order', 'id_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
|
||||
$data = $this->getData();
|
||||
|
||||
if(isset($data->status) and $data->status == 'success')
|
||||
{
|
||||
$cases = $data->data->cases;
|
||||
$pager = $data->data->pager;
|
||||
$result = array();
|
||||
foreach($cases as $case)
|
||||
{
|
||||
$case->statusName = $this->lang->testcase->statusList[$case->status];
|
||||
$result[] = $this->format($case, 'openedDate:time,reviewedDate:date,lastEditedDate:time,lastRunDate:time');
|
||||
}
|
||||
|
||||
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'cases' => $result));
|
||||
}
|
||||
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
return $this->sendError(400, 'error');
|
||||
}
|
||||
}
|
||||
78
api/v1/entries/projectreleases.php
Normal file
78
api/v1/entries/projectreleases.php
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
/**
|
||||
* The projectreleases entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class projectReleasesEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($projectID = 0)
|
||||
{
|
||||
if(empty($projectID)) $projectID = $this->param('project');
|
||||
if(empty($projectID)) return $this->sendError(400, 'Need project id.');
|
||||
|
||||
$page = intval($this->param('page', 1));
|
||||
$limit = intval($this->param('limit', 20));
|
||||
$control = $this->loadController('projectrelease', 'browse');
|
||||
$control->browse($projectID, $this->param('execution', 0), $this->param('status', 'all'), $this->param('order', 't1.date_desc'), 0, $limit, $page);
|
||||
|
||||
/* Response */
|
||||
$data = $this->getData();
|
||||
|
||||
if(isset($data->status) and $data->status == 'success')
|
||||
{
|
||||
$result = array();
|
||||
$releases = $data->data->releases;
|
||||
$pager = $data->data->pager;
|
||||
foreach($releases as $release) $result[] = $this->format($release, 'deleted:bool,date:date,mailto:userList');
|
||||
|
||||
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'releases' => $result));
|
||||
}
|
||||
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
return $this->sendError(400, 'error');
|
||||
}
|
||||
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($projectID = 0)
|
||||
{
|
||||
$control = $this->loadController('projectrelease', 'create');
|
||||
$project = $this->loadModel('project')->getByID($projectID);
|
||||
if(!$project) return $this->send404();
|
||||
|
||||
$fields = 'name,build,product,date,notify,mailto';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$this->setPost('desc', $this->request('desc', ''));
|
||||
|
||||
$this->requireFields('name,date');
|
||||
|
||||
$control->create($projectID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
if(isset($data->result) and!isset($data->id)) return $this->sendError(400, $data->message);
|
||||
|
||||
$release = $this->loadModel('projectrelease')->getByID($data->id);
|
||||
|
||||
return $this->send(201, $release);
|
||||
}
|
||||
}
|
||||
152
api/v1/entries/projects.php
Normal file
152
api/v1/entries/projects.php
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
<?php
|
||||
/**
|
||||
* The project entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class projectsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $programID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($programID = 0)
|
||||
{
|
||||
if(!$programID) $programID = $this->param('program', 0);
|
||||
$appendFields = $this->param('fields', '');
|
||||
if(stripos(strtolower(",{$appendFields},"), ',dropmenu,') !== false) return $this->getDropMenu();
|
||||
|
||||
$_COOKIE['involved'] = $this->param('involved', 0);
|
||||
|
||||
$this->config->systemMode = 'ALM';
|
||||
|
||||
if($programID)
|
||||
{
|
||||
$control = $this->loadController('program', 'project');
|
||||
$control->project($programID, $this->param('status', 'all'), $this->param('order', 'order_asc'), 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
$data = $this->getData();
|
||||
}
|
||||
else
|
||||
{
|
||||
$control = $this->loadController('project', 'browse');
|
||||
$control->browse($programID, $this->param('status', 'all'), 0, $this->param('order', 'order_asc'), 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
$data = $this->getData();
|
||||
}
|
||||
|
||||
if(isset($data->status) and $data->status == 'success')
|
||||
{
|
||||
$pager = $data->data->pager;
|
||||
$users = $data->data->users;
|
||||
$result = array();
|
||||
foreach($data->data->projectStats as $project)
|
||||
{
|
||||
$result[] = $this->format($project, 'openedBy:user,openedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,realBegan:date,realEnd:date,whitelist:userList,deleted:bool');
|
||||
}
|
||||
|
||||
$data = array();
|
||||
$data['page'] = $pager->pageID;
|
||||
$data['total'] = $pager->recTotal;
|
||||
$data['limit'] = (int)$pager->recPerPage;
|
||||
$data['projects'] = $result;
|
||||
|
||||
$withUser = $this->param('withUser', '');
|
||||
if(!empty($withUser)) $data['users'] = $users;
|
||||
|
||||
return $this->send(200, $data);
|
||||
}
|
||||
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
return $this->sendError(400, 'error');
|
||||
}
|
||||
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post()
|
||||
{
|
||||
$control = $this->loadController('project', 'create');
|
||||
|
||||
$fields = 'name,begin,end,products,multiple';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$_POST['hasProduct'] = isset($_POST['products']) ? 1 : 0;
|
||||
|
||||
$multiple = $this->request('multiple', '');
|
||||
if($multiple !== '') $this->setPost('multiple', 'on');
|
||||
if($multiple == 'no') $this->setPost('multiple', '');
|
||||
|
||||
$useCode = $this->checkCodeUsed();
|
||||
|
||||
if($useCode) $this->setPost('code', $this->request('code', ''));
|
||||
$this->setPost('acl', $this->request('acl', 'private'));
|
||||
$this->setPost('parent', $this->request('program', 0));
|
||||
$this->setPost('whitelist', $this->request('whitelist', array()));
|
||||
$this->setPost('PM', $this->request('PM', ''));
|
||||
$this->setPost('model', $this->request('model', 'scrum'));
|
||||
$this->setPost('parent', $this->request('parent', 0));
|
||||
|
||||
$requireFields = 'name,begin,end,products';
|
||||
if($useCode) $requireFields .= ',code';
|
||||
$this->requireFields($requireFields);
|
||||
|
||||
$control->create($this->request('model', 'scrum'));
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
if(!isset($data->result)) return $this->sendError(400, 'error');
|
||||
|
||||
$project = $this->loadModel('project')->getByID($data->id);
|
||||
|
||||
return $this->send(201, $this->format($project, 'openedBy:user,openedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,realBegan:date,realEnd:date,PM:user,whitelist:userList,deleted:bool'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get drop menu.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getDropMenu()
|
||||
{
|
||||
$control = $this->loadController('project', 'ajaxGetDropMenu');
|
||||
$control->ajaxGetDropMenu($this->request('projectID', 0), $this->request('module', 'project'), $this->request('method', 'browse'));
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
|
||||
$dropMenu = array('owner' => array(), 'other' => array(), 'closed' => array());
|
||||
foreach($data->data->projects as $programID => $projects)
|
||||
{
|
||||
foreach($projects as $project)
|
||||
{
|
||||
if(helper::diffDate(date('Y-m-d'), $project->end) > 0) $project->delay = true;
|
||||
$project = $this->filterFields($project, 'id,model,type,name,code,parent,status,PM,delay');
|
||||
|
||||
if($project->status == 'closed')
|
||||
{
|
||||
$dropMenu['closed'][] = $project;
|
||||
}
|
||||
elseif($project->PM == $this->app->user->account)
|
||||
{
|
||||
$dropMenu['owner'][] = $project;
|
||||
}
|
||||
else
|
||||
{
|
||||
$dropMenu['other'][] = $project;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->send(200, $dropMenu);
|
||||
}
|
||||
}
|
||||
49
api/v1/entries/projectstories.php
Normal file
49
api/v1/entries/projectstories.php
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
/**
|
||||
* The project entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package project
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class projectStoriesEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($projectID)
|
||||
{
|
||||
if(!$projectID) $projectID = $this->param('project');
|
||||
if(!$projectID) return $this->sendError(400, 'Need product id.');
|
||||
|
||||
$control = $this->loadController('projectstory', 'story');
|
||||
$control->story($projectID, $this->param('product', 0), $this->param('branch', ''), $this->param('status', 'unclosed'), 0, 'story', $this->param('order', 'id_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
$data = $this->getData();
|
||||
|
||||
if(isset($data->status) and $data->status == 'success')
|
||||
{
|
||||
$stories = $data->data->stories;
|
||||
$pager = $data->data->pager;
|
||||
$result = array();
|
||||
$this->loadModel('product');
|
||||
foreach($stories as $story)
|
||||
{
|
||||
$product = $this->product->getById($story->product);
|
||||
$story->productStatus = $product->status;
|
||||
|
||||
$result[] = $this->format($story, 'openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList');
|
||||
}
|
||||
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'stories' => $result));
|
||||
}
|
||||
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
return $this->sendError(400, 'error');
|
||||
}
|
||||
}
|
||||
75
api/v1/entries/release.php
Normal file
75
api/v1/entries/release.php
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
/**
|
||||
* The release entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class releaseEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $planID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($releaseID)
|
||||
{
|
||||
$control = $this->loadController('release', 'view');
|
||||
$control->view($releaseID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$release = $this->format($data->data->release, 'date:date,deleted:bool');
|
||||
|
||||
return $this->send(200, $release);
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT method.
|
||||
*
|
||||
* @param int $releaseID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function put($releaseID)
|
||||
{
|
||||
$control = $this->loadController('release', 'edit');
|
||||
$oldRelease = $this->loadModel('release')->getByID($releaseID);
|
||||
|
||||
/* Set $_POST variables. */
|
||||
$fields = 'name,build,status,desc';
|
||||
$this->batchSetPost($fields, $oldRelease);
|
||||
|
||||
$control->edit($releaseID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
|
||||
$release = $this->release->getByID($releaseID);
|
||||
return $this->sendSuccess(200, $this->format($release, 'date:date,deleted:bool'));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE method.
|
||||
*
|
||||
* @param int $releaseID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function delete($releaseID)
|
||||
{
|
||||
$control = $this->loadController('release', 'delete');
|
||||
$control->delete($releaseID, 'yes');
|
||||
|
||||
$this->getData();
|
||||
return $this->sendSuccess(200, 'success');
|
||||
}
|
||||
}
|
||||
44
api/v1/entries/releases.php
Normal file
44
api/v1/entries/releases.php
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
/**
|
||||
* The productplans entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class releasesEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $productID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($productID = 0)
|
||||
{
|
||||
if(empty($productID)) $productID = $this->param('product');
|
||||
if(empty($productID)) return $this->sendError(400, 'Need product id.');
|
||||
|
||||
$control = $this->loadController('release', 'browse');
|
||||
$control->browse($productID, $this->param('branch', 'all'), $this->param('status', 'all'), $this->param('order', 't1.date_desc'), '', 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
|
||||
/* Response */
|
||||
$data = $this->getData();
|
||||
if(isset($data->status) and $data->status == 'success')
|
||||
{
|
||||
$result = array();
|
||||
$releases = $data->data->releases;
|
||||
$pager = $data->data->pager;
|
||||
foreach($releases as $release) $result[] = $this->format($release, 'deleted:bool,date:date,mailto:userList');
|
||||
|
||||
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'releases' => $result));
|
||||
}
|
||||
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
return $this->sendError(400, 'error');
|
||||
}
|
||||
}
|
||||
374
api/v1/entries/reports.php
Normal file
374
api/v1/entries/reports.php
Normal file
|
|
@ -0,0 +1,374 @@
|
|||
<?php
|
||||
/**
|
||||
* The reports entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class reportsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
$fields = $this->param('fields', '');
|
||||
$dept = $this->param('dept', 0);
|
||||
$account = $this->param('account', '');
|
||||
$year = $this->param('year', date('Y'));
|
||||
if(empty($fields)) return $this->send(400, 'Need fields param for report.');
|
||||
|
||||
$accounts = array();
|
||||
if($account) $accounts = array($account => $account);
|
||||
if(empty($accounts) and $dept) $accounts = array_keys($this->loadModel('dept')->getDeptUserPairs($dept));
|
||||
if(empty($accounts) and empty($dept)) $accounts = array_keys($this->loadModel('user')->getPairs('noclosed'));
|
||||
|
||||
$fields = explode(',', strtolower($fields));
|
||||
$report = array();
|
||||
foreach($fields as $field)
|
||||
{
|
||||
$field = trim($field);
|
||||
if(empty($field)) continue;
|
||||
|
||||
if($field == 'projectoverview')
|
||||
{
|
||||
$report['projectOverview'] = $this->projectOverview($accounts);
|
||||
}
|
||||
elseif($field == 'radar')
|
||||
{
|
||||
$report['radar'] = $this->radar($accounts, $year);
|
||||
}
|
||||
elseif($field == 'projectprogress')
|
||||
{
|
||||
$report['projectProgress'] = $this->projectProgress();
|
||||
}
|
||||
elseif($field == 'executionprogress')
|
||||
{
|
||||
$report['executionProgress'] = $this->executionProgress();
|
||||
}
|
||||
elseif($field == 'productprogress')
|
||||
{
|
||||
$report['productProgress'] = $this->productProgress();
|
||||
}
|
||||
elseif($field == 'bugprogress')
|
||||
{
|
||||
$report['bugProgress'] = $this->bugProgress();
|
||||
}
|
||||
elseif($field == 'bugprogress')
|
||||
{
|
||||
$report['bugProgress'] = $this->bugProgress();
|
||||
}
|
||||
elseif($field == 'output')
|
||||
{
|
||||
$report['output'] = $this->loadModel('report')->getOutput4API($accounts, $year);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->send(200, $report);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project overview by status.
|
||||
*
|
||||
* @param array $accounts
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function projectOverview($accounts)
|
||||
{
|
||||
$statusOverview = $this->loadModel('report')->getProjectStatusOverview($accounts);
|
||||
|
||||
$this->app->loadLang('project');
|
||||
$total = 0;
|
||||
$overview = array();
|
||||
foreach($statusOverview as $status => $count)
|
||||
{
|
||||
$total += $count;
|
||||
$statusName = zget($this->lang->project->statusList, $status);
|
||||
|
||||
$overview[$status] = array();
|
||||
$overview[$status]['code'] = $status;
|
||||
$overview[$status]['name'] = $statusName;
|
||||
$overview[$status]['total'] = $count;
|
||||
}
|
||||
|
||||
$projectOverview = array();
|
||||
$projectOverview['total'] = $total;
|
||||
$projectOverview['overview'] = array_values($overview);
|
||||
|
||||
return $projectOverview;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get radar data. include product, execution, qa, devel and other.
|
||||
*
|
||||
* @param array $accounts
|
||||
* @param string $year
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function radar($accounts, $year)
|
||||
{
|
||||
$contributions = $this->loadModel('report')->getUserYearContributions($accounts, $year);
|
||||
$annualDataConfig = $this->config->report->annualData;
|
||||
|
||||
$radarData = array('product' => 0, 'execution' => 0, 'devel' => 0, 'qa' => 0, 'other' => 0);
|
||||
foreach($contributions as $objectType => $objectContributions)
|
||||
{
|
||||
foreach($objectContributions as $actionName => $count)
|
||||
{
|
||||
$radarTypes = isset($annualDataConfig['radar'][$objectType][$actionName]) ? $annualDataConfig['radar'][$objectType][$actionName] : array('other');
|
||||
foreach($radarTypes as $radarType) $radarData[$radarType] += $count;
|
||||
}
|
||||
}
|
||||
|
||||
$radar = array();
|
||||
foreach($radarData as $radarType => $total)
|
||||
{
|
||||
$radar[$radarType]['code'] = $radarType;
|
||||
$radar[$radarType]['name'] = $this->lang->report->annualData->radarItems[$radarType];
|
||||
$radar[$radarType]['total'] = $total;
|
||||
}
|
||||
|
||||
return array_values($radar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project progress.
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function projectProgress()
|
||||
{
|
||||
$projects = $this->loadModel('program')->getProjectStats(0, 'all');
|
||||
$this->app->loadLang('project');
|
||||
|
||||
$processedProjects = array();
|
||||
$statusList['all']['total'] = 0;
|
||||
$statusList['doing']['total'] = 0;
|
||||
$statusList['wait']['total'] = 0;
|
||||
$statusList['closed']['total'] = 0;
|
||||
foreach($projects as $project)
|
||||
{
|
||||
$newProject = new stdclass();
|
||||
$newProject->id = $project->id;
|
||||
$newProject->name = $project->name;
|
||||
$newProject->status = $project->status;
|
||||
$newProject->progress = round($project->progress, 1);
|
||||
$newProject->totalConsumed = round($project->totalConsumed, 1);
|
||||
$newProject->totalLeft = round($project->totalLeft, 1);
|
||||
if(isset($project->delay)) $newProject->delay = $project->delay;
|
||||
|
||||
$statusList['all']['total'] += 1;
|
||||
if(isset($statusList[$project->status])) $statusList[$project->status]['total'] += 1;
|
||||
|
||||
$processedProjects[$project->id] = $newProject;
|
||||
}
|
||||
|
||||
foreach(array_keys($statusList) as $status)
|
||||
{
|
||||
$statusName = zget($this->lang->project->statusList, $status);
|
||||
if($status == 'all') $statusName = $this->lang->project->featureBar['browse']['all'];
|
||||
|
||||
$statusList[$status]['code'] = $status;
|
||||
$statusList[$status]['name'] = $statusName;
|
||||
}
|
||||
|
||||
return array('statusList' => $statusList, 'projects' => array_values($processedProjects));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get execution progress.
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function executionProgress()
|
||||
{
|
||||
$executions = $this->loadModel('execution')->getStatData(0, 'all', 0, 0, false, '', 'id_desc');
|
||||
|
||||
$processedExecutions = array();
|
||||
$statusList['all']['total'] = 0;
|
||||
$statusList['doing']['total'] = 0;
|
||||
$statusList['wait']['total'] = 0;
|
||||
$statusList['closed']['total'] = 0;
|
||||
foreach($executions as $execution)
|
||||
{
|
||||
$newExecution = new stdclass();
|
||||
$newExecution->id = $execution->id;
|
||||
$newExecution->name = $execution->name;
|
||||
$newExecution->status = $execution->status;
|
||||
$newExecution->progress = round($execution->progress, 1);
|
||||
$newExecution->totalConsumed = round($execution->totalConsumed, 1);
|
||||
$newExecution->totalLeft = round($execution->totalLeft, 1);
|
||||
if(isset($execution->delay)) $newExecution->delay = $execution->delay;
|
||||
|
||||
$statusList['all']['total'] += 1;
|
||||
if(isset($statusList[$execution->status])) $statusList[$execution->status]['total'] += 1;
|
||||
|
||||
$processedExecutions[$execution->id] = $newExecution;
|
||||
}
|
||||
|
||||
foreach(array_keys($statusList) as $status)
|
||||
{
|
||||
$statusName = zget($this->lang->execution->statusList, $status);
|
||||
if($status == 'all') $statusName = $this->lang->execution->allTasks;
|
||||
|
||||
$statusList[$status]['code'] = $status;
|
||||
$statusList[$status]['name'] = $statusName;
|
||||
}
|
||||
|
||||
return array('statusList' => $statusList, 'executions' => array_values($processedExecutions));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product progress with story.
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function productProgress()
|
||||
{
|
||||
$this->app->loadLang('product');
|
||||
$this->app->loadLang('story');
|
||||
|
||||
$storyStatusStat = $this->dao->select('t1.product, t2.name, t2.status, t1.status AS storyStatus, COUNT(1) AS storyCount')->from(TABLE_STORY)->alias('t1')
|
||||
->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product=t2.id')
|
||||
->where('t2.deleted')->eq(0)
|
||||
->andWhere('t1.deleted')->eq(0)
|
||||
->beginIF(!$this->app->user->admin)->andWhere('t2.id')->in($this->app->user->view->products)->fi()
|
||||
->groupBy('t1.product,t1.status')
|
||||
->orderBy('t1.product_desc,t1.status')
|
||||
->fetchAll();
|
||||
|
||||
$productStatusList['all']['total'] = 0;
|
||||
$productStatusList['normal']['total'] = 0;
|
||||
$productStatusList['closed']['total'] = 0;
|
||||
|
||||
$processedProducts = array();
|
||||
$productStoryStat = array();
|
||||
foreach($storyStatusStat as $product)
|
||||
{
|
||||
$productStoryStat[$product->product][$product->storyStatus] = $product->storyCount;
|
||||
|
||||
if(isset($processedProducts[$product->product])) continue;
|
||||
|
||||
$newProduct = new stdclass();
|
||||
$newProduct->id = $product->product;
|
||||
$newProduct->name = $product->name;
|
||||
$newProduct->status = $product->status;
|
||||
|
||||
$processedProducts[$product->product] = $newProduct;
|
||||
$productStatusList['all']['total'] += 1;
|
||||
if(isset($productStatusList[$product->status])) $productStatusList[$product->status]['total'] += 1;
|
||||
}
|
||||
|
||||
/* Set story status statistics integrate into product. */
|
||||
$storyStatusList = array('draft' => array(), 'reviewing' => array(), 'active' => array(), 'changing' => array(), 'closed' => array());
|
||||
foreach($processedProducts as $productID => $product)
|
||||
{
|
||||
$product->storyStat = array();
|
||||
foreach(array_keys($storyStatusList) as $storyStatus) $product->storyStat[$storyStatus] = isset($productStoryStat[$productID][$storyStatus]) ? $productStoryStat[$productID][$storyStatus] : 0;
|
||||
$product->progress = $product->storyStat['closed'] == 0 ? 0 : round($product->storyStat['closed'] / array_sum($product->storyStat) * 100, 1);
|
||||
}
|
||||
|
||||
foreach(array_keys($productStatusList) as $status)
|
||||
{
|
||||
$statusName = zget($this->lang->product->statusList, $status);
|
||||
if($status == 'all') $statusName = $this->lang->product->allStory;
|
||||
if($status == 'normal') $statusName = $this->lang->product->unclosed;
|
||||
|
||||
$productStatusList[$status]['code'] = $status;
|
||||
$productStatusList[$status]['name'] = $statusName;
|
||||
}
|
||||
|
||||
foreach(array_keys($storyStatusList) as $status)
|
||||
{
|
||||
$statusName = zget($this->lang->story->statusList, $status);
|
||||
|
||||
$storyStatusList[$status]['code'] = $status;
|
||||
$storyStatusList[$status]['name'] = $statusName;
|
||||
}
|
||||
|
||||
return array('productStatusList' => $productStatusList, 'products' => array_values($processedProducts), 'storyStatusList' => $storyStatusList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bug progress by product.
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function bugProgress()
|
||||
{
|
||||
$this->app->loadLang('product');
|
||||
$this->app->loadLang('bug');
|
||||
|
||||
$bugStatusStat = $this->dao->select('t1.product, t2.name, t2.status, t1.status AS bugStatus, COUNT(1) AS bugCount')->from(TABLE_BUG)->alias('t1')
|
||||
->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product=t2.id')
|
||||
->where('t2.deleted')->eq(0)
|
||||
->andWhere('t1.deleted')->eq(0)
|
||||
->beginIF(!$this->app->user->admin)->andWhere('t2.id')->in($this->app->user->view->products)->fi()
|
||||
->groupBy('t1.product,t1.status')
|
||||
->orderBy('t1.product_desc,t1.status')
|
||||
->fetchAll();
|
||||
|
||||
$productStatusList['all']['total'] = 0;
|
||||
$productStatusList['normal']['total'] = 0;
|
||||
$productStatusList['closed']['total'] = 0;
|
||||
|
||||
$processedProducts = array();
|
||||
$productBugStat = array();
|
||||
foreach($bugStatusStat as $product)
|
||||
{
|
||||
$productBugStat[$product->product][$product->bugStatus] = $product->bugCount;
|
||||
|
||||
if(isset($processedProducts[$product->product])) continue;
|
||||
|
||||
$newProduct = new stdclass();
|
||||
$newProduct->id = $product->product;
|
||||
$newProduct->name = $product->name;
|
||||
$newProduct->status = $product->status;
|
||||
|
||||
$processedProducts[$product->product] = $newProduct;
|
||||
$productStatusList['all']['total'] += 1;
|
||||
if(isset($productStatusList[$product->status])) $productStatusList[$product->status]['total'] += 1;
|
||||
}
|
||||
|
||||
/* Set bug status statistics integrate into product. */
|
||||
$bugStatusList = array('active' => array(), 'resolved' => array(), 'closed' => array());
|
||||
foreach($processedProducts as $productID => $product)
|
||||
{
|
||||
$product->bugStat = array();
|
||||
foreach(array_keys($bugStatusList) as $bugStatus) $product->bugStat[$bugStatus] = isset($productBugStat[$productID][$bugStatus]) ? $productBugStat[$productID][$bugStatus] : 0;
|
||||
}
|
||||
|
||||
foreach(array_keys($productStatusList) as $status)
|
||||
{
|
||||
$statusName = zget($this->lang->product->statusList, $status);
|
||||
if($status == 'all') $statusName = $this->lang->product->allStory;
|
||||
if($status == 'normal') $statusName = $this->lang->product->unclosed;
|
||||
|
||||
$productStatusList[$status]['code'] = $status;
|
||||
$productStatusList[$status]['name'] = $statusName;
|
||||
}
|
||||
|
||||
foreach(array_keys($bugStatusList) as $status)
|
||||
{
|
||||
$statusName = zget($this->lang->bug->statusList, $status);
|
||||
|
||||
$bugStatusList[$status]['code'] = $status;
|
||||
$bugStatusList[$status]['name'] = $statusName;
|
||||
}
|
||||
|
||||
return array('productStatusList' => $productStatusList, 'bugs' => array_values($processedProducts), 'bugStatusList' => $bugStatusList);
|
||||
}
|
||||
}
|
||||
32
api/v1/entries/reporules.php
Normal file
32
api/v1/entries/reporules.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
/**
|
||||
* The reporules entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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 Yidong Wang <yidong@cnezsoft.com>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class repoRulesEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
$control = $this->loadController('repo', 'ajaxGetRules');
|
||||
$control->ajaxGetRules();
|
||||
|
||||
$data = $this->getData();
|
||||
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
return $this->send(200, $data->rules);
|
||||
}
|
||||
}
|
||||
56
api/v1/entries/repos.php
Normal file
56
api/v1/entries/repos.php
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
/**
|
||||
* The repos entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class reposEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
$control = $this->loadController('repo', 'maintain');
|
||||
$repoUrl = $this->param('repoUrl', '');
|
||||
|
||||
if(empty($repoUrl))
|
||||
{
|
||||
$control->maintain(0, $this->param('order', 'id_desc'), 0, $this->param('limit', 100), $this->param('page', 1));
|
||||
/* Response */
|
||||
$data = $this->getData();
|
||||
}
|
||||
else
|
||||
{
|
||||
$data = (object)$this->loadModel('repo')->getRepoListByUrl($repoUrl);
|
||||
}
|
||||
|
||||
if(isset($data->status) and $data->status == 'success')
|
||||
{
|
||||
if(empty($repoUrl))
|
||||
{
|
||||
$result = array();
|
||||
$pager = $data->data->pager;
|
||||
$repos = $data->data->repoList;
|
||||
foreach($repos as $repo) $result[] = $this->format($repo, 'deleted:bool,lastSync:datetime,synced:bool,product:idList');
|
||||
|
||||
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'repos' => $result));
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->send(200, array('repos' => $data->repos));
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
return $this->sendError(400, 'error');
|
||||
}
|
||||
}
|
||||
67
api/v1/entries/requiredfields.php
Normal file
67
api/v1/entries/requiredfields.php
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
/**
|
||||
* The required fields entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(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 Ruogu Liu <liuruogu@easycorp.ltd>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class requiredFieldsEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
* 获取所有模块的自定义必填字段配置
|
||||
* Get required fields configuration for all modules.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
$this->loadModel('custom');
|
||||
|
||||
/* Load language for all required modules. */
|
||||
foreach($this->config->custom->requiredModules as $requiredModule) $this->app->loadLang($requiredModule);
|
||||
|
||||
$result = array();
|
||||
|
||||
/* Get required fields for each module. */
|
||||
foreach($this->config->custom->requiredModules as $moduleName)
|
||||
{
|
||||
/* Load module config. */
|
||||
$this->loadModel($moduleName);
|
||||
if($moduleName == 'user') $this->app->loadModuleConfig($moduleName);
|
||||
|
||||
/* Get required fields. */
|
||||
$requiredFields = $this->custom->getRequiredFields($this->config->$moduleName);
|
||||
|
||||
/* Handle special case for doc module. */
|
||||
if($moduleName == 'doc')
|
||||
{
|
||||
unset($requiredFields['createlib']);
|
||||
unset($requiredFields['editlib']);
|
||||
}
|
||||
|
||||
/* Format result. */
|
||||
if(!empty($requiredFields))
|
||||
{
|
||||
$moduleFields = array();
|
||||
foreach($requiredFields as $method => $fields)
|
||||
{
|
||||
$moduleFields[$method] = array(
|
||||
'method' => $method,
|
||||
'fields' => explode(',', $fields),
|
||||
'fieldsString' => $fields
|
||||
);
|
||||
}
|
||||
|
||||
$result[$moduleName] = $moduleFields;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->send(200, $result);
|
||||
}
|
||||
}
|
||||
75
api/v1/entries/risk.php
Normal file
75
api/v1/entries/risk.php
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
/**
|
||||
* The risk entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class riskEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $riskID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($riskID)
|
||||
{
|
||||
$control = $this->loadController('risk', 'view');
|
||||
$control->view($riskID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data or (isset($data->message) and $data->message == '404 Not found')) return $this->send404();
|
||||
if(isset($data->status) and $data->status == 'success') return $this->send(200, $this->format($data->data->risk, 'createdDate:time,editedDate:time'));
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$this->sendError(400, 'error');
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT method.
|
||||
*
|
||||
* @param int $riskID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function put($riskID)
|
||||
{
|
||||
$control = $this->loadController('risk', 'edit');
|
||||
$oldRisk = $this->loadModel('risk')->getByID($riskID);
|
||||
if(!$oldRisk) return $this->send404();
|
||||
|
||||
/* Set $_POST variables. */
|
||||
$fields = 'source,name,category,strategy,status,impact,probability,rate,identifiedDate,plannedClosedDate,actualClosedDate,resolvedBy,assignedTo,prevention,remedy,resolution';
|
||||
$this->batchSetPost($fields, $oldRisk);
|
||||
|
||||
$control->edit($riskID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(400, $data->message);
|
||||
|
||||
$risk = $this->risk->getByID($riskID);
|
||||
return $this->send(200, $this->format($risk, 'createdDate:time,editedDate:time'));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE method.
|
||||
*
|
||||
* @param int $riskID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function delete($riskID)
|
||||
{
|
||||
$control = $this->loadController('risk', 'delete');
|
||||
$control->delete($riskID, 'true');
|
||||
|
||||
$this->getData();
|
||||
return $this->sendSuccess(200, 'success');
|
||||
}
|
||||
}
|
||||
87
api/v1/entries/risks.php
Normal file
87
api/v1/entries/risks.php
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
/**
|
||||
* The risks entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class risksEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($projectID = 0)
|
||||
{
|
||||
if(!$projectID)
|
||||
{
|
||||
/* Get my risks defaultly. */
|
||||
$control = $this->loadController('my', 'risk');
|
||||
$control->risk($this->param('type', 'assignedTo'), $this->param('order', 'id_desc'), $this->param('total', 0), $this->param('limit', 20), $this->param('page', 1));
|
||||
$data = $this->getData();
|
||||
}
|
||||
else
|
||||
{
|
||||
$project = $this->loadModel('project')->getByID($projectID);
|
||||
if(!$project) return $this->send404();
|
||||
|
||||
/* Get risks by project. */
|
||||
$control = $this->loadController('risk', 'browse');
|
||||
$control->browse($projectID, $this->param('type', 'all'), '', $this->param('order', ''), $this->param('total', 0), $this->param('limit', 20), $this->param('page', 1));
|
||||
$data = $this->getData();
|
||||
}
|
||||
|
||||
if(!isset($data->status)) return $this->sendError(400, 'error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$pager = $data->data->pager;
|
||||
$result = array();
|
||||
foreach($data->data->risks as $risk)
|
||||
{
|
||||
$result[] = $this->format($risk, 'createdDate:time,editedDate:time');
|
||||
}
|
||||
|
||||
return $this->send(200, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'risks' => $result));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($projectID = 0)
|
||||
{
|
||||
$control = $this->loadController('risk', 'create');
|
||||
$project = $this->loadModel('project')->getByID($projectID);
|
||||
if(!$project) return $this->send404();
|
||||
|
||||
$fields = 'source,name,category,strategy,status,impact,probability,rate,identifiedDate,plannedClosedDate,actualClosedDate,resolvedBy,assignedTo,prevention,remedy,resolution';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$this->setPost('impact', $this->request('impact', 3));
|
||||
$this->setPost('probability', $this->request('probability', 3));
|
||||
$this->setPost('rate', $this->request('rate', 9));
|
||||
$this->setPost('pri', 'middle');
|
||||
|
||||
$this->requireFields('name');
|
||||
|
||||
$control->create($projectID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
if(isset($data->result) and !isset($data->id)) return $this->sendError(400, $data->message);
|
||||
|
||||
$risk = $this->loadModel('risk')->getByID($data->id);
|
||||
|
||||
return $this->send(201, $this->format($risk, 'createdDate:time,editedDate:time'));
|
||||
}
|
||||
}
|
||||
133
api/v1/entries/stakeholders.php
Normal file
133
api/v1/entries/stakeholders.php
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
<?php
|
||||
/**
|
||||
* The stakeholder entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class stakeholdersEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $programID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($programID = 0)
|
||||
{
|
||||
if(!$programID) $programID = $this->param('program', 0);
|
||||
|
||||
if($programID)
|
||||
{
|
||||
$control = $this->loadController('program', 'stakeholder');
|
||||
$control->stakeholder($programID, $this->param('order', 't1.id_desc'), 0, $this->param('limit', 20), $this->param('page', 1));
|
||||
$data = $this->getData();
|
||||
}
|
||||
|
||||
if(isset($data->status) and $data->status == 'success')
|
||||
{
|
||||
$this->app->loadLang('stakeholder');
|
||||
$pager = $data->data->pager;
|
||||
$users = $data->data->users;
|
||||
$result = array();
|
||||
foreach($data->data->stakeholders as $stakeholder)
|
||||
{
|
||||
$stakeholder->roleName = zget($this->lang->user->roleList, $stakeholder->role, '');
|
||||
$stakeholder->typeName = zget($this->lang->stakeholder->fromList, $stakeholder->from, '');
|
||||
|
||||
$result[] = $stakeholder;
|
||||
}
|
||||
|
||||
$data = array();
|
||||
$data['page'] = $pager->pageID;
|
||||
$data['total'] = $pager->recTotal;
|
||||
$data['limit'] = (int)$pager->recPerPage;
|
||||
$data['stakeholders'] = $result;
|
||||
|
||||
$withUser = $this->param('withUser', '');
|
||||
if(!empty($withUser)) $data['users'] = $users;
|
||||
|
||||
return $this->send(200, $data);
|
||||
}
|
||||
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
return $this->sendError(400, 'error');
|
||||
}
|
||||
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post()
|
||||
{
|
||||
$control = $this->loadController('project', 'create');
|
||||
|
||||
$fields = 'name,begin,end,products';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$this->setPost('code', $this->request('code', ''));
|
||||
$this->setPost('acl', $this->request('acl', 'private'));
|
||||
$this->setPost('parent', $this->request('program', 0));
|
||||
$this->setPost('whitelist', $this->request('whitelist', array()));
|
||||
$this->setPost('PM', $this->request('PM', ''));
|
||||
$this->setPost('model', $this->request('model', 'scrum'));
|
||||
|
||||
$this->requireFields('name,code,begin,end,products');
|
||||
|
||||
$control->create($this->request('model', 'scrum'));
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
if(!isset($data->result)) return $this->sendError(400, 'error');
|
||||
|
||||
$project = $this->loadModel('project')->getByID($data->id);
|
||||
|
||||
return $this->send(201, $this->format($project, 'openedDate:time,lastEditedDate:time,closedDate:time,canceledDate:time'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get drop menu.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getDropMenu()
|
||||
{
|
||||
$control = $this->loadController('project', 'ajaxGetDropMenu');
|
||||
$control->ajaxGetDropMenu($this->request('projectID', 0), $this->request('module', 'project'), $this->request('method', 'browse'));
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
|
||||
$dropMenu = array('owner' => array(), 'other' => array(), 'closed' => array());
|
||||
foreach($data->data->projects as $programID => $projects)
|
||||
{
|
||||
foreach($projects as $project)
|
||||
{
|
||||
if(helper::diffDate(date('Y-m-d'), $project->end) > 0) $project->delay = true;
|
||||
$project = $this->filterFields($project, 'id,model,type,name,code,parent,status,PM,delay');
|
||||
|
||||
if($project->status == 'closed')
|
||||
{
|
||||
$dropMenu['closed'][] = $project;
|
||||
}
|
||||
elseif($project->PM == $this->app->user->account)
|
||||
{
|
||||
$dropMenu['owner'][] = $project;
|
||||
}
|
||||
else
|
||||
{
|
||||
$dropMenu['other'][] = $project;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->send(200, $dropMenu);
|
||||
}
|
||||
}
|
||||
127
api/v1/entries/stories.php
Normal file
127
api/v1/entries/stories.php
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
<?php
|
||||
/**
|
||||
* The stories entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class storiesEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $productID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($productID = 0)
|
||||
{
|
||||
if(!$productID) $productID = $this->param('product');
|
||||
if(!$productID) return $this->sendError(400, 'Need product id.');
|
||||
|
||||
$control = $this->loadController('product', 'browse');
|
||||
$control->browse($productID, $this->param('branch', ''), $this->param('status', 'unclosed'), 0, $this->param('type', 'story'), $this->param('order', 'id_desc'), 0, $this->param('limit', 500), $this->param('page', 1));
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data or !isset($data->status)) return $this->sendError(400, 'error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$stories = $data->data->stories;
|
||||
$pager = $data->data->pager;
|
||||
$requirements = $this->loadModel('story')->getRequirements($productID);
|
||||
if(!empty($requirements)) $requirements = $this->story->getByList(array_keys($requirements));
|
||||
|
||||
$result = array();
|
||||
$this->loadModel('product');
|
||||
foreach($stories as $story)
|
||||
{
|
||||
$product = $this->product->getById($story->product);
|
||||
$story->productStatus = $product->status;
|
||||
if(isset($story->children))
|
||||
{
|
||||
$story->children = array_values((array)$story->children);
|
||||
foreach($story->children as $id => $children)
|
||||
{
|
||||
$childrenProduct = $this->product->getById($children->product);
|
||||
$story->children[$id]->productStatus = $childrenProduct->status;
|
||||
}
|
||||
}
|
||||
|
||||
$result[] = $this->format($story, 'title:decodeHtml,openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList');
|
||||
}
|
||||
return $this->send(201, array('page' => $pager->pageID, 'total' => $pager->recTotal, 'limit' => $pager->recPerPage, 'stories' => $result, 'requirements' => $requirements));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $productID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($productID = 0)
|
||||
{
|
||||
if(!$productID) $productID = $this->param('product', 0);
|
||||
if(!$productID and isset($this->requestBody->product)) $productID = $this->requestBody->product;
|
||||
if(!$productID) return $this->sendError(400, 'Need product id.');
|
||||
|
||||
$control = $this->loadController('story', 'create');
|
||||
|
||||
$fields = 'title,spec,verify,module,reviewer,type,parent,moduleOptionMenu,source,sourceNote,category,pri,estimate,mailto,keywords,notifyemail,uid,status';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$module = $this->request('module', 0) ? $this->request('module', 0) : 0;
|
||||
$this->setPost('plans', array($this->request('plan', 0)));
|
||||
$this->setPost('branches', array($this->request('branch')));
|
||||
$this->setPost('modules', array($module));
|
||||
$this->setPost('product', $productID);
|
||||
$this->setPost('type', $this->request('type', 'story'));
|
||||
$this->setPost('grade', $this->request('grade', ''));
|
||||
|
||||
/* 获取评审相关参数 */
|
||||
$reviewer = $this->request('reviewer');
|
||||
$status = $this->request('status', 'active'); // 创建时默认状态为 'active'
|
||||
$forceReview = $this->loadModel('story')->checkForceReview($this->request('type', 'story'));
|
||||
if($forceReview)
|
||||
{
|
||||
$needNotReview = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
$needNotReview = empty($reviewer) ? 1 : 0;
|
||||
}
|
||||
|
||||
$this->setPost('reviewer', $reviewer);
|
||||
$this->setPost('needNotReview', $needNotReview);
|
||||
|
||||
/* 设置状态逻辑,与web端保持一致(参考 common.ui.js 中的 clickSubmit 函数) */
|
||||
/* 如果状态是 'active' 且有评审人且未勾选不需要评审,则将状态设置为 'reviewing' */
|
||||
$hasReviewer = !empty($reviewer);
|
||||
$isActiveNeedReview = $status == 'active' && !$needNotReview;
|
||||
|
||||
if($hasReviewer && $isActiveNeedReview)
|
||||
{
|
||||
$this->setPost('status', 'reviewing');
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 如果未指定状态,保持默认值 'active';如果指定了 'draft',保持 'draft' */
|
||||
$this->setPost('status', $status);
|
||||
}
|
||||
|
||||
$this->requireFields('title,spec,pri,category');
|
||||
|
||||
$control->create($productID, $this->param('branch', 0), $this->param('moduleID', 0), $this->param('storyID', 0), $this->param('objectID', 0), $this->param('bugID', 0), 0, 0, '', $this->param('type', 'story'));
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
if(isset($data->result) and !isset($data->id)) return $this->sendError(400, $data->message);
|
||||
|
||||
$story = $this->loadModel('story')->getByID($data->id);
|
||||
return $this->send(200, $this->format($story, 'openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList'));
|
||||
}
|
||||
}
|
||||
161
api/v1/entries/story.php
Normal file
161
api/v1/entries/story.php
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
<?php
|
||||
/**
|
||||
* The story entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class storyEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($storyID)
|
||||
{
|
||||
$this->resetOpenApp($this->param('tab', 'product'));
|
||||
|
||||
$control = $this->loadController('story', 'view');
|
||||
$control->view($storyID, 0, 0, $this->param('type', 'story'));
|
||||
|
||||
$data = $this->getData();
|
||||
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$story = $data->data->story;
|
||||
|
||||
if(!empty($story->children)) $story->children = array_values((array)$story->children);
|
||||
if(isset($story->planTitle)) $story->planTitle = array_values((array)$story->planTitle);
|
||||
if($story->parent > 0) $story->parentPri = $this->dao->select('pri')->from(TABLE_STORY)->where('id')->eq($story->parent)->fetch('pri');
|
||||
|
||||
/* Set product name and status*/
|
||||
$story->productName = $data->data->product->name;
|
||||
$story->productStatus = $data->data->product->status;
|
||||
|
||||
/* Set module title */
|
||||
$moduleTitle = '';
|
||||
if(empty($story->module)) $moduleTitle = '/';
|
||||
if($story->module)
|
||||
{
|
||||
$modulePath = $data->data->modulePath;
|
||||
foreach($modulePath as $key => $module)
|
||||
{
|
||||
$moduleTitle .= $module->name;
|
||||
if(isset($modulePath[$key + 1])) $moduleTitle .= '/';
|
||||
}
|
||||
}
|
||||
$story->moduleTitle = $moduleTitle;
|
||||
|
||||
$storyTasks = array();
|
||||
foreach($story->tasks as $executionTasks)
|
||||
{
|
||||
foreach($executionTasks as $task)
|
||||
{
|
||||
if(!isset($data->data->executions->{$task->execution})) continue;
|
||||
$storyTasks[] = $this->filterFields($task, 'id,name,type,status,assignedTo');
|
||||
}
|
||||
}
|
||||
$story->tasks = $this->format($storyTasks, 'assignedTo:user');
|
||||
|
||||
$story->bugs = array();
|
||||
foreach($data->data->bugs as $bug) $story->bugs[] = $this->filterFields($bug, 'id,title,status,pri,severity');
|
||||
|
||||
$story->cases = array();
|
||||
foreach($data->data->cases as $case) $story->cases[] = $this->filterFields($case, 'id,title,pri,status');
|
||||
|
||||
$story->requirements = array();
|
||||
foreach($data->data->relations as $relation) $story->requirements[] = $this->filterFields($relation, 'id,title');
|
||||
|
||||
$story->actions = $this->loadModel('action')->processActionForAPI($data->data->actions, $data->data->users, $this->lang->story);
|
||||
|
||||
$preAndNext = $data->data->preAndNext;
|
||||
$story->preAndNext = array();
|
||||
$story->preAndNext['pre'] = $preAndNext->pre ? $preAndNext->pre->id : '';
|
||||
$story->preAndNext['next'] = $preAndNext->next ? $preAndNext->next->id : '';
|
||||
|
||||
$actionBtnList = $this->loadModel('common')->buildOperateMenu($story, $story->type);
|
||||
$story->actionBtnList = array_column(zget($actionBtnList, 'mainActions', array()), 'icon');
|
||||
|
||||
return $this->send(200, $this->format($story, 'title:decodeHtml,openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList'));
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT method.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function put($storyID)
|
||||
{
|
||||
$control = $this->loadController('story', 'edit');
|
||||
$oldStory = $this->loadModel('story')->getByID($storyID);
|
||||
|
||||
/* Set $_POST variables. */
|
||||
$fields = 'title,product,parent,reviewer,type,plan,module,source,sourceNote,category,pri,estimate,mailto,keywords,uid,stage,notifyEmail,status,needNotReview';
|
||||
$this->batchSetPost($fields, $oldStory);
|
||||
|
||||
/* 设置状态逻辑,与web端保持一致(参考 common.ui.js 中的 clickSubmit 函数) */
|
||||
$reviewer = $this->request('reviewer');
|
||||
$status = $this->request('status', $oldStory->status);
|
||||
$forceReview = $this->loadModel('story')->checkForceReview($oldStory->type);
|
||||
if($forceReview)
|
||||
{
|
||||
$needNotReview = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
$needNotReview = empty($reviewer) ? 1 : 0;
|
||||
}
|
||||
|
||||
$this->setPost('reviewer', $reviewer);
|
||||
$this->setPost('needNotReview', $needNotReview);
|
||||
|
||||
/* 如果设置了评审人且满足以下条件之一,则将状态设置为 'reviewing':
|
||||
* 1. 状态是 'active' 且未勾选不需要评审
|
||||
* 2. 原状态是 'draft' 或 'changing' 且未在请求中指定状态
|
||||
*/
|
||||
$hasReviewer = !empty($reviewer);
|
||||
$isActiveNeedReview = $status == 'active' && !$needNotReview;
|
||||
$isDraftChangingWithoutStatus = strpos('draft,changing', $oldStory->status) !== false && !isset($this->requestBody->status);
|
||||
|
||||
if($hasReviewer && ($isActiveNeedReview || $isDraftChangingWithoutStatus))
|
||||
{
|
||||
$this->setPost('status', 'reviewing');
|
||||
}
|
||||
|
||||
$control->edit($storyID);
|
||||
|
||||
$data = $this->getData();
|
||||
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(400, $data->message);
|
||||
if(!isset($data->data)) return $this->sendError(400, 'error');
|
||||
|
||||
$story = $this->story->getByID($storyID);
|
||||
return $this->send(200, $this->format($story, 'openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList'));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE method.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function delete($storyID)
|
||||
{
|
||||
$control = $this->loadController('story', 'delete');
|
||||
$control->delete($storyID, 'yes');
|
||||
|
||||
$this->getData();
|
||||
return $this->sendSuccess(200, 'success');
|
||||
}
|
||||
}
|
||||
40
api/v1/entries/storyactive.php
Normal file
40
api/v1/entries/storyactive.php
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
/**
|
||||
* The bug change point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
**/
|
||||
|
||||
class storyActiveEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($storyID)
|
||||
{
|
||||
$control = $this->loadController('story', 'activate');
|
||||
|
||||
$fields = 'assignedTo,status,comment';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$control->activate($storyID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data || !isset($data->result)) return $this->send400('error');
|
||||
if($data->result == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$story = $this->loadModel('story')->getByID($storyID);
|
||||
|
||||
return $this->send(200, $story);
|
||||
}
|
||||
}
|
||||
|
||||
38
api/v1/entries/storyassignto.php
Normal file
38
api/v1/entries/storyassignto.php
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
/**
|
||||
* The story assignto entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class storyAssignToEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($storyID)
|
||||
{
|
||||
$control = $this->loadController('story', 'assignTo');
|
||||
|
||||
$fields = 'assignedTo,comment';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$control->assignTo($storyID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data) return $this->send400('error');
|
||||
if(isset($data->result) and $data->result == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$story = $this->loadModel('story')->getByID($storyID);
|
||||
|
||||
return $this->send(200, $this->format($story, 'openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList'));
|
||||
}
|
||||
}
|
||||
53
api/v1/entries/storychange.php
Normal file
53
api/v1/entries/storychange.php
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
/**
|
||||
* The bug change point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class storyChangeEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($storyID)
|
||||
{
|
||||
$control = $this->loadController('story', 'change');
|
||||
$oldStory = $this->loadModel('story')->getByID($storyID);
|
||||
|
||||
$fields = 'reviewer,comment,executions,bugs,cases,tasks,reviewedBy,uid';
|
||||
$this->batchSetPost($fields);
|
||||
$fields = 'title,spec,verify';
|
||||
$this->batchSetPost($fields, $oldStory);
|
||||
$this->setPost('status', 'reviewing');
|
||||
|
||||
/* If reviewer is not post, set needNotReview. */
|
||||
if(!$this->request('reviewer'))
|
||||
{
|
||||
$this->setPost('status', $oldStory->status);
|
||||
$this->setPost('reviewer', array());
|
||||
$this->setPost('needNotReview', 1);
|
||||
}
|
||||
|
||||
$this->requireFields('title');
|
||||
|
||||
$control->change($storyID, '', $oldStory->type);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data) return $this->send400('error');
|
||||
if(isset($data->result) && $data->result == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
if(isset($data->status) && $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$story = $this->loadModel('story')->getByID($storyID);
|
||||
|
||||
return $this->send(200, $this->format($story, 'openedDate:time,assignedDate:time,reviewedDate:time,lastEditedDate:time,closedDate:time'));
|
||||
}
|
||||
}
|
||||
38
api/v1/entries/storyclose.php
Normal file
38
api/v1/entries/storyclose.php
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
/**
|
||||
* The story close entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class storyCloseEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($storyID)
|
||||
{
|
||||
$control = $this->loadController('story', 'close');
|
||||
|
||||
$fields = 'closedReason,duplicateStory,comment';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$control->close($storyID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data) return $this->send400('error');
|
||||
if(isset($data->result) && $data->result == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$story = $this->loadModel('story')->getByID($storyID);
|
||||
|
||||
return $this->send(200, $this->format($story, 'openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList'));
|
||||
}
|
||||
}
|
||||
89
api/v1/entries/storygrade.php
Normal file
89
api/v1/entries/storygrade.php
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
/**
|
||||
* The story grade entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(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 Ruogu Liu <liuruogu@chandao.com>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class storygradeEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
* 获取所有层级
|
||||
* Get all story grades.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
$type = $this->param('type', '');
|
||||
$status = $this->param('status', 'enable');
|
||||
|
||||
$storyModel = $this->loadModel('story');
|
||||
|
||||
/* 如果指定了类型,获取该类型的层级列表 */
|
||||
if($type)
|
||||
{
|
||||
$gradeList = $storyModel->getGradeList($type);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 获取所有类型的层级,按类型分组 */
|
||||
$gradeList = array();
|
||||
$types = array('story', 'requirement', 'epic');
|
||||
foreach($types as $storyType)
|
||||
{
|
||||
$grades = $storyModel->getGradeList($storyType);
|
||||
if(!empty($grades))
|
||||
{
|
||||
foreach($grades as $grade)
|
||||
{
|
||||
$gradeList[] = $grade;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 根据status参数过滤 */
|
||||
if($status != 'all' && !empty($gradeList))
|
||||
{
|
||||
$filteredList = array();
|
||||
foreach($gradeList as $grade)
|
||||
{
|
||||
if(isset($grade->status) && $grade->status == $status)
|
||||
{
|
||||
$filteredList[] = $grade;
|
||||
}
|
||||
}
|
||||
$gradeList = $filteredList;
|
||||
}
|
||||
|
||||
/* 格式化返回数据 */
|
||||
$result = array();
|
||||
foreach($gradeList as $grade)
|
||||
{
|
||||
/* 如果指定了类型,返回数组格式 */
|
||||
if($type)
|
||||
{
|
||||
$result[] = $grade;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 如果未指定类型,按类型分组返回 */
|
||||
$gradeType = isset($grade->type) ? $grade->type : '';
|
||||
if(!isset($result[$gradeType]))
|
||||
{
|
||||
$result[$gradeType] = array();
|
||||
}
|
||||
$result[$gradeType][] = $grade;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->send(200, $result);
|
||||
}
|
||||
}
|
||||
29
api/v1/entries/storyrecall.php
Normal file
29
api/v1/entries/storyrecall.php
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
/**
|
||||
* The story recall entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class storyRecallEntry extends entry
|
||||
{
|
||||
/**
|
||||
* Delete method.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function delete($storyID)
|
||||
{
|
||||
$control = $this->loadController('story', 'recall');
|
||||
$control->recall($storyID, 'view', 'yes', $this->param('type', 'story'));
|
||||
|
||||
$this->getData();
|
||||
return $this->sendSuccess(200, 'success');
|
||||
}
|
||||
}
|
||||
62
api/v1/entries/storyrecordestimate.php
Normal file
62
api/v1/entries/storyrecordestimate.php
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
/**
|
||||
* The story recordWorkhour entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class storyRecordEstimateEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($storyID)
|
||||
{
|
||||
if($this->config->edition == 'open') return $this->send400('ZenTaoPMS does not have story effort function.');
|
||||
|
||||
$control = $this->loadController('effort', 'createForObject');
|
||||
$control->createForObject('story', $storyID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data) return $this->error('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$effort = $data->data->efforts;
|
||||
|
||||
return $this->send(200, array('effort' => $effort));
|
||||
}
|
||||
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($storyID)
|
||||
{
|
||||
if($this->config->edition == 'open') return $this->send400('ZenTaoPMS does not have story effort function.');
|
||||
|
||||
$control = $this->loadController('effort', 'createForObject');
|
||||
$fields = 'id,dates,consumed,objectType,objectID,work';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$control->createForObject('story', $storyID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$story = $this->loadModel('story')->getById($storyID);
|
||||
|
||||
return $this->send(200, $this->format($story, 'openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList'));
|
||||
}
|
||||
}
|
||||
40
api/v1/entries/storyreview.php
Normal file
40
api/v1/entries/storyreview.php
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
/**
|
||||
* The story review of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
**/
|
||||
|
||||
class storyReviewEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($storyID)
|
||||
{
|
||||
$control = $this->loadController('story', 'review');
|
||||
|
||||
$fields = 'reviewedDate,result,closedReason,pri,estimate,comment';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$control->review($storyID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$story = $this->loadModel('story')->getByID($storyID);
|
||||
|
||||
return $this->send(200, $this->format($story, 'openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList'));
|
||||
}
|
||||
}
|
||||
|
||||
31
api/v1/entries/storyreviewerrequired.php
Normal file
31
api/v1/entries/storyreviewerrequired.php
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
/**
|
||||
* The story reviewer required entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(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 Ruogu Liu <liuruogu@chandao.com>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class storyreviewerrequiredEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param string $storyType
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($storyType = '')
|
||||
{
|
||||
if(empty($storyType)) $storyType = $this->param('type', 'story');
|
||||
if(!in_array($storyType, array('story', 'requirement', 'epic'))) return $this->sendError(400, 'Invalid story type. Must be one of: story, requirement, epic.');
|
||||
|
||||
$this->loadModel('story');
|
||||
$reviewerRequired = $this->story->checkForceReview($storyType);
|
||||
|
||||
return $this->send(200, array('storyType' => $storyType, 'reviewerRequired' => (bool)$reviewerRequired));
|
||||
}
|
||||
}
|
||||
39
api/v1/entries/storysubmitreview.php
Normal file
39
api/v1/entries/storysubmitreview.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
/**
|
||||
* The story submit review entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class storySubmitReviewEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $storyID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($storyID)
|
||||
{
|
||||
$control = $this->loadController('story', 'submitReview');
|
||||
|
||||
$fields = 'reviewer,needNotReview';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$control->submitReview($storyID, $this->param('storyType', 'story'));
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data) return $this->send400('error');
|
||||
if(isset($data->result) && $data->result == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
if(isset($data->status) && $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$story = $this->loadModel('story')->getByID($storyID);
|
||||
|
||||
return $this->send(200, $this->format($story, 'openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList'));
|
||||
}
|
||||
}
|
||||
82
api/v1/entries/tabs.php
Normal file
82
api/v1/entries/tabs.php
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
/**
|
||||
* The tabs entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class tabsEntry extends baseEntry
|
||||
{
|
||||
/**
|
||||
* Get tabs.
|
||||
*
|
||||
* @param string $moduleName work|
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($moduleName)
|
||||
{
|
||||
$menus = array();
|
||||
if($moduleName == 'work')
|
||||
{
|
||||
$this->app->loadLang('my');
|
||||
$tabs = array('calendar', 'task', 'bug', 'story', 'issue', 'risk', 'myMeeting');
|
||||
|
||||
foreach($tabs as $menuKey)
|
||||
{
|
||||
if(!isset($this->lang->my->$menuKey)) continue;
|
||||
if(!common::hasPriv('my', 'work')) continue;
|
||||
$label = $this->lang->my->$menuKey;
|
||||
if($menuKey == 'calendar') $label = $this->lang->my->calendarAction;
|
||||
|
||||
$menu = new stdclass();
|
||||
$menu->code = $menuKey;
|
||||
$menu->name = $label;
|
||||
|
||||
$menus[] = $menu;
|
||||
}
|
||||
}
|
||||
elseif($moduleName == 'product')
|
||||
{
|
||||
$this->app->loadLang('product');
|
||||
$tabs = array('story', 'plan', 'project', 'release', 'epic', 'requirement', 'doc', 'view');
|
||||
|
||||
foreach($tabs as $menuKey)
|
||||
{
|
||||
if($menuKey == 'requirement' and empty($this->config->URAndSR)) continue;
|
||||
if(isset($this->lang->product->menu->$menuKey))
|
||||
{
|
||||
$menuName = $this->lang->product->menu->$menuKey;
|
||||
if(!isset($menuName['link'])) continue;
|
||||
|
||||
list($label, $module, $method) = explode('|', $menuName['link']);
|
||||
if(!common::hasPriv($module, $method)) continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!common::hasPriv('product', $menuKey)) continue;
|
||||
}
|
||||
|
||||
$label = zget($this->lang->product, $menuKey, '');
|
||||
if($menuKey == 'view') $label = $this->lang->overview;
|
||||
if($menuKey == 'doc') $label = $this->lang->doc->common;
|
||||
if($menuKey == 'project') $label = $this->lang->project->common;
|
||||
if($menuKey == 'story') $label = $this->lang->createObjects['story'];
|
||||
if($menuKey == 'requirement') $label = $this->lang->URCommon;
|
||||
if($menuKey == 'epic') $label = $this->lang->ERCommon;
|
||||
|
||||
$menu = new stdclass();
|
||||
$menu->code = $menuKey;
|
||||
$menu->name = $label;
|
||||
|
||||
$menus[] = $menu;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->send(200, array('tabs' => $menus));
|
||||
}
|
||||
}
|
||||
142
api/v1/entries/task.php
Normal file
142
api/v1/entries/task.php
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
<?php
|
||||
/**
|
||||
* The task entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class taskEntry extends entry
|
||||
{
|
||||
/**
|
||||
* GET method.
|
||||
*
|
||||
* @param int $taskID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function get($taskID)
|
||||
{
|
||||
$this->resetOpenApp($this->param('tab', 'execution'));
|
||||
|
||||
$control = $this->loadController('task', 'view');
|
||||
$control->view($taskID);
|
||||
|
||||
$data = $this->getData();
|
||||
|
||||
if(!$data or !isset($data->status)) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$task = $data->data->task;
|
||||
|
||||
if(!empty($task->children)) $task->children = array_values((array)$task->children);
|
||||
if($task->parent > 0) $task->parentPri = $this->dao->findById($task->parent)->from(TABLE_TASK)->fetch('pri');
|
||||
|
||||
/* Set execution name */
|
||||
$task->executionName = $data->data->execution->name;
|
||||
$task->executionStatus = $data->data->execution->status;
|
||||
|
||||
/* Set module title */
|
||||
$moduleTitle = '';
|
||||
if(empty($task->module)) $moduleTitle = '/';
|
||||
if($task->module)
|
||||
{
|
||||
$modulePath = $data->data->modulePath;
|
||||
foreach($modulePath as $key => $module)
|
||||
{
|
||||
$moduleTitle .= $module->name;
|
||||
if(isset($modulePath[$key + 1])) $moduleTitle .= '/';
|
||||
}
|
||||
}
|
||||
$task->moduleTitle = $moduleTitle;
|
||||
|
||||
$queryAccounts = array();
|
||||
if($task->assignedTo) $queryAccounts[$task->assignedTo] = $task->assignedTo;
|
||||
if(!empty($task->team))
|
||||
{
|
||||
foreach($task->team as $account => $team) $queryAccounts[$account] = $account;
|
||||
}
|
||||
$usersWithAvatar = $this->loadModel('user')->getListByAccounts($queryAccounts, 'account');
|
||||
|
||||
if(!empty($task->team))
|
||||
{
|
||||
$teams = array();
|
||||
foreach($task->team as $account => $team)
|
||||
{
|
||||
$user = zget($usersWithAvatar, $account, '');
|
||||
$team->realname = $user ? $user->realname : $account;
|
||||
$team->avatar = $user ? $user->avatar : '';
|
||||
$team->estimate = round($team->estimate, 1);
|
||||
$team->consumed = round($team->consumed, 1);
|
||||
$team->left = round($team->left, 1);
|
||||
|
||||
$allHours = $team->consumed + $team->left;
|
||||
$team->progress = empty($allHours) ? 0 : round($team->consumed / $allHours * 100, 1);
|
||||
|
||||
$teams[] = $team;
|
||||
}
|
||||
$task->team = $teams;
|
||||
}
|
||||
|
||||
$task->actions = $this->loadModel('action')->processActionForAPI($data->data->actions, $data->data->users, $this->lang->task);
|
||||
|
||||
$preAndNext = $data->data->preAndNext;
|
||||
$task->preAndNext = array();
|
||||
$task->preAndNext['pre'] = $preAndNext->pre ? $preAndNext->pre->id : '';
|
||||
$task->preAndNext['next'] = $preAndNext->next ? $preAndNext->next->id : '';
|
||||
|
||||
$operateMenu = $this->loadModel('common')->buildOperateMenu($task, 'task');
|
||||
$task->operateMenu = array_column(zget($operateMenu, 'mainActions', array()), 'name');
|
||||
|
||||
return $this->send(200, $this->format($task, 'deadline:date,openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,realStarted:time,finishedBy:user,finishedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,lastEditedBy:user,lastEditedDate:time,deleted:bool,mailto:userList'));
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT method.
|
||||
*
|
||||
* @param int $taskID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function put($taskID)
|
||||
{
|
||||
$control = $this->loadController('task', 'edit');
|
||||
$oldTask = $this->loadModel('task')->getByID($taskID);
|
||||
|
||||
/* Set $_POST variables. */
|
||||
$fields = 'name,type,mode,desc,assignedTo,pri,estimate,left,consumed,story,parent,execution,module,closedReason,status,estStarted,deadline,team,teamEstimate,teamConsumed,teamLeft,multiple,mailto,uid,teamSource,team,teamEstimate,teamConsumed,teamLeft';
|
||||
$this->batchSetPost($fields, $oldTask);
|
||||
|
||||
if($_POST['status'] == 'done')
|
||||
{
|
||||
if(!empty($oldTask->finishedBy)) $this->setPost('finishedBy', $oldTask->finishedBy);
|
||||
if(!empty($oldTask->finishedDate)) $this->setPost('finishedDate', $oldTask->finishedDate);
|
||||
}
|
||||
|
||||
$control->edit($taskID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
$task = $this->task->getByID($taskID);
|
||||
return $this->send(200, $this->format($task, 'deadline:date,openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,realStarted:time,finishedBy:user,finishedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,lastEditedBy:user,lastEditedDate:time,deleted:bool,mailto:userList'));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE method.
|
||||
*
|
||||
* @param int $taskID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function delete($taskID)
|
||||
{
|
||||
$control = $this->loadController('task', 'delete');
|
||||
$control->delete(0, $taskID, 'true');
|
||||
|
||||
$this->getData();
|
||||
return $this->sendSuccess(200, 'success');
|
||||
}
|
||||
}
|
||||
39
api/v1/entries/taskactive.php
Normal file
39
api/v1/entries/taskactive.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
/**
|
||||
* The task active entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
**/
|
||||
class taskActiveEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $taskID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($taskID)
|
||||
{
|
||||
$control = $this->loadController('task', 'activate');
|
||||
|
||||
$fields = 'assignedTo,team,teamSource,teamEstimate,teamConsumed,teamLeft,left,mode,multiple,comment';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$control->activate($taskID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$task = $this->loadModel('task')->getByID($taskID);
|
||||
|
||||
return $this->send(200, $this->format($task, 'openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,reviewedBy:user,reviewedDate:time,lastEditedBy:user,lastEditedDate:time,closedBy:user,closedDate:time,deleted:bool,mailto:userList'));
|
||||
}
|
||||
}
|
||||
|
||||
41
api/v1/entries/taskassignto.php
Normal file
41
api/v1/entries/taskassignto.php
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
/**
|
||||
* The task assignto entry point of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(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>
|
||||
* @package entries
|
||||
* @version 1
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class taskAssignToEntry extends entry
|
||||
{
|
||||
/**
|
||||
* POST method.
|
||||
*
|
||||
* @param int $taskID
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function post($taskID)
|
||||
{
|
||||
$control = $this->loadController('task', 'assignTo');
|
||||
$task = $this->loadModel('task')->getByID($taskID);
|
||||
|
||||
$fields = 'assignedTo,comment,left';
|
||||
$this->batchSetPost($fields);
|
||||
|
||||
$this->requireFields('assignedTo');
|
||||
|
||||
$control->assignTo($task->execution, $taskID);
|
||||
|
||||
$data = $this->getData();
|
||||
if(!$data) return $this->send400('error');
|
||||
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
|
||||
|
||||
$task = $this->loadModel('task')->getByID($taskID);
|
||||
|
||||
return $this->send(200, $this->format($task, 'openedDate:time,assignedDate:time,realStarted:time,finishedDate:time,canceledDate:time,closedDate:time,lastEditedDate:time'));
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue